数据双向绑定改动
vue3采用proxy代理的方式实现对象劫持,同时也支持Object.defineproperty方法进行对象劫持(为了兼容IE浏览器)
注意事项
- 代理返回的新对象!==对源对象
- 由于使用了proxy代理对象,所以在使用时不可以使用对象展开符直接展开对象获取属性,否则会使对象的响应式失效
Teleport
选择插入
新增内置标签Teleport
,支持将子组件自由插入到dom文档的任何地方
<teleport to="body">
<div>我是需要插入到body的子元素</div>
</teleport>
组合式API
与其相对的是vue2的选项式API,组合式API可以将相关代码的距离拉的更近或者进行模块化引入。
新增setup()
函数,有props
、context
两个参数,props
为父级传入的属性,context
为包含有attrs
、slots
、emits
三个函数的对象。运行于created
(包含)之前的周期,所以在setup()
中无法获取到其他周期信息
<template>
// dom
</template>
<script>
export default{
setup(props,{attrs,slots,emits}){
// do somethings
return {}
}
}
</script>
在setup函数中getCurrentInstance获取组件实例
import { getCurrentInstance } from 'vue'
const MyComponent = {
setup() {
const internalInstance = getCurrentInstance()
internalInstance.appContext.config.globalProperties // 访问 globalProperties
}
}
vue3的Vue暴露出一些新的模块以供调用用来辅助组合式API
生命周期:
beforeCreate -> use setup()
created -> use setup()
beforeMount -> onBeforeMount
mounted -> onMounted
boforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeUnmount -> onBeforeUnmount
unmount -> onUnmount
// 捕获来自一个子孙组件的错误
errorCaptured -> onErrorCaptured
// 跟踪虚拟DOM重新渲染时调用,告诉你哪个操作跟踪了组件,对象,键
renderTracked -> onRenderTracked
// 跟踪虚拟DOM重新渲染时调用,告诉你哪个操作触发了重新渲染,对象,键
renderTriggered -> onRenderTriggered
响应性API
reactive
返回对象的响应式副本
const obj = reactive({count:0})
readonly
返回一个只读的proxy对象
const original = reactive({count: 0})
const copy = readonly(original)
-
isProxy
检查对象是否是由reactive
或readonly
创建的 proxy -
isReactive
检查对象是否是reactive
创建的proxy -
isReadonly
检查对象是否是readonly
创建的只读proxy -
toRaw
返回reactive
或readonly
proxy 的原始对象 -
markRaw
标记一个对象,使其永远不会转换为 proxy -
shallowReactive
创建一个响应式 proxy,跟踪其自身 property 的响应性,但不执行嵌套对象的深度响应式转换 (暴露原始值) -
shallowReadonly
创建一个 proxy,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换 (暴露原始值) -
ref
接受一个内部值并返回一个响应式且可变的 ref 对象
const count = ref(0)
console.log(count.value) //0
count.value++
console.log(count.value) //1
-
unref
如果参数为 ref,则返回内部值,否则返回参数本身。这是val = isRef(val) ? val.value : val
-
toRef
可以用来为源响应式对象上的 property 新创建一个 ref,然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。
// 相当于是添加一个对state.foo解构,但不影响其响应性
const state = reactive({
foo: 1,
bar: 2
})
const fooRef = toRef(state,"foo")
fooRef.value++
console.log(state.foo) //2
satte.foo++
console.log(fooRef.value) //3
-
toRefs
将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的ref。(相当于解构对象) -
isRef
检查是否是ref对象 -
customRef
创建一个带有get
和set
函数的ref对象 -
shallowRef
创建一个 ref,它跟踪自己的 .value 更改,但不会使其值成为响应式的。(浅转换) -
triggerRef
手动执行与 shallowRef 关联的任何效果。 -
computed
可自动调用的computed函数,返回一个不变的响应式ref
对象,或者使用get
和set
函数创建可写的ref对象 -
watchEffect
在响应式地跟踪其依赖项时立即运行一个函数,并在更改依赖项时重新运行它。
const count = ref(0)
watchEffect(() => console.log(count.value))
// -> logs 0
setTimeout(() => {
count.value++
// -> logs 1
}, 100)
watch
与watch完全等效
注意事项
- props是响应式对象,不可使用对象展开符
片段
vue2.x不支持在template中有多片段
<!-- Layout.vue -->
<template>
<div>
<header>...</header>
<main>...</main>
<footer>...</footer>
</div>
</template>
vue3.x中支持多片段,但需要设置attribute的分布
<!-- Layout.vue -->
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
异步组件更改
- 新增
defineAyncComponent
助手方法,用于显式的定义异步组件 component
选项重命名为loader
- Loader函数本身不在接收
resolve
和reject
参数,必须返回一个Promise
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
})
自定义事件
- 新增
emits
选项,需要显式声明子组件中定义的自定义事件 - 现在父级组件可以直接在子组件上使用
v-on:click
监听子组件的点击事件
自定义渲染器
<script setup>
语法糖
当使用组合式API的时候可以直接使用此语法糖,减少不必要的代码
<script setup="props, { emit }">
import { watchEffect } from 'vue'
watchEffect(() => console.log(props.msg))
emit('foo')
</script>
<style vars="{ color }">
语法糖
<template>
<div class="text">hello</div>
</template>
<script>
export default {
data() {
return {
color: 'red'
}
}
}
</script>
<style vars="{ color }">
.text {
color: var(--color);
}
</style>
更加灵活的scoped作用域
>>>
和/deep/
被弃用
<style scoped>
/* 深层选择 */
::v-deep(.foo) {}
/* 缩写 */
:deep(.foo) {}
/* 目标插槽选择 */
::v-slotted(.foo) {}
/* 缩写 */
:slotted(.foo) {}
/* 一次性的全局选择 */
::v-global(.foo) {}
/* 缩写 */
:global(.foo) {}
</style>
API改动
使用tree shaking的方式引入api,减少打包后的代码体积
全局api
为了减少对全局Vue的污染,全局API使用Vue暴露出createApp模块的形式创建实例
createApp
新增config
config.productionTip
移除config.ignoredElements
=>config.isCustomElement
并支持接受一个函数为参数Vue.prototype
=>config.globalProperties
component
、directive
、minxin
、use
都由createApp
生成的app实例调用
组件api
- 组件级别的API使用Vue模块导出
- 受影响的API有
nextTick
、observable
=>reactive
、version
、compile
、set
、delete
- 内部一些api如:v-show等也将会被vue内部使用tree shaking的方式编译
v-model用法修改
- prop:
value
->modelValue
- event:
input
->update:modelValue
.sync
修饰符和组件的model
选项被移除
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />
<!-- 是以下的简写: -->
<ChildComponent
:title="pageTitle"
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
/>
data
更改为必须由函数返回
mixins
合并data改为浅合并
key
值用法小修改
- 现在vue可以自动生成key值,
v-if
/v-else
/v-else-if
不需要单独设置key
<template>
支持设置key
v-if
/v-for
优先级修改
现在同级v-if
优先级总是大于v-for
v-bind
合并顺序修改
现在总是会按照书写顺序来合并v-bind
属性,后书写的覆盖前书写的
移除.native
修饰符
watch
选项不再支持.分割字符串路径,改用第一个参数为计算函数的形式
生命周期改名
destroyed
=>unmounted
beforeDestroy
=>beforeUnmounted
自定义指令周期改为与组件生命周期一致
过度类名变更
.v-enter
=>v-enter-from
.v-leave
=>v-leave-from
transitionGroup
不在默认渲染根节点
仍然可以用 tag
prop 创建根元素。
$on
、$off
、$once
方法废除
vue3中事件车可引入第三方库mitt、tiny-emitter解决
不再支持过滤器语法
vue3更推荐使用使用计算属性或者全局属性的方式处理数据
移除内联特性inline-template
属性
vue3使用内联模板有两种方式
<script>
标签
<script type="text/html" id="my-comp-template">
<div>{{ hello }}</div>
</script>
const MyComp = {
template: '#my-comp-template'
// ...
}
- 默认slot
<!-- 2.x 语法 -->
<my-comp inline-template :msg="parentMsg">
{{ msg }} {{ childState }}
</my-comp>
<!-- 默认 Slot 版本 -->
<my-comp v-slot="{ childState }">
{{ parentMsg }} {{ childState }}
</my-comp>
移除$children
属性
vue3可直接再子组件上添加ref
来获取子组件的实例
keycode形式的按键修饰符被移除
watch监听数组
默认只能监听数组被替换的回调,数组元素被修改需要添加deep
选项