国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

vue雙向數據綁定知識點總結

2019-11-19 14:00:59
字體:
來源:轉載
供稿:網友

1.原理

vue的雙向數據綁定的原理相信大家都十分了解;主要是通過ES5的Object對象的defineProperty屬性;重寫data的set和get函數來實現的

所以接下來不使用ES6進行實際的代碼開發;過程中如果函數使用父級this的情況;還是使用顯示緩存中間變量和閉包來處理;原因是箭頭函數沒有獨立的執行上下文this;所以箭頭函數內部出現this對象會直接訪問父級;所以也能看出箭頭函數是無法完全替代function的使用場景的;比如我們需要獨立的this或者argument的時候

1.2 defineProperty是什么

語法:

Object.defineProperty(obj, prop, descriptor)

參數:

obj:必要的目標對象

prop:必要的需要定義或者修改的屬性名

descriptor:必要的目標屬性全部擁有的屬性

返回值:

返回傳入的第一個函數;即第一個參數obj

該方法允許精確的添加或者修改對象的屬性;通過賦值來添加的普通屬性會創建在屬性枚舉期間顯示(fon...in;object.key);這些添加的值可以被改變也可以刪除;也可以給這個屬性設置一些特性;比如是否只讀不可寫;目前提供兩種形式:數據描述(set;get;value;writable;enumerable;confingurable)和存取器描述(set;get)

數據描述

當修改或者定義對象的某個屬性的時候;給這個屬性添加一些特性

var obj = { name:'xiangha'}// 對象已有的屬性添加特性描述Object.defineProperty(obj,'name',{ configurable:true | false, // 如果是false則不可以刪除 enumerable:true | false, // 如果為false則在枚舉時候會忽略 value:'任意類型的值,默認undefined' writable:true | false // 如果為false則不可采用數據運算符進行賦值});但是存在一個交叉;如果wrirable為true;而configurable為false的時候;所以需要枚舉處理enumerable為false--- 我是一個writable栗子 ---var obj = {};Object.defineProperty(obj,'val',{ value:'xiangha', writable:false, // false enumerable:true, configurable:true});obj.val = '書記'; // 這個時候是更改不了a的--- 我是一個configurable栗子 ---var obj = {};Object.defineProperty(obj,'val',{ value:'xiangha', writable:true, // true enumerable:true, configurable:false // false});obj.val = '書記'; // 這個時候是val發生了改變delete obj.val 會返回false;并且val沒有刪除--- 我是一個enumerable栗子 --- var obj = {};Object.defineProperty(obj,'val',{ value:'xiangha', writable:true, enumerable:false, // false configurable:true});for(var i in obj){ console.log(obj[i]) // 沒有具體值}綜上:對于我們有影響主要是configurable控制是否可以刪除;writable控制是否可以修改賦值;enumerable是否可以枚舉

所以說一旦使用Object.defineProperty()給對象添加屬性;那么如果不設置屬性的特性;則默認值都為false

var obj = {}; Object.defineProperty(obj,'name',{}); // 定義了心屬性name后;這個屬性的特性的值都為false;這就導致name這個是不能重寫不能枚舉不能再次設置特性的obj.name = '書記'; console.log(obj.name); // undefinedfor(var i in obj){ console.log(obj[i])}

總結特性:

  • value:設置屬性的值
  • writable ['raɪtəbl] :值是否可以重寫
  • enumerable [ɪ'nju:mərəbəl]:目標屬性是否可以被枚舉
  • configurable [kən'fɪgərəbl]:目標屬性是否可以被刪除是否可以再次修改特性

存取器描述

var obj = {};Object.defineProperty(obj,'name',{ get:function(){} | undefined, set:function(){} | undefined, configuracble:true | false, enumerable:true | false})注意:當前使用了setter和getter方法;不允許使用writable和value兩個屬性

gettet&& setter

當設置獲取對象的某個屬性的時候;可以提供getter和setter方法

var obj = {};var value = 'xiangha';Object.defineProperty(obj,'name',{ get:function(){  // 獲取值觸發  return value }, set:function(val){  // 設置值的時候觸發;設置的新值通過參數val拿到  value = val; }});console.log(obj.name); // xianghaobj.name = '書記';console,.log(obj.name); // 書記

get和set不是必須成對出現對;任寫一個就行;如果不設置set和get方法;則為undefined

哈哈;前戲終于鋪墊完成了

補充:如果使用vue開發項目;嘗試去打印data對象的時候;會發現data內的每一個屬性都有get和set屬性方法;這里說明一下vue和angular的雙向數據綁定不同

angular是用臟數據檢測;Model發生改變的時候;會檢測所有視圖是否綁定了相關的數據;再更新視圖

vue是使用的發布訂閱模式;點對點的綁定數據

2.實現

<div id="app"> <form>  <input type="text" v-model="number">  <button type="button" v-click="increment">增加</button> </form> <h3 v-bind="number"></h3> </div>

頁面很簡單;包含:

  1. 一個input,使用v-model指令
  2. 一個button,使用v-click指令
  3. 一個h3,使用v-bind指令。

我們最后也會類似vue對方式來實現雙向數據綁定

var app = new xhVue({  el:'#app',  data: {  number: 0  },  methods: {  increment: function() {   this.number ++;  },  } })

2.1 定義

首先我們需要定義一個xhVue的構造函數

function xhVue(options){ }

2.2 添加

為了初始化這個構造函數;給其添加一個_init屬性

function xhVue(options){ this._init(options);}xhVue.prototype._init = function(options){ this.$options = options; // options為使用時傳入的結構體;包括el,data,methods等 this.$el = document.querySelector(options.el); // el就是#app,this.$el是id為app的Element元素 this.$data = options.data; // this.$data = {number:0} this.$methods = options.methods; // increment}

2.3 改造升級

改造_init函數;并且實現_xhob函數;對data進行處理;重寫set和get函數

xhVue.prototype._xhob = function(obj){ // obj = {number:0} var value; for(key in obj){  if(obj.hasOwnProperty(ket)){   value = obj[key];   if(typeof value === 'object'){    this._xhob(value);   }   Object.defineProperty(this.$data,key,{    enumerable:true,    configurable:true,    get:function(){     return value;    },    set:function(newVal){     if(value !== newVal){      value = newVal;     }    }   })  } }}xhVue.prototype._init = function(options){ this.$options = options; this.$el = document.querySelector(options.el); this.$data = options.data; this.$method = options.methods; this._xhob(this.$data);}

2.4 xhWatcher

指令類watcher;用來綁定更新函數;實現對DOM更新

function xhWatcher(name,el,vm,exp,attr){ this.name = name; // 指令名稱;對于文本節點;例如text this.el = el; // 指令對應DOM元素 this.vm = vm; // 指令所屬vue實例 this.exp = exp; // 指令對應的值;例如number this.attr = attr; // 綁定的屬性值;例如innerHTML this.update();}xhWatcher.prototype.update = function(){ this.el[this.attr] = this.vm.$data[this.exp]; // 例如h3的innerHTML = this.data.number;當numner改變則會觸發本update方法;保證對應的DOM實時更新}

2.5 完善_init和_xhob

繼續完善_init和_xhob函數

// 給init的時候增加一個對象來存儲model和view的映射關系;也就是我們前面定義的xhWatcher的實例;當model發生變化時;我們會觸發其中的指令另其更新;保證了view也同時更新xhVue.prototype._init = function(options){ this.$options = options; this.$el = document.querySelector(options.el); this.$data = options.data; this.$method = options.methods;  this._binding = {}; // _binding this._xhob(this.$data);}// 通過init出來的_bindingxhVue.prototype._xhob = function(obj){ // obj = {number:0} var value; for(key in obj){  if(obj.hasOwnProperty(ket)){   this._binding[key] = {    // _binding = {number:_directives:[]}    _directives = []   }   value = obj[key];   if(typeof value === 'object'){    this._xhob(value);   }   var binding = this._binding[key];   Object.defineProperty(this.$data,key,{    enumerable:true,    configurable:true,    get:function(){     return value;    },    set:function(newVal){     if(value !== newVal){      value = newVal;      // 當number改變時;觸發_binding[number]._directives中已綁定的xhWatcher更新      binding._directives.forEach(function(item){       item.update();       });     }    }   })  } }}

2.6 解析指令

怎么才能將view與model綁定;我們定義一個_xhcomplie函數來解析我們的指令(v-bind;v-model;v-clickde)并這這個過程中對view和model進行綁定

xhVue.prototype._xhcompile = function (root) { // root是id為app的element的元素;也就是根元素 var _this = this; var nodes = root.children; for (var i = 0,len = nodes.length; i < len; i++) {  var node = nodes[i];  if (node.children.length) {   // 所有元素進行處理   this._xhcompile(node)  };  // 如果有v-click屬性;我們監聽他的click事件;觸發increment事件,即number++  if (node.hasAttribute('v-click')) {   node.onclick = (function () {    var attrVal = nodes[i].getAttribute('v-click');    // bind讓data的作用域與methods函數的作用域保持一致    return _this.$method[attrVal].bind(_this.$data);   })();  };  // 如果有v-model屬性;并且元素是input或者textrea;我們監聽他的input事件  if (node.hasAttribute('v-model') && (node.tagName = 'INPUT' || node.tagName == 'TEXTAREA')) {   node.addEventListener('input', (function (key) {    var attrVal = node.getAttribute('v-model');    _this._binding[attrVal]._directives.push(new xhWatcher(     'input',      node,      _this,     attrVal,      'value'    ));    return function () {     // 讓number的值和node的value保持一致;就實現了雙向數據綁定     _this.$data[attrVal] = nodes[key].value    }   })(i));  };  // 如果有v-bind屬性;我們要讓node的值實時更新為data中number的值  if (node.hasAttribute('v-bind')) {   var attrVal = node.getAttribute('v-bind');   _this._binding[attrVal]._directives.push(new xhWatcher(    'text',     node,     _this,    attrVal,    'innerHTML'   ))  } }}

并且將解析函數也加到_init函數中

xhVue.prototype._init = function(options){ this.$options = options; this.$el = document.querySelector(options.el); this.$data = options.data; this.$method = options.methods;  this._binding = {}; // _binding this._xhob(this.$data); this._xhcompile(this.$el);}

最后

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title></head><body> <div id="app">  <form>   <input type="text" v-model="number">   <button type="button" v-click="increment">增加</button>  </form>  <h3 v-bind="number"></h3> </div></body><script> function xhVue(options) {  this._init(options); } xhVue.prototype._init = function (options) {  this.$options = options;  this.$el = document.querySelector(options.el);  this.$data = options.data;  this.$method = options.methods;  this._binding = {}; // _binding  this._xhob(this.$data);  this._xhcompile(this.$el); } xhVue.prototype._xhob = function (obj) {  var value;  for (key in obj) {   if (obj.hasOwnProperty(key)) {    this._binding[key] = {     _directives: []    }    value = obj[key];    if (typeof value === 'object') {     this._xhob(value);    }    var binding = this._binding[key];    Object.defineProperty(this.$data, key, {     enumerable: true,     configurable: true,     get: function () {      console.log(`get${value}`)      return value;     },     set: function (newVal) {      if (value !== newVal) {       value = newVal;       console.log(`set${newVal}`)       // 當number改變時;觸發_binding[number]._directives中已綁定的xhWatcher更新       binding._directives.forEach(function (item) {        item.update();       });      }     }    })   }  } } xhVue.prototype._xhcompile = function (root) {  // root是id為app的element的元素;也就是根元素  var _this = this;  var nodes = root.children;  for (var i = 0, len = nodes.length; i < len; i++) {   var node = nodes[i];   if (node.children.length) {    // 所有元素進行處理    this._xhcompile(node)   };   // 如果有v-click屬性;我們監聽他的click事件;觸發increment事件,即number++   if (node.hasAttribute('v-click')) {    node.onclick = (function () {     var attrVal = node.getAttribute('v-click');     console.log(attrVal);     // bind讓data的作用域與method函數的作用域保持一致     return _this.$method[attrVal].bind(_this.$data);    })();   };   // 如果有v-model屬性;并且元素是input或者textrea;我們監聽他的input事件   if (node.hasAttribute('v-model') && (node.tagName = 'INPUT' || node.tagName == 'TEXTAREA')) {    node.addEventListener('input', (function (key) {     var attrVal = node.getAttribute('v-model');     _this._binding[attrVal]._directives.push(new xhWatcher(      'input',      node,      _this,      attrVal,      'value'     ));     return function () {      // 讓number的值和node的value保持一致;就實現了雙向數據綁定      _this.$data[attrVal] = nodes[key].value     }    })(i));   };   // 如果有v-bind屬性;我們要讓node的值實時更新為data中number的值   if (node.hasAttribute('v-bind')) {    var attrVal = node.getAttribute('v-bind');    _this._binding[attrVal]._directives.push(new xhWatcher(     'text',     node,     _this,     attrVal,     'innerHTML'    ))   }  } } function xhWatcher(name, el, vm, exp, attr) {  this.name = name; // 指令名稱;對于文本節點;例如text  this.el = el; // 指令對應DOM元素  this.vm = vm; // 指令所屬vue實例  this.exp = exp; // 指令對應的值;例如number  this.attr = attr; // 綁定的屬性值;例如innerHTML  this.update(); } xhWatcher.prototype.update = function () {  this.el[this.attr] = this.vm.$data[this.exp];  // 例如h3的innerHTML = this.data.number;當numner改變則會觸發本update方法;保證對應的DOM實時更新 } var app = new xhVue({  el: '#app',  data: {   number: 0  },  methods: {   increment: function () {    this.number++;   }  } });</script></html>

所有的代碼;復制到編輯器就可查看效果了~~

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 池州市| 阿拉尔市| 汝阳县| 阿拉善盟| 富阳市| 喀什市| 马尔康县| 陇南市| 大姚县| 新乐市| 杨浦区| 庆元县| 高雄市| 枣强县| 丹棱县| 永川市| 磐安县| 丰原市| 精河县| 台东市| 华蓥市| 云南省| 贺州市| 南乐县| 句容市| 宁远县| 乌拉特前旗| 麦盖提县| 莱芜市| 平顶山市| 鄂温| 威海市| 蓬莱市| 宝坻区| 七台河市| 沙田区| 龙江县| 隆回县| 荔浦县| 万宁市| 恩平市|