一入前端深似海,今後紅塵是路人系列第九彈之如何實現一個"雙向"數據綁定

前言javascript

簡單介紹一下雙向數據綁定實現的是一個什麼樣的東西。首先有兩個東西,他們分別是:
V-視圖層
M-數據層
一、視圖層傳向數據層:V發生改變,M也發生改變
二、數據層傳向視圖層:M發生改變,V也發生改變
那麼接下來咱們也將本身書寫代碼實現這樣兩種功能,從而實現雙向數據綁定。最終實現的效果如圖:


修改input框裏面的內容,p標籤內容也實時相對應發生改變,data裏面的數據也會發生改變
html

1、先奉獻上本身完整的代碼java

這裏我是基於jQuery進行的代碼編寫,其中的方法將在下面進行詳細的解析jquery

;(function($,doc,win) {
var VM = function(opt) {
  this.setting = {};
  $.extend(this.setting, opt.data);

  // 初始化VM
  this.init();
};
VM.prototype = {
  init: function() {
    this.render('input');
    this._render('p');
  },
  render: function(dom) {
    var self = this
      , data = self.setting;
    $(dom).each(function() {
      var _attr = $(this).attr('xq-model');
      if (_attr !== undefined) {
        if (data[_attr] !== undefined) {
          $(this).attr('value', data[_attr]);
          self.inputChange($(this), _attr);
        }
      }
    });
  },
  _render: function(dom) {
    var self = this;
    $(dom).each(function() {
      var val = $(this).html() || $(this).text() || $(this).val();
      if (val.indexOf('}}') !== -1 && val.indexOf('}}') !== -1) {
        val = val.replace(/^s+|{{|s+/,'');
        val = val.replace(/}}|[\s+]/g,'');
        self.labelChange(this, val);
      }
    })
  },
  labelRender: function(dom, _attr) {
    var self = this
      , data = self.setting;
    $(dom).each(function() {
      var val = $(this).attr(_attr);
      if (val !== undefined) {
        if (data[_attr] !== undefined) {
          $(this).html(data[_attr]) || $(this).text(data[_attr]) || $(this).val(data[_attr]);
        }
      }
    })
  },
  inputChange: function(_this, _attr) {
    var self = this
      , data = self.setting;
    _this.unbind('keydown');
    _this.keydown(function(){
      _this.unbind('keyup');
      _this.keyup(function() {
        var changeVal = _this.val()
          , oldVal = data[_attr];
        data[_attr] = changeVal;
        self.render('input');
        self.labelRender('p', _attr);
      })
    })
  },
  labelChange: function(_this,val) {
    var self = this
      , data = self.setting;
    if (val !== undefined) {
      if (data[val] !== undefined) {
        $(_this).html(data[val]) || $(_this).text(data[val]) || $(_this).val(data[val]);
      }
    }
    $(_this).attr(val,'')
  }
};
window.VM = VM;
})(jQuery,document,window);

2、建立本身的綁定規則api

這裏關於指令,我沒有作做用域的包裹,比較完善的是須要用一個controller指令講須要展現的view視圖層包裹起來的。若是有想法的小夥伴們能夠在最後自行去思考,接下來先直接上html代碼dom

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>雙向數據綁定</title>
</head>
<body>
    <input type="text" xq-model="msg">
    <p>
      {{ msg }}
    </p>
    <input type="text" xq-model="my">
    <p>{{ my }}</p>
</body>
<script src="js/jquery.js"></script>
<script src="js/api.js"></script>
</html>

這裏我制定的雙向指令是xq-model,內容的解析規則是{{}}。你們有本身喜歡的指令能夠自行制定。ui

3、實現本身的綁定規則this

咱們如今須要作的就是一步一步去實現咱們本身規定的一些綁定規則prototype

首先咱們須要作的第一步就是渲染出input中的xq-model指令指定的數據code

/**
 * [render input框渲染]
 * @param  {[type]} dom [input]
 */
render: function(dom) {
  var self = this
    , data = self.setting;
  // 遍歷dom中全部的input,搜尋帶xq-model指令的input
  $(dom).each(function() {
    var _attr = $(this).attr('xq-model');
    // 判斷是否有對應綁定data數據
    if (_attr !== undefined) {
      if (data[_attr] !== undefined) {
        $(this).attr('value', data[_attr]);
        // 調用input值改變方法
        self.inputChange($(this), _attr);
      }
    }
  });
}

實現inputChange方法

/**
 * [inputChange 值改變]
 * @param  {[type]} _this [當前input]
 * @param  {[type]} _attr [當前綁定對應的data數據]
 */
inputChange: function(_this, _attr) {
  var self = this
    , data = self.setting;
  // 綁定鍵盤事件進行監聽
  _this.unbind('keydown');
  _this.keydown(function(){
    _this.unbind('keyup');
    _this.keyup(function() {
      var changeVal = _this.val()
        , oldVal = data[_attr];
      data[_attr] = changeVal;
      // 調用input框渲染方法
      self.render('input');
      // 調用標籤值改變渲染方法
      self.labelRender('p', _attr);
    })
  })
}

到這裏,對於input框的渲染及data數據的雙向算完成了第一個了,接下來咱們須要實現的即是對於標籤的渲染

/**
 * [_render 標籤渲染]
 * @param  {[type]} dom [element]
 */
_render: function(dom) {
  var self = this;
  // 遍歷標籤,拿到裏面的內容
  $(dom).each(function() {
    var val = $(this).html() || $(this).text() || $(this).val();
    // 判斷是否存在{{}},並截取拿到{{}} 裏面的內容
    if (val.indexOf('}}') !== -1 && val.indexOf('}}') !== -1) {
      val = val.replace(/^s+|{{|s+/,'');
      val = val.replace(/}}|[\s+]/g,'');
      // 調用標籤賦值方法
      self.labelChange(this, val);
    }
  })
}

實現labelChange方法

/**
 * [inputChange 值改變]
 * @param  {[type]} _this [當前input]
 * @param  {[type]} _attr [當前綁定對應的data數據]
 */
labelChange: function(_this,val) {
  var self = this
    , data = self.setting;
  if (val !== undefined) {
    if (data[val] !== undefined) {
      $(_this).html(data[val]) || $(_this).text(data[val]) || $(_this).val(data[val]);
    }
  }
  // 給當前對象綁定一個屬性對應其data數據
  $(_this).attr(val,'')
}

最後實現input框輸入,實時修改對應的標籤的值labelRender方法

/**
 * [labelRender 標籤實時渲染]
 * @param  {[type]} dom   [element]
 * @param  {[type]} _attr [當前data數據的key]
 */
labelRender: function(dom, _attr) {
  var self = this
    , data = self.setting;
  $(dom).each(function() {
    // 經過labelChange獲取到對應data數據的attr屬性
    var val = $(this).attr(_attr);
    if (val !== undefined) {
      if (data[_attr] !== undefined) {
        $(this).html(data[_attr]) || $(this).text(data[_attr]) || $(this).val(data[_attr]);
      }
    }
  })
}

最後咱們調用一下實現好的VM

$(function() {
  new VM({
    data: {
      msg: 'hello',
      my: 'hehe'
    }
  });
})

好了,屬於咱們本身的一個簡單的雙向數據綁定至此便算是完成了,你們也能夠本身將這個進行不斷的完善,本身去實現一個完整的雙向數據綁定。小夥伴們,加油↖(^ω^)↗

相關文章
相關標籤/搜索