1. 组合式API
1)setup组件选项
新的 setup 选项在组件创建之前执行,一旦 props 被解析,就将作为组合式 API 的入口。
使用 setup 函数时,它将接收两个参数:
propscontext因为props是响应式的,所以我们不能使用 ES6 解构,它会消除 props 的响应性。 如果一定需要使用结构,vue提供了toRefs方法,来完成此操作
import { toRefs } from 'vue'
setup(props) {
const { title } = toRefs(props)
console.log(title.value)
}
如果 title 是可选的 prop,则传入的 props 中可能没有 title 。在这种情况下,toRefs 将不会为 title 创建一个 ref 。你需要使用 toRef 替代它:
import { toRef } from 'vue'
setup(props) {
const title = toRef(props, 'title')
console.log(title.value)
}
context 是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着我们可以安全地对 context 使用 ES6 解构。
export default {
setup(props, context) {
// Attribute (非响应式对象,等同于 $attrs)
console.log(context.attrs)
// 插槽 (非响应式对象,等同于 $slots)
console.log(context.slots)
// 触发事件 (方法,等同于 $emit)
console.log(context.emit)
// 暴露公共 property (函数)
console.log(context.expose)
}
}
2)不能在setup中使用this
因为setup执行在除了props之外的其他组件选项之前的
在 setup 中应该避免使用 this,因为它不会找到组件实例。setup 的调用发生在 data property、computed property 或 methods 被解析之前,所以它们无法在 setup 中被获取。
setup 选项是一个接收 props 和 context 的函数
3)setup中可以使用任何生命周期钩子,需要在前面加 on
前提是需要引入这些钩子函数
4)Vue3 如何跟踪变化的
- 当一个值被读取时进行追踪:proxy 的
get处理函数中track函数记录了该 property 和当前副作用。 - 当某个值改变时进行检测:在 proxy 上调用
set处理函数。 - 重新运行代码来读取原始值:
trigger函数查找哪些副作用依赖于该 property 并执行它们。
5)带 ref 的响应式变量
import { ref } from 'vue'
const counter = ref(0)
ref解包
Ref 解包仅发生在被响应式 Object 嵌套的时候。当从 Array 或原生集合类型如 Map访问 ref 时,不会进行解包
6)watch 响应式更改
就像我们在组件中使用 watch 选项并在 user property 上设置侦听器一样,我们也可以使用从 Vue 导入的 watch 函数执行相同的操作。它接受 3 个参数:
- 一个想要侦听的响应式引用或 getter 函数
- 一个回调
- 可选的配置选项
import { ref, watch } from 'vue'
const counter = ref(0)
watch(counter, (newValue, oldValue) => {
console.log('The new counter value is: ' + counter.value)
})
7)独立的 computed 属性
import { ref, computed } from 'vue'
const counter = ref(0)
const twiceTheCounter = computed(() => counter.value * 2)
counter.value++
console.log(counter.value) // 1
console.log(twiceTheCounter.value) // 2
2.teleport
Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下渲染了 HTML,而不必求助于全局状态或将其拆分为两个组件。
这仅仅是移动实际的 DOM 节点,而不是被销毁和重新创建,并且它还将保持任何组件实例的活动状态。所有有状态的 HTML 元素 (即播放的视频) 都将保持其状态。
app.component('modal-button', {
template: `
<button @click="modalOpen = true">
Open full screen modal! (With teleport!)
</button>
<teleport to="body">
<div v-if="modalOpen" class="modal">
<div>
I'm a teleported modal!
(My parent is "body")
<button @click="modalOpen = false">
Close
</button>
</div>
</div>
</teleport>
`,
data() {
return {
modalOpen: false
}
}
})
简而言之<teleport>中的to="body"告诉 Vue Teleport 这个 HTML 将会渲染为该body标签的子级。
如果 <teleport> 包含 Vue 组件,则它仍将是 <teleport> 父组件的逻辑子组件,即使这个子组件会在不同的地方渲染,但是它仍将是 父组件的子级,并从父组件中接受传参prop
props:
+ to: 必须是有效的查询选择器或 HTMLElement (如果在浏览器环境中使用)。指定将在其中移动 <teleport> 内容的目标元素
+ disabled: 禁用<teleport>的功能
3.触发组件选项
可以在单个组件实例上创建多个v-model绑定
组件上的 v-model 使用 modelValue 作为 prop 和 update:modelValue 作为事件。我们可以通过向 v-model 传递参数来修改这些名称
<user-name
v-model:first-name="firstName"
v-model:last-name="lastName"
></user-name>
app.component('user-name', {
props: {
firstName: String,
lastName: String
},
emits: ['update:firstName', 'update:lastName'],
template: `
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)">
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)">
`
})
v-model自定义修饰符
<my-component v-model.capitalize="myText"></my-component> // 自定义修饰符 capitalize
组件内部通过modelModifiers prop 来承接修饰符
app.component('my-component', {
props: {
modelValue: String,
modelModifiers: { // 组件内部通过modelModifiers prop 来承接修饰符
default: () => ({})
}
},
emits: ['update:modelValue'],
template: `
<input type="text"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)">
`,
created() {
this.modelModifiers.capitalize // 默认值为 true
console.log(this.modelModifiers) // { capitalize: true }
}
})
对于带参数的 v-model 绑定,生成的 prop 名称将为 arg + "Modifiers":
<my-component v-model:description.capitalize="myText"></my-component>
app.component('my-component', {
props: ['description', 'descriptionModifiers'],
emits: ['update:description'],
template: `
<input type="text"
:value="description"
@input="$emit('update:description', $event.target.value)">
`,
created() {
console.log(this.descriptionModifiers) // { capitalize: true }
}
})
4.单文件组件<script setup>
<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。相比于普通的 <script> 语法,它具有更多优势:
- 样板内容更少,代码更简洁
- 能够使用纯TS声明props和抛出事件
- 更好的运行时性能(其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理)
- 更好的IDE类型推断性能
5.关于provide和inject
vue3 中在setup中使用这两个 也是要
import { provide } from 'vue' 和
import { inject } from 'vue'
来引入的。
provide 函数允许你通过两个参数定义 property:
- name (
<String>类型) - value
provide('location', 'North Pole')
如果想让location变为响应式的话,那么在provide这里就要使用ref和reactive使值变为响应式的
修改响应式的话需要在provide组件中修改
一定要在inject中修改的话,那么就从provide传一个修改函数过去,inject使用这个修改函数修改
inject 函数有两个参数:
- 要 inject 的 property 的 name
- 默认值 (可选)
const userLocation = inject('location', 'The Universe')
6. filter过滤器被移除了
- 建议使用计算属性和方法来处理
- 全局的过滤器 可以声明一个
$filter挂载到全局可以使用
7.一些小改变
-
destroyed生命周期选项被重命名为unmounted -
beforeDestroy生命周期选项被重命名为beforeUnmount -
data只接受函数的返回- mixin和组件本身的合并只会是浅拷贝
-
当侦听一个数组时,只有当数组被替换时,回调才会触发,如果需要在变更时触发,则必须指定
deep选项 -
<template>如果没有特殊的指令在上面(v-if/else-if/else、v-for或v-slot),现在被视为普通元素,并将渲染为原生的<template>元素,而不是渲染其内部内容。- 渲染成document-fragment
-
已挂载的应用不会取代他所挂载的元素
- 在 Vue 2.x 中,当挂载一个具有
template的应用时,被渲染的内容会替换我们要挂载的目标元素。在 Vue 3.x 中,被渲染的应用会作为子元素插入,从而替换目标元素的innerHTML。
- 在 Vue 2.x 中,当挂载一个具有
-
生命周期的
hook:事件前缀改为vnode-vue2中的写法
<template> <child-component @hook:updated="onUpdated"> </template>vue3中可以有下面的两种写法
<template> <child-component @vnode-updated="onUpdated"> </template><template> <child-component @vnodeUpdated="onUpdated"> </template>
8.自定义元素检测现在在模板编译时执行
在 Vue 2.x 中,通过 Vue.config.ignoredElements 将标签配置为自定义元素:
```
// 这将使 Vue 忽略在其外部定义的自定义元素
// (例如:使用 Web Components API)
Vue.config.ignoredElements = ['plastic-button']
```
在vue3中是通过vue-loader中的配置项来在模板编译时执行检测
```
// webpack 中的配置
rules: [
{
test: /.vue$/,
use: 'vue-loader',
options: {
compilerOptions: {
isCustomElement: tag => tag === 'plastic-button'
}
}
}
// ...
]
```
或者可以设置 app.config.compilerOptions.isCustomElement
```
const app = Vue.createApp({})
app.config.compilerOptions.isCustomElement = tag => tag === 'plastic-button'
```
9.定制内置元素
在 3.0 中,我们将 Vue 对 is attribute 的特殊处理限制在了 <component> 标签中。
-
在保留的
<component>标签上使用时,它的行为将与 2.x 中完全相同; -
在普通组件上使用时,它的行为将类似于普通 attribute:
<foo is="bar" />- 2.x 的行为:渲染
bar组件。 - 3.x 的行为:渲染
foo组件,并将isattribute 传递给它。
- 2.x 的行为:渲染
-
在普通元素上使用时,它将作为
isattribute 传递给createElement调用,并作为原生 attribute 渲染。这支持了自定义内置元素的用法。<button is="plastic-button">点击我!</button>-
2.x 的行为:渲染
plastic-button组件。 -
3.x 的行为:通过调用以下函数渲染原生的 button
document.createElement('button', { is: 'plastic-button' })
-
**总结: **
动态组件中
- 3.x 只关注
<component>标签,只有<component>标签才会把is传入的值当做组件渲染出来,其余的 只当成is 属性来渲染 - 2.x 中,无论是
<component><div>亦或者是<foo />自定义组件,只要有is属性,都会把传入的当成组件渲染出来
10.emits选项
子组件的emits需要预先定义,子组件的emits接收一个数组或者对象
11.v-model的用法更改
-
非兼容:用于自定义组件时,
v-modelprop 和事件默认名称已更改:- prop:
value->modelValue; - 事件:
input->update:modelValue;
- prop:
- 新增:现在可以在同一个组件上使用多个
v-model绑定; - 新增:现在可以自定义
v-model修饰符。
2.x的语法
在 2.x 中,在组件上使用 v-model 相当于绑定 value prop 并触发 input 事件:
<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
如果想要更改 prop 或事件名称,则需要在 ChildComponent 组件中添加 model 选项:
<!-- ParentComponent.vue -->
<ChildComponent v-model="pageTitle" />
// ChildComponent.vue
export default {
model: {
prop: 'title',
event: 'change'
},
props: {
// 这将允许 `value` 属性用于其他用途
value: String,
// 使用 `title` 代替 `value` 作为 model 的 prop
title: {
type: String,
default: 'Default title'
}
}
}
3.x的语法
在 3.x 中,自定义组件上的 v-model 相当于传递了 modelValue prop 并接收抛出的 update:modelValue 事件:
<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent
:modelValue="pageTitle"
@update:modelValue="pageTitle = $event"
/>
若需要更改 model 的名称,现在我们可以为 v-model 传递一个参数,以作为组件内 model 选项的替代:
<ChildComponent v-model:title="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
这里子组件里面原本的modelValue就被替换成了title, 同理,在自定义组件中使用多个v-model时
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />
<!-- 是以下的简写: -->
<ChildComponent
:title="pageTitle"
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
/>
当我们设置自定义修饰符的时候,
<ChildComponent v-model.capitalize="pageTitle" />
在子组件中通过 props承接一个modelModifiers对象,而这个capitalize自定义修饰符就是存在于modelModifiers对象中的属性,我们需要在子组件模板中的@input或者重新定义的事件名称的函数中,做一些这个自定义修饰符需要做的事情
12.<template v-for>语法
<!-- Vue 2.x -->
<template v-for="item in list">
<div :key="'heading-' + item.id">...</div>
<span :key="'content-' + item.id">...</span>
</template>
<!-- Vue 3.x key应被设置在template标签上 -->
<template v-for="item in list" :key="item.id">
<div>...</div>
<span>...</span>
</template>
13.v-for 和v-if 使用在同一个元素上时,优先级修改
首先是不推荐这么使用,但是有时候我们不得不这么用
- 2.x中 v-for的优先级更高
- 3.x中 v-if的优先级更高