<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] ---------- ## MVVM是什么? MVVM 是Model-View-ViewModel 的縮寫,它是一種基于前端開發的架構模式,其核心是提供對View 和 ViewModel 的雙向數據綁定,這使得ViewModel 的狀態改變可以自動傳遞給 View,即所謂的數據雙向綁定。 ![](https://box.kancloud.cn/eb5c6e9f9bb7107c374dd892f6d7d38f_600x287.png) Vue.js 是一個提供了 MVVM 風格的雙向數據綁定的 Javascript 庫,專注于View 層。它的核心是 MVVM 中的 VM,也就是 ViewModel。 ViewModel負責連接 View 和 Model,保證視圖和數據的一致性,這種輕量級的架構讓前端開發更加高效、便捷。 ### Vue 雙向綁定原理 Vue.js 是采用[ Object.defineProperty ](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)的 getter 和 setter,并結合觀察者模式來實現數據綁定的。當把一個普通 Javascript 對象傳給 Vue 實例來作為它的 data 選項時,Vue 將遍歷它的屬性,用 Object.defineProperty 將它們轉為 getter/setter。用戶看不到 getter/setter,但是在內部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時通知變化。 ![](https://box.kancloud.cn/04772e55186c0805646fe1bd1696d5d3_647x334.png) >[success]預覽:https://ityanxi.github.io/Vue-tutorial/chapter02/js-mvvm.html >[success]代碼示例如下: ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>it研習社-Vue雙向數據綁定實現原理</title> </head> <body> <div id="app"> <input type="text" v-model="text"> {{ text }} </div> <script> function observe (obj, vm) { Object.keys(obj).forEach(function (key) { defineReactive(vm, key, obj[key]); }); } function defineReactive (obj, key, val) { var dep = new Dep(); Object.defineProperty(obj, key, { get: function () { // 添加訂閱者watcher到主題對象Dep if (Dep.target) dep.addSub(Dep.target); return val }, set: function (newVal) { if (newVal === val) return       val = newVal; // 作為發布者發出通知 dep.notify(); } }); } function nodeToFragment (node, vm) { var flag = document.createDocumentFragment(); var child; while (child = node.firstChild) { compile(child, vm); flag.append(child); // 將子節點劫持到文檔片段中 } return flag; } function compile (node, vm) { var reg = /\{\{(.*)\}\}/; // 節點類型為元素 if (node.nodeType === 1) { var attr = node.attributes; // 解析屬性 for (var i = 0; i < attr.length; i++) { if (attr[i].nodeName == 'v-model') { var name = attr[i].nodeValue; // 獲取v-model綁定的屬性名 node.addEventListener('input', function (e) { // 給相應的data屬性賦值,進而觸發該屬性的set方法 vm[name] = e.target.value; }); node.value = vm[name]; // 將data的值賦給該node node.removeAttribute('v-model'); } }; } // 節點類型為text if (node.nodeType === 3) { if (reg.test(node.nodeValue)) { var name = RegExp.$1; // 獲取匹配到的字符串 name = name.trim(); // node.nodeValue = vm[name]; // 將data的值賦給該node new Watcher(vm, node, name); } } } function Watcher (vm, node, name) { Dep.target = this; this.name = name; this.node = node; this.vm = vm; this.update(); Dep.target = null; } Watcher.prototype = { update: function () { this.get(); this.node.nodeValue = this.value; }, // 獲取data中的屬性值 get: function () { this.value = this.vm[this.name]; // 觸發相應屬性的get } } function Dep () { this.subs = [] } Dep.prototype = { addSub: function(sub) { this.subs.push(sub); }, notify: function() { this.subs.forEach(function(sub) { sub.update(); }); } }; function Vue (options) { this.data = options.data; var data = this.data; observe(data, this); var id = options.el; var dom = nodeToFragment(document.getElementById(id), this); // 編譯完成后,將dom返回到app中 document.getElementById(id).appendChild(dom); } var vm = new Vue({ el: 'app', data: { text: 'hello world' } }); </script> </body> </html> ~~~ ![](https://box.kancloud.cn/3dd36cae8a7a50e31425254155b53b3b_624x346.png) >**Observer 數據監聽器**,能夠對數據對象的所有屬性進行監聽,如有變動可拿到最新值并通知訂閱者,內部采用Object.defineProperty的getter和setter來實現。 **Compile 指令解析器**,它的作用對每個元素節點的指令進行掃描和解析,根據指令模板替換數據,以及綁定相應的更新函數。 **Watcher 訂閱者**, 作為連接 Observer 和 Compile 的橋梁,能夠訂閱并收到每個屬性變動的通知,執行指令綁定的相應回調函數。 **Dep 消息訂閱器**,內部維護了一個數組,用來收集訂閱者(Watcher),數據變動觸發notify 函數,再調用訂閱者的 update 方法。 從圖中可以看出,當執行 new Vue() 時,Vue 就進入了初始化階段,一方面Vue 會遍歷 data 選項中的屬性,并用 Object.defineProperty 將它們轉為 getter/setter,實現數據變化監聽功能;另一方面,Vue 的指令編譯器Compile 對元素節點的指令進行掃描和解析,初始化視圖,并訂閱Watcher 來更新視圖, 此時Wather 會將自己添加到消息訂閱器中(Dep),初始化完畢。 當數據發生變化時,Observer 中的 setter 方法被觸發,setter 會立即調用Dep.notify(),Dep 開始遍歷所有的訂閱者,并調用訂閱者的 update 方法,訂閱者收到通知后對視圖進行相應的更新。 ### 雙向綁定示例 MVVM模式本身是實現了雙向綁定的,在Vue.js中可以使用v-model指令在表單元素上創建雙向數據綁定。 ~~~ <!--這是我們的View--> <div id="app"> <p>{{ message }}</p> <input type="text" v-model="message"/> </div> ~~~ >[success]預覽:https://ityanxi.github.io/Vue-tutorial/chapter02/vue-mvvm.html >[success]代碼示例如下: ~~~ <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>it研習社-基于Vue實現的 數據雙向綁定</title> <style type="text/css"> #demo{ width: 800px; margin: 200px auto; } input{ width: 600px; height: 50px; border:10px solid green; padding-left: 10px; font:30px/50px "微軟雅黑"; } .msg{ width: 600px; font:30px/50px "微軟雅黑"; color:red; } </style> <script src="vue.js"></script> <script type="text/javascript"> window.onload=function(){ new Vue({ el: '#demo', data: { msg:'welcome vue.js', } }) } </script> </head> <body> <div id="demo"> <input v-model='msg'/> <div class="msg"> {{msg}} </div> </div> </body> </html> ~~~ 將message綁定到文本框,當更改文本框的值時,{{ message }} 中的內容也會被更新。 ![](https://box.kancloud.cn/3dd7204e47bdcfebbc88e75e2a40d7f2_449x212.gif) 反過來,如果改變message的值,文本框的值也會被更新,我們可以在Chrome控制臺進行嘗試。 ![](https://box.kancloud.cn/184bf84402dd679852660846f51df5f0_678x596.gif) Vue實例的data屬性指向exampleData,它是一個引用類型,改變了exampleData對象的屬性,同時也會影響Vue實例的data屬性。 接下來,我們來做一個關于數據綁定的小練習 >[success]預覽:https://ityanxi.github.io/Vue-tutorial/chapter02/vue-mvvm1.html ![](https://box.kancloud.cn/f3fe8c58de408b704ae84c6785e2417f_472x77.png) >[success]代碼示例如下: ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Vue雙向數據綁定練習</title> <script src="vue.js"></script> </head> <body> <div id="demo"> 姓:<input type="text" v-model="firstName"> 名:<input type="text" v-model="lastName"> <hr> 姓名:{{firstName+lastName}} </div> <script> var vm=new Vue({ el:"#demo", data:{ firstName:"huang", lastName:"jack", } }); </script> </body> </html> ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看