最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue單向數(shù)據(jù)綁定和雙向數(shù)據(jù)綁定方式

 更新時(shí)間:2023年07月06日 08:43:10   作者:菜鳥上道?請多指教  
這篇文章主要介紹了vue單向數(shù)據(jù)綁定和雙向數(shù)據(jù)綁定方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一、總結(jié)

vue中有2種數(shù)據(jù)綁定的方式:

  • 單向數(shù)據(jù)綁定(v-bind):數(shù)據(jù)只能從data流向頁面;
  • 雙向數(shù)據(jù)綁定(v-model):數(shù)據(jù)不僅能從data流向頁面,還可以從頁面流向data;

備注:

  • 雙向數(shù)據(jù)綁定一般都應(yīng)用在表單類(輸入類)元素上 (如:input、select等);
  • v-model:value可以簡寫為v-model,因?yàn)関-model默認(rèn)收集的就是value的值;

二、分析

  • 單向數(shù)據(jù)綁定:就是把Model綁定到View,當(dāng)我們用JavaScript代碼更新Model時(shí),View就會(huì)自動(dòng)更新雙向綁定就很容易聯(lián)想到了;
  • 雙向數(shù)據(jù)綁定:在單向綁定的基礎(chǔ)上,用戶更新了View,Model的數(shù)據(jù)也自動(dòng)被更新了

三、 雙向綁定的原理

 Vue 是數(shù)據(jù)雙向綁定的框架,雙向綁定由三個(gè)重要部分構(gòu)成:

  • 數(shù)據(jù)層(Model):應(yīng)用的數(shù)據(jù)及業(yè)務(wù)邏輯
  • 視圖層(View):應(yīng)用的展示效果,各類UI組件
  • 業(yè)務(wù)邏輯層(ViewModel):框架封裝的核心,它負(fù)責(zé)將數(shù)據(jù)與視圖關(guān)聯(lián)起來

理解ViewModel,它的主要職責(zé)就是:

  • 數(shù)據(jù)變化后更新視圖
  • 視圖變化后更新數(shù)據(jù)

它還有兩個(gè)主要部分組成

  • 監(jiān)聽器(Observer):對(duì)所有數(shù)據(jù)的屬性進(jìn)行監(jiān)聽
  • 解析器(Compiler):對(duì)每個(gè)元素節(jié)點(diǎn)的指令進(jìn)行掃描跟解析,根據(jù)指令模板替換數(shù)據(jù),以及綁定相應(yīng)的更新函數(shù)

四、實(shí)現(xiàn)雙向綁定

  • new vue()首先執(zhí)行初始化,對(duì)data執(zhí)行響應(yīng)式處理,這個(gè)過程發(fā)生在observe中;
  • 同時(shí)對(duì)模板執(zhí)行編譯,找到其中動(dòng)態(tài)綁定的數(shù)據(jù),從data中獲取并初始化視圖,這個(gè)過程發(fā)生在Compile中;
  • 同時(shí)定義一個(gè)更新函數(shù)和Watcher,將來對(duì)應(yīng)數(shù)據(jù)變化時(shí)Watcher會(huì)調(diào)用更新函數(shù);
  • 由于data中的某個(gè)key在一個(gè)視圖中可能出現(xiàn)多次,所以每個(gè)key都需要一個(gè)管家Dep來管理多個(gè)Watcher
  • 將來data中數(shù)據(jù)一旦發(fā)生變化,會(huì)首先找到對(duì)應(yīng)的Dep,通知所有Watcher執(zhí)行更新函數(shù);

 

五、實(shí)現(xiàn)

先來一個(gè)構(gòu)造函數(shù):執(zhí)行初始化,對(duì)data執(zhí)行響應(yīng)化處理

class Vue {  
  constructor(options) {  
    this.$options = options;  
    this.$data = options.data;  
    // 對(duì)data選項(xiàng)做響應(yīng)式處理  
    observe(this.$data);  
    // 代理data到vm上  
    proxy(this);  
    // 執(zhí)行編譯  
    new Compile(options.el, this);  
  }  
}  

對(duì)data選項(xiàng)執(zhí)行響應(yīng)化具體操作

function observe(obj) {  
  if (typeof obj !== "object" || obj == null) {  
    return;  
  }  
  new Observer(obj);  
}  
class Observer {  
  constructor(value) {  
    this.value = value;  
    this.walk(value);  
  }  
  walk(obj) {  
    Object.keys(obj).forEach((key) => {  
      defineReactive(obj, key, obj[key]);  
    });  
  }  
}  

編譯Compile

對(duì)每個(gè)元素節(jié)點(diǎn)的指令進(jìn)行掃描跟解析,根據(jù)指令模板替換數(shù)據(jù),以及綁定相應(yīng)的更新函數(shù)

class Compile {  
  constructor(el, vm) {  
    this.$vm = vm;  
    this.$el = document.querySelector(el);  // 獲取dom  
    if (this.$el) {  
      this.compile(this.$el);  
    }  
  }  
  compile(el) {  
    const childNodes = el.childNodes;   
    Array.from(childNodes).forEach((node) => { // 遍歷子元素  
      if (this.isElement(node)) {   // 判斷是否為節(jié)點(diǎn)  
        console.log("編譯元素" + node.nodeName);  
      } else if (this.isInterpolation(node)) {  
        console.log("編譯插值?本" + node.textContent);  // 判斷是否為插值文本 {{}}  
      }  
      if (node.childNodes && node.childNodes.length > 0) {  // 判斷是否有子元素  
        this.compile(node);  // 對(duì)子元素進(jìn)行遞歸遍歷  
      }  
    });  
  }  
  isElement(node) {  
    return node.nodeType == 1;  
  }  
  isInterpolation(node) {  
    return node.nodeType == 3 && /\{\{(.*)\}\}/.test(node.textContent);  
  }  
}  

收集依賴

視圖中會(huì)用到data中某key,這稱為依賴。同一個(gè)key可能出現(xiàn)多次,每次都需要收集出來用一個(gè)Watcher來維護(hù)它們,此過程稱為依賴收集多個(gè)Watcher需要一個(gè)Dep來管理,需要更新時(shí)由Dep統(tǒng)一通知;

實(shí)現(xiàn)思路

  • defineReactive是為每一個(gè)key創(chuàng)建一個(gè)Dep實(shí)例;
  • 初始化視圖時(shí)讀取某個(gè)key,例如name1,創(chuàng)建一個(gè)Wathcher1;
  • 由于觸發(fā)name1的getter方法,便將Wathcher1添加到name1的對(duì)應(yīng)的Dep中;
  • 當(dāng)name1更新,setter觸發(fā)時(shí),便可通過對(duì)應(yīng)Dep通知其管理所有Watncer更新;
// 負(fù)責(zé)更新視圖  
class Watcher {  
  constructor(vm, key, updater) {  
    this.vm = vm  
    this.key = key  
    this.updaterFn = updater  
    // 創(chuàng)建實(shí)例時(shí),把當(dāng)前實(shí)例指定到Dep.target靜態(tài)屬性上  
    Dep.target = this  
    // 讀一下key,觸發(fā)get  
    vm[key]  
    // 置空  
    Dep.target = null  
  }  
  // 未來執(zhí)行dom更新函數(shù),由dep調(diào)用的  
  update() {  
    this.updaterFn.call(this.vm, this.vm[this.key])  
  }  
}  

聲明Dep

class Dep {  
  constructor() {  
    this.deps = [];  // 依賴管理  
  }  
  addDep(dep) {  
    this.deps.push(dep);  
  }  
  notify() {   
    this.deps.forEach((dep) => dep.update());  
  }  
}  

創(chuàng)建watcher時(shí)觸發(fā)getter

class Watcher {  
  constructor(vm, key, updateFn) {  
    Dep.target = this;  
    this.vm[this.key];  
    Dep.target = null;  
  }  
}  

依賴收集,創(chuàng)建Dep實(shí)例

function defineReactive(obj, key, val) {  
  this.observe(val);  
  const dep = new Dep();  
  Object.defineProperty(obj, key, {  
    get() {  
      Dep.target && dep.addDep(Dep.target);// Dep.target也就是Watcher實(shí)例  
      return val;  
    },  
    set(newVal) {  
      if (newVal === val) return;  
      dep.notify(); // 通知dep執(zhí)行更新方法  
    },  
  });  
}  

最后

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論

共和县| 酒泉市| 瓦房店市| 芮城县| 乡城县| 耿马| 乡城县| 洞头县| 凤城市| 如皋市| 五莲县| 南漳县| 建宁县| 海伦市| 门头沟区| 治县。| 崇信县| 侯马市| 晋江市| 昌平区| 邢台县| 通州区| 宜兰市| 黎城县| 定州市| 鄂托克前旗| 阳新县| 芦山县| 独山县| 中方县| 罗平县| 来宾市| 三门峡市| 渝北区| 莒南县| 白山市| 如东县| 申扎县| 政和县| 高雄县| 阳原县|