用Vue.js實(shí)現(xiàn)監(jiān)聽(tīng)屬性的變化
前言
創(chuàng)建 Vue 實(shí)例時(shí),Vue 將遍歷 data 的屬性,通過(guò) ES5 的 Object.defineProperty
將它們轉(zhuǎn)為 getter/setter,在其內(nèi)部 Vue 可以追蹤依賴(lài)、通知變化。
const vm = new Vue({ data: {foo: 1} // 'vm.foo' (在內(nèi)部,同 'this.foo') 是響應(yīng)的 })
觀察屬性變化
Vue 的實(shí)例提供了 $watch 方法,用于觀察屬性變化。
const vm = new Vue({ data: {foo: 1} }) vm.$watch('foo', function (newValue, oldValue) { console.log(newValue, oldValue) // 輸出 2 1 console.log(this.foo) // 輸出 2 }) vm.foo = 2
當(dāng)屬性變化后,響應(yīng)函數(shù)將會(huì)被調(diào)用,在其內(nèi)部,this 自動(dòng)綁定到 Vue 的實(shí)例 vm 上。
需要注意的是,響應(yīng)是異步的。
如下:
const vm = new Vue({ data: {foo: 1} }) vm.$watch('foo', function (newValue, oldValue) { console.log('inner:', newValue) // 后輸出 "inner" 2 }) vm.foo = 2 console.log('outer:', vm.foo) // 先輸出 "outer" 2
通過(guò) $watch Vue
實(shí)現(xiàn)了數(shù)據(jù)和視圖的綁定。觀察到數(shù)據(jù)變化,Vue 便異步更新 DOM ,在同一事件循環(huán)內(nèi),多次數(shù)據(jù)變化將會(huì)被緩存起來(lái),在下次事件循環(huán)中,Vue 刷新隊(duì)列并僅執(zhí)行必要的更新。
如下:
const vm = new Vue({ data: {foo: 1} }) vm.$watch('foo', function (newValue, oldValue) { console.log('inner:', newValue) // 后只輸出一次 "inner" 5 }) vm.foo = 2 vm.foo = 3 vm.foo = 4 console.log('outer:', vm.foo) // 先輸出 "outer" 4 vm.foo = 5
計(jì)算屬性
MV* 中,將 Model 層數(shù)據(jù)展現(xiàn)到 View,經(jīng)常有復(fù)雜的數(shù)據(jù)處理邏輯,這種情況下,使用計(jì)算屬性 (computed property) 更加明智。
const vm = new Vue({ data: { width: 0, height: 0, }, computed: { area () { let output = '' if (this.width > 0 && this.height > 0) { const area = this.width * this.height output = area.toFixed(2) + 'm²' } return output } } }) vm.width = 2.34 vm.height = 5.67 console.log(vm.area) // 輸出 "13.27m²"
在計(jì)算屬性?xún)?nèi)部,this 自動(dòng)綁定 vm,因此聲明計(jì)算屬性時(shí)需要避免使用箭頭函數(shù)。
上例中,vm.width
和 vm.height
是響應(yīng)的,vm.area
內(nèi)部首次讀取 this.width
和 this.height
時(shí),Vue 收集其做為 vm.area
的依賴(lài),此后 vm.width
或 vm.height
變化時(shí),vm.area
重新求值。計(jì)算屬性是基于它的依賴(lài)緩存,如果 vm.width
和 vm.height
沒(méi)有變化,多次讀取 vm.area
,會(huì)立即返回之前的計(jì)算結(jié)果,而不必再次求值。
同樣由于 vm.width
和 vm.height
是響應(yīng)的,在 vm.area
中可以將依賴(lài)的屬性賦值給一個(gè)變量,通過(guò)讀取變量來(lái)減少讀取屬性次數(shù),同時(shí)解決在條件分支中,Vue 有時(shí)會(huì)無(wú)法收集到依賴(lài)的問(wèn)題。
實(shí)現(xiàn)如下:
const vm = new Vue({ data: { width: 0, height: 0, }, computed: { area () { let output = '' const {width, height} = this if (width > 0 && height > 0) { const area = width * height output = area.toFixed(2) + 'm²' } return output } } }) vm.width = 2.34 vm.height = 5.67 console.log(vm.area) // 輸出 "13.27m²"
通過(guò) ob.js 單獨(dú)使用 Vue 的屬性觀察模塊
為方便學(xué)習(xí)和使用,ob.js 將 Vue 中屬性觀察模塊提取并封裝了一下。
ob.js GitHub 地址:https://github.com/cnlon/ob.js
安裝
npm install --save ob.js
觀察屬性變化
const target = {a: 1} ob(target, 'a', function (newValue, oldValue) { console.log(newValue, oldValue) // 3 1 }) target.a = 3
添加計(jì)算屬性
const target = {a: 1} ob.compute(target, 'b', function () { return this.a * 2 }) target.a = 10 console.log(target.b) // 20
像聲明 Vue 實(shí)例一樣傳入?yún)?shù)集合
const options = { data: { PI: Math.PI, radius: 1, }, computed: { 'area': function () { return this.PI * this.square(this.radius) }, }, watchers: { 'area': function (newValue, oldValue) { console.log(newValue) // 28.274333882308138 }, }, methods: { square (num) { return num * num }, }, } const target = ob.react(options) target.radius = 3
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。
相關(guān)文章
Vite+TS+Vue開(kāi)啟eslint和prettier規(guī)范及校驗(yàn)方式
這篇文章主要介紹了Vite+TS+Vue開(kāi)啟eslint和prettier規(guī)范及校驗(yàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06VUE3子表格嵌套分頁(yè)查詢(xún)互相干擾的問(wèn)題解決方案
這篇文章主要介紹了VUE3子表格嵌套分頁(yè)查詢(xún)互相干擾的問(wèn)題解決方案,如果不需要做子表格的分頁(yè)查詢(xún),那么可以直接在主表格中嵌套子表格,本文給大家介紹兩種方式,需要的朋友可以參考下2024-01-01vue 跳轉(zhuǎn)到其他頁(yè)面并關(guān)閉當(dāng)前頁(yè)面的實(shí)現(xiàn)代碼
我在做一個(gè)調(diào)用虛擬機(jī)錄屏的一個(gè)操作,需要在瀏覽器頁(yè)面上,點(diǎn)擊按鈕后,關(guān)閉當(dāng)前頁(yè)面里的某一個(gè)頁(yè)面,并且打開(kāi)瀏覽器新頁(yè)面是虛擬機(jī)的頁(yè)面,本文給大家介紹vue 跳轉(zhuǎn)到其他頁(yè)面并關(guān)閉當(dāng)前頁(yè)面的實(shí)現(xiàn)代碼,感興趣的朋友一起看看吧2023-09-09淺談Vue2.4.0 $attrs與inheritAttrs的具體使用
這篇文章主要介紹了淺談Vue2.4.0 $attrs與inheritAttrs的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03詳解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 構(gòu)建記事本應(yīng)用
本篇文章主要介紹了詳解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 構(gòu)建記事本應(yīng)用 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Vue使用CDN引用項(xiàng)目組件,減少項(xiàng)目體積的步驟
這篇文章主要介紹了Vue使用CDN引用項(xiàng)目組件,減少項(xiàng)目體積的步驟,幫助大家提高項(xiàng)目加載速度,感興趣的朋友可以了解下2020-10-10Vue Element前端應(yīng)用開(kāi)發(fā)之獲取后端數(shù)據(jù)
這篇文章主要介紹了Vue Element前端應(yīng)用開(kāi)發(fā)之獲取后端數(shù)據(jù),對(duì)vue感興趣的同學(xué),可以參考下2021-05-05