亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

vue2.0雙向數據綁定的方法是什么

發布時間:2022-01-27 09:37:58 來源:億速云 閱讀:152 作者:iii 欄目:開發技術

這篇文章主要介紹“vue2.0雙向數據綁定的方法是什么”,在日常操作中,相信很多人在vue2.0雙向數據綁定的方法是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”vue2.0雙向數據綁定的方法是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

一.首先了解什么是發布訂閱模式

直接上代碼:一個簡單的發布訂閱模式,幫助大家更好的理解雙向數據綁定原理

//發布訂閱模式
function Dep() {
    this.subs = []//收集依賴(也就是手機watcher實例),
}
Dep.prototype.addSub = function (sub) { //添加訂閱者
    this.subs.push(sub); //實際上添加的是watcher這個實例
}
Dep.prototype.notify = function (sub) { //發布,這個方法的作用是遍歷數組,讓每個訂閱者的update方法去執行
    this.subs.forEach((sub) => sub.update())
}

function Watcher(fn) {
    this.fn = fn;
}
Watcher.prototype.update = function () { //添加一個update屬性讓每一個實例都可以繼承這個方法
    this.fn();
}
let watcher = new Watcher(function () {
    alert(1)
});//訂閱
let dep = new Dep();
dep.addSub(watcher);//添加依賴,添加訂閱者
dep.notify();//發布,讓每個訂閱者的update方法執行

二.new Vue()的時候做了什么?

只是針對雙向數據綁定做說明

<template>
      <div id="app">
        <div>obj.text的值:{{obj.text}}</div>
        <p>word的值:{{word}}</p>
        <input type="text" v-model="word">
    </div>
</template>
<script>
   new Vue({
        el: "#app",
        data: {
            obj: {
                text: "向上",
            },
            word: "學習"
        },
        methods:{
        //  ...
        }
    })
</script>

Vue 構造函數都干什么了?

function Vue(options = {}) {
    this.$options = options;//接收參數
    var data = this._data = this.$options.data;
    observer(data);//對data中的數據進型循環遞歸綁定
    for (let key in data) {
       let val = data[key];
       observer(val);
       Object.defineProperty(this, key, {
           enumerable: true,
           get() {
               return this._data[key];
           },
           set(newVal) {
               this._data[key] = newVal;
           }
        })
    }
    new Compile(options.el, this)
};

在 new Vue({…})構造函數時,首先獲取參數 options ,然后把參數中的 data 數據賦值給當前實例的 _data 屬性上(this._data = this.$options.data),重點來了,那下面的遍歷是為什么呢?首先我們在操作數據的時候是 this.word 獲取,而不是 this._data.word,所以是做了一個映射,在獲取數據的時候 this.word,其實是獲取的 this._data.word 的值,大家可以在自己項目中輸出this查看一下

vue2.0雙向數據綁定的方法是什么

1.接下來看看 observer 方法干了什么

function observer(data) {
    if (typeof data !== "object") return;
    return new Observer(data);//返回一個實例
}
function Observer(data) {
    let dep = new Dep();//創建一個dep實例
    for (let key in data) {//對數據進行循環遞歸綁定
        let val = data[key];
        observer(val);
        Object.defineProperty(data, key, {
            enumerable: true,
            get() {
               Dep.target && dep.depend(Dep.target);//Dep.target就是Watcher的一個實例
                return val;
            },
            set(newVal) {
                if (newVal === val) {
                    return;
                }
                val = newVal;
                observer(newVal);
                dep.notify() //讓所有方法執行
            }
        })
    }
}

Observer 構造函數,首先 let dep=new Dep(),作為之后的觸發數據劫持的 get 方法和 set 方法時,去收集依賴和發布時調用,主要的操作就是通過 Object.defineProperty 對 data 數據進行循環遞歸綁定,使用 getter/setter 修改其默認讀寫,用于收集依賴和發布更新。

2.再來看看 Compile 具體干了那些事情

function Compile(el, vm) {
    vm.$el = document.querySelector(el);
    let fragment = document.createDocumentFragment(); //創建文檔碎片,是object類型
    while (child = vm.$el.firstChild) {
        fragment.appendChild(child);
    };//用while循環把所有節點都添加到文檔碎片中,之后都是對文檔碎片的操作,最后再把文檔碎片添加到頁面中,這里有一個很重要的特性是,如果使用appendChid方法將原dom樹中的節點添加到fragment中時,會刪除原來的節點。
    replace(fragment);

    function replace(fragment) {
        Array.from(fragment.childNodes).forEach((node) => {//循環所有的節點
            let text = node.textContent;
            let reg = /\{\{(.*)\}\}/;
            if (node.nodeType === 3 && reg.test(text)) {//判斷當前節點是不是文本節點且符不符合{{obj.text}}的輸出方式,如果滿足條件說明它是雙向的數據綁定,要添加訂閱者(watcher)
                console.log(RegExp.$1); //obj.text
                let arr = RegExp.$1.split("."); //轉換成數組的方式[obj,text],方便取值
                let val = vm;
                arr.forEach((key) => { //實現取值this.obj.text
                    val = val[key];
                });
                new Watcher(vm, RegExp.$1, function (newVal) {
                    node.textContent = text.replace(/\{\{(.*)\}\}/, newVal)
                });
                node.textContent = text.replace(/\{\{(.*)\}\}/, val); //對節點內容進行初始化的賦值
            }
            if (node.nodeType === 1) { //說明是元素節點
                let nodeAttrs = node.attributes;
                Array.from(nodeAttrs).forEach((item) => {
                    if (item.name.indexOf("v-") >= 0) {//判斷是不是v-model這種指令
                        node.value = vm[item.value]//對節點賦值操作
                    }
                    //添加訂閱者
                    new Watcher(vm, item.value, function (newVal) {
                        node.value = vm[item.value]
                    });
                    node.addEventListener("input", function (e) {
                        let newVal = e.target.value;
                        vm[item.value] = newVal;
                    })
                })
            }
            if (node.childNodes) { //這個節點里還有子元素,再遞歸
                replace(node);
            }
        })
    }

    //這是頁面中的文檔已經沒有了,所以還要把文檔碎片放到頁面中
    vm.$el.appendChild(fragment);
}

Compile(編譯方法)首先解釋一下 DocuemntFragment(文檔碎片)它是一個 dom 節點收容器,當你創造了多個節點,當每個節點都插入到文檔當中都會引發一次回流,也就是說瀏覽器要回流多次,十分耗性能,而使用文檔碎片就是把多個節點都先放入到一個容器中,最后再把整個容器直接插入就可以了,瀏覽器只回流了1次。
Compile 方法首先遍歷文檔碎片的所有節點,
1.判斷是否是文本節點且符不符合{{obj.text}}的雙大括號的輸出方式,如果滿足條件說明它是雙向的數據綁定,要添加訂閱者(watcher),new Watcher(vm,動態綁定的變量,回調函數fn)
2.判斷是否是元素節點且屬性中是否含有 v-model 這種指令,如果滿足條件說明它是雙向的數據綁定,要添加訂閱者(watcher),new Watcher(vm,動態綁定的變量,回調函數fn) ,直至遍歷完成。最后別忘了把文檔碎片放到頁面中

3.Dep構造函數(怎么收集依賴的)

var uid=0;
//發布訂閱
function Dep() {
    this.id=uid++;
    this.subs = [];
}
Dep.prototype.addSub = function (sub) { //訂閱
    this.subs.push(sub); //實際上添加的是watcher這個實例
}
Dep.prototype.depend = function () { // 訂閱管理器
    if(Dep.target){//只有Dep.target存在時采取添加
        Dep.target.addDep(this);
    }
}
Dep.prototype.notify = function (sub) { //發布,遍歷數組讓每個訂閱者的update方法去執行
    this.subs.forEach((sub) => sub.update())
}

Dep 構造函數內部有一個 id 和一個 subs,id=uid++ ,id用于作為 dep 對象的唯一標識,subs 就是保存 watcher 的數組。depend 方法就是一個訂閱的管理器,會調用當前 watcher 的 addDep 方法添加訂閱者,當觸發數據劫持(Object.defineProperty)的 get 方法時會調用 Dep.target && dep.depend(Dep.target)添加訂閱者,當數據改變時觸發數據劫持(Object.defineProperty)的 set 方法時會調用 dep.notify 方法更新操作。

4.Watcher構造函數干了什么

function Watcher(vm, exp, fn) {
   this.fn = fn;
   this.vm = vm;
   this.exp = exp //
   this.newDeps = [];
   this.depIds = new Set();
   this.newDepIds = new Set();
   Dep.target = this; //this是指向當前(Watcher)的一個實例
   let val = vm;
   let arr = exp.split(".");
   arr.forEach((k) => { //取值this.obj.text
       val = val[k] //取值this.obj.text,就會觸發數據劫持的get方法,把當前的訂閱者(watcher實例)添加到依賴中
   });
   Dep.target = null;
}
Watcher.prototype.addDep = function (dep) {
   var id=dep.id;
   if(!this.newDepIds.has(id)){
       this.newDepIds.add(id);
       this.newDeps.push(dep);
       if(!this.depIds.has(id)){
           dep.addSub(this);
       }
   }
  
}
Watcher.prototype.update = function () { //這就是每個綁定的方法都添加一個update屬性
   let val = this.vm;
   let arr = this.exp.split(".");
   arr.forEach((k) => { 
       val = val[k] //取值this.obj.text,傳給fn更新操作
   });
   this.fn(val); //傳一個新值
}

Watcher 構造函數干了什么
1.接收參數,定義了幾個私有屬性( this.newDep ,this.depIds,this.newDepIds)
2. Dep.target = this,通過參數進行 data 取值操作,這就會觸發 Object.defineProperty 的 get 方法,它會通過訂閱者管理器(dep.depend())添加訂閱者,添加完之后再將 Dep.target=null 置為空;
3.原型上的 addDep 是通過id這個唯一標識,和幾個私有屬性的判斷防止訂閱者被多次重復添加
4.update 方法就是當數據更新時,dep.notify()執行,觸發訂閱者的 update 這個方法, 執行發布更新操作。

到此,關于“vue2.0雙向數據綁定的方法是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

vue
AI

延安市| 离岛区| 宁化县| 凭祥市| 泰和县| 锦屏县| 正蓝旗| 灵山县| 错那县| 涞源县| 宿松县| 石门县| 涪陵区| 古丈县| 红原县| 深圳市| 内乡县| 烟台市| 海安县| 射阳县| 昆山市| 体育| 科尔| 吴堡县| 雷波县| 黄浦区| 略阳县| 新蔡县| 三都| 乾安县| 玛曲县| 长顺县| 鹰潭市| 林甸县| 红原县| 女性| 中阳县| 黔西县| 奈曼旗| 庄河市| 东明县|