最近自己也在学习vue3,在看文档与博客的过程中,发现有有些博主的vue3关于双向绑定实现响应式有部分误解,评论区更是有人直接开喷,所以啊,自己去一个一个实践才是最靠谱的,在此分享我的实践干货。
直入主题:
ref:
<template>
<div>
<h3>{{ count.num }}</h3>
<button @click="add">增加</button>
</div>
</template>
<script>
import { ref } from "@vue/reactivity";
export default {
setup() {
let test = {
num: 11,
};
let count = ref(test);
function add() {
count.value.num++;
console.log(count.value); // 12
console.log(test); // 12
}
return {
count,
add,
};
},
};
</script>
点击一次增加按钮,控制台打印均为12,先别急总结,继续看
<template>
<div>
<h3>{{ count }}</h3>
<button @click="add">增加</button>
</div>
</template>
<script>
import { ref } from "@vue/reactivity";
export default {
setup() {
let test = {
num: 11,
};
let count = ref(test.num);
function add() {
count.value++;
console.log(count.value); //11
console.log(test.num); //12
}
return {
count,
add,
};
},
};
</script>
这次点击增加按钮,控制台打印count值为12,test.num值仍为11
由此可见:通过ref去定义的变量,如果赋值的是原始对象本身,变量改变会影响原始对象也改变,如果赋值为原始对象的某个属性值,变量改变原始对象本身不会发生任何改变。
reactive:
<template>
<div>
<h3>{{ count.num }}</h3>
<button @click="add">增加</button>
</div>
</template>
<script>
import { reactive } from "@vue/reactivity";
export default {
setup() {
let test = {
num: 11,
};
let count = reactive(test);
function add() {
count.num++;
console.log(count.num); //12
console.log(test.num); //12
}
return {
count,
add,
};
},
};
</script>
点击增加按钮控制台打印均为12,因为reactive只能赋值对象与数组类型,我们再来试试数组类型
<template>
<div>
<h3>{{ count[0] }}</h3>
<button @click="add">增加</button>
</div>
</template>
<script>
import { reactive } from "@vue/reactivity";
export default {
setup() {
let test=[11,12,13]
let count = reactive(test);
function add() {
count[0]++;
console.log(count[0]); //12
console.log(test[0]); //12
}
return {
count,
add,
};
},
};
</script>
点击增加按钮控发现制台打印也均为12,,所以在此看来通过reactive定义的变量改变同时也会改变原始对象或数组
在不少博主哪里可以看到将return出去的变量通过扩展符号点点点解构,这样return出去的变量的属性均会被暴露,标签中可以直接引用属性。但是这样的坏处就是通过点点点以后的变量会失去响应式
<template>
<div>
<h3>{{ num }}</h3>
<button @click="add">增加</button>
</div>
</template>
<script>
import { reactive } from "@vue/reactivity";
export default {
setup() {
let test = {
num: 11,
};
let count = reactive(test);
function add() {
count.num++;
console.log(count.num); //12
console.log(test.num); //12
}
return {
...count,
add,
};
},
};
</script>
点击增加按钮控制台打印均为12,但是视图没有更新,由此可见,失去响应式的变量改变仍然可以影响原始数据改变,但是视图不会更新。那么如果解决呢?
<template>
<div>
<h3>{{ num }}</h3>
<button @click="add">增加</button>
</div>
</template>
<script>
import { reactive, toRefs } from "@vue/reactivity";
export default {
setup() {
let test = {
num: 11,
};
let count = reactive(test);
function add() {
count.num++;
console.log(count.num); //12
console.log(test.num); //12
}
return {
...toRefs(count),
add,
};
},
};
</script>
点击增加按钮控制台打印均为12,使用toRefs可以将变量恢复响应式。有朋友要问了,ref的对象可以使用扩展运算符点点点吗,博主做了测试,不行嗷,我还看见有人使用toRefs去定义:let count = toRefs(test); 博主也做了测试,这样是可以使用的,且变量改变原始数据也会改变,视图不会更新,并且控制台会有警告提示:toRefs()需要一个反应对象,但收到一个普通对象。所以还是不用为好。
toRef:
<template>
<div>
<h3>{{ count }}</h3>
<button @click="add">增加</button>
</div>
</template>
<script>
import { toRef } from "@vue/reactivity";
export default {
setup() {
let test = {
num: 11,
};
let count = toRef(test, "num");
function add() {
count.value++;
console.log(count.value); //12
console.log(test.num); //12
}
return {
count,
add,
};
},
};
</script>
点击增加按钮控制台打印均为12,但是视图没有更新,所以toRef定义的变量不是响应式的。但是奇怪的事情来了。
<template>
<div>
<h3>{{ count }}----{{ count2 }}</h3>
<button @click="add">增加</button>
</div>
</template>
<script>
import { toRef, ref } from "@vue/reactivity";
export default {
setup() {
let test = {
num: 11,
};
let count = toRef(test, "num");
let count2 = ref(22);
function add() {
count2.value++;
count.value++;
console.log(count.value); //12
console.log(test.num); //12
}
return {
count,
count2,
add,
};
},
};
</script>
我发现只要改变了count2的值视图更新了,原本视图中count未更新,现在也更新了。
思考:如果定义一个其他的响应式变量可以更新视图,响应式变量改变时候视图更新,能够带动不能使视图更新的变量,视图中的值也更新吗?
<template>
<div>
<h3>{{ num }}----{{ count2 }}</h3>
<button @click="add">增加</button>
</div>
</template>
<script>
import { reactive, ref } from "@vue/reactivity";
export default {
setup() {
let test = {
num: 11,
};
let count = reactive(test);
let count2 = ref(22);
function add() {
count2.value++;
count.num++;
console.log(count.num); //12
console.log(test.num); //12
}
return {
...count,
count2,
add,
};
},
};
</script>
进一步的实践,我发现如果让reactive定义的变量失去响应式,按照上例同样的操作,并不能通过改变响应式变量更新视图中的值,去带动其他不响应式变量更新视图中的值。这就很奇怪了啊。那就不存在响应式带动非响应式,因为我是在写博客过程中发现的,具体原因只能后面深究了。 待定…