Vue3 快速掌握,了解常用新特性(适用于会 Vue2.0 开发的)
一、Vue3 与 Vue2 的区别
-
新加了组件:
Fragment、Teleport、Suspense。 -
语法
v-on的.native修饰符被移除,不在支持。 -
Vue3的template中,不再需要唯一的根元素,如果这么使用报错可能是ESLint没有配置好或版本太低不支持这种写法。<template><div>123div><div>456div> template> -
全局导入方式调整
// vue - main.js import { createApp } from 'vue' createApp(App).use(store).use(router).mount('#app')// vuex import { createStore } from 'vuex' export default createStore({ ... })// vue-router import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' const routes: Array<RouteRecordRaw> = [] export default createRouter({history: createWebHistory(process.env.BASE_URL),routes })... -
Vue3支持Vue2生命周期的使用 -
生命周期对比
Vue2 Vue3 含义 区别 beforeCreate() setup() 创建前, data和el并未初始化Vue3中被setup()替代created() setup() 创建完毕, data数据完成初始化,el没有Vue3中被setup()替代beforeMount() onBeforeMount() 挂载前, data和el完成初始化mounted() onMounted() 挂载结束,完成挂载,渲染页面 beforeUpdate() onBeforeUpdate() 更新前 updated() onUpdated() 更新完成 beforeDestroy() onBeforeUnmount() 销毁前 Vue3中被改名destroyed() onUnmounted() 销毁完成 Vue3中被改名errorCaptured() onErrorCaptured() 异常捕获 onRenderTracked() 虚拟 dom重新渲染Vue3新增,只有在调试的时候有用,生产环境会忽略onRenderTriggered() 虚拟 dom重新渲染,输出更详细准确的数据Vue3新增,只有在调试的时候有用,生产环境会忽略 -
以前自带的方法可以直接使用,现在需要通过
import引入之后才可以进行使用import {ref,reactive,onMounted,onUpdated,onUnmounted, onBeforeMount, onBeforeUpdate,onBeforeUnmount... } from 'vue'
二、setup 函数
-
setup函数中,不能使用this,this指向的是undefined。 -
setup只会在组件初始化的时候执行一次,执行顺便对比:beforeCreate () {console.log('---- beforeCreate') }, created () {console.log('---- created') }, setup () {console.log('---- setup') }// 输出顺序: // ---- setup // ---- beforeCreate // ---- created -
参数分析
setup(props ,context) { }-
props为一个对象,内部包含了父组件传递过来的所有prop数据。 -
context对象包含了attrs、slots、emit属性。
-
-
属性、函数的优先级、生命周期的调用先后
-
一样的属性与函数,
Vue3的会覆盖Vue2的。 -
同一个生命周期函数
Vue3的先调用,Vue2的后调用,不会覆盖Vue2的。
<template><div @click="touchButton">{{ sex }}div> template><script> import { defineComponent, ref, onMounted } from 'vue'export default defineComponent({// vue2data() {return {sex:'男'}},// vue2mounted () {console.log('mounted - vue2')},// vue3setup() {// 比 vue2 优先调用onMounted(() => {console.log('onMounted - vue3')})// 优先使用这个,会覆盖 vue2 中的 touchButton 方法function touchButton () {console.log('touchButton - vue3')}// 优先使用这个,会覆盖 vue2 中的 sex 值const sex = ref('女')return {sex,touchButton}},// vue2methods: {touchButton () {console.log('touchButton - vue2')}} }) script> -
三、ref 函数(响应式数据 方式一)
-
在
setup中使用时,要加.value,模板中使用的时候不需要加.value -
包装简单数据类型
<template><div @click="touchButton">{{ sex }}div> template><script> import { defineComponent, ref } from 'vue'export default defineComponent({setup () {// 定义响应式属性const sex = ref('女')// 点击按钮function touchButton () {// 修改值时,需要加上 .valuesex.value = '男'}// 定义的属性或函数需要 return 出去才会生效return {sex,touchButton}} }) script> -
包装复杂数据类型
<template><div @click="touchButton">{{ user.job.salary }}div> template><script> import { defineComponent, ref } from 'vue'export default defineComponent({setup () {// 定义响应式属性const user = ref({id: 1,name: 'dzm'})// 中途添加字段user.value.job = { salary: 10 }// 点击按钮function touchButton () {// 修改值时,需要加上 .valueuser.value.job.salary += 1}// 定义的属性或函数需要 return 出去才会生效return {user,touchButton}} }) script>
四、reactive 函数(响应式数据 方式二)
-
ref和reactive都是用来定义响应式数据的,reactive推荐去定义复杂数据类型,ref推荐定义基本类型。-
ref包装的简单数据(例如:number),可以被监听,可以被修改。 -
reactive包装简单数据(例如:number),会报警告,且不能直接被修改。 -
ref包装的复杂数据(例如:json),不可以被监听,可以新增、修改字段。 -
reactive包装的复杂数据(例如:json),可以被监听,可以新增、修改字段。
-
-
下面
十一、中有介绍reactive与shallowReactive函数的使用区别。<template><div @click="touchButton">{{ user.name }}div> template><script> import { defineComponent, reactive } from 'vue'export default defineComponent({setup () {// 定义响应式属性const user = reactive({id: 1,name: 'dzm'})// 点击按钮function touchButton () {// 修改值user.name = 'xyq'}// 返回return {user,touchButton}} }) script>
五、toRef 与 toRefs 函数
-
toRef与toRefs的使用区别-
toRef: 将一个数据变成响应式数据。 -
toRefs: 将多个数据变成响应式数据。
-
-
reactive定义的对象,如果直接用...解构,就会失去响应式的特点,然而使用toRef() 或 toRefs()解构,则可以保留响应式特点。总结:解构之后还具有响应式。let { 属性1, 属性2 } = toRefs(响应式数据)<template><!-- 模板中使用 --><div @click="touchButton">{{ user.name }}</div> </template><script> import { defineComponent, toRef, toRefs, reactive } from 'vue'export default defineComponent({setup () {// 定义响应式属性const user = reactive({id: 1,name: 'dzm'})// 通过 toRef 取值,保留响应式特点(通过 key 单个取值)// let name = toRef(user, 'name')// 通过 toRefs 取值,保留响应式特点let { name } = toRefs(user)// 点击按钮function touchButton () {// 修改值name.value = 'xyq'}// 返回return {user,name,touchButton}} }) </script>
六、computed 函数
-
computed支持get、set写法,普通写法只用到了get。-
普通写法:返回值就是计算属性的值
import { computed } from 'vue' const 计算属性名 = computed(() => {return 响应式数据相关计算 }) -
高阶写法:
get返回的是计算属性的值,set监听计算属性的变化(v-model绑定计算属性)import { computed } from 'vue' const 计算属性名 = computed(() => {// 取值get: () => { }// 赋值set: (val) => { } })
-
-
普通写法
<template><div @click="touchButton">{{ newAge }}div> template><script> import { defineComponent, ref, computed } from 'vue'export default defineComponent({setup () {// 定义响应式属性const age = ref(1)// 计算方法const newAge = computed(() => {return age.value * 10})// 点击按钮function touchButton () {// 修改值age.value += 1}// 返回return {age,newAge,touchButton}} }) script> -
高阶写法(
get、set组合使用)<template><div @click="touchButton">{{ newAge }}div> template><script> import { defineComponent, ref, computed } from 'vue'export default defineComponent({setup () {// 定义响应式属性const age = ref(1)// 计算方法const newAge = computed({// 取值get: () => {return age.value * 10},// 赋值set: (val) => {age.value = val / 10}})// 点击按钮function touchButton () {// 修改值age.value += 1}// 返回return {age,newAge,touchButton}} }) script>
七、watch 函数
-
监听深层次对象时,新旧对象的值都会发生变化,
watch是惰性的,页面第一次加载时不触发watch函数,只有监听的数据发生变化时,才会触发watch函数。-
使用
deep为深层次监听 -
使用
immediate为第一次直接触发,默认第一次不触发
-
-
监听格式
watch(监听参数, 新旧值变化回调, 配置)// 监听普通属性 watch(age, (newVal, oldVal) => { console.log('变化了') }) // 监听 json 数据 watch(json, (newVal, oldVal) => { console.log('变化了') }, { immediate: true, deep: true }) // 监听多个数据 watch([age, json], (newVal, oldVal) => { console.log('变化了') }, { immediate: true, deep: true }) -
使用案例
<template><div @click="touchButton">{{ age }}div> template><script> import { defineComponent, ref, reactive, watch } from 'vue'export default defineComponent({setup () {// 定义响应式属性const age = ref(1)const user = reactive({id: 1,name: 'dzm'})// 监听普通数据watch(age, (newVal, oldVal) => {console.log('Age 变化:', newVal, oldVal)})// 监听深层次数据watch(user, (newVal, oldVal) => {console.log('User 变化:', newVal, oldVal)}, { immediate: true, deep: true })// 监听多个数据watch([age, user], (newVal, oldVal) => {console.log('Age User 变化:', newVal, oldVal)}, { immediate: true, deep: true })// 点击按钮function touchButton () {// 修改值age.value += 1user.id += 1}// 返回return {age,touchButton}} }) script>
八、watchEffect 函数(高级监听)
-
watchEffect是非惰性的,一开始就会自动调用一次,可配置执行时机,还可以监听某个值之前,可以先执行一个函数。 -
在页面第一次加载时就会触发,并且会一直监听追踪内部使用的响应式数据,只要追踪的响应式数据发生变化,
watchEffect都会运行。 -
也可以监听多个参数,只是不能监听对象,因为他无法监测对象内部的变化,可能是watchEffect 无法实现深度监听吧(具体原因还不清楚)。
-
普通监听使用
<template><div @click="touchButton">{{ age }}div><div @click="touchStop">停止监听div> template><script> import { defineComponent, ref, reactive, watchEffect } from 'vue'export default defineComponent({setup () {// 定义响应式属性const age = ref(1)const user = reactive({id: 1,name: 'dzm'})// 普通监听使用const stop = watchEffect(() => {console.log(age.value, user.id)})// 点击按钮function touchButton () {// 修改值age.value += 1user.id += 1}// 停止监听function touchStop () {stop()}// 返回return {age,touchButton,touchStop}} }) script> -
高级监听使用
<template><div @click="touchButton">{{ age }}div><div @click="touchStop">停止监听div> template><script> import { defineComponent, ref, reactive, watchEffect } from 'vue'export default defineComponent({setup () {// 定义响应式属性const age = ref(1)const user = reactive({id: 1,name: 'dzm'})// 监听值变化之前,会先执行一下函数,无论什么位置,都会先执行函数,在执行其他内容,只有在监听值发生变化时,才会触发const stop = watchEffect((oninvalidata) => {// 在函数前面输入一下console.log('oninvalidata - 前', age.value, user.id)// 先执行这个函数,可以用来提前处理一些需要的东西oninvalidata(() => {console.log('before')})// 在函数后面输入一下console.log('oninvalidata - 后', age.value, user.id)}, {// 执行时机: pre(组件更新前)、sync(强制效果始终同步)、post(组件更新后执行)flush: 'post', // dom 加载完毕后执行// 数据发生变化时,比上面的 oninvalidata 函数还会先调用onTrigger(e) {console.log('onTrigger')// console.log(e) // 数据变化信息,可以在这里拿到新旧值、变化对象、变化类型、变化key// debugger // 用于 debugger 调试}})// 这里是上面监听的输出结果:// 1、oninvalidata - 前 1 1// 2、oninvalidata - 后 1 1// 3、onTrigger// 4、onTrigger// 5、before// 6、oninvalidata - 前 2 2// 7、oninvalidata - 后 2 2// 第 1、2 行是初始化默认调用的第一次// 第 3、4 行是监听到值变化之后调用的,如果多个数据同时发生改变,每个数据都会调用一遍// 第 5、6、7 行是监听到变化之后调用的,如果多个数据同时发生改变,只触发一次// 点击按钮function touchButton () {// 修改值age.value += 1user.id += 1}// 停止监听function touchStop () {stop()}// 返回return {age,touchButton,touchStop}} }) script>
九、emit 函数 与 emits 自定义事件注册
-
子组件中所有自定义事件都需要在
emits中进行注册,不然会报警告:[Vue warn]: Extraneous non-emits event listeners (success1, success2) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits" option. -
子组件自定义事件
<template><div @click="touchButton1">点击按钮1div><div @click="touchButton2">点击按钮2div> template><script> export default {// 申明自定义事件emits: ['success1', 'success2'],setup (props, context) {// 点击按钮1function touchButton1 () {context.emit('success1')}// 点击按钮2function touchButton2 () {context.emit('success2')}// 返回return {touchButton1,touchButton2}} } script> -
父组件接受事件
<template><Temp @success1="touchButton1" @success2="touchButton2">Temp> template><script> import Temp from './Temp.vue' import { defineComponent } from 'vue'export default defineComponent({components: {Temp},setup () {// 点击按钮1function touchButton1 () {console.log('点击按钮1')}// 点击按钮2function touchButton2 () {console.log('点击按钮2')}// 返回return {touchButton1,touchButton2}} }) script>
十、readonly 与 shallowReadonly 函数
-
readonly为深只读,shallowReadonly为浅只读。

十、reactive 与 shallowReactive 函数
-
reactive为深劫持,shallowReactive为浅减持。 -
按上面
九、的同类型数据,被reactive劫持的数据,修改任何层级的数据都会刷新页面,被shallowReactive劫持的数据,修改深层级的数据都不会刷新页面,只有第一层次的会刷新页面。
十一、toRaw 函数
-
toRaw: 将一个reactive生成的响应式对象转换为普通对象。<script> import { defineComponent, reactive, toRaw } from 'vue'export default defineComponent({setup () {// 定义响应式属性const user = reactive({id: 1,name: 'dzm',job: {salary: 30}})// 点击按钮function touchButton () {console.log(user) // Proxy {id: 1, name: 'dzm', job: {…}}const user1 = toRaw(user) // 将一个 reactive 生成的响应式对象转换为普通对象console.log(user1) // {id: 1, name: 'dzm', job: {…}}}// 返回return {user,touchButton}} }) </script>
十二、markRaw 函数
-
markRaw:标记一个对象,使其永远不再成为响应式的数据<template><div @click="touchButton1">新增数据div><div @click="touchButton2">叠加数据 {{ user.job && user.job.salary }}div> template><script> import { defineComponent, reactive, markRaw } from 'vue'export default defineComponent({setup () {// 定义响应式属性const user = reactive({id: 1,name: 'dzm'})// 新增数据function touchButton1 () {// 通过 reactive 包装后,默认增加数据,是支持响应式的// user.job = { salary: 10 }// 但是增加的数据通过 markRaw 包装之后,是不支持响应式的user.job = markRaw({ salary: 10 })}// 增加数值function touchButton2 () {// user.job.salary 无论是支持或不支持响应式,值都会变化// 但是不支持响应式,则值变页面不变,支持响应式,则值变页面也变if (user.job) { user.job.salary += 1 }// 无论支持与否,输出值是在增加变化的console.log(user.job.salary)}// 返回return {user,touchButton1,touchButton2}} }) script>
十三、其他的后续会持续更新
- 但是基本掌握上面的也就能进入正常开发了,其他情况的现查现用就行了!
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
