众所周知,Vue3相对于Vue2来说发生了断崖式地更新,那么作为开发者,我们需要紧跟技术的发展趋势,将新的内容应用于日常的技术开发当中😎。本文简要地总结了作为一个Vue2的开发者,如何快速上手Vue3的开发实践,让Vue3新手不再迷茫👇👇👇
注:本篇当中的代码的<script>片段,统一采用<script setup>写法,和项目代码保持统一,<script setup>是我们写Vue3一定要去了解的内容,建议在阅读本文之前或是之后去浏览一下这方面的小知识,可以直接看本人的另一篇文章->Vue3当中的setup script - 掘金 (juejin.cn)
一、 了解响应式API
在Vue2当中,我们实现响应式数据的方式是将数据定义在data函数当中返回,在Vue3中虽然同样也可以使用这种方式,但是尤大在Vue3当中是对响应式实现的底层原理做出改进的,改用了ES6的Proxy来实现,因此建议使用新版当中的Reactive和Ref来实现页面内容的响应式。
Vue2写法:
<template>
<p>{{msg}}</p>
</template>
<script>
export default {
data() {
return {
msg: 'message',
data:{
text:'xxx',
status: 1
}
};
}
};
</script>
Vue3写法:
<template>
<p>{{msg}}</p>
</template>
<script setup lang="ts">
export default {
const msg = ref('message')
const data = reative({
text:'xxx',
status: 1
})
msg.value = 'new message' //通过value属性进行访问
data.status = 2 //直接访问
};
</script>
ref ——接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value 属性,指向该内部值。
reactive ——接受复杂类型的数据并返回对象的响应式副本。
注意点:
- 使用
reactive定义基本数据类型时,vue会给出了一个警告,reactive更推荐用于对象或数组的数据类型(因为vue在实现reactive方法,会首先判断传入的数据是否为对象,只有对象才会进行数据响应式处理) - 使用
ref定义数据时,在script当中获取值需要通过.value属性访问,在模板中直接使用 ref可以定义基本数据类型,也可以定义复杂数据类型,不会报错- 二者简单区分就是一个负责基本数据类型、一个负责复杂数据类型,底层响应式实现逻辑不同
这是我们在日常开发当中使用频率最高的两个响应式API,但除了它们,还有**toRef、toRefs**、computed、watch、watchEffect... 可以在具体使用的时候,进行了解;官方文档指路 -> v3.cn.vuejs.org/api/basic-r…
二、 方法定义的差异
在之前的版本当中,我们定义逻辑代码的方式是写在methods和各个生命周期当中,而在Vue3当中可以直接进行方法函数的定义,并且对生命周期的方法重新进行了分配。
Vue2写法:
<template>
<button @click="getMessage">点击</button>
</template>
<script>
export default {
...
methods {
getMessage(){
console.log('this is msg')
}
}
};
</script>
Vue3写法:
<template>
<button @click="getMessage">点击</button>
</template>
<script setup lang="ts">
import { onMounted, onUpdated, onUnmounted } from 'vue' //需要导入
const getMessage = () => {
console.log('this is msg')
}
onMounted(() => {
console.log('mounted!')
})
onUpdated(() => {
console.log('updated!')
})
onUnmounted(() => {
console.log('unmounted!')
})
...
</script>
各生命周期对应如下:
beforeCreate -> 使用 setup()
created -> 使用 setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
errorCaptured -> onErrorCaptured
Vue3 当中的父子组件传值
在<script setup>中主要采用defineProps和defineEmit两个API来完成
父组件向子组件传递数据
- 在子组件标签当中上通过
v-bind+ 自定义变量名 进行数据绑定,这里是:info - 子组件
defineProps定义接收到的props - 从
props解构出需要的数据
子组件向父组件传递数据
- 父组件编写接收函数,例如这里的
clickEven - 在子组件标签上通过"@" + 自定义事件名 绑定该接收函数
defineEmits注册发射事件名emit(事件名,数据值)
父组件:
<template>
<div>老父亲
<!-- 父组件通过变量(这里是info)进行值的绑定 -->
<!-- 父组件定义clickEven接收子组件的值 -->
<Child :info="parentMsg" @clickChild="clickEven" ></Child>
</div>
</template>
<script setup lang="ts">
import Child from './Child'
const parentMsg = ref('toChild')
//父组件接受子组件传值---start
const clickEven=(val)=>{
console.log(val)
}
//父组件接受子组件传值---end
</script>
子组件:
<template>
<!-- info是父组件传递过来的值 -->
<div>我是乖儿子拿到了父组件的值是{{info}}</div>
<!-- clickChild子组件事件 -->
<button @click="clickChild">点击子组件</button>
</template>
<script setup>
import { toRefs, defineProps,defineEmits } from 'vue'
//接受父亲的值---start
const props = defineProps({
//子组件接收父组件传递过来的值
info: String,
})
//使用父组件传递过来的值
const {info} = toRefs(props)
//传递给老父亲---start
const emit = defineEmits([clickChild]) //数组形式,可以定义多个
//1.包在方法里使用
const clickChild = () => {
emit('clickChild','toFather')
}
//2.直接使用
emit('clickChild','toFather')
</script>
对于子组件向父组件传值,还可以使用defineExpose进行属性和方法的暴露,父组件定义ref接收
- 父组件中定义一个
ref,并绑定在子组件标签上,例如这里的controlRef - 子组件通过
defineExpose()暴露数据或方法 - 父组件通过
ref获取,例如controlRef.value.myTag
子组件:
<template>
<div>
<h2>乖儿子</h2>
<p>tag:{{ myTag }}</p>
</div>
</template>
<script setup lang=ts>
import { defineExpose } from "vue";
const myTag=ref('小可爱')
const changeTag = () => {
myTag.value = '大美丽'
}
defineExpose({ myTag, changeTag })
</script>
父组件:
<template>
<div>
<!-- 在组件上绑定ref -->
<Child ref="controlRef"></Child>
</div>
</template>
<script setup lang=ts>
import Child from './Child'
const controlRef = ref()
const data = controlRef.value.myTag
//使用方法
controlRef.changeTag()
</script>
除以上两种方法之外,也可以使用provide和inject ,支持多层父子级嵌套,深层套娃时使用效果佳,如下:
具体的API介绍,可以看官网->v3.cn.vuejs.org/guide/compo…
//Father.vue
<template>
<Child />
</template>
<script setup>
import Child from '../components/HelloWorld.vue'
import { reactive, provide } from 'vue'
const state=reactive({
title:'你好'
})
//provide
provide('provideToChild', {
state,
changeTitle: (FromChildParams) => {
state.title=FromChildParams
}
})
// provide('provideToChild',state )
</script>
//child.vue
<template>
我是子组件 {{injectFromParent}}
</template>
<script setup>
import {inject} from 'vue'
//注入
const injectFromParent= inject('provideToChild');
injectFromParent.changeTitle('MontherFucker');
</script>
小结
通过了解以上Vue2和Vue3的一些写法上基础性差异,就可以去动手写一个vue3的页面了,实践出真知!再根据具体的需求来查看再Vue3当中应如何去实现(本人亲测有效);
But 这些只是我们在写代码的时候,能感受出来的很表面的差异,具体Vue3内部如何实现,为什么可以这样使用这些API,都是可以进一步去探索的。同时,这些用法差异仅仅冰山一角,本文也只是编写了一小部分,目的是让读者看完之后可以简单上手,更多的差异还等待着大家亲自去探索噢👸~