主要特点
- Vue3 通过 ES6 的
Proxy
代理整个对象,不再使用defineProperty
(getter/setter)监听对象单个属性,性能有所提升。
因 IE 11 不支持 Proxy,且 Babel 也无法将 Proxy 转为 ES5,Vue3 无法兼容 IE11。 - Vue3 优化了diff 算法(不再比对所有dom)和 渲染算法(闭包缓存),性能更强大
- Vue3 引入了组合式API:
setup
,将为同一功能服务的代码尽量写在一起,代码结构更清晰。
构建工具
- Vue2 通过
vue-cli
(webpack)构建 - Vue3 通过
@vue/cli
(基于webpack)构建,或直接通过 Vite 构建
Vite
目前支持 vue 和 react
仅支持 ES Module,不支持 CommonJS。
- 本地开发运行时,不进行预打包和编译。通过浏览器本身支持的 ES Module 语法,仅请求并编译当前所需的模块,因此运行和热更新时都会更快。
- 正式发布时和 webpack 区别不大。
与 Vue2 的一些语法区别
创建vm
- 2中通过
new Vue({render: h => h(App)}).$mount('#app')
创建实例,3中通过Vue.createApp(App).mount('#app')
创建 - 2中
.component
、.directive
、.use
都是Vue的方法,3中是vm实例的方法
生命周期
- 使用
beforeUnmount
、unmounted
代替beforeDestroy
、destroyed
组件
- 2中一个template中必须有一个根元素,3中没有该限制,且支持通过
$attrs
取得引用元素的class属性
<my-component class="baz"></my-component>
<template>
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>
</template>
- v-model 的默认 prop 不再是 value,而是
modelValue
默认emit方法不再是input,而是update:modelValue
通过v-model:xxx
来将modelValue
改为xxx而不再使用options的model
属性修改,因此也可以实现同一组件上共存多个v-model
新增通过modelModifiers
自定义v-model修饰符
<HelloWorld v-model="aaa"/>
export default {
components: {
HelloWorld
},
data(){
return {
aaa:"i am aa in home"
}
},
watch:{
aaa(){
console.log("watch aaa change")
}
}
}
...
export default {
name: 'HelloWorld',
props: {
modelValue: String,
},
mounted(){
this.$emit("update:modelValue","jjwjjw")
}
};
- options新增
emits
属性,用于传入该组件中所有需要 $emit 的事件数组或对象(用于校验)
删除了事件的.native
修饰。如包含了原生事件同名的事件,则会覆盖原生事件的监听
//此时对custom元素的点击事件不会触发xxx
<custom @click="xxx"/>
app.component('custom', {
emits: ['click'],
mounted() {
this.$emit("click", "hello world");
},
})
emits: {
// 没有验证
click: null,
// 验证submit 事件
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
},
- 异步加载组件
使用defineAsyncComponent
代替原来的直接加载
指令
- v-if 和 v-for 可以在一个元素上同时生效了,但 v-if 优先级更高,因此其中无法引用 v-for 里的变量
- v-if 不再需要 key,v-for 的 key 可以配置在 template 中而非实际元素
api
Vue.prototype 替换为 config.globalProperties
组合式api setup
用于解决 mixins 的痛点,实现高内聚低耦合,将服务于每种功能的 data、computed、methods、watch 代码尽量书写在一起。其返回值会根据类型,落实到上述属性中。
setup 的调用发生在 props 之后,data property、computed property 、methods 解析之前,其中不存在指向当前组件实例的 this
。
参数
第一个参数通常命名为 props,即组件的 props,为一个 reactive 实例。
第二个参数通常命名为 context,包含如下属性:
- attrs 属性,非响应式对象,等同于 $attrs
- slots 插槽,非响应式对象,等同于 $slots
- emit 触发事件,方法,等同于 $emit
- expose 暴露公共 property (函数)
响应性API
- reactive
传入一个对象进行 深层递归 Proxy处理,并解包该对象中存在的 ref 属性,且与其保持响应式连接。
返回一种特殊的 Proxy 实例,对该实例的属性赋值 ref 实例时,也会自动解包
const count = ref(1)
const obj = reactive({ count })
// ref 会被解包
console.log(obj.count === count.value) // true
// 它会更新 `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2
// 它也会更新 `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3
const count2= ref(1)
obj.count2 = count2
console.log(obj.count2) // 1
console.log(obj.count2 === count2.value) // true
- ref
返回 RefImpl 实例,一个具有 value 属性的响应式对象
如果传入值为基本数据类型,则直接赋值给 value。如果传入值为对象,则通过reactive
深层响应式处理后,再赋值给 value。 - isRef
判断入参是否为 RefImpl 或 ObjectRefImpl 实例 - unRef
isRef(val) ? val.value : val
的语法糖 - toRef
将一个 reactive 实例的某个属性,以 ObjectRefImpl 实例返回出来。两者间保持响应式连接。
如该属性不存在则新建属性。
ObjectRefImpl 实例的变化本身不会触发视图更新
import { reactive, ref, isRef, unRef, toRef, toRefs } from "vue";
const counter = ref(0)
console.log(counter) // { value: 0 }
console.log(counter.value) // 0
const state = reactive({});
const fooRef = toRef(state, "age");
fooRef.value = 100;
console.log(state.age); // 100
state.age++;
console.log(fooRef.value); // 101
- toRefs
将一个 reactive 实例返回为普通对象,该对象每个属性经过toRef
处理,与原 Proxy 对象一一保持响应式连接
const state = reactive({
foo: 1,
bar: 2
})
const stateAsRefs = toRefs(state)
state.foo++
console.log(stateAsRefs.foo.value) // 2
stateAsRefs.foo.value++
console.log(state.foo) // 3
生命周期
组合式 API 上的生命周期钩子与选项式 API 的名称相同,但需要添加前缀 on
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted } from 'vue'
// 在我们的组件中
setup (props) {
const repositories = ref([])
const getUserRepositories = async () => {
repositories.value = await fetchUserRepositories(props.user)
}
onMounted(getUserRepositories) // 在 `mounted` 时调用 `getUserRepositories`
return {
repositories,
getUserRepositories
}
}
网友评论