欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue雙向綁定及觀察者模式詳解

 更新時(shí)間:2019年03月19日 15:28:08   作者:qq_安之虛靜于幻_0  
這篇文章主要介紹了vue雙向綁定及觀察者模式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

在Vue中,使用了Object.defineProterty()這個(gè)函數(shù)來(lái)實(shí)現(xiàn)雙向綁定,這也就是為什么Vue不兼容IE8

1 響應(yīng)式原理

讓我們先從相應(yīng)式原理開(kāi)始。我們可以通過(guò)Object.defineProterty()來(lái)自定義Object的getter和setter 從而達(dá)到我們的目的。

代碼如下

function observe(value, cb) {
 Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}

function defineReactive (obj, key, val, cb) {
 Object.defineProperty(obj, key, {
  enumerable: true,
  configurable: true,
  get: ()=>{
   /*....依賴收集等....*/
   /*Github:https://github.com/answershuto*/
   return val
  },
  set:newVal=> {
   val = newVal;
   cb();/*訂閱者收到消息的回調(diào)*/
  }
 })
}

class Vue {
 constructor(options) {
  this._data = options.data;
  observe(this._data, options.render)
 }
}

let app = new Vue({
 el: '#app',
 data: {
  text: 'text',
  text2: 'text2'
 },
 render(){
  console.log("render");
 }
})

通過(guò)observe函數(shù)對(duì)app.data上的每一個(gè)key和value都設(shè)定getter和setter。當(dāng)value改變的時(shí)候觸發(fā)setter,就會(huì)觸發(fā)render這個(gè)函數(shù)。響應(yīng)式的目的就達(dá)成,如果是視圖更新的話我們通過(guò)監(jiān)聽(tīng)dom的input事件來(lái)觸發(fā)數(shù)據(jù)更新
但是現(xiàn)在我們只有在改變vue._data.text的時(shí)候才會(huì)觸發(fā)他們的setter,但是我想偷懶,只改變vue.text就能觸發(fā)到setter怎么做呢?

我們使用代理的方法

_proxy.call(this, options.data);/*構(gòu)造函數(shù)中*/

/*代理*/
function _proxy (data) {
 const that = this;
 Object.keys(data).forEach(key => {
  Object.defineProperty(that, key, {
   configurable: true,
   enumerable: true,
   get: function proxyGetter () {
    return that._data[key];
   },
   set: function proxySetter (val) {
    that._data[key] = val;
   }
  })
 });
}

依賴收集

讓我們?cè)賮?lái)看看下面的代碼

new Vue({
 template: 
  `<div>
   <span>text1:</span> {{text1}}
   <span>text2:</span> {{text2}}
  <div>`,
 data: {
  text1: 'text1',
  text2: 'text2',
  text3: 'text3'
 }
});

當(dāng)你的text3變化的時(shí)候,實(shí)際上text3并沒(méi)有被渲染,但是也會(huì)觸發(fā)一次render函數(shù),這顯然是不對(duì)的。所以我們需要收集依賴。

我們只需要在初始化的時(shí)候渲染一遍,那所有渲染所依賴的數(shù)據(jù)都會(huì)被觸發(fā)getter,這時(shí)候我們只要把這個(gè)數(shù)據(jù)放到一個(gè)列表里就好啦!

我們先來(lái)認(rèn)識(shí)一下Dep(dependencies)這個(gè)類,下圖是一個(gè)最簡(jiǎn)單的Dep類。我們可以把他理解為發(fā)布者(這點(diǎn)很重要?。。?br />

class Dep {
 constructor () {
  this.subs = [];
 }

 addSub (sub: Watcher) {
  this.subs.push(sub)
 }

 removeSub (sub: Watcher) {
  remove(this.subs, sub)
 }
 /*Github:https://github.com/answershuto*/
 notify () {
  // stabilize the subscriber list first
  const subs = this.subs.slice()
  for (let i = 0, l = subs.length; i < l; i++) {
   subs[i].update()
  }
 }
}
function remove (arr, item) {
 if (arr.length) {
  const index = arr.indexOf(item)
  if (index > -1) {
   return arr.splice(index, 1)
 }
}

我們每次觸發(fā)getter的時(shí)候,只要把觸發(fā)的對(duì)象放到dep.sub里面就好啦!
但是現(xiàn)在問(wèn)題來(lái)了,我們用什么來(lái)裝這個(gè)觸發(fā)的'對(duì)象',也可以說(shuō)式訂閱者呢?

我們使用Watcher這個(gè)類

class Watcher {
 constructor (vm, expOrFn, cb, options) {
  this.cb = cb;
  this.vm = vm;

  /*在這里將觀察者本身賦值給全局的target,只有被target標(biāo)記過(guò)的才會(huì)進(jìn)行依賴收集*/
  Dep.target = this;
  /*Github:https://github.com/answershuto*/
  /*觸發(fā)渲染操作進(jìn)行依賴收集*/
  this.cb.call(this.vm);
 }

 update () {
  this.cb.call(this.vm);
 }
}

vm即是vue實(shí)例, expOrFn就是{{a+b}}里面的a+b, cb就是回調(diào)函數(shù)就是return a+b, options是一些配置項(xiàng)。

Vue在第一次渲染列表的時(shí)候如果碰到{{xxx}}這樣的表達(dá)式,就會(huì)new Watcher()。解析里面的函數(shù),然后把當(dāng)前的watcher實(shí)例賦給Dep.target(Dep.target是全局的,一次性只能有一個(gè)存在,因?yàn)閂ue一次只處理一個(gè)依賴)。然后執(zhí)行回調(diào)函數(shù)。(這里看似是執(zhí)行回調(diào)函數(shù)渲染,其實(shí)又觸發(fā)了一次getter,然后就會(huì)把當(dāng)前的依賴添加到sub里去)

接下來(lái)開(kāi)始依賴收集

class Vue {
 constructor(options) {
  this._data = options.data;
  observer(this._data, options.render);
  let watcher = new Watcher(this, );
 }
}

function defineReactive (obj, key, val, cb) {
 /*在閉包內(nèi)存儲(chǔ)一個(gè)Dep對(duì)象*/
 const dep = new Dep();

 Object.defineProperty(obj, key, {
  enumerable: true,
  configurable: true,
  get: ()=>{
   if (Dep.target) {
    /*Watcher對(duì)象存在全局的Dep.target中*/
    dep.addSub(Dep.target);
   }
  },
  set:newVal=> {
   /*只有之前addSub中的函數(shù)才會(huì)觸發(fā)*/
   dep.notify();
  }
 })
}

Dep.target = null; //防止依賴重復(fù)添加

這兒我們通過(guò)示例來(lái)講解

<template>
 <div>
 {{a+b}}
 </div>
 <div>
 {{a-c}}
 </div>
</template>

<script>
let app = new Vue( {
 data :{
  a: 1,
  b: 2,
  c: 3
 }
 })

我們編譯到{{a+b}},會(huì)去實(shí)例化一個(gè)對(duì)應(yīng)的Watcher對(duì)象,Watcher的構(gòu)造函數(shù)中有這么一句

this.cb.call(this.vm);this.cb指的是function(){return a+b};this.vm指的是這個(gè)vue對(duì)象,這樣就會(huì)觸發(fā)vue.a和vue.b的getter方法,a,b都有自己的dep對(duì)象,我們通過(guò)Dep.target將這個(gè)Watcher對(duì)象就加到dep的subs數(shù)組中去了,當(dāng)我們變更a或者b是就會(huì)觸發(fā)setter,進(jìn)而觸發(fā)subs數(shù)組中的update方法,視圖中的a+b就會(huì)更新

有個(gè)小知識(shí)點(diǎn):我們新建一個(gè)屬性對(duì)象時(shí)必須通過(guò)Vue.set的方法去實(shí)現(xiàn),而不能直接通過(guò)=實(shí)現(xiàn),這樣會(huì)檢測(cè)不到,因?yàn)槲覀冊(cè)诔跏蓟瘯r(shí)就通過(guò)defineProperty重構(gòu)了這個(gè)對(duì)象屬性的getter和setter方法,新建的屬性則沒(méi)有所以不會(huì)被檢測(cè)到

下圖為Vue框架在數(shù)據(jù)初始化中使用觀察者模式的示意圖:

以上所述是小編給大家介紹的vue雙向綁定及觀察者模式詳解整合,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Vue項(xiàng)目部署的實(shí)現(xiàn)(阿里云+Nginx代理+PM2)

    Vue項(xiàng)目部署的實(shí)現(xiàn)(阿里云+Nginx代理+PM2)

    這篇文章主要介紹了Vue項(xiàng)目部署的實(shí)現(xiàn)(阿里云+Nginx代理+PM2),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-03-03
  • vue 錄制視頻并壓縮視頻文件的方法

    vue 錄制視頻并壓縮視頻文件的方法

    這篇文章主要介紹了vue 錄制視頻并壓縮視頻文件的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • Vue.use()在new Vue() 之前使用的原因淺析

    Vue.use()在new Vue() 之前使用的原因淺析

    本文通過(guò)實(shí)例代碼給大家介紹了為什么Vue.use()在new Vue() 之前使用,需要的朋友可以參考下
    2019-08-08
  • vue源碼解讀子節(jié)點(diǎn)優(yōu)化更新

    vue源碼解讀子節(jié)點(diǎn)優(yōu)化更新

    這篇文章主要為大家介紹了vue源碼解讀子節(jié)點(diǎn)優(yōu)化更新示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 項(xiàng)目中Axios二次封裝實(shí)例Demo

    項(xiàng)目中Axios二次封裝實(shí)例Demo

    vue項(xiàng)目經(jīng)常會(huì)用到axios來(lái)請(qǐng)求數(shù)據(jù),那么首先肯定需要對(duì)這個(gè)請(qǐng)求方法進(jìn)行一個(gè)二次封裝,這篇文章主要給大家介紹了關(guān)于項(xiàng)目中Axios二次封裝的相關(guān)資料,需要的朋友可以參考下
    2021-06-06
  • Vue3中slot插槽基本使用

    Vue3中slot插槽基本使用

    插槽slot可以說(shuō)在一個(gè)Vue項(xiàng)目里面處處都有它的身影,比如我們使用一些UI組件庫(kù)的時(shí)候,我們通??梢允褂貌宀蹃?lái)自定義我們的內(nèi)容,這篇文章主要介紹了Vue3中slot插槽使用方式,需要的朋友可以參考下
    2022-08-08
  • Vue綁定用戶接口實(shí)現(xiàn)代碼示例

    Vue綁定用戶接口實(shí)現(xiàn)代碼示例

    這篇文章主要介紹了Vue綁定用戶接口代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • vue3+高德地圖只展示指定市、區(qū)行政區(qū)域的地圖以及遮罩反向鏤空其他地區(qū)

    vue3+高德地圖只展示指定市、區(qū)行政區(qū)域的地圖以及遮罩反向鏤空其他地區(qū)

    vue大屏項(xiàng)目開(kāi)發(fā),客戶覺(jué)得地圖上的文字標(biāo)注太多了,要求地圖上只顯示省市等主要城市的標(biāo)注,這篇文章主要給大家介紹了關(guān)于vue3+高德地圖只展示指定市、區(qū)行政區(qū)域的地圖以及遮罩反向鏤空其他地區(qū)的相關(guān)資料,需要的朋友可以參考下
    2024-02-02
  • vue中使用axios請(qǐng)求post接口發(fā)送兩次

    vue中使用axios請(qǐng)求post接口發(fā)送兩次

    這篇文章主要為大家介紹了vue中使用axios請(qǐng)求post接口,請(qǐng)求會(huì)發(fā)送兩次原因解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Vue中使用vux配置代碼詳解

    Vue中使用vux配置代碼詳解

    這篇文章主要介紹了Vue中使用vux配置代碼詳解,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-09-09

最新評(píng)論