vue的响应式-2
-
除了未被声明过和未被渲染的数据外,还有什么数据更改后不会渲染页面?
1. 利用索引直接设置一个数组项时:
<!-- 即使向数组中添加了第4项,数组仍然显示3项 --> <!-- 咳咳,一家三口,有第4个人也不能摆出来给大家看呀~ --> <div id="app">{{ dengFamily }}</div>
const vm = new Vue({ el: '#app' data: { dengFamily: ['邓哥', '小刘', '王小宝'] } }) vm.dengFamily[3] = '铁锤妹妹'; // 不是响应式的
2. 修改数组的长度时:
<!-- 更改了数组长度后,数组仍然显示1项 --> <div id="app">{{ dengWife }}</div>
const vm = new Vue({ el: '#app' data: { dengWife: ['小刘'] } }) vm.dengWife.length = 0; // 不是响应式的
3. 添加或删除对象:
<!-- 身高还是那个身高,媳妇也只有一个,不要痴心妄想 --> <div id="app">{{ deng }}</div>
const vm = new Vue({ el: '#app' data: { deng: { wife: '小刘', son: '王小宝', weight: '100kg', height: '140cm', age: 60 } } }) vm.deng.secondWife = '铁锤妹妹'; // 不是响应式的 delete vm.deng.height; // 不是响应式的
-
问:要如何响应式的更新数组和对象?
更改数组:
1. 利用数组变异方法:push、pop、shift、unshift、splice、sort、reverse
2. 利用vm.$set/Vue.set实例方法
3. 利用vm.$set或Vue.set删除数组中的某一项vm.$set是Vue.set的别名
使用方法:Vue.set(object, propertyName, value),也就是这个意思:Vue.set(要改谁,改它的什么,改成啥)vm.$delete是Vue.delete的别名
使用方法:Vue.delete(object, target),也就是这个意思:Vue.delete(要删除谁的值,删除哪个)<!-- 从此,一家三口过上了愉快生活 --> <div id="app">{{ list }}</div>
const vm = new Vue({ el: '#app' data: { dengFamily: ['邓哥', '小刘', '王小宝'] } }) // 使用数组变异方法 vm.dengFamily.push('铁锤妹妹'); // 使用vm.$set vm.$set(vm.dengFamily, 3, '铁锤妹妹');
<!-- 邓哥的媳妇多了起来~ --> <div id="app">{{ list }}</div>
const vm = new Vue({ el: '#app' data: { dengWife: ['小刘'] } }) // 更改长度时,可以用数组的splice方法 vm.dengWife.splice(100);
更改对象:
1. 添加利用vm.$set/Vue.set实例方法
2. 删除利用vm.$delete/Vue.delete方法<div id="app">{{ deng }}</div>
const vm = new Vue({ el: '#app' data: { deng: { wife: '小刘', son: '王小宝', weight: '100kg', height: '140cm', age: 60 } } }) // 添加 vm.$set(vm.deng, 'secondWife', '铁锤妹妹'); // 删除 vm.$delete(vm.deng, 'height')
-
总结:
更改数组用变异方法,就够了
更改对象就用vm.$set和vm.$delete
剖析Vue响应式原理
const data = {
name: 'shanshan',
age: 18,
shan: {
name: 'shanshan',
age: 18,
obj: {}
},
arr: [1, 2, 3]
}
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push', 'pop', 'shift', 'unshift' ,'sort', 'splice', 'reverse'].forEach(method => {
arrayMethods[method] = function () {
arrayProto[method].call(this, ...arguments);
render();
}
})
function defineReactive (data, key, value) {
observer(value);
Object.defineProperty(data, key, {
get () {
return value;
},
set (newVal) {
if(value === newVal) {
return;
}
value = newVal;
render();
}
})
}
function observer (data) {
if(Array.isArray(data)) {
data.__proto__ = arrayMethods;
return;
}
if(typeof data === 'object') {
for(let key in data) {
defineReactive(data, key, data[key])
}
}
}
function render () {
console.log('页面渲染啦');
}
function $set (data, key, value) {
if(Array.isArray(data)) {
data.splice(key, 1, value);
return value;
}
defineReactive(data, key, value);
render();
return value;
}
function $delete(data, key) {
if(Array.isArray(data)) {
data.splice(key, 1);
return;
}
delete data[key];
render();
}
observer(data);
利用Object.defineProperty实现响应式的劣势
- 天生就需要进行递归
- 监听不到数组不存在的索引的改变
- 监听不到数组长度的改变
- 监听不到对象的增删