Vue2响应式存在的问题
Vue2响应式存在以下问题(当然,Vue2也提供了对应的解决方法),
- 新增或删除对象属性,界面不会更新。
- 直接通过下标修改数组,界面不会更新。
暴露问题
- 入口文件main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
- App.vue
<template>
<div id="app">
<h2 v-show="person.name">姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<h2 v-show="person.gender">性别:{{person.gender}}</h2>
<h2>爱好:{{person.hobby}}</h2>
<button @click="addGender">新增属性:性别</button><br><br>
<button @click="deleteName">删除属性:姓名</button><br><br>
<button @click="updateArr">通过下标修改数组元素</button>
</div>
</template>
<script>
export default {
name: 'App',
data(){
return{
person:{
name:"张三",
age:18,
hobby:['吃饭','睡觉','打豆豆']
}
}
},
methods:{
addGender(){
console.log(this.person.gender);
this.person.gender = "男";
console.log(this.person.gender);
},
deleteName(){
console.log(this.person.name);
delete this.person.name;
console.log(this.person.name);
},
updateArr(){
console.log(this.person.hobby[0]);
this.person.hobby[0] = "阅读";
console.log(this.person.hobby[0]);
}
}
}
</script>
- 启动应用,测试效果
可以看到:新增属性、删除属性、通过下标修改数组元素,界面没有更新。
解决问题
解决方法有: this.$set
、 Vue.set
和 splice
(仅数组适用)。
- 修改后的App.vue
<template>
<div id="app">
<h2 v-show="person.name">姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<h2 v-show="person.gender">性别:{{person.gender}}</h2>
<h2>爱好:{{person.hobby}}</h2>
<button @click="addGender">新增属性:性别</button><br><br>
<button @click="deleteName">删除属性:姓名</button><br><br>
<button @click="updateArr">通过下标修改数组元素</button>
</div>
</template>
<script>
import Vue from "vue";
export default {
name: 'App',
data(){
return{
person:{
name:"张三",
age:18,
hobby:['吃饭','睡觉','打豆豆']
}
}
},
methods:{
addGender(){
//第一种方法
// this.$set(this.person,'gender','男');
//第二种方法
Vue.set(this.person,'gender','男');
},
deleteName(){
//第一种方法
// this.$delete(this.person,'name');
//第二种方法
Vue.delete(this.person,'name');
},
updateArr(){
//第一种方法
// this.$set(this.person.hobby,0,'阅读');
//第二种方法
// Vue.set(this.person.hobby,0,'阅读');
//第三种方法
this.person.hobby.splice(0,1,'阅读');
}
}
}
</script>
- 重启应用,测试效果
Vue3的响应式
刚刚提到Vue2响应式的缺点,如新增对象属性界面不更新、删除对象属性界面不更新、通过下标修改数组元素界面不更新,而这些问题在Vue3中不存在。
- 入口文件main.js
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app')
- App.vue
<template>
<h2 v-show="person.name">姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<h2 v-show="person.gender">性别:{{person.gender}}</h2>
<h2>爱好:{{person.hobby}}</h2>
<button @click="addGender">新增属性:性别</button><br><br>
<button @click="deleteName">删除属性:姓名</button><br><br>
<button @click="updateArr">通过下标修改数组元素</button>
</template>
<script>
import {reactive} from "vue";
export default {
name: 'App',
setup(){
let person = reactive({
name:"张三",
age:18,
hobby:['吃饭','睡觉','打豆豆']
})
function addGender(){
person.gender = "男";
}
function deleteName(){
delete person.name;
}
function updateArr(){
person.hobby[0] = "阅读";
}
return {
person,
addGender,
deleteName,
updateArr
}
}
}
</script>
- 启动项目,测试效果
Vue3响应式原理
Vue3的响应式原理是,通过 代理对象 对 源对象的属性 进行操作。下面将模拟Vue3响应式原理。
- Proxy实现代理
const person = {
name:"张三",
age:18
}
const p = new Proxy(person,{
get(target,propName){
console.log("读取了属性");
return target[propName];
},
set(target,propName,value){
console.log("修改了属性,将通知界面更新");
target[propName] = value;
},
deleteProperty(target,propName){
console.log("删除了属性,将通知界面更新");
return delete target[propName];
}
})
- 用Reflect对源对象进行操作
const person = {
name:"张三",
age:18
}
const p = new Proxy(person,{
get(target,propName){
console.log("读取了属性");
// return target[propName];
return Reflect.get(target,propName);
},
set(target,propName,value){
console.log("修改了属性,将通知界面更新");
// target[propName] = value;
return Reflect.set(target,propName,value);
},
deleteProperty(target,propName){
console.log("删除了属性,将通知界面更新");
// return delete target[propName];
return Reflect.deleteProperty(target,propName);
}
})