data () {
return {
nameList: ['jiang', 'ru', 'yi']
}
},
methods: {
handleClick () {
// 經過push,unshift等方法改變數組能夠經過watch監聽到
this.nameList.push('瑤')
// 直接經過數組下標進行修改數組沒法經過watch監聽到
this.nameList[2] = '愛'
// 經過$set修改數組能夠經過watch監聽到
this.$set(this.nameList, 2, '張')
// 利用數組splice方法修改數組能夠經過watch監聽到
this.nameList.splice(2, 1, '蔣如意')
}
},
watch: {
nameList (newVal) {
console.log(newVal)
}
}
複製代碼
變異方法
Vue包含一組觀察數組的變異方法,因此它們也將會觸發視圖更新,這些方法以下:vue
替換數組
變異方法,顧名思義,會改變被這些方法調用的原始數組。相比之下,也有非變異方法,例如:filter(),concat()和slice()。這些不會改變原始數組,但老是返回一個新數組。當使用非變異方法時,能夠用新數組替換就數組數組
注意事項
因爲JavaScript的限制,Vue不能檢測如下變更的數組
1.當你利用索引直接設置一個項時,例如:vm.items[index] = newValue
2.當你修改數組的長度時,例如:vm.items.length = newLength
爲了解決第一類問題,如下兩種方式能夠實現
瀏覽器
// 方法一
Vue.set(vm.items, index, newValue)
Vue.splice(index, 1, newValue)
複製代碼
爲了解決第二類問題,可使用splice
bash
vm.items.splice(newLength)
複製代碼
小發現:經過下標直接更改數組元素,沒法觸發渲染機制更新視圖,但此時數組的值已經發生變化,若同時有其餘數據更改致使從新渲染時,綁定數組的dom也會更新顯示最新的數據dom
obj: {
name: '蔣',
age: '28'
}
複製代碼
name和age兩個屬性從初始化的時候就已經肯定了,此時更改obj中的兩個屬性值是能夠被監聽到而且觸發視圖更新的; 若是經過js代碼對obj對象添加一個新屬性,那麼當這個屬性發生變化時是沒法被監聽到的,除非使用this.$set方法添加的新對象; 2. 數組也是一個對象,索引至關於對象屬性的key值,可是vue在針對單一的數組時,是沒有對該索引對應的值進行數據劫持的,因此直接更改數組元素的值沒法被監聽到, 而且不能觸發視圖更新,例如:測試
arr1: [1, 2, 3, 4];
經過arr1[0] = 666,沒法被監聽到
arr2: [
{
name: 'a'
},
{
name: 'b'
}
]
arr2[0].name = 'cc';
複製代碼
此時的更改是能夠被監聽到,而且觸發視圖更新的ui
個人疑問:爲何vue不對單一的數組元素進行數據劫持呢,親測能夠經過數據劫持的方式來觸發set方法this
// 個人測試方式以下
------------- def開始 -----------------
function def (obj, key, val) {
var value = val
Object.defineProperty(obj, key, {
set (newVal) {
console.log('觸發set')
value = newVal
},
get () {
return value
}
})
}
-------------- def結束 ----------------
var arr = [1, 2, 3]
arr.forEach((item, index) => {
def(arr, index, item)
})
arr[0] = 11
arr[1] = 22
console.log(arr) // [11, 22, 3]
-----------------------------
var obj = {
list: ['a', 'b', 'c']
}
obj.list.forEach((item, index) => {
def(obj.list, index, item)
})
obj.list[0] = 'jiang'
obj.list[1] = 'ru'
console.log(obj.list) // ['jiang', 'ru', 'c']
複製代碼
// 因爲瀏覽器兼容問題,Object.observe方法不能起到監聽數據變更,因此vue在實現的過程當中本身有封裝了Observe類spa
new Observer(value)
方法去處理該元素,就返回到最早類繼續往下走; 從第4步就能發現爲何經過索引改動數組的元素沒法觸發視圖更新了Object.keys()
方法來遍歷對象,而且調用 defineReactive(obj, keys[i])
方法Object.defineProperty()
方法去監聽對象中的每一個屬性;dep.notify()
方法,該方法就是去通知watcher觸發update方法去從新渲染視圖;// 因爲瀏覽器兼容問題,Object.observe
方法不能起到監聽數據變更,因此vue在實現的過程當中本身有封裝了 Observe 類
3d
// 例一:一個簡單的數組
data () {
return {
dataList: [1, 2, 3, 4]
}
},
methods: {
handleClick () {
this.dataList.forEach((item, index) => {
// 首先這裏經過遍歷數組改變元素的值,不能直接進行賦值更改,不然沒法被監聽到
// item = '你好'
// 須要用$set方法進行賦值
this.$set(this.dataList, index, '你好')
})
}
},
watch: {
dataList (newVal) {
console.log(newVal) // ['你好', '你好', '你好', '你好']
}
}
// 例二: 一個對象數組
data () {
return {
dataList: [
{
label: '一年級',
status: '上課'
},
{
label: '二年級',
status: '上課'
},
{
label: '三年級',
status: '上課'
},
{
label: '四年級',
status: '上課'
},
{
label: '五年級',
status: '上課'
},
{
label: '六年級',
status: '上課'
}
]
}
},
methods: {
handleClick () {
// 若是是對象數組,能夠經過這種方法改變元素的值,而且可以觸發視圖更行
this.dataList.forEach(item => {
item.status = '下課'
})
}
},
watch: {
// dataList (newVal) { // 沒法監聽到數組變化
// newVal.forEach(item => {
// console.log(item.status)
// })
// },
dataList: { // 經過設置deep的值能夠監聽到
handler () {
newVal.forEach(item => {
console.log(item.status) // '下課', '下課', '下課', '下課', '下課', '下課'
})
},
deep: true
}
}
複製代碼
經過上述例子能夠發現: