<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>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] ***** ## 1 意義 >[info] 前端的視圖層和數據層之間的互動 >[info] 可以從視圖層發生改變后數據層發生改變 >[info] 也可以從數據層發生改變后視圖層發生改變 >[info] 因此需要雙向綁定實現視圖和數據之間的互動 ## 2 手動綁定 >[info] (1)從數據到視圖層 在數據對象上定義get和set方法 調用時手動調用get或set數據,改變數據后發出UI層的渲染操作 >[info] (2)從視圖到數據層的變化驅動 主要是input,select,textarea等表單元素的UI層發生變化 通過監聽dom的change,keypress,keyup等事件激活數據層數據的更新 ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>data-binding-method-set</title> </head> <body> ;UI視圖層 <input q-value="value" type="text" id="input"> <div q-text="value" id="el"></div> ;雙向綁定 <script> ;UI層 var elems = [document.getElementById('el'), document.getElementById('input')]; ;數據層 var data = { value: 'hello!' }; ;UI層修改 var command = { text: function(str){ this.innerHTML = str; }, value: function(str){ this.setAttribute('value', str); } }; ;節點掃描數據綁定處理 var scan = function(){ for(var i = 0, len = elems.length; i < len; i++){ ;當前元素節點 var elem = elems[i]; elem.command = []; ;元素節點屬性處理 for(var j = 0, len1 = elem.attributes.length; j < len1; j++){ ;當前處理屬性 var attr = elem.attributes[j]; ;屬性值修改 if(attr.nodeName.indexOf('q-') >= 0){ command[attr.nodeName.slice(2)].call(elem, data[attr.nodeValue]); elem.command.push(attr.nodeName.slice(2)); } } } } ;從數據層到UI層 function mvSet(key, value){ data[key] = value; scan(); } ;UI事件監聽 elems[1].addEventListener('keyup', function(e){ mvSet('value', e.target.value); }, false); ;開始掃描 scan(); ;定時修改數據層 setTimeout(function(){ mvSet('value', 'fuck'); },1000) </script> </body> </html> ~~~ ## 3 臟檢查 >[info] 檢查臟數據進行UI層的操作更新,臟檢查機制在數據發生變化時進行的。 >[info] 對UI層的dom事件,xht事件做了封裝,在里面觸發進入digest流程 >[info] digest流程里面,從rootscope開始遍歷,檢查所有的watcher。 >[info] 通過設置的數據來查找與數據相關的元素,比較數據變化,如果變化則進行指令操作 ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>data-binding-drity-check</title> </head> <body> ;UI層 <input q-event="value" ng-bind="value" type="text" id="input"> <div q-event="text" ng-bind="value" id="el"></div> ;數據綁定處理 <script> ;UI層 var elems = [document.getElementById('el'), document.getElementById('input')]; ;數據層 var data = { value: 'hello!' }; ;UI層修改 var command = { text: function(str) { this.innerHTML = str; }, value: function(str) { this.setAttribute('value', str); } }; ;UI層節點掃描處理 var scan = function(elems) { for (var i = 0, len = elems.length; i < len; i++) { ;當前節點 var elem = elems[i]; ;節點指令 elem.command = {}; ;節點屬性遍歷 for (var j = 0, len1 = elem.attributes.length; j < len1; j++) { var attr = elem.attributes[j]; ;事件屬性獲取 if (attr.nodeName.indexOf('q-event') >= 0) { ;獲取ng-bind屬性 var dataKey = elem.getAttribute('ng-bind') || undefined; ;注冊到節點指令 command[attr.nodeValue].call(elem, data[dataKey]); ;獲取節點指令對應的值 elem.command[attr.nodeValue] = data[dataKey]; } } } } ;臟檢查機制 var digest = function(elems) { ;節點遍歷 for (var i = 0, len = elems.length; i < len; i++) { ;當前節點 var elem = elems[i]; ;節點屬性遍歷 for (var j = 0, len1 = elem.attributes.length; j < len1; j++) { var attr = elem.attributes[j]; ;事件屬性獲取 if (attr.nodeName.indexOf('q-event') >= 0) { ;獲取ng-bind屬性的值 var dataKey = elem.getAttribute('ng-bind') || undefined; ;節點指令注冊 if(elem.command[attr.nodeValue] !== data[dataKey]){ command[attr.nodeValue].call(elem, data[dataKey]); elem.command[attr.nodeValue] = data[dataKey]; } } } } } ;遍歷節點初始化指令 scan(elems); ;數據劫持監聽 function $digest(value){ var list = document.querySelectorAll('[ng-bind='+ value + ']'); digest(list); } ;UI層事件注冊 if(document.addEventListener){ elems[1].addEventListener('keyup', function(e) { data.value = e.target.value; $digest(e.target.getAttribute('ng-bind')); }, false); }else{ elems[1].attachEvent('onkeyup', function(e) { data.value = e.target.value; $digest(e.target.getAttribute('ng-bind')); }, false); } ;數據層定時更新 setTimeout(function() { data.value = 'fuck'; $digest('value'); }, 2000) </script> </body> </html> ~~~ ## 4 前端數據劫持 >[info] 使用Object.defineProperty對數據對象做屬性get和set的監聽 >[info] 所有數據的讀取和賦值操作時則調用節點的指令。 >[info] 對應Object.defineProperty需要做瀏覽器兼容處理 ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>data-binding-hijacking</title> </head> <body> ;UI層 <input q-value="value" type="text" id="input"> <div q-text="value" id="el"></div> ;數據綁定 <script> ;UI層 var elems = [document.getElementById('el'), document.getElementById('input')]; ;數據層 var data = { value: 'hello!' }; ;UI層修改指令 var command = { text: function(str) { this.innerHTML = str; }, value: function(str) { this.setAttribute('value', str); } }; ;節點遍歷生成指令 var scan = function() { ;節點遍歷 for (var i = 0, len = elems.length; i < len; i++) { ;當前節點 var elem = elems[i]; ;節點的指令 elem.command = []; ;節點屬性遍歷 for (var j = 0, len1 = elem.attributes.length; j < len1; j++) { ;當前屬性 var attr = elem.attributes[j]; ;指令屬性 if (attr.nodeName.indexOf('q-') >= 0) { command[attr.nodeName.slice(2)].call(elem, data[attr.nodeValue]); elem.command.push(attr.nodeName.slice(2)); } } } } ;默認屬性 var bValue; ;屬性劫持 var defineGetAndSet = function(obj, propName) { try { Object.defineProperty(obj, propName, { get: function() { return bValue; }, set: function(newValue) { bValue = newValue; scan(); }, enumerable: true, configurable: true }); } catch (error) { console.log("browser not supported."); } } ;指令初始化 scan(); ;注冊數據監聽指令 defineGetAndSet(data, 'value'); ;UI層事件注冊 if(document.addEventListener){ elems[1].addEventListener('keyup', function(e) { data.value = e.target.value; }, false); }else{ elems[1].attachEvent('onkeyup', function(e) { data.value = e.target.value; }, false); } ;數據層自動更新 setTimeout(function() { data.value = 'fuck'; }, 2000) </script> </body> </html> ~~~ ## 5 小結 >[info] 數據綁定實現UI層與數據層的同步更新 >[info] UI層發生變化后數據層進行自動同步 >[info] 數據層發送變化UI層自動同步更新 >[info] 核心思路是UI層的事件監聽與數據層的set/get劫持 ## 6 參考連接 [數據綁定](https://ouvens.github.io/frontend-javascript/2015/11/29/js-data-two-ways-binding.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>

                              哎呀哎呀视频在线观看