<font id="zqva1"></font>
<rt id="zqva1"></rt>
  • <tt id="zqva1"></tt>
    <cite id="zqva1"></cite>

    <cite id="zqva1"><noscript id="zqva1"></noscript></cite>
      <rp id="zqva1"><meter id="zqva1"></meter></rp>

        <cite id="zqva1"></cite>
          <b id="zqva1"></b>
          <rp id="zqva1"></rp>
          <cite id="zqva1"></cite>

          <rt id="zqva1"></rt>

        1. <rp id="zqva1"></rp>

          原生js實現數據雙向綁定的三種方式總匯

          時間:?2017-11-29閱讀:?2176標簽:?雙向綁定

          前端數據的雙向綁定方法

          前端的視圖層和數據層有時需要實現雙向綁定(two-way-binding),例如mvvm框架,數據驅動視圖,視圖狀態機等,研究了幾個目前主流的數據雙向綁定框架,總結了下。目前實現數據雙向綁定主要有以下三種。


          1、手動綁定

          比較老的實現方式,有點像觀察者編程模式,主要思路是通過在數據對象上定義get和set方法(當然還有其它方法),調用時手動調用get或set數據,改變數據后出發UI層的渲染操作;以視圖驅動數據變化的場景主要應用與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>
              <input q-value="value" type="text" id="input">
              <div q-text="value" id="el"></div>
              <script>
                  var elems = [document.getElementById('el'), document.getElementById('input')];
          
                  var data = {
                      value: 'hello!'
                  };
          
                  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));
                              }
                          }
                      }
                  }
          
                  /**
                   * 設置數據后掃描
                   */
                  function mvSet(key, value){
                      data[key] = value;
                      scan();
                  }
                  /**
                   * 數據綁定監聽
                   */
                  elems[1].addEventListener('keyup', function(e){
                      mvSet('value', e.target.value);
                  }, false);
          
                  scan();
          
                  /**
                   * 改變數據更新視圖
                   */
                  setTimeout(function(){
                      mvSet('value', 'fuck');
                  },1000)
          
              </script>
          </body>
          </html>
          
          


          2、臟檢查機制

          以典型的mvvm框架angularjs為代表,angular通過檢查臟數據來進行UI層的操作更新。關于angular的臟檢測,有幾點需要了解些:

          • 臟檢測機制并不是使用定時檢測。
          • 臟檢測的時機是在數據發生變化時進行。
          • angular對常用的dom事件,xhr事件等做了封裝, 在里面觸發進入angular的digest流程。
          • 在digest流程里面, 會從rootscope開始遍歷, 檢查所有的watcher。 (關于angular的具體設計可以看其他文檔,這里只討論數據綁定),那我們看下臟檢測該如何去做:主要是通過設置的數據來需找與該數據相關的所有元素,然后再比較數據變化,如果變化則進行指令操作
          <!DOCTYPE html>
          <html lang="en">
          
          <head>
              <meta charset="UTF-8">
              <title>data-binding-drity-check</title>
          </head>
          
          <body>
              <input q-event="value" ng-bind="value" type="text" id="input">
              <div q-event="text" ng-bind="value" id="el"></div>
              <script>
          
              var elems = [document.getElementById('el'), document.getElementById('input')];
              
              var data = {
                  value: 'hello!'
              };
          
              var command = {
                  text: function(str) {
                      this.innerHTML = str;
                  },
                  value: function(str) {
                      this.setAttribute('value', str);
                  }
              };
          
              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) {
                              /**
                               * 調用屬性指令
                               */
                              var dataKey = elem.getAttribute('ng-bind') || undefined;
                              /**
                               * 進行數據初始化
                               */
                              command[attr.nodeValue].call(elem, data[dataKey]);
                              elem.command[attr.nodeValue] = data[dataKey];
                          }
                      }
                  }
              }
          
              /**
               * 臟循環檢測
               * @param  {[type]} elems [description]
               * @return {[type]}       [description]
               */
              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) {
                              /**
                               * 調用屬性指令
                               */
                              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);
              }
          
              /**
               * 輸入框數據綁定監聽
               */
              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這里關鍵的是需要手動調用$digest方法來啟動臟檢測
                   */
                  $digest('value');
              }, 2000)
          
              </script>
          </body>
          </html>
          


          3、前端數據劫持(Hijacking)

          第三種方法則是avalon等框架使用的數據劫持方式。基本思路是使用Object.defineProperty對數據對象做屬性get和set的監聽,當有數據讀取和賦值操作時則調用節點的指令,這樣使用最通用的=等號賦值就可以了。具體實現如下:

          <!DOCTYPE html>
          <html lang="en">
          
          <head>
              <meta charset="UTF-8">
              <title>data-binding-hijacking</title>
          </head>
          
          <body>
              <input q-value="value" type="text" id="input">
              <div q-text="value" id="el"></div>
              <script>
          
          
              var elems = [document.getElementById('el'), document.getElementById('input')];
          
              var data = {
                  value: 'hello!'
              };
          
              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');
          
              /**
               * 數據綁定監聽
               */
              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>
          
          

          但值得注意的是defineProperty支持IE8以上的瀏覽器,這里可以使用__defineGetter__ 和 __defineSetter__ 來做兼容但是瀏覽器兼容性的原因,直接用defineProperty就可以了。至于IE8瀏覽器仍需要使用其它方法來做hack。如下代碼可以對IE8進行hack,defineProperty支持IE8。例如使用es5-shim.js就可以了。(IE8以下瀏覽器忽略)


          4、小結

          首先這里的例子只是簡單的實現,讀者可以深入感受三種方式的異同點,復雜的框架也是通過這樣的基本思路滾雪球滾大的。

          參考:https://gist.github.com/brettz9/4093766#file_html5_dataset.js https://github.com/xufei/blog/issues/10
          原文鏈接:http://jixianqianduan.com/frontend-javascript/2015/11/29/js-data-two-ways-binding.html  


          站長推薦

          1.阿里云: 本站目前使用的是阿里云主機,安全/可靠/穩定。點擊領取2000元代金券、了解最新阿里云產品的各種優惠活動點擊進入

          2.騰訊云: 提供云服務器、云數據庫、云存儲、視頻與CDN、域名等服務。騰訊云各類產品的最新活動,優惠券領取點擊進入

          3.廣告聯盟: 整理了目前主流的廣告聯盟平臺,如果你有流量,可以作為參考選擇適合你的平臺點擊進入

          鏈接: http://www.modern-decoration.com.cn/article/detial/198

          如何理解vue中的v-model?

          說到v-model,就想到了雙向數據綁定,而且往往最常見的是在表單元素<input>,<textarea>,<select>中的使用。那么為什么v-model雙向數據綁定,自動更新元素呢?

          Vue - 自定義組件雙向綁定

          無論在任何的語言或框架中,我們都提倡代碼的復用性。對于Vue來說也是如此,相同的代碼邏輯會被封裝成組件,除了復用之外,更重要的是統一管理提高開發效率。我真就接手過一個項目,多個頁面都會用到的列表

          js 超濃縮 雙向綁定

          綁定確實是個有趣的話題。現在我的綁定器有了不少的功能1. 附著在Object對象上,一切以對象為中心2. 與頁面元素進行雙向綁定

          簡單實現一個vue的雙向綁定

          首先我們來看一些,vue的基本使用方法;然后我們根據使用方法,來設計一個類和一些基礎的聲明周期;獲取根元素;生命周期 beforeCreate;獲取初始數據;獲取渲染函數

          angular數據雙向綁定的原理是什么?

          頁面中每綁定一個數據或者事件時,就會向$watch隊列中加入一條$watch,當瀏覽器接受到可以被angular context(當事件觸發,調用$apply進入angular context)處理的事件時,就會觸發digest循環,它會遍歷每一個$watch檢查其屬性和值是否發生改變

          VUE:computed 和 v-model 配合使用,雙向綁定失效

          今天在實現一個表單賦值并修改的功能時,由于其中數值直觀顯示不美觀,所以使用了 computed 計算屬性,同時使用 v-model 的雙向綁定,來處理顯示。但卻發現 v-model 的雙向綁定失效了,控制臺警告信息如下:

          React input表單雙向數據綁定仿Vue v-model實現

          用過Vue的同學都知道,Vue里<input> 、 <textarea> 及 <select>等表單元素可以通過v-model指令實現雙向數據綁定,也就是說,當用戶通過交互改變表單的值時,表單綁定的數據也會同步響應,這一點也是Vue對開發人員非常友好的點之一。

          vue雙向綁定原理分析

          當我們學習angular或者vue的時候,其雙向綁定為我們開發帶來了諸多便捷,今天我們就來分析一下vue雙向綁定的原理。vue.js 則是采用數據劫持結合發布者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter

          vue2 實現 div contenteditable=true 類似于 v-model雙向數據綁定的效果

          用到 contenteditable=true的 div ,而在這個 div 上是使用 v-model 是沒有效果的,這里的雙向數據綁定該如何實現?解決思路:一自定義指令,二使用組件。

          vue實現雙向綁定其他元素以及自定義表單控件

          v-model 只能用于表單控件,如果用于其他元素。如何讓組件的 v-model 生效呢?需要按照 Vue 的約定:接受一個 value 屬性,在有新的 value 時觸發 input 事件

          內容以共享、參考、研究為目的,不存在任何商業目的。其版權屬原作者所有,如有侵權或違規,請與小編聯系!情況屬實本人將予以刪除!

          文章投稿關于web前端網站點搜索站長推薦網站地圖站長QQ:522607023

          小程序專欄: 土味情話心理測試腦筋急轉彎幽默笑話段子句子語錄成語大全運營推廣

          国产精品高清视频免费 - 视频 - 在线观看 - 影视资讯 - 唯爱网