文章目录
- Teleport
- `v-for`中的Ref数组
- 异步组件(新增)
- `$attrs`包含`class`和`style`
- `$children`
- 自定义指令
- Data选项
- Data的Mixin合并
- `emits`选项
- 移除了`v-on.native`修饰符
- 事件API
- 过滤器
- 多根节点组件支持
- 全局API
- 全局Tree Shaking
- `key`属性
- 按键修饰符
- 移除`$listeners`
- Props默认函数中不能访问`this`
- 渲染函数
- 插槽统一
- 过渡CSS类名更改
- ``过渡组件
- `v-model`和`.sync`
- `v-model`自定义修饰符
- `v-for`与`v-if`的优先级
- `v-bind`合并行为
- 对数组的监听
Teleport
一个新增的内置组件,用来提供一种干净的方法,允许我们控制在DOM哪个父节点下渲染HTML,不必求助于全局状态或者将其拆分为两个组件
<teleport to="body">
<div v-if="modalOpen" class="model-wrapper">
<div class="modal">
<i class="el-icon-close" @click="modalOpen = false"></i>
<p>Hello</p>
</div>
</div>
</teleport>
Vue会将<teleport>
标签内的内容渲染为<body>
标签的子级
它接受两个参数,第一个参数to
是有效的查询选择器,指定要挂载的目标元素,第二个参数disabled
用来禁用<teleport>
的功能,元素会在原组件位置渲染
注意,disabled
状态变化后,将移动实际的DOM节点,而不是被销毁和重新创建,并且它还将保持任何组件实例的活动状态(例如播放的视频等)
在同一个目标上使用多个<teleport>
组件,会将内容挂载到同一个目标元素,顺序就是简单的追加,稍后挂载的将位于目标元素中较早的挂载之后
v-for
中的Ref数组
从单个绑定获取多个Ref时,需要将ref
绑定到一个更灵活的函数上,在函数中,将函数的参数el
推书预置的数组中:
<div v-for="item in list" :ref="setItemRef"></div>
选项式API:
export default {
data() {
return {
itemRefs: []
}
},
methods: {
setItemRef(el) {
if (el) {
this.itemRefs.push(el)
}
}
},
beforeUpdate() {
this.itemRefs = []
},
updated() {
console.log(this.itemRefs)
}
}
组合式API:
import { onBeforeUpdate, onUpdated } from 'vue'
export default {
setup() {
let itemRefs = []
const setItemRef = el => {
if (el) {
itemRefs.push(el)
}
}
onBeforeUpdate(() => {
itemRefs = []
})
onUpdated(() => {
console.log(itemRefs)
})
return {
setItemRef
}
}
}
注意:
itemRefs
不必是数组,可以是一个对象- 如果需要,
itemRef
也可以是响应式的,可以被监听 - 需要在
onBeforeUpdate
中对itemRefs
重置,否则会出问题
异步组件(新增)
Vue3中函数式组件被定义为纯函数,异步组件的定义需要通过defineAsyncComponent
方法显示定义:
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'
// 不带选项的异步组件
const asyncPage = defineAsyncComponent(() => import('./NextPage.vue'))
// 带选项的异步组件
const asyncPageWithOptions = defineAsyncComponent({
loader: () => import('./NextPage.vue'),
delay: 200,
timeout: 3000,
errorComponent: ErrorComponent,
loadingComponent: LoadingComponent
})
相比于Vue2,component
选项被重命名为loader
,loader
函数不接受resolve
和reject
参数,必须始终返回Promise
const { createApp, defineAsyncComponent } = Vue
const app = createApp({})
const AsyncComp = defineAsyncComponent(
() =>
new Promise((resolve, reject) => {
resolve({
template: '<div>I am async!</div>'
})
})
)
app.component('async-example', AsyncComp)
如果利用Webpack和ES2015的能力,可以使用import
直接导入:
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
app.component('async-component', AsyncComp)
defineAsyncComponent
的完整用法:
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent({
// 工厂函数
loader: () => import('./Foo.vue')
// 加载异步组件时要使用的组件
loadingComponent: LoadingComponent,
// 加载失败时要使用的组件
errorComponent: ErrorComponent,
// 在显示 loadingComponent 之前的延迟 | 默认值:200(单位 ms)
delay: 200,
// 如果提供了 timeout ,并且加载组件的时间超过了设定值,将显示错误组件
// 默认值:Infinity(即永不超时,单位 ms)
timeout: 3000,
// 定义组件是否可挂起 | 默认值:true
suspensible: false,
/**
*
* @param {*} error 错误信息对象
* @param {*} retry 一个函数,用于指示当 promise 加载器 reject 时,加载器是否应该重试
* @param {*} fail 一个函数,指示加载程序结束退出
* @param {*} attempts 允许的最大重试次数
*/
onError(error, retry, fail, attempts) {
if (error.message.match(/fetch/) && attempts <= 3) {
// 请求发生错误时重试,最多可尝试 3 次
retry()
} else {
// 注意,retry/fail 就像 promise 的 resolve/reject 一样:
// 必须调用其中一个才能继续错误处理。
fail()
}
}
})
$attrs
包含class
和style
Vue2中v-bind="$attrs"
会把除了class
和style
的属性应用到元素上,而Vue3中的$attrs
则会包含class
和style
组件的
inheritAttrs
默认为true
,这样加载组件的不被认作Props的Attribute会应用到子组件的根元素上,通过设置inheritAttrs
为false
,这个默认行为会被取消,通过配合v-bind="$attrs"
会把这些Attribute显性的绑定到非根元素上
$children
Vue2中可以通过$children
访问当前组件实例的子组件,这个API在Vue3中取消了,需要使用ref
来访问子组件
自定义指令
Vue3中自定义指令的钩子有了很大变化:
created
(new):在元素的Attribute或事件侦听器创建前调用bind
→beforeMount
inserted
→ <