vm.$set(vm.info,'newKey','newValue')
vue是構建用戶界面的漸進式框架。所謂的漸進式:vue + components + vue-router + vuex + vue-cli
能夠根據須要選擇相應的功能。javascript
來串命令mkdir vue-apply;cd vue-apply;npm init -y;npm i vue
。html
來一個html文件以下,瀏覽器瞄下~,瀏覽器控制檯vm.msg=0
再看下vue
<div id="app">{{msg}}</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script> let vm = new Vue({ el:'#app', // template加上以後會替換掉#app這個標籤 // template:'<h1>en</h1>', data:{msg:'msg'} }) vm.msg = 'msg' </script>
複製代碼
mvc
實際上是model view Model
傳統全部邏輯在controller,難以維護。用戶輸入 => 控制器 => 數據改變,若是數據變了須要獲取dom,操做屬性,再渲染到視圖上。
mvvm
實際上是model view viewModel
數據變化驅動視圖。數據變了,不須要你獲取dom,而後改變dom的內容。這邊數據變了,vm負責監聽,視圖那邊自動發生變化。最明顯的是不須要document.querySelector
之類的了。java
上面說了vm負責讓數據變了,視圖能自動發生變化。這麼神奇魔術背後的原理是Object.defineProperty
。其實就是屬性的讀取和設置操做都進行了監聽,當有這樣的操做的時候,進行某種動做。來一個demo玩下。node
// 對obj上面的屬性進行讀取和設置監聽
let obj = {
name:'huahua',
age:18
}
function observer(obj){
if(typeof obj === 'object'){
for (const key in obj) {
defineReactive(obj,key,obj[key])
}
}
}
// get的return的值纔是最終你讀取到的值。因此設的值是爲讀取準備的。
// set傳的參數是設置的值,注意這裏不要有obj.name = newVal 這樣又觸發set監聽,會死循環的。
function defineReactive(obj,key,value){
Object.defineProperty(obj,key,{
get:function(){
console.log('你在讀取')
// happy的話這邊能夠value++,這樣你發現讀取的值始終比設置的大一個,由於return就是讀取到的值
return value
},
set:function(newVal){
console.log('數據更新了')
value = newVal
}
})
}
observer(obj)
obj.age = 2
console.log(obj.age)
複製代碼
在瀏覽器執行的時候,控制檯隨手也能夠obj.name="hua1"
相似的操做,發現都監聽到了。可是若是更深一步,obj.name={firstname:'hua',lastname:'piaoliang'};obj.name.lastname='o'
就不能監聽到屬性修改了。由於並無將新的賦值對象監聽其屬性。因此函數須要改進。 須要在defineReactive的第一行加上observer(value)
。設置值的時候若是是對象的話,也須要將這個對象數據劫持。同理,set那邊也須要加這行。vue-router
function defineReactive(obj,key,value){
// 注意這裏!!!!!!!
observer(value)
Object.defineProperty(obj,key,{
get:function(){
return value
},
set:function(newVal){
// 注意這裏!!!!!!!
observer(newVal)
console.log('數據更新了')
value = newVal
}
})
}
複製代碼
繼續,若是obj.name=[1,2,3];obj.name.push(4)
發現又沒有通知了,這是由於Object.defineProperty不支持監聽數組變化。因此須要重寫數組上面的方法。話說,最近看了個文章,理論上也能夠監聽數組,可是性能消耗和收益不成正比,因此,vue就沒去實現了。vuex
// 把數組上大部分方法重寫了,這裏不一一列舉。可是若是你 [1,2].length--,這是捕捉不到的
let arr = ['push','slice','split']
arr.forEach(method=>{
let oldPush = Array.property[method]
Array.property[method] = function(value){
console.log('數據更新')
oldPush.call(this,value)
}
})
複製代碼
正如上面的解釋,vue2.0的底層約莫是這個邏輯,因此使用須要注意的點:vue-cli
由於是一開始就數據劫持了。因此後來若是新綁定屬性,是沒有數據劫持的。若是須要調用 vm.$set(vm.info,'newKey','newValue')
,vm是vue的實例。npm
當屬性值是數組,數組變化的時候,跟蹤不到變化。由於數組雖然是對象,可是Object.defineProperty不支持數組,因此vue改寫了數組的全部方法,當調用數組方法的時候,就調動變更事件。可是不能經過屬性或者索引控制數組,好比length,index。數組
總結:data上,綁定全部屬性避免後期加新屬性。若是是數組,只能經過數組方法修改數組。以下例子,控制檯vm.arr--
發現視圖並不會變化,vm.arr.push(4)
就能變化
<div id="app">{{msg}}{{arr}}</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script> let vm = new Vue({ el:'#app', // template加上以後會替換掉#app這個標籤 // template:'<h1>en</h1>', data:{msg:'msg',arr:[1,2,3]} }) vm.msg = 'msg' </script>
複製代碼