有没有小伙伴跟笔者一样项目做了好几个了,但是一直没有去总结的新特性呢?
今天笔者通过对比来总结新特性,希望可以让你们在回顾知识点的时候还能学习新的知识。相信你认真看完一定会有收获。
正所谓工欲善其事,必先利其器。在讲解新特性之前,笔者先来介绍几个插件。这样会大大提高我们的开发效率和体验。
使用开发项目的小伙伴肯定都认识这个神级插件。但是在中这个插件就显得捉襟见肘了,比如的多片段这个插件就会报错。
这个时候就需要使用,可以理解为版本的,代码高亮,语法提示,基本上有的它都有。
在中我们一直使用,在我们推荐使用,因为它支持的同时完全向前兼容,所以小伙伴们赶快去升级吧。
版本的不再支持,我们需要单独下载Vue.js devtools beta。(下载是需要梯子的哦,如果没有可以联系笔者)。
在下载之前,我们需要先卸载版本的,不然会有不能同时使用两个devtools的警告。
固然好用但是我们还是不能盲目追求新东西,在使用开发之前我们需清楚的知道它的兼容性。
不支持 IE8 及以下版本,因为 使用了 IE8 无法模拟的 ECMAScript 5 特性。但它支持所有兼容 ECMAScript 5 的浏览器。
不支持 IE11 及以下版本。
在中,我们只要定义在方法中的数据就是响应式数据。或者使用方法来定义响应式数据。
在中,如下情况响应式会失效
- 无法检测对象属性的添加或移除。
- 当你利用索引直接设置一个数组项时,例如:
- 当你修改数组的长度时,例如:
对于上面的缺陷,我们需要使用或来给对象或数组添加响应式属性。
还可以使用或来给对象或数组删除响应式属性。
在中使用方法。
但在中主要是使用和来定义响应式数据。由于使用的是进行响应式监听,所以新增、删除属性也都是响应式的,也就不需要使用上面的了。
接受一个内部值并返回一个响应式且可变的 对象。 对象仅有一个 ,指向该内部值。
一般用来定义基本类型的响应式数据。注意这里说的是一般,并不是说ref就不能定义引用类型的响应式数据。
使用定义的响应式数据在函数中使用需要加上,但在模板中可以直接使用。
检查值是否为一个 对象。
除了定义响应式数据还可以定义模板引用,类似的这个后面笔者在讲模板引用的时候会细说。
创建一个跟踪自身 变化的 ,但不会使其值也变成响应式的。
这句话怎么理解呢?就是我们使用创建出来的数据不是响应式的,也就是我们的修改页面并不会重新渲染。但是我们直接修改数据是会响应式的。
下面我们来看例子。
通过上面的例子我们可以发现,当响应式数据是基本数据类型的时候和没有差别。但是如果数据是引用数据类型的话的数据是响应式的而不是,需要给重新赋值才会触发响应式。
用来定义引用类型的响应式数据。注意,不能用来定义基本数据类型的响应式数据,不然会报错。
定义的对象是不能直接使用语法解构的,不然就会失去它的响应式,如果硬要解构需要使用方法。
用来检查对象是否是由 创建的响应式代理。
将解包所有深层的 ,同时维持 的响应性。
怎么理解这句话呢,就是使用定义响应式对象,里面的属性是定义的话可以直接赋值而不需要再,并且数据的修改是响应式的。
浅响应式,创建一个响应式代理,它跟踪其自身 的响应性,但不执行嵌套对象的深层响应式转换 (暴露原始值)。
并且与 不同,任何使用 的 都不会被代理自动解包。
简单理解就是响应式只会在第一层,不会深层响应式。类似于浅拷贝。
接受一个对象 (响应式或纯对象) 或 数据 并返回原始对象的只读代理。只读代理是深层的:任何被访问的嵌套 也是只读的。
怎么理解这句话呢,就是说只要是对象不管是普通对象还是定义的对象或者是定义的数据,定义成后就不能被修改了。
这里需要特别注意,是 返回的对象变成只读,源对象不会受到影响,所以修改源对象还是可以的。
用来检查对象是否是由 创建的只读代理。
与 一样,如果任何 使用了 ,当它通过代理访问时,则被自动解包。
浅只读,创建一个 ,使其自身的 为只读,但不执行嵌套对象的深度只读转换 (暴露原始值)。
并且与 不同,任何使用 的 都不会被代理自动解包。
简单理解就是只读的限制只会在第一层,不会深层只读。类似于浅拷贝。
检查对象是否是由 或 创建的 。
上面的例子有些小伙伴看了会比较懵逼,为什么有些是有些又是呢?其实你弄懂了就大概会清楚了。是不能处理基本数据类型的,所以不成功就会返回。
返回 或 代理的原始对象。这是一个“逃生舱”,可用于临时读取数据而无需承担代理访问/跟踪的开销,也可用于写入数据而避免触发更改。不建议保留对原始对象的持久引用。请谨慎使用。
标记一个对象,使其永远不会转换为 。返回对象本身。
因为不会被,也就是说不会响应式,相当于一个普通值。
如果参数是一个 ,则返回内部值,否则返回参数本身。这是 的语法糖函数。
可以用来为源响应式对象上的某个 新创建一个 。然后, 可以被传递,它会保持对其源 的响应式连接。
当你要将 的 传递给复合函数时, 很有用:
即使源 不存在, 也会返回一个可用的 。这使得它在使用可选 时特别有用,可选 并不会被 处理。
将响应式对象转换为普通对象,其中结果对象的每个 都是指向原始对象相应 的 。
当从组合式函数返回响应式对象时, 非常有用,这样消费组件就可以在不丢失响应性的情况下对返回的对象进行解构/展开:
只会为源对象中包含的 生成 。如果要为特定的 创建 ,则应当使用 。
创建一个自定义的 ,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收 和 函数作为参数,并且应该返回一个带有 和 的对象。
这个在我们自定义响应式的时候非常有用。比如我们在获取、设置值的时候做些特殊处理。
这个在中是没办法直接修改响应值的实现的,但是在可以。
下面是一个延迟响应式的例子。
手动执行与 关联的任何作用 ()。
为了让相关代码更紧凑提出了组合式,组合式能将同一个逻辑关注点相关代码收集在一起。 组合式的入口就是方法。
用官方语言说,是一个组件选项,在组件被创建之前, 被解析之后执行。它是组合式 的入口。
的写法有两种,可以跟一样直接导出也可以导出对象。若要对传递给 的参数进行类型推断,你需要使用 defineComponent。
执行时机
从生命周期的角度来看,它会在之前执行。也就是创建组件会依次执行、、。
this指向
在 中你应该避免使用 ,因为它不会找到组件实例。 的调用发生在 property、 property 或 被解析之前,所以它们无法在 中被获取。
参数
选项是一个接收 和 的函数。
props
函数中的第一个参数是 。就是我们父组件给子组件传递的参数。
正如在一个标准组件中所期望的那样, 函数中的 是响应式的,当传入新的 时,它将被更新。
因为 是响应式的,你 不能使用 ES6 解构,它会消除 prop 的响应性。
如果需要解构请使用方法。
如果 是可选的 ,则传入的 中可能没有 。在这种情况下, 将不会为 创建一个 。你需要使用 替代它:
context
是一个普通的 对象,也就是说,它不是响应式的,这意味着你可以安全地对 使用 解构。
和 是有状态的对象,它们总是会随组件本身的更新而更新。这意味着你应该避免对它们进行解构,并始终以 或 的方式引用 。请注意,与 不同, 和 的 是非响应式的。如果你打算根据 或 的更改应用副作用,那么应该在 生命周期钩子中执行此操作。
这里我们重点说下的使用。
假如我们想在父组件中直接调用子组件的方法该怎么做呢?我们就可以在子组件中使用把属性或方法暴露出去。在父组件我们就可以通过子组件的直接调用了。
使用的时候需要注意:
- 当组件没定义暴露内容的时候,通过获取到的就是组件自身的内容,也就是函数的内容。
- 当定义了暴露内容的时候,通过ref获取到的就是组件暴露内容,并且函数的内容会失效,也就是会被覆盖。
返回值
返回的所有内容都暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。所以我们在模板中需要使用到的数据都需要通过方法出来。
上面的话怎么理解呢?就是我们在模板,或者选项式写法的计算属性、方法、生命周期钩子等等中使用的数据都需要在方法中通过返回出来。
结合模板使用
如果 返回一个对象,那么该对象的 以及传递给 的 参数中的 就都可以在模板中访问到。
结合渲染函数使用
还可以返回一个渲染函数,该函数可以直接使用在同一作用域中声明的响应式状态。
返回一个渲染函数将阻止我们返回任何其它的东西。我们可以通过我们上面介绍的 来解决这个问题,给它传递一个对象,其中定义的 将可以被外部组件实例访问。
要使用这个语法,需要将 attribute 添加到 代码块上:
里面的代码会被编译成组件 函数的内容。这意味着与普通的 只在组件被首次引入的时候执行一次不同, 中的代码会在每次组件实例被创建的时候执行。
顶层的绑定会被暴露给模板
当使用 的时候,任何在 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用:
import 导入的内容也会以同样的方式暴露。意味着可以在模板表达式中直接使用导入的 helper 函数,并不需要通过 选项来暴露它:
响应式
响应式状态需要明确使用响应式 APIs来创建。和从 函数中返回值一样, 值在模板中使用的时候会自动解包:
使用组件
范围里的值也能被直接作为自定义组件的标签名使用:
将 看做被一个变量所引用。如果你使用过 JSX,在这里的使用它的心智模型是一样的。其 kebab-case 格式的 同样能在模板中使用。不过,我们强烈建议使用 PascalCase 格式以保持一致性。同时也有助于区分原生的自定义元素。
动态组件
由于组件被引用为变量而不是作为字符串键来注册的,在 中要使用动态组件的时候,就应该使用动态的 来绑定:
递归组件
一个单文件组件可以通过它的文件名被其自己所引用。例如:名为 的组件可以在其模板中用 引用它自己。
请注意这种方式相比于 import 导入的组件优先级更低。如果有命名的 import 导入和组件的推断名冲突了,可以使用 import 别名导入:
命名空间组件
可以使用带点的组件标记,例如 来引用嵌套在对象属性中的组件。这在需要从单个文件中导入多个组件的时候非常有用:
使用自定义指令
全局注册的自定义指令将以符合预期的方式工作,且本地注册的指令可以直接在模板中使用,就像上文所提及的组件一样。
但这里有一个需要注意的限制:必须以 的形式来命名本地自定义指令,以使得它们可以直接在模板中使用。
和
在 中必须使用 和 API 来声明 和 ,它们具备完整的类型推断并且在 中是直接可用的:
和 都是只在 中才能使用的编译器宏。他们不需要导入且会随着 处理过程一同被编译掉。
接收与 相同的值, 也接收 相同的值。
传入到 和 的选项会从 setup 中提升到模块的范围。因此,传入的选项不能引用在 setup 范围中声明的局部变量。这样做会引起编译错误。但是,它可以引用导入的绑定,因为它们也在模块范围内。
defineExpose
使用 的组件是默认关闭的,也即通过模板 ref 或者 链获取到的组件的公开实例,不会暴露任何在 中声明的绑定。
为了在 组件中明确要暴露出去的属性,使用 编译器宏,他也是不需要导入且会随着 处理过程一同被编译掉。
当父组件通过模板 ref 的方式获取到当前组件的实例,获取到的实例可以获取到属性 (ref 会和在普通实例中一样被自动解包)。跟前面说的是一样的。
useSlots 和 useAttrs
在 使用 和 的情况应该是很罕见的,因为可以在模板中通过 和 来访问它们。在你的确需要使用它们的罕见场景中,可以分别用 和 两个辅助函数:
和 是真实的运行时函数,它会返回与 和 等价的值,同样也能在普通的组合式 API 中使用。
与普通的 一起使用
可以和普通的 一起使用。普通的 在有这些需要的情况下或许会被使用到:
- 无法在 声明的选项,例如 或通过插件启用的自定义的选项。
- 声明命名导出。
- 运行副作用或者创建只需要执行一次的对象。
该场景下不支持使用 函数。请使用一个普通的 结合 选项来代替。
顶层
中可以使用顶层 。结果代码会被编译成 :
另外, 的表达式会自动编译成在 之后保留当前组件实例上下文的格式。
注意 必须与 组合使用, 目前还是处于实验阶段的特性。
不能和src混合使用
不能和 attribute 一起使用。
计算属性和监听器
是计算属性,意思就是会缓存值,只有当依赖属性发生变化的时候才会重新计算。
在中计算属性很简单,是一个对象,只需要简单定义就可以使用。
在中,是函数式的,并且需要先引入。
立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。
怎么理解这句话呢?就是它会自动收集依赖,不需要手动传入依赖。当里面用到的数据发生变化时就会自动触发。并且 会先执行一次用来自动收集依赖。而且 无法获取到变化前的值,只能获取变化后的值。
在上面这个例子中,首先会执行输出27,当我们触发方法改变的时候,因为是的依赖,所以会再次执行,输出28。
停止侦听
当 在组件的 函数或生命周期钩子被调用时,侦听器会被链接到该组件的生命周期,并在组件卸载时自动停止。
在一些情况下,也可以显式调用返回值以停止侦听:
清除副作用
有时副作用函数会执行一些异步的副作用,这些响应需要在其失效时清除。所以侦听副作用传入的函数可以接收一个 函数作入参,用来注册清理失效时的回调。当以下情况发生时,这个失效回调会被触发:
- 副作用即将重新执行时
- 侦听器被停止 (如果在 或生命周期钩子函数中使用了 ,则在组件卸载时)
清除副作用很多同学可能不太理解,下面笔者用个例子解释下。
假设我们需要在框输入关键字进行实时搜索,又不想请求太频繁我们就可以用到这个功能了。
上面的例子中依赖了,所以我们只要在输入值就会立马进入。如果不处理的话后端服务压力可能会很大,因为我们只要输入框值改变了就会发送请求。
我们可以利用清除副作用回调函数,在用户输入完一秒后再向后端发送请求。因为第一次是不会执行回调方法的,只有在副作用重新执行或卸载的时候才会执行该回调函数。
所以在我们输入的时候,会一直输出,当我们停止输入一秒后会输出,然后发送请求给后端。这样就达到我们最开始的目标了。
类似的还可以应用到事件监听上。这个小伙伴们可以自己试试。
副作用刷新时机
的响应性系统会缓存副作用函数,并异步地刷新它们,这样可以避免同一个“tick” 中多个状态改变导致的不必要的重复调用。在核心的具体实现中,组件的 函数也是一个被侦听的副作用。当一个用户定义的副作用函数进入队列时,默认情况下,会在所有的组件 前执行。也就是会在组件生命周期函数之前执行。
上面的例子,当我们触发方法修改的时候,会先执行然后执行。
如果需要在组件更新后重新运行侦听器副作用,我们可以传递带有 选项的附加 对象 (默认为 )。
上面的例子,当我们触发方法修改的时候,会先执行然后执行。
选项还接受 ,这将强制效果始终同步触发。然而,这是低效的,应该很少需要。这个参数是什么意思呢?很多同学可能不理解,这里我们重点解释下。
当只有一个依赖的时候这个参数和是没区别的。但是当有多个依赖的时候,和 只会执行一次副作用,但是会执行多次,也就是有一个依赖改变就会执行一次。
下面我们看例子
在上面的例子中,有和两个依赖,当我们触发方法的时候,如果这个副作用会执行两次,依次输出、、。
如果你想让每个依赖发生变化都执行但又不想设置你也可以使用等待侦听器在下一步改变之前运行。
上面的例子会依次输出、、、。
从 开始,我们也可以使用别名方法 和 ,这样可以用来让代码意图更加明显。
watchPostEffect
就是 的别名,带有 选项。
watchSyncEffect
就是 的别名,带有 选项。
侦听器调试
和 选项可用于调试侦听器的行为。
- 将在响应式 或 作为依赖项被追踪时被调用。
- 将在依赖项变更导致副作用被触发时被调用。
这个有点类似前面说的生命周期函数和,一个最初次渲染时调用,一个在数据更新的时候调用。
这两个回调都将接收到一个包含有关所依赖项信息的调试器事件。
和 只能在开发模式下工作。
所以可以简单理解为、和的组合。
需要侦听特定的数据源,并在单独的回调函数中执行副作用。默认情况下,它也是惰性的——即回调仅在侦听源发生变化时被调用。
与 相比, 有如下特点
- 惰性地执行副作用
- 更具体地说明应触发侦听器重新运行的状态
- 可以访问被侦听状态的先前值和当前值
类似里面的。
监听单一源
需要注意,当监听的数据是基本数据类型是需要使用箭头函数写法,不然监听不到。
上面说了,当监听的数据是基本数据类型时需要使用箭头函数写法,那使用箭头函数监听引用数据类型,能监听到吗?
除非开启深度监听
监听多个源
监听多个源我们使用数组。
这里我们需要注意,监听多个源只要有一个源发生变化,回调函数都会执行。
监听引用数据类型
有时我们可能需要监听一个对象的改变,而不是具体某个属性。
上面的写法有没有问题呢?当我们触发方法修改的时候可以发现我们输出两个值是一样的。这就是引用数据类型的坑。当我们不需要知道的时候这样写没问题,但是当我们需要对比新老值的时候这种写法就不行了。
我们需要监听这个引用数据类型的拷贝。当引用数据类型简单的时候我们可以直接解构成新对象。
这样输出来的值才是正确的。
但是当引用数据类型复杂的时候我们就需要用到深拷贝了。深拷贝前面笔者有文章介绍,可以自己写深拷贝方法或者引用库。
比如这里,我们想监听就必须使用深度拷贝,不然改变我们是监听不到的。
通过拷贝,我们就能获取到新老值了。如果不用拷贝,是获取不到老值的。
中好像没办法解决这个问题。
关于引用数据类型,还有个坑需要特别注意,就是监听引用数据类型里面的引用数据类型。也就是上面的。能直接监听吗?
对于引用数据类型里面的引用数据类型,需要分两种情况讨论。如果引用数据类型发生改变但是并没换地址,只是里面属性值的修改是能监听到的。比如下面的例子:
但是对于直接修改地址是监听不到的,如果要监听,需要使用下面这种箭头函数的监听方式。
深度监听和立即执行
还是支持的深度监听和立即执行的
所以关于监听总结就是
- 监听基本数据类型需要使用箭头函数方式,否则监听不到。
- 监听引用数据类型可以直接监听,但是新老值是一样的,如果需要对比新老值需要使用箭头函数并搭配深拷贝或浅拷贝的方式。
- 使用箭头函数也能监听引用数据类型,我们如果不需要对比新老值,可以直接使用第三个参数开启深度监听即可。如果需要对比新老值就没必要使用这种方式了,需要看情况使用深拷贝和浅拷贝。
- 对于监听引用数据类型里面的引用数据类型需要格外注意,需要判断引用数据类型是属性值改变还是地址改变,属性值改变可以直接监听,地址改变需要使用箭头函数的方式或者看情况使用深拷贝和浅拷贝。
还支持 的停止侦听、清除副作用、副作用刷新时机、侦听器调试,下面笔者只简单介绍使用方法,就不详细解释了。
停止侦听
在中,停止侦听用法和一样。
清除副作用
在中,函数会作为回调的第三个参数传递进来。
副作用刷新时机
在中,副作用刷新时机是在第三个参数中配置。
侦听器调试
在中,侦听器调试是在第三个参数中配置。
提供了一种干净的方法,允许我们控制在 中哪个父节点下渲染了 ,而不必求助于全局状态或将其拆分为两个组件。
什么意思呢?就是我们组件的节点可以通过挂载到任意位置。
比如我们的组件里面就可以通过把挂载到为的节点下。
我们来看看渲染效果,发现我们写在页面的元素被挂载到了节点下。
的属性必须是有效的查询选择器或
还支持选项。此可选属性可用于禁用 的功能,这意味着其插槽内容将不会移动到任何位置,而是在你在周围父组件中指定了 的位置渲染。
我们在中肯定写过这样的代码
就是用来更优雅的展示内容。需要搭配使用。
组件有两个插槽。它们都只接收一个直接子节点。 插槽里的节点会尽可能展示出来。如果不能,则展示 插槽里的节点。
注意,Suspense 是一个试验性的新特性,其 API 可能随时会发生变动。特此声明,以便社区能够为当前的实现提供反馈。生产环境请勿使用。我们目前了解有这个东西即可。
现在正式支持了多根节点的组件,也就是片段!什么意思呢?下面看个例子就明白了。
在 中,由于不支持多根节点组件,当其被开发者意外地创建时会发出警告。结果是,为了修复这个问题,许多组件被包裹在了一个 中。
在 中,组件可以包含多个根节点!但是,这要求开发者显式定义 应该分布在哪里。
这一段是什么意思呢?我们先来说说。
在中,我们知道包含了父作用域中不作为 被识别 (且获取) 的 绑定 ( 和 除外)。
上面的例子输出没在子组件接收的和所以会输出(因为 和 会被忽略)。
在中有了更改,被转移到的第二个参数上,。并且 和 也都不再忽略了。也就是说 和 也会在里面。
上面会输出全部未被接收的,输出。
在中由于只有一个片段,所以未在定义的属性会直接挂载在根片段上。但是由于支持多个片段,所以如果使用了多片段并且有未在定义的属性就会抛出警告,因为它不知道把这些未定义在中的属性挂载到哪个片段上,所以就需要我们使用来显示指定了。
我们先来看看只有一个片段的时候,未定义在中的属性都挂载在根片段上了。
但是我们使用多片段的时候它会提示警告,
当我们在第1个定义后我们发现未定义在中的属性都挂载在该片段上了。
看到这小伙伴们是不是就懂了呢。虽然支持多片段,但是我们需要定义。
既然讲到了,我们再讲讲的改动。
我们知道在中包含了父作用域中的 (不含 修饰器的) 事件监听器。
但是在,被移除了,父作用域中的事件监听器也被放到了里面。相当于是合并在一起了。
首先我们来看看和的生命周期函数。
虽然提倡把生命周期函数都放到中,但是那种选项式写法还是支持的。
总结
- 相较于少了、两个生命周期方法。
- 销毁生命周期方法名也发生了变化,由、变为、,这样是为了更好的与、 相对应。
- 写在函数中生命周期方法名就是前面多加了。
基本的生命周期函数我想不必笔者多说小伙伴们应该都很清楚了。下面重点说下 、 两个方法。
简单理解就是,首次渲染时,模板里面进行了哪些操作,以及该操作的目标对象和键。
如果有多个属性,这个方法会被触发多次。
我们来看例子
页面首次加载只会触发方法。
因为模板里面用到了和所以该方法会被触发两次输出和。因为是定义的,所以始终是,并且只是读操作,所以为。是定义的,并且我们只使用了属性所以是并且只是读操作,所以为。
简单理解就是,页面更新渲染时,模板里面进行了哪些操作,以及该操作的目标对象和键。
如果有多个属性被修改,这个方法会被触发多次。
我们来看例子
我们点击按钮来修改name,这里只会触发方法一次。并且输出,因为是修改所以是。
有些人可能好奇,所有的生命周期函数顺序到底是怎么样的呢?
我们分单组件和父子组件来说明。
单组件
页面首次加载
页面更新
页面卸载
父子组件
页面首次加载
页面更新
纯父组件属性更新
纯子组件属性更新
父组件属性更新,该属性在子组件中有被使用
子组件属性更新,该属性在父组件中有被使用
页面卸载
注意上面生命周期函数调用顺序在 中也是一致的,只不过 没有 、 、 ,并且销毁方法是 、 。
在 中,我们可以通过事件来监听组件生命周期中的关键阶段。这些事件名都是以 前缀开头,并跟随相应的生命周期钩子的名字。
在 中,这个前缀已被更改为 。额外地,这些事件现在也可用于 HTML 元素,和在组件上的用法一样。
或者在驼峰命名法的情况下附带前缀 :
任何全局改变 行为的 现在都会移动到应用实例上上,以下是部分全局 及其相应实例 的表,如需了解很多可以查看官网。
通过方法创建。
在中我们是这样使用的
在中是这样的,需要手动引入
在中 这样的全局 API 是不支持 的,不管它们实际上是否被使用了,都会被包含在最终的打包产物中。
而中的引入时写法可以能减少打包体积。
在中 指令在表单 、 及 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
在内部为不同的输入元素使用不同的 并抛出不同的事件:
- text 和 textarea 元素使用 property 和 事件;
- checkbox 和 radio 使用 property 和 事件;
- select 字段将 作为 prop 并将 作为事件。
在中只对上面几个表单项做了特殊处理。如果在自定义组件上使用需要在组件内通过参数指明的属性和事件。
如果不指明它的值默认是,事件默认是事件。
有了这样我们的自定义组件也能使用啦。在输入框输入的时候会出事件,这个事件会直接修改父组件的值。
除了使用,还可以使用修饰符来直接修改父元素数据。
父组件传递给子组件的值如果带了就可以在子组件通过事件直接修改该值而不用再暴露事件在父组件去修改。
这样我们点击子组件按钮触发方法,父组件的值会变成。
在中得到了加强,自定义组件也可以使用了。而不用去指定或者使用参数了。
默认情况下,组件上的 使用 作为 prop 和 作为事件。
当我们点击子组件按钮触发方法,会直接修改父组件的值。
自定义参数名
我们可以通过向 传递参数来修改这些名称:
当我们点击子组件按钮触发、方法,会直接修改父组件的、值。
多个参数
我们还可以通过向 传递多个参数,这在中是不可以的。
修饰符
除了支持、 和 修饰符。还支持添加自己的自定义修饰符。
下面笔者写个修饰符,用来转换字母为大写。
我们通过传递,在子组件中接收,这个属性里面存放传递的修饰符,比如我们传递了它的值就是,所以我们可以根据这个属性还自定义操作。
对于带参数的 绑定,生成的 prop 名称将为 ,这里笔者就不再细说了。
在中,是不能定义在节点上的。但是在中支持了。
在中的优先级是比高的,在一个元素上同时使用 和 时, 会优先作用。
下面我们根据数据字段进行遍历展示,在中是可行的。但是在这样是不可行的。因为在中的优先级比更高,所以在中访问不到。
在中需要这样写。
在一个元素上动态绑定 attribute 时,同时使用 语法和独立 attribute 是常见的场景。然而,这就引出了关于合并的优先级的问题。
在 中,如果一个元素同时定义了 和一个相同的独立 attribute,那么这个独立 attribute 总是会覆盖 中的绑定。
在 中,如果一个元素同时定义了 和一个相同的独立 attribute,那么绑定的声明顺序将决定它们如何被合并。后面的会覆盖前面的。
在中,传递给带有 的组件的事件监听器只能通过 触发。如果要将原生 DOM 监听器添加到子组件的根元素中,可以使用 修饰符:
这里的被修饰的就是原生事件,当点击的时候才会触发。
在中 的 修饰符已被移除。同时,新增的 选项允许子组件定义真正会被触发的事件。
因此,对于子组件中未被定义为组件触发的所有事件监听器,Vue 现在将把它们作为原生事件监听器添加到子组件的根元素中 (除非在子组件的选项中设置了 )。
子组件
在上面的例子中,因为子组件定义了,也就是说组件说明了,我只会暴露出事件,其他的事件你就当原生事件处理就可以了。所以事件就是原生事件了。
在 vue2 中,在 中使用的 attribute 会用 ref 数组填充相应的 property。当存在嵌套的 时,这种行为会变得不明确且效率低下。
在 vue3 中,此类用法将不再自动创建 数组。要从单个绑定获取多个 ref,请将 绑定到一个更灵活的函数上 (这是一个新特性):
选项式 API:
组合式 API:
不必是数组:它也可以是一个对象,其 ref 可以通过迭代的 key 被设置。如有需要, 也可以是响应式的,且可以被侦听。
在中我们使用定义函数式组件。有如下特点
- 作为性能优化,因为它们的初始化速度比有状态组件快得多
- 返回多个根节点
比如使用 组件,负责提供适当的标题 (即:、、 等等),在 vue2 中,这可以通过单文件组件编写:
或者,对于喜欢在单文件组件中使用 的用户:
但是在 中,所有的函数式组件都是用普通函数创建的。换句话说,不需要定义 组件选项。也就是说 已经被移除了。
它们将接收两个参数: 和 。 参数是一个对象,包含组件的 、 和 property。
此外, 现在是全局导入的,而不是在 函数中隐式提供。
以前面提到的 组件为例,下面是它现在的样子。
在中异步组件是通过将组件定义为返回 的函数来创建的,例如:
在中异步组件通过定义
组件里面新增了选项,可以通过 选项在组件上定义发出的事件。
下面看例子
在这个例子中,子组件对外暴露了事件,所以需要在里面定义。
原生事件替代
当在 选项中定义了原生事件 (如 ) 时,将使用组件中的事件替代原生事件侦听器。
下面笔者再出一个例子就会明白了。
上面的例子我们在输入框输入内容的时候控制台会打印值。虽然我们在子组件上监听了方法,但是并不会起作用,他被事件替代了。
虽然vue支持这种写法但是笔者不太建议用原生方法命名,容易混淆。
暴露的事件一定要定义emits中,因为没被定义在emits中的事件会被当做原生事件处理。当你命名和原生事件一样的时候就会发现有问题了。
比如上面的例子,当你定义的方法名和原生事件名一样比如,又没在里面定义,这样会导致你自定义的事件会触发你的方法而且当你点击的时候还会触发你的方法,会触发两次。
事件验证
与 类型验证类似,如果使用对象语法而不是数组语法定义发出的事件,则可以对它进行验证。
要添加验证,请为事件分配一个函数,该函数接收传递给 调用的参数,并返回一个布尔值以指示事件是否有效。
验证不通过并不会报错,而是出现控制台警告。
在中里面只能识别标签或者组件,如果是其它不认识的标签会报错。如果要自定义元素怎么办呢?比如自定义一个
在中需要通过 将标签配置为自定义元素
在中需要通过 传递。
这样我们在模板里面就能正常使用该标签了。
在中,可以用在普通元素和上。不管用在哪个上面都会渲染指定的组件。
下面渲染的都是组件
在vue3中,也可以用在普通元素和上。但是只有用在上才会渲染指定组件,用在普通元素上只会作为一个属性传递。如果想在普通元素上渲染组件怎么办呢?这就需要加上前缀了。
下面渲染的都是组件
在中渲染函数现在全局导入,而不是作为参数传递给渲染函数。并且在setup中需要返回函数,而不是渲染函数。
在 vue2 中, 具名插槽的写法:
在父组件中使用:
如果我们要在 slot 上面绑定数据,可以使用作用域插槽,实现如下:
在 vue2 中具名插槽和作用域插槽分别使用和来实现, 在 vue3 中将和进行了合并同意使用,使用代替。
新增了样式穿透方法,支持了全局样式和slot样式定义,还支持了模块化样式和样式变量。
在中我们使用来做样式穿透,在vue3中推荐使用
我们知道使用scoped修饰的style样式只会在当前文件生效。
但是我们想创建全局样式应该怎么做呢?
在中有两种方法
创建一个不带 的的标签。
还可以使用 伪类来实现
标签会被编译为 CSS Modules 并且将生成的 CSS 类作为 对象的键暴露给组件:
实现了和 一样将 仅作用于当前组件的效果。所以我们不需要再加属性了。
我们还可以通过给 attribute 一个值来自定义注入的类对象的 property 键:
注意使用模块化的话我们的样式不要嵌套哦,不然会获取不到。
注入的类可以通过 API 在 和 中使用。对于使用了自定义注入名称的 模块, 接收一个对应的 attribute 值作为第一个参数。
单文件组件的 标签可以通过 这一 CSS 函数将 CSS 的值关联到动态的组件状态上:
这里的样式是响应式的,中值改变样式也会更新。
默认情况下,作用域样式不会影响到 渲染出来的内容,因为它们被认为是父组件所持有并传递进来的。使用 伪类以确切地将插槽内容作为选择器的目标:
其实我们把样式写在父元素也是可以实现该功能的。
使用过的同学肯定知道使用来组件间传递值的。我们来看看和中使用差别。
在中,我们能直接使用。
在中,我们需要引入和,并且在方法中返回才能使用。
为了增加 值和 值之间的响应性,我们可以在 值时使用 或 。
现在,如果这两个 中有任何更改, 组件也将自动更新!
当使用响应式 值时,建议尽可能将对响应式 property 的所有修改限制在定义 provide 的组件内部。
然而,有时我们需要在注入数据的组件内部更新 的数据。在这种情况下,我们建议 一个方法来负责改变响应式 。
最后,如果要确保通过 传递的数据不会被 的组件更改,我们建议对提供者的 使用 ,这样就万无一失啦。
模板引用在中是非常简单的,通过就能获取到。
在中相对麻烦,需要先引入,并在方法中返回。
在中
在中
我们知道,中,如果是循环的话会是一个数组。但是在 中 内部使用时没有特殊处理。相反,使用函数引用执行自定义处理。
在侦听模板中
我们也可以不在生命周期钩子使用而是在监听器中使用,但与生命周期钩子的一个关键区别是, 和 在 挂载或更新之前运行副作用,所以当侦听器运行时,模板引用还未被更新。
因此,使用模板引用的侦听器应该用 选项来定义,这将在 更新后运行副作用,确保模板引用与 保持同步,并引用正确的元素。
指令的钩子函数已经被重命名,以更好地与组件的生命周期保持一致。并且, 字符串不再作为 对象的一部分被传入。
在 vue2 中,自定义指令通过使用下列钩子来创建,以对齐元素的生命周期,它们都是可选的:
- bind - 指令绑定到元素后调用。只调用一次。
- inserted - 元素插入父 DOM 后调用。
- update - 当元素更新,但子元素尚未更新时,将调用此钩子。
- componentUpdated - 一旦组件和子级被更新,就会调用这个钩子。
- unbind - 一旦指令被移除,就会调用这个钩子。也只调用一次。
下面是一个例子:
此处,在这个元素的初始设置中,通过给指令传递一个值来绑定样式,该值可以在应用中任意更改。
然而,在 中,我们为自定义指令创建了一个更具凝聚力的 API。正如你所看到的,它们与我们的组件生命周期方法有很大的不同,即使钩子的目标事件十分相似。我们现在把它们统一起来了:
- created - 新增!在元素的 attribute 或事件监听器被应用之前调用。
- bind → beforeMount
- inserted → mounted
- beforeUpdate:新增!在元素本身被更新之前调用,与组件的生命周期钩子十分相似。
- update → 移除!该钩子与 有太多相似之处,因此它是多余的。请改用 。
- componentUpdated → updated
- beforeUnmount:新增!与组件的生命周期钩子类似,它将在元素被卸载之前调用。
- unbind -> unmounted
最终的 API 如下:
因此,API 可以这样使用,与前面的示例相同:
在vue2中,我们可以通过 或者是 定义 选项。
vue3 中, 选项已标准化为只接受返回 的 。
我们先来复习下。对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
- 和组件的数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。
- 同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
- 值为对象的选项,例如 、 和 ,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。
这次的调整主要是在。
当来自组件的 及其 或 基类被合并时,合并操作现在将被浅层次地执行:
在 中,生成的 是:
在 中,其结果将会是:
因为组件已经有了属性,所以不会再替换了。
在中当使用 选项侦听数组时,只有在数组被替换时才会触发回调。换句话说,在数组被改变时侦听回调将不再被触发。要想在数组被改变时触发侦听回调,必须指定 选项。
class 名更改
过渡类名 修改为 、过渡类名 修改为 。
下面笔者用两张图总结
在中
在中
组件的相关 prop 名称也发生了变化:
已经被重命名为 (在渲染函数或 JSX 中可以写为:)
已经被重命名为 (在渲染函数或 JSX 中可以写为:)
transition-group 不再默认渲染根元素
在 中, 像其它自定义组件一样,需要一个根元素。默认的根元素是一个 ,但可以通过 attribute 定制。
在 中 不再默认渲染根元素,但仍然可以用 attribute 创建根元素。
没有特殊指令的标记 (、 或 ) 的 现在被视为普通元素,并将渲染为原生的 元素,而不是渲染其内部内容。
上面的例子在中会渲染出,在中会渲染并没有内容。
当我们的是这样的
根组件是这样的
会渲染成
会渲染成
看出差别了吧,就是不会替换被挂载的元素。
在中移除了部分。
在中我们这样使用。
在中移除过滤器,不在支持。建议使用去替代。
在 中, 可以作为修改 方法的一种方式。
此外,也可以通过全局的 选项定义自己的别名。
对任何要用作修饰符的键使用 (短横线) 名称。
因此,这意味着 现在也已弃用,不再受支持。
, 和 实例方法已被移除,组件实例不再实现事件触发接口。
在 中,Vue 实例可用于触发由事件触发器 API 通过指令式方式添加的处理函数 (, 和 )。这可以用于创建一个事件总线,以创建在整个应用中可用的全局事件监听器:
在中已经从实例中完全移除了 、 和 方法。 仍然包含于现有的 API 中,因为它用于触发由父组件声明式添加的事件处理函数。
实例 已从 中移除,不再支持。
在 中,开发者可以使用 访问当前实例的直接子组件:
在 中, property 已被移除,且不再支持。如果你需要访问子组件实例,我们建议使用 。
选项之前用于在创建 Vue 实例的过程中传入 ,现在它被移除了。如果想为 应用的根组件传入 ,请使用 的第二个参数。
在 中,我们可以在创建 Vue 实例的时候传入 prop:
在 中 选项已经被移除。如果你需要在实例创建时向根组件传入 prop,你应该使用 的第二个参数:
在中移除了,用户不应再手动管理单个 Vue 组件的生命周期。
在中移除了全局函数 和 以及实例方法 和 。因为在中响应式检测是基于的,基于代理的变化检测已经不再需要它们了。
在 中, 为子组件提供了 attribute,以便将其内部内容作为模板使用,而不是作为分发内容。
上面会在页面渲染,也就是组件自己不再渲染任何内容,而是把内部内容全部渲染出来。
我们看看不加 attribute
上面会在页面渲染的真实内容,内部内容将被忽略。如果没内容将渲染为空。
在 中将不再支持此功能。
由于篇幅原因,笔者就不再这里赘述了,感兴趣可以看看笔者写的Vue3路由新特性(Vue-Router3和Vue-Router4对比总结)一文。
由于篇幅原因,笔者就不再这里赘述了,感兴趣可以看看笔者写的Vux4新特性(Vuex3和Vuex4对比总结)一文。
官方文档
如果想继续学习的话,欢迎看看笔者和对比学习系列文章。
Vue和React对比学习之生命周期函数(Vue2、Vue3、老版React、新版React)
Vue和React对比学习之组件传值(Vue2 12种、Vue3 9种、React 7种)
Vue和React对比学习之Style样式
Vue和React对比学习之Ref和Slot
Vue和React对比学习之Hooks
Vue和React对比学习之路由(Vue-Router、React-Router)
Vue和React对比学习之状态管理 (Vuex和Redux)
Vue和React对比学习之条件判断、循环、计算属性、属性监听
感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ri-ji/74090.html