一、写法上面的不同
以往我们写的代码是
<script>
export default {
name: "App",
data () {
return {
a:1
}
},
methods: {
myFn() {
console.log('方法')
}
},
computed:{
},
watch:{
}
};
</script>
vue3 中直接写在setup中,并且需要return出去。并且计算属性(computed )和监听属性(watch)都有相对应的变化
<script>
import { ref, reactive, watch, computed } from 'vue'
export default ({
name:'vue3',
setup() {
let age = ref(0)
const person = reactive ({
test:'vue3',
name:'张三'
})
/**
computed 的两种写法:
1.普通写法不考虑计算属性被修改问题。
2.完整写法考虑到计算出来的结果被修改之后的处理
**/
// 简写
let sumName = computed(()=> {
return person.test + '-' + person.name
})
// 完整
let sumName = computed({
get () {
return person.test + '-' + person.name
},
set (value) {
const newArr = value.split('-')
person.test = newArr[0]
person.name = newArr[1]
}
})
/**
watch的一些坑
1.如果监听的是reactive中的响应式数据oldvalue将无法被正确获取
2.监听reactive对象全部属性时,强制开启深度监听,并且deep配置无效(即当你设置deep为false时依然会触发深度监听)
3.如果监听的屎对象中的某一个属性,则需要写成函数,并且oldvalue能正确获取
watch(()=>person.name,(newvalue, oldvalue) => {
console.log(newvalue)
console.log(oldvalue)
})
4.当你监听的是reactive中响应式数据中的对象的时候,这个时候就巧了,你需要开启deep深度监听
如:
当你需要监听peson中paly的时候,这个时候你就需要开启deep深度监听
person = reactive ({
test:'vue3',
name:'张三',
paly:{
one:'111',
two:{
tow_a:'1'
}
}
})
总结:
1.当你监听整个返回的reactive响应式数据,默认深度监听并且无法关闭。
2.当你需要监听reactive响应式数据中的某一个值并且不是对象时需要写成函数式,当监听多个值时候[()=>person.name,()=>person.age]
3.当你监听reactive响应式数据中的值是一个对象时,需要开启deep深度监听
**/
watch(test ,(newvalue, oldvalue) => {
console.log(newvalue)
console.log(oldvalue)
})
return{
test
}
},
})
</script>
2. 生命周期的写法和改变
vue2中当组件消失用的是销毁destroyde,但是vue3中取消了这个销毁转而用与之更加符合描述的卸载unmounted 。写法上也有不同,vue3中生命周期需要引入,它们也与之前的api命名不同,不同点在于在vue2命名的基础上加了on
// 这里只做最常用的几个演示,其他的都一样 分别是 挂载 更新 卸载 其中onUnmounted 对应的就是 destroyde
import { onBeforeMount, onMounted, onUpdated, onUnmounted } from 'vue'
export default ({
name:'vue3',
setup() {
console.log('····setup!!!触发····')
onBeforeMount(() => {
console.log('····onBeforeMount挂载触发····')
})
onMounted(() => {
console.log('····onMounted挂载触发····')
})
onUpdated(() => {
console.log('····onUpdated更新触发····')
})
onUnmounted(() => {
console.log('····onUnmounted卸载触发····')
})
}
}
这里有需要注意的是,setup肯定是第一个触发的,其次再到 onBeforeMount
3.另一种监听 watchEffect
普通的watch监听需要定义监听的是谁,而watchEffect则是你在函数内使用了谁就监视谁
<template>
<div class="son">
<h3>我的名字:{{name}}---年龄{{age}}</h3>
<button @click="age++">修改测试监听</button>
</div>
</template>
<script>
import { watchEffect, reactive, toRefs } from 'vue'
export default ({
name:'vue3',
setup() {
let person = reactive({
name:'张三',
age:18
})
watchEffect(()=>{
const a = person.age
console.log('····监听到了数据的变化····',a)
})
return {...toRefs(person)}
}
}
)
</script>
4. toRef、toRefs
简单用法:当你想在标签上面直接用对象里面的值不想老是多一个前序的时候就能用toRef/toRefs
例子:
// 浅层用法
// 当使用toRefs时 标签直接写对象里面的属性 name 和 age
// 如不使用toRefs 则需要写成 person.name 和 person.age相当的麻烦
<template>
<div class="son">
<h3>我的名字:{{name}}---年龄{{age}}</h3>
<button @click="age++">修改测试监听</button>
</div>
</template>
<script>
import { watchEffect, reactive, toRefs } from 'vue'
export default ({
name:'vue3',
setup() {
let person = reactive({
name:'张三',
age:18
})
return {...toRefs(person)}
}
}
)
/** 对比 错误
当你想把person.age 用另外的名字交出去的时候 这时候你可能会写
let person = reactive({
name:'张三',
age:18
})
return {
nianling:person.age
}
但是这种写法陷入了一个误区 ,这其实相当于返回了
nianling:18
他的指向并不是你所定义的响应式数据,这个时候就需要使用toRef
nianling:toRef(person,'age')
而 toRefs 则是直接将对象的一层批量返回出去,这里需要注意的是
如果你的对象是
person{
name:'张三',
age:18,
job:{
money:40
}
}
那么你写成 ...toRef(person)的话 那么他只能解析第一层返回出去,job里面的money依然需要写job.money在标签上
**/
</script>
5. provide和inject
这个属性在vue2也有但是说实话,这个方法被提及的很少。当我学习vue3时从新又复习到了,并且做了对比。这个属性的作用是 祖孙组件之间的数据传递 就是订阅发布一样的功能
vue3中这个的使用更加的方便和可控,因为他不像vue2中是一个像生命周期和data这样的分类式并且使用上也是得到了很大的提升
,
注意:以下例子是简写,并不完全,需要自定义成 祖-父-孙 进行通讯,这里省略了父组件的东西
对比:
以下实例都是想要实现响应式,vue3中拆分得更加精细,手动设置响应式数据区分了 浅响应和深响应,只读等…
//==========vue2===========//
// 经过简单测试,当你的数据是data()中,就默认会把数据做成响应式的,如果直接赋值传输则只是传输了数据并且没有响应式,而且vue2中他是默认直接触发的。
// 祖辈组件 App.vue
<div class="app">
<h3>我的是APP 组件 === {{car.name}}----{{car.money}}}</h3>
<h4>配置套装:{{car.son.name}}----{{car.son.pi}}</h4>
</div>
export default {
name: 'App',
data() {
return {
car:{}
}
},
provide(){
return {
proCar:this.carFn()
}
},
methods: {
carFn () {
return this.car = {name:'梅赛德斯奔驰',money:'30W',son:{name:'RS6',pi:'低'}}
}
},
}
// 孙组件 son.vue
<template>
<div class="son">
<h3>我的son组件---{{proCar}}</h3>
<button @click="revampCar">vue2修改car数据测试</button>
</div>
</template>
<script>
export default {
name: 'son',
data() {
return {
car:{}
}
},
mounted() {
this.car = this.proCar
console.log('这是使用总程',this.car )
},
inject:{
// 使用一个默认值使其变成可选项
proCar: { // 健名
from: 'proCar' // 来源
}
},
methods: {
revampCar () {
this.car.son.name = 's260l'
}
},
}
</script>
// ====== vue3 ===== //
// App.vue
<template>
<div class="app">
<h3>我的是APP 组件 === {{car.name}}----{{car.money}}}</h3>
</div>
</template>
import {provide,reactive} from 'vue'
export default {
name: 'App',
setup() {
let car = reactive({name:'梅赛德斯奔驰',money:'30W'})
provide('car',car)
return {
car
}
}
}
// son.vue
<template>
<div class="son">
<h3>我的son组件---{{car.name}}</h3>
<button @click="revampCar">修改car数据测试</button>
</div>
</template>
<script>
import {inject} from 'vue'
export default {
name: 'son',
setup() {
let car = inject('car')
function revampCar () {
car.name = '奥迪'
}
return {
car,
revampCar
}
}
}
</script>
从上面的对比可以看出 vue3比vue2更加的灵活,使用更加的方便。(注意:这个传值模式在vue2的时候都是不推荐使用的,除非祖孙之间套层太深使用会比较好)
效果图如下:
祖孙之间相互影响,如果不想相互影响直接不使用reactive就是了
这里简单总结了vue3的一些功能的变化,学海无涯!!!