前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >maven 插件之 maven-shade-plugin,解决同包同名 class 共存问题的神器

maven 插件之 maven-shade-plugin,解决同包同名 class 共存问题的神器

作者头像
青石路
发布于 2024-08-31 08:42:35
发布于 2024-08-31 08:42:35
47900
代码可运行
举报
文章被收录于专栏:开发技术开发技术
运行总次数:0
代码可运行

概述

maven-shade-plugin 官网已经介绍的很详细了,我给大家简单翻译一下

This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies.

这段话简明扼要的概述了 maven-shade-plugin 的功能

  1. 能够将项目连同其依赖,一并打包到一个 uber-jar 中 uber-jar 就是一个超级 jar,不仅包含我们的工程代码,还包括依赖的 jar,和 spring-boot-maven-plugin 类似
  2. 能够对依赖 jar 中的包名进行重命名 这个功能就有意思了,后面我们详说

maven-shade-plugin 必须和 Maven 构建生命周期的 package 阶段绑定,那么当 Maven 执行 mvn package 时会自动触发 maven-shade-plugin;使用很简单,在 pom.xml 添加该插件依赖即可

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.6.0</version>
    <executions>
        <execution>
            <!-- 和 maven package 阶段绑定 -->
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>

            <configuration>
                <!-- 按需自定义配置 -->
            </configuration>
        </execution>
    </executions>
</plugin>

phasegoal 按如上固定配置,configuration 才是我们自由发挥的平台;有了基本了解后,我们再结合官方提供的 Examples 来看看 maven-shade-plugin 具体能干啥

选择打包内容

假设我们有项目 maven-shade-plugin-demo,其项目结构如下

项目结构
项目结构

如果不做任何剔除,可以按如下配置进行全打包

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependencies>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.26</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.6.0</version>
            <executions>
                <execution>
                    <!--package 阶段绑定 -->
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <!-- 按需自定义配置 -->
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

执行 mvn package 后,我们会看到两个包

全打包
全打包

maven-shade-plugin-demo-1.0-SNAPSHOT.jar 就是 uber-jar;解压可看其结构

uber-jar结构
uber-jar结构

不仅包括 package、还包括各种配置文件、元文件,统统打包进 uber-jar;而 original-maven-shade-plugin-demo-1.0-SNAPSHOT.jar 则是不包括依赖 jar 的原始项目包;如果我们比较细心的话,会发现打包的时候告警了

全打包告警
全打包告警

意思是说 hutool jar 包中有 META-INF/MANIFEST.MF,而 maven-shade-plugin-demo 打包成 jar 后也包含 META-INF/MANIFEST.MF,两者重复了,只会将其中一个复制进 uber jar;默认情况下,是将我们项目的 jar 中的 META-INF/MANIFEST.MF 复制进 uber jar

默认用项目的MANIFEST
默认用项目的MANIFEST

那如果我们想保留 hutool 下的 MANIFEST.MF,而去掉 maven-shade-plugin-demo 中的 MANIFEST.MF,该如何处理呢?只需要微调下 configuration

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
    <filters>
        <filter>
            <artifact>com.qsl:maven-shade-plugin-demo</artifact>
            <excludes>
                <exclude>META-INF/*.MF</exclude>
            </excludes>
        </filter>
    </filters>
</configuration>

此时 uber jar 中的 MANIFEST.MF 就来自 hutool jar 了

换成hutool下的MANIFEST
换成hutool下的MANIFEST

回到前面的 configuration 配置,我们需要明白其每个子标签的含义

  1. filter:过滤器,可以配置多个
  2. artifact:复合标识符,用来匹配 jar,简单点说,就是匹配 jar 的 匹配规则 按 Maven 的坐标:groupId:artifactId[[:type]:classifier] 进行配置,groupId:artifactId 必配,[[:type]:classifier] 选配;支持通配符 *?,例如:<artifact>*:*</artifact>(相当于匹配上所有jar)
  3. exclude:排除项,也就是不会复制进 uber-jar;支持通配符配置
  4. include:包含项,也就是只有这些会被复制进 uber-jar;支持通配符配置

我们实战下,假设我们项目结构如下所示

明细配置项目结构
明细配置项目结构

configuration 配置如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
    <filters>
        <filter>
            <artifact>com.qsl:maven-shade-plugin-demo</artifact>
            <excludes>
                <exclude>com/qsl/test/**</exclude>
                <exclude>com/qsl/Entry.class</exclude>
            </excludes>
        </filter>
        <filter>
            <artifact>cn.hutool:hutool-all</artifact>
            <includes>
                <include>cn/hutool/Hutool.class</include>
                <include>cn/hutool/json/**</include>
            </includes>
        </filter>
    </filters>
</configuration>

执行 mvn package 后,uber-jar 内部结构你们能想到吗?我们来看看实际结果

明细配置后uber-jar结构
明细配置后uber-jar结构

是不是和跟你们想的一样?

除了手动指定 filter 外,此插件还支持自动移除项目中没有使用到的依赖类,以此来最小化 uber jar 的体积;configuration 配置如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
    <minimizeJar>true</minimizeJar>
</configuration>

我们在 StringUtil 中引入 hutool 的 StrUtil(相当于项目依赖了 StrUtil)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.qsl.util;

import cn.hutool.core.util.StrUtil;

/**
 * @author: 青石路
 */
public class StringUtil {

    public static boolean isBlank(String str) {
        return StrUtil.isBlank(str);
    }
}

然后打包,uber-jar 内部结构如下所示

最小依赖
最小依赖

从 maven-shade-plugin 1.6 开始,minimizeJar 会保留 filterinclude 配置的类,但是要注意:

inlcude 默认会排除所有不在 include 配置中的类

这就会导致问题,我们来看个案例,我们引入 logback 依赖,但代码中未用到它,而我们又想将其下的 class 复制进 uber-jar,另外我们还想将 hutool 的 cn/hutool/json 包下的全部类都复制进 uber-jar,并且开启 minimizeJar,是不是按如下配置?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependencies>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.26</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.3.14</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.6.0</version>
            <executions>
                <execution>
                    <!--package 阶段绑定 -->
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <minimizeJar>true</minimizeJar>
                        <filters>
                            <filter>
                                <artifact>ch.qos.logback:logback-classic</artifact>
                                <includes>
                                    <include>**</include>
                                </includes>
                            </filter>
                            <filter>
                                <artifact>cn.hutool:hutool-all</artifact>
                                <includes>
                                    <include>cn/hutool/json/**</include>
                                </includes>
                            </filter>
                        </filters>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

打包后看 uber-jar 目录结构

最小依赖_include
最小依赖_include

hutool 的 core 包没有复制进来,这是因为我们对 hutool 配置了 include ,默认把最小依赖的 core 包给排除掉了,那怎么办呢?插件提供了配置 <excludeDefaults>false</excludeDefaults> 来处理此种情况,它会覆盖 include 默认排除行为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<filter>
    <artifact>cn.hutool:hutool-all</artifact>
    <excludeDefaults>false</excludeDefaults>
    <includes>
        <include>cn/hutool/json/**</include>
    </includes>
</filter>

这样配置之后,既能包含 hutool 的 json 包,又能包含最小依赖的 core 包

false 通常配合 true 来使用,不然 <configuration> <filters> <filter> <artifact>cn.hutool:hutool-all</artifact> <excludeDefaults>false</excludeDefaults> <includes> <include>cn/hutool/json/**</include> </includes> </filter> </filters> </configuration> 这么配置有何意义?

重定位 class

如果 uber-jar 被其他项目依赖,而我们的 uber-jar 又是保留了依赖 jar 的 class 的全类名,那么就可能类重复而导致类加载冲突;比如项目A依赖了我们的 maven-shade-plugin-demo,还依赖了 B.jar,两个 jar 中都存在 cn.hutool.core.util.StrUtil.class,但 api 完全不一样,根据 双亲委派模型,只会成功加载其中某个 cn.hutool.core.util.StrUtil.class,那么另一个的 api 则使用不了。为了解决这个问题,插件提供了重定位功能,通过创建 class 字节码的私有副本,按新配置的 package,打包进 uber-jar

我们来看个案例,假设我们只需要 hutool 的 core 包,将其下所有的 class 按 com.qsl.core 包打包进 uber-jar,可以按如下配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependencies>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.26</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.6.0</version>
            <executions>
                <execution>
                    <!--package 阶段绑定 -->
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <relocations>
                            <relocation>
                                <pattern>cn.hutool.core</pattern>
                                <shadedPattern>com.qsl.core</shadedPattern>
                            </relocation>
                        </relocations>
                        <filters>
                            <filter>
                                <artifact>cn.hutool:hutool-all</artifact>
                                <includes>
                                    <include>cn/hutool/core/**</include>
                                </includes>
                            </filter>
                        </filters>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

打包后 uber-jar 目录结构如下

relocate
relocate

我们来看下 uber-jar 中的 StringUtil.class

StringUtil中的StrUtil路径
StringUtil中的StrUtil路径

依赖的 StrUtil 也被正确调整了,是不是很牛皮?

此时项目A 依赖 B.jar 的同时,又依赖我们的 maven-shade-plugin-demo,就不会类重名了(package 不一致了)

relocation 同样支持 excludeinclude

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
    <relocations>
        <relocation>
            <pattern>cn.hutool.core</pattern>
            <shadedPattern>com.qsl.core</shadedPattern>
            <!-- exclude 指定的不重定向,其他重定向 -->
            <excludes>
                <exclude>cn.hutool.core.util.ObjUtil</exclude>
                <!-- 一个*只会过滤包下的class,两个*会过滤包下的class和子包 -->
                <exclude>cn.hutool.core.date.**</exclude>
            </excludes>
        </relocation>
        <relocation>
            <pattern>cn.hutool.json</pattern>
            <shadedPattern>com.qsl.json</shadedPattern>
            <!-- include 指定的重定向,其他不重定向 -->
            <includes>
                <include>cn.hutool.json.JSONUtil</include>
                <!-- 一个*只会过滤包下的class,两个*会过滤包下的class和子包 -->
                <include>cn.hutool.json.xml.**</include>
            </includes>
        </relocation>
    </relocations>
    <filters>
        <filter>
            <artifact>cn.hutool:hutool-all</artifact>
            <includes>
                <include>cn/hutool/core/**</include>
                <include>cn/hutool/json/**</include>
            </includes>
        </filter>
    </filters>
</configuration>

此时 uber-jar 的目录结构是怎样的?你们自己去试!

生成附属包

前面已经介绍过,打包后会生成两个包

全打包
全打包

original 开头的那个明显不是按 Maven 坐标命名的,所以它是不能够 install 到本地或者远程仓库的;如果需要将两个 jar 都 install 到仓库中,那么就需要用到插件的 Attaching the Shaded Artifact (生成附属包)功能

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
    <relocations>
        <relocation>
            <pattern>cn.hutool.core</pattern>
            <shadedPattern>com.qsl.core</shadedPattern>
            <!-- exclude 指定的不重定向,其他重定向 -->
            <excludes>
                <exclude>cn.hutool.core.util.ObjUtil</exclude>
                <!-- 一个*只会过滤包下的class,两个*会过滤包下的class和子包 -->
                <exclude>cn.hutool.core.date.**</exclude>
            </excludes>
        </relocation>
        <relocation>
            <pattern>cn.hutool.json</pattern>
            <shadedPattern>com.qsl.json</shadedPattern>
            <!-- include 指定的重定向,其他不重定向 -->
            <includes>
                <include>cn.hutool.json.JSONUtil</include>
                <!-- 一个*只会过滤包下的class,两个*会过滤包下的class和子包 -->
                <include>cn.hutool.json.xml.**</include>
            </includes>
        </relocation>
    </relocations>
    <filters>
        <filter>
            <artifact>cn.hutool:hutool-all</artifact>
            <includes>
                <include>cn/hutool/core/**</include>
                <include>cn/hutool/json/**</include>
            </includes>
        </filter>
    </filters>
    <shadedArtifactAttached>true</shadedArtifactAttached>
    <shadedClassifierName>qsl</shadedClassifierName>
</configuration>

部署到仓库的 jar 如下

生成附属包
生成附属包

可执行 JAR

这个就比较简单了,我们直接看配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
    <transformers>
        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>com.qsl.Entry</mainClass>
        </transformer>
    </transformers>
</configuration>

如上配置会将 Main-Class 写进 uber-jar 的 MANIFEST.MF,还可以通过 manifestEntries 自定义属性

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
    <transformers>
        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <manifestEntries>
                <mainClass>com.qsl.Entry</mainClass>
                <Build-Author>qsl</Build-Author>
            </manifestEntries>
        </transformer>
    </transformers>
</configuration>

打包之后,uber-jar 的 MANIFEST.MF 内容如下

可执行jar
可执行jar

资源转换器

Resource Transformers 已经介绍的很详细了,我就不一一介绍了,挑几个个人认为比较重要的简单讲一下

ServicesResourceTransformer

合并 META-INF/services/ 下的文件,并对文件中的 class 进行重定向;我们来看个例子,hutool 下有文件 cn.hutool.aop.proxy.ProxyFactory

services_proxyFactory
services_proxyFactory

我们也自定义一个

自定义QslFactory
自定义QslFactory

configuration 配置如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
    <relocations>
        <relocation>
            <pattern>cn.hutool.aop</pattern>
            <shadedPattern>com.qsl.aop</shadedPattern>
        </relocation>
    </relocations>
    <transformers>
        <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
    </transformers>
</configuration>

打包后,hutool 与 uber-jar 的 cn.hutool.aop.proxy.ProxyFactory 文件内容差异如下

services_合并后前后对比
services_合并后前后对比

如果不配置 ServicesResourceTransformer,结果是怎样,你们自己去试

AppendingTransformer

将多个同名文件的内容合并追加到一起(不配置的情况下会覆盖,最终文件内容只是其中某个文件的内容),configuration 配置如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
    <transformers>
        <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
            <resource>META-INF/spring.factories</resource>
        </transformer>
    </transformers>
</configuration>

打包后文件内容合并如下

Append转换器
Append转换器

XmlAppendingTransformerResourceBundleAppendingTransformer 功能类似,只是针对的文件内容格式略微有点特殊,就不演示了,你们自行去测试

同包同名 class 共存

回到我们的主题,如果我们项目依赖的 jar 中出现了同名的 class (包名和类名均相同),根据 双亲委派模型,只会加载其中某一个 class,虽然两个 class 同名了,但功能完全不一样,另一个未被加载的 class 的功能则用不了,如果想同时使用这两个同名 class 的功能,我们该如何处理?

甲方扔给两个存在包名与类名均相同的Jar包,要在工程中同时使用怎么办?

文中给出了几种解决方案(注意看评论区),最高效最实用的当属 maven-shade-plugin;假设我们项目依赖的 A.jar 和 B.jar 都存在 com.qsl.Hello.class,我们可以新建一个项目,名字叫 qsl-a,没有任何代码,仅仅依赖 A.jar,然后利用 maven-shade-plugin 的 Relocating Classes 功能对 A.jar 中存在重名的 class 进行重定向,例如

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<configuration>
    <relocations>
        <relocation>
            <pattern>com.qsl</pattern>
            <shadedPattern>com.qsla</shadedPattern>
        </relocation>
        <includes>
            <include>com.qsl.Hello</include>
        </includes>
    </relocations>
</configuration>

然后打包得到 uber jar(qsl-a.jar),项目依赖从 A.jar 更改成 qsl-a.jar,B.jar 依赖继续保留,那么项目中可用的 Hello.class 就包括

com.qsl.Hello(B.jar) com.qsla.Hello(qsl-a.jar)

问题是不是就得到解决了?更实际的案例,敬请期待我下篇博客

总结

  1. maven-shade-plugin 的输入目标是 项目原始jar 以及 项目依赖的所有jar,而输出目标是 uber-jar,所以 maven-shade-plugin 的规则对 项目原始jar 是无效的
  2. minimizeJar 针对的只是 class,其他类型的文件不受此约束
  3. 同 class 共存问题,可以利用 maven-shade-plugin 的 Relocating Classes 功能,将其中一个或多个 jar 重新打包成新的 jar,保证类名相同但包名不同,然后项目依赖新的 jar,变相解决了同 class 共存问题
  4. 示例项目:maven-shade-plugin-demo
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-08-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
第八章:vue生命周期、vue的DOM操作、mixin混入,插件
开发过程中当多个组件开发时有相同类名时,此时vue会按照组件的导入顺序进行解析,后导入的组件 会覆盖先导入的组件类名样式
张哥编程
2024/12/13
1850
Vue 3 获取 DOM
訾博ZiBo
2025/01/06
940
Vue 3 获取 DOM
浅学Vue3
NPM的全称是Node Package Manager,是一个NodeJS包管理和分发工具,已经成为了非官方的发布Node模块(包)的标准。2020年3月17日,Github宣布收购npm,GitHub现在已经保证npm将永远免费。
QGS
2024/01/14
3940
vue中的 ref 和 $refs
都经历过被Dom操作支配的恐惧,现在很多框架也都帮我们完成了这部分操作,我们不用再去子元素、父元素,只负责数据逻辑即可,如Vue,但是如果我们在某些条件下,依然需要操作Dom时,怎么办呢?Vue提供了ref、$ref。本次,我们就详细讲讲这两个属性。
青年码农
2020/12/17
9580
vue中的 ref 和 $refs
每日一学Vue脚手架中基础的ref属性与原生id区别
vue脚手架的作用是用来自动一键生成vue+webpack的项目模版,包括依赖库,免去你手动安装各种插件,寻找各种cdn并一个个引入的麻烦。
淼学派对
2022/11/20
6410
每日一学Vue脚手架中基础的ref属性与原生id区别
vue操作dom元素的三种方法
vue中的ref是把当前dom元素 “ 抽离出来 ” ,只要通过 this.$refs就可以获取到
我不是费圆
2020/09/22
2.5K0
Vue组件
组件:拆分vue实例代码量,不同的组件来划分不同的功能模块,需要什么功能调用什么组件
切图仔
2022/09/08
6160
Vue组件
vue3与vue2的区别
新增context.emit,与this.$emit(vue3中只能在methods里使用)作用相同
前端小tips
2021/11/29
6930
vue3与vue2的区别
44. Vue使用ref获取dom元素以及组件引用
在普通的js操作中,一般都是直接操作dom元素,但是对于Vue.js框架来说,一般是不允许直接操作dom元素的。
Devops海洋的渔夫
2020/07/20
12.1K0
44. Vue使用ref获取dom元素以及组件引用
Vue子组件与父组件(看了就会)
<font color="red" size=4>另外,组件创建还有两种创建方式:
程序员海军
2022/02/15
1.1K0
vue组件高级(下)
每个vue的组件实例上,都包含一个 refs对象,里面存储着对应的DOM元素或组件的引用。默认情况下,组件的 refs指向一个空对象。
岳泽以
2022/10/26
1.9K0
Vue 05.组件
组件: 组件是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可; 组件化和模块化区别:
LittlePanger
2020/04/14
1K0
Vue篇(010)-vue3如何通过ref属性获取元素
1.在template中的写法跟vue2一样,给元素添加个ref='xxx' 2.在setup中,先创建一个响应式数据,并且要把响应式数据暴露出去 3.当元素被创建出来的时候,就会给对应的响应数据赋值 4.当响应式数据被赋值之后,就可以利用生命周期方法onMounted中获取对应的响应式数据,即DOM元素
齐丶先丶森
2022/05/12
3.7K0
Vue篇(010)-vue3如何通过ref属性获取元素
Vue学习笔记(二)
单页面应用程序 SPA,指的是一个 Web 网站中只有唯一一个 HTML 页面,所有的功能和交互都在这个唯一的页面内完成。
赤蓝紫
2023/01/01
2.4K0
Vue学习笔记(二)
Vue教程(ref和$refs的使用)
  在Vue中一般很少会用到直接操作DOM,但不可避免有时候需要用到,这时我们可以通过ref和$refs这两个来实现,本文我们就来详细的介绍下这个内容
用户4919348
2019/08/03
29.1K0
vue父子组件传值
父组件可以在引用子组件的时候, 通过属性绑定(v-bind:) 的形式, 把需要传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用。
砖业洋__
2023/05/06
5630
vue父子组件传值
Vue中$refs的理解
$refs是一个对象,持有注册过ref attribute的所有DOM元素和组件实例。
WindRunnerMax
2020/08/27
1.3K0
一口气复习完 Vue3 相关基础知识点
看完你就基本可以上手搞开发了,本文适合Vue初学者,或者Vue2迁移者,当然还是建议Vue3官网完全过一遍。不适合精通原理,源码的大佬们。
前端达人
2021/09/09
2.4K0
一口气复习完 Vue3 相关基础知识点
7.vue组件(二)--双向绑定,父子组件访问
子组件通过属性props: ["cmessage"], 来接收父组件的message属性. 并且父组件修改message的值, 子组件跟随改变
用户7798898
2021/03/04
1.1K0
7.vue组件(二)--双向绑定,父子组件访问
【Vue.js】934- 一文带你掌握Vue3新特性,再也不怕面试官啦
在Vue2.x时,我们要想给子组件传值,还得单独传入。Vue3.x直接以v-model:xxx形式传入参数,并且配合修饰符.sync进行数据同步更新。
pingan8787
2021/04/26
1.4K0
【Vue.js】934- 一文带你掌握Vue3新特性,再也不怕面试官啦
相关推荐
第八章:vue生命周期、vue的DOM操作、mixin混入,插件
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档