是一個計算屬性,相似於過濾器,對綁定到view的數據進行處理html
data: { firstName: 'Foo', lastName: 'Bar' }, computed: { fullName: function () { return this.firstName + ' ' + this.lastName } }
fullName不可在data裏面定義,
若是定義會報以下圖片的錯誤,由於對應的computed做爲計算屬性定義fullName並返回對應的結果給這個變量,變量不可被重複定義和賦值vue
data: { firstName: 'Foo', lastName: 'Bar' }, computed: { fullName:{ get(){//回調函數 當須要讀取當前屬性值是執行,根據相關數據計算並返回當前屬性的值 return this.firstName + ' ' + this.lastName }, set(val){//監視當前屬性值的變化,當屬性值發生變化時執行,更新相關的屬性數據 //val就是fullName的最新屬性值 console.log(val) const names = val.split(' '); console.log(names) this.firstName = names[0]; this.lastName = names[1]; } } }
watch是一個觀察的動做vuex
data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } }
上面是監聽firstName和lastName的變化,可是僅限簡單數據類型segmentfault
data(){ return{ 'first':2 } }, watch:{ first(){ console.log(this.first) } },
1.監聽複雜數據類型需用深度監聽api
data(){ return{ 'first':{ second:0 } } }, watch:{ secondChange:{ handler(oldVal,newVal){ console.log(oldVal) console.log(newVal) }, deep:true } },
2.console.log打印的結果,發現oldVal和newVal值是同樣的,因此深度監聽雖然能夠監聽到對象的變化,可是沒法監聽到具體對象裏面那個屬性的變化數組
3.oldVal和newVal值同樣的緣由是它們索引同一個對象/數組。Vue 不會保留修改以前值的副本
vm.$watch的深度監聽緩存
4.深度監聽對應的函數名必須爲handler,不然無效果,由於watcher裏面對應的是對handler的調用異步
方法一:能夠直接對用對象.屬性的方法拿到屬性 data(){ return{ 'first':{ second:0 } } }, watch:{ first.second:function(newVal,oldVal){ console.log(newVal,oldVal); } },
方法二:watch若是想要監聽對象的單個屬性的變化,必須用computed做爲中間件轉化,由於computed能夠取到對應的屬性值ide
data(){ return{ 'first':{ second:0 } } }, computed:{ secondChange(){ return this.first.second } }, watch:{ secondChange(){ console.log('second屬性值變化了') } },
1.是計算值,
2.應用:就是簡化tempalte裏面{{}}計算和處理props或$emit的傳值
3.具備緩存性,頁面從新渲染值不變化,計算屬性會當即返回以前的計算結果,而沒必要再次執行函數函數
1.是觀察的動做,
2.應用:監聽props,$emit或本組件的值執行異步操做
3.無緩存性,頁面從新渲染時值不變化也會執行
傳入的值想做爲局部變量來使用,直接使用會
props:['listShop'], data(){ return{} }, created(){ this.listShop=30 }
報錯
這個錯誤是說的避免直接修改父組件傳入的值,由於會改變父組件的值,貼上官網介紹
簡單數據類型解決方案:
因此能夠在data中從新定義一個變量,改變指向,可是也只是針對簡單數據類型,由於複雜數據類型棧存貯的是指針,
props:['listShop'], data(){ return{ listShopChild:this.listShop } }, created(){ this.listShopChild=30 }
這樣就能夠愉快的更改傳入的簡單數據類型的數據啦!不會有任何報錯,也不會影響父組件!
複雜數據類型在棧中存貯的是指針,因此賦值給新的變量也會改變原始的變量值.那麼應該咋整呢?
1.能夠手動深度克隆一個複雜的數據出來,循環或者遞歸都行
數組深度克隆:
var x = [1,2,3]; var y = []; for (var i = 0; i < x.length; i++) { y[i]=x[i]; } console.log(y); //[1,2,3] y.push(4); console.log(y); //[1,2,3,4] console.log(x); //[1,2,3]
對象深度克隆:
var x = {a:1,b:2}; var y = {}; for(var i in x){ y[i] = x[i]; } console.log(y); //Object {a: 1, b: 2} y.c = 3; console.log(y); //Object {a: 1, b: 2, c: 3} console.log(x); //Object {a: 1, b: 2}
函數深度克隆
var x = function(){console.log(1);}; var y = x; y = function(){console.log(2);}; x(); //1 y(); //2
爲何函數能夠直接賦值克隆?
因爲函數對象克隆以後的對象會單獨複製一次並存儲實際數據,所以並不會影響克隆以前的對象。因此採用簡單的複製「=」便可完成克隆。
2.Object.assign
只會對只是一級屬性複製,比淺拷貝多深拷貝了一層而已,因此仍是沒法達到深度克隆的目的.
詳請請戳
3.強大的JSON.stringify和JSON.parse
const obj1 = JSON.parse(JSON.stringify(obj));
這是ES5新出來的API,先將對象轉化爲字符串,就是簡單數據類型賦值,再用JSON.parse轉化
直接用computed改變
computed:{ listShopChild(){ return this.listShop } }
注意:此時用computed時,若是是數組this.$set(arr,1,true)對應的值耶不更新,
這個很坑,這個bug我找個好久
若是傳入的值只是在data定義,並未在methods或生命週期鉤子更改,直接改變也會報錯
因此仍是能夠先用局部變量接收,再修改,這個坑比較多
監聽本組件計算和監聽
計算或監聽父傳子的props值
分爲簡單數據類型和複雜數據類型監聽,監聽方法如上watch的使用
監聽vuex的state或者getters值的變化
computed:{ stateDemo(){ return this.$store.state.demoState; } } watch:{ stateDemo(){ console.log('vuex變化啦') } }
很開心小夥伴們能看到這裏,接下來給你們簡單羅列下他們的原理!
分爲三個過程:實例化Vue、調用$watch方法、屬性變化,觸發回調
Vue的數據依賴實現原理簡析
vue中$watch源碼閱讀筆記
公共類
function defineReactive(data, key, val, fn) { let subs = [] // 新增 Object.defineProperty(data, key, { configurable: true, enumerable: true, get: function() { // 新增 if (data.$target) { subs.push(data.$target) } return val }, set: function(newVal) { if (newVal === val) return fn && fn(newVal) // 新增 if (subs.length) { // 用 setTimeout 由於此時 this.data 還沒更新 setTimeout(() => { subs.forEach(sub => sub()) }, 0) } val = newVal }, }) }
function computed(ctx, obj) { let keys = Object.keys(obj) let dataKeys = Object.keys(ctx.data) dataKeys.forEach(dataKey => { defineReactive(ctx.data, dataKey, ctx.data[dataKey]) }) let firstComputedObj = keys.reduce((prev, next) => { ctx.data.$target = function() { ctx.setData({ [next]: obj[next].call(ctx) }) } prev[next] = obj[next].call(ctx) ctx.data.$target = null return prev }, {}) ctx.setData(firstComputedObj) }
function watch(ctx, obj) { Object.keys(obj).forEach(key => { defineReactive(ctx.data, key, ctx.data[key], function(value) { obj[key].call(ctx, value) }) }) }
https://segmentfault.com/a/11...你們若是發現有什麼錯誤,歡迎指正,共同交流。若是以爲篇文章真的對你有點做用。謝謝親們能看完!