目錄
1、原理" >1、原理
#2、實作" >#2、實作
首頁 web前端 js教程 Vue實現雙向資料綁定功能(附程式碼)

Vue實現雙向資料綁定功能(附程式碼)

Apr 27, 2018 pm 03:41 PM
功能 數據 綁定

這次帶給大家Vue實作雙向資料綁定功能(附程式碼),Vue實作雙向資料綁定功能的注意事項有哪些,以下就是實戰案例,一起來看一下。

1、原理

Vue的雙向資料綁定的原理相信大家也都十分了解了,主要是透過Object物件的defineProperty屬性,重寫data的set和get函數來實現的,這裡對原理不做過多描述,主要還是來實現一個實例。為了讓程式碼更加的清晰,這裡只會實現最基本的內容,主要實作v-model,v-bind 和v-click三個指令,其他指令也可以自行補充。

新增網路上的一張圖

#2、實作

頁結構很簡單,如下

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

包含:

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

我們最後會透過類似vue的方式來使用我們的雙向資料綁定,結合我們的資料結構來加入註解

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

首先我們需要定義一個myVue建構子

function myVue(options) {
}

為了初始化這個建構函數,給它加上一個_init屬性

function myVue(options) {
 this._init(options);
}
myVue.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; // this.$methods = {increment: function(){}}
 }

接下來實作_obverse函數,對data進行處理,重寫data的set和get函數

並改造_init函數

myVue.prototype._obverse = function (obj) { // obj = {number: 0}
 var value;
 for (key in obj) { //遍历obj对象
  if (obj.hasOwnProperty(key)) {
  value = obj[key]; 
  if (typeof value === 'object') { //如果值还是对象,则遍历处理
   this._obverse(value);
  }
  Object.defineProperty(this.$data, key, { //关键
   enumerable: true,
   configurable: true,
   get: function () {
   console.log(`获取${value}`);
   return value;
   },
   set: function (newVal) {
   console.log(`更新${newVal}`);
   if (value !== newVal) {
    value = newVal;
   }
   }
  })
  }
 }
 }
 myVue.prototype._init = function (options) {
 this.$options = options;
 this.$el = document.querySelector(options.el);
 this.$data = options.data;
 this.$methods = options.methods;
 this._obverse(this.$data);
 }

接下來我們寫一個指令類別Watcher,用來綁定更新函數,實作對DOM元素的更新

function Watcher(name, el, vm, exp, attr) {
 this.name = name;   //指令名称,例如文本节点,该值设为"text"
 this.el = el;    //指令对应的DOM元素
 this.vm = vm;    //指令所属myVue实例
 this.exp = exp;   //指令对应的值,本例如"number"
 this.attr = attr;   //绑定的属性值,本例为"innerHTML"
 this.update();
 }
 Watcher.prototype.update = function () {
 this.el[this.attr] = this.vm.$data[this.exp]; //比如 H3.innerHTML = this.data.number; 当number改变时,会触发这个update函数,保证对应的DOM内容进行了更新。
 }

更新_init函數以及_obverse函數

myVue.prototype._init = function (options) {
 //...
 this._binding = {}; //_binding保存着model与view的映射关系,也就是我们前面定义的Watcher的实例。当model改变时,我们会触发其中的指令类更新,保证view也能实时更新
 //...
 }
 myVue.prototype._obverse = function (obj) {
 //...
  if (obj.hasOwnProperty(key)) {
  this._binding[key] = { // 按照前面的数据,_binding = {number: _directives: []}                                     
   _directives: []
  };
  //...
  var binding = this._binding[key];
  Object.defineProperty(this.$data, key, {
   //...
   set: function (newVal) {
   console.log(`更新${newVal}`);
   if (value !== newVal) {
    value = newVal;
    binding._directives.forEach(function (item) { // 当number改变时,触发_binding[number]._directives 中的绑定的Watcher类的更新
    item.update();
    })
   }
   }
  })
  }
 }
 }

那麼如何將view與model進行綁定呢?接下來我們定義一個_compile函數,用來解析我們的指令(v-bind,v-model,v-clickde)等,並在這個過程中對view與model進行綁定。

 myVue.prototype._init = function (options) {
 //...
 this._complie(this.$el);
 }
myVue.prototype._complie = function (root) { root 为 id为app的Element元素,也就是我们的根元素
 var _this = this;
 var nodes = root.children;
 for (var i = 0; i < nodes.length; i++) {
  var node = nodes[i];
  if (node.children.length) { // 对所有元素进行遍历,并进行处理
  this._complie(node);
  }
  if (node.hasAttribute(&#39;v-click&#39;)) { // 如果有v-click属性,我们监听它的onclick事件,触发increment事件,即number++
  node.onclick = (function () {
   var attrVal = nodes[i].getAttribute(&#39;v-click&#39;);
   return _this.$methods[attrVal].bind(_this.$data); //bind是使data的作用域与method函数的作用域保持一致
  })();
  }
  if (node.hasAttribute(&#39;v-model&#39;) && (node.tagName == &#39;INPUT&#39; || node.tagName == &#39;TEXTAREA&#39;)) { // 如果有v-model属性,并且元素是INPUT或者TEXTAREA,我们监听它的input事件
  node.addEventListener(&#39;input&#39;, (function(key) { 
   var attrVal = node.getAttribute(&#39;v-model&#39;);
   //_this._binding[&#39;number&#39;]._directives = [一个Watcher实例]
   // 其中Watcher.prototype.update = function () {
   // node[&#39;vaule&#39;] = _this.$data[&#39;number&#39;]; 这就将node的值保持与number一致
   // }
   _this._binding[attrVal]._directives.push(new Watcher( 
   &#39;input&#39;,
   node,
   _this,
   attrVal,
   &#39;value&#39;
   ))
   return function() {
   _this.$data[attrVal] = nodes[key].value; // 使number 的值与 node的value保持一致,已经实现了双向绑定
   }
  })(i));
  } 
  if (node.hasAttribute(&#39;v-bind&#39;)) { // 如果有v-bind属性,我们只要使node的值及时更新为data中number的值即可
  var attrVal = node.getAttribute(&#39;v-bind&#39;);
  _this._binding[attrVal]._directives.push(new Watcher(
   &#39;text&#39;,
   node,
   _this,
   attrVal,
   &#39;innerHTML&#39;
  ))
  }
 }
 }

至此,我們已經實作了一個簡單vue的雙向綁定功能,包括v-bind, v-model, v-click三個指令。效果如下圖

附上全部程式碼,不到150行



 myVue

 <p id="app">  <form>   <input type="text" v-model="number">   <button type="button" v-click="increment">增加</button>  </form>  <h3 v-bind="number"></h3>  </p> <script>  function myVue(options) {  this._init(options);  }  myVue.prototype._init = function (options) {  this.$options = options;  this.$el = document.querySelector(options.el);  this.$data = options.data;  this.$methods = options.methods;  this._binding = {};  this._obverse(this.$data);  this._complie(this.$el);  }  myVue.prototype._obverse = function (obj) {  var value;  for (key in obj) {   if (obj.hasOwnProperty(key)) {   this._binding[key] = {                                           _directives: []   };   value = obj[key];   if (typeof value === 'object') {    this._obverse(value);   }   var binding = this._binding[key];   Object.defineProperty(this.$data, key, {    enumerable: true,    configurable: true,    get: function () {    console.log(`获取${value}`);    return value;    },    set: function (newVal) {    console.log(`更新${newVal}`);    if (value !== newVal) {     value = newVal;     binding._directives.forEach(function (item) {     item.update();     })    }    }   })   }  }  }  myVue.prototype._complie = function (root) {  var _this = this;  var nodes = root.children;  for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; if (node.children.length) { this._complie(node); } if (node.hasAttribute(&#39;v-click&#39;)) { node.onclick = (function () { var attrVal = nodes[i].getAttribute(&#39;v-click&#39;); return _this.$methods[attrVal].bind(_this.$data); })(); } if (node.hasAttribute(&#39;v-model&#39;) && (node.tagName == &#39;INPUT&#39; || node.tagName == &#39;TEXTAREA&#39;)) { node.addEventListener(&#39;input&#39;, (function(key) { var attrVal = node.getAttribute(&#39;v-model&#39;); _this._binding[attrVal]._directives.push(new Watcher( &#39;input&#39;, node, _this, attrVal, &#39;value&#39; )) return function() { _this.$data[attrVal] = nodes[key].value; } })(i)); } if (node.hasAttribute(&#39;v-bind&#39;)) { var attrVal = node.getAttribute(&#39;v-bind&#39;); _this._binding[attrVal]._directives.push(new Watcher( &#39;text&#39;, node, _this, attrVal, &#39;innerHTML&#39; )) } } } function Watcher(name, el, vm, exp, attr) { this.name = name; //指令名称,例如文本节点,该值设为"text" this.el = el; //指令对应的DOM元素 this.vm = vm; //指令所属myVue实例 this.exp = exp; //指令对应的值,本例如"number" this.attr = attr; //绑定的属性值,本例为"innerHTML" this.update(); } Watcher.prototype.update = function () { this.el[this.attr] = this.vm.$data[this.exp]; } window.onload = function() { var app = new myVue({ el:&#39;#app&#39;, data: { number: 0 }, methods: { increment: function() { this.number ++; }, } }) } </script>

相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!

推薦閱讀:

jQuery$. 和$().使用詳解

vue之.sync修飾符使用詳解

以上是Vue實現雙向資料綁定功能(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

使用ddrescue在Linux上恢復數據 使用ddrescue在Linux上恢復數據 Mar 20, 2024 pm 01:37 PM

DDREASE是一種用於從檔案或區塊裝置(如硬碟、SSD、RAM磁碟、CD、DVD和USB儲存裝置)復原資料的工具。它將資料從一個區塊設備複製到另一個區塊設備,留下損壞的資料區塊,只移動好的資料區塊。 ddreasue是一種強大的恢復工具,完全自動化,因為它在恢復操作期間不需要任何干擾。此外,由於有了ddasue地圖文件,它可以隨時停止和恢復。 DDREASE的其他主要功能如下:它不會覆寫恢復的數據,但會在迭代恢復的情況下填補空白。但是,如果指示工具明確執行此操作,則可以將其截斷。將資料從多個檔案或區塊還原到單

小紅書怎麼綁定子帳號?它怎麼檢測帳號是否正常? 小紅書怎麼綁定子帳號?它怎麼檢測帳號是否正常? Mar 21, 2024 pm 10:11 PM

在現今這個資訊爆炸的時代,個人品牌和企業形象的建立變得越來越重要。小紅書作為國內領先的時尚生活分享平台,吸引了大量用戶關注和參與。對於那些希望擴大影響力、提高內容傳播效率的使用者來說,綁定子帳號成為了一種有效的手段。那麼,小紅書怎麼綁定子帳號呢?又如何檢測帳號是否正常呢?本文將為您詳細解答這些問題。一、小紅書怎麼綁定子帳號? 1.登入主帳號:首先,您需要登入您的小紅書主帳號。 2.開啟設定選單:點選右上角的“我”,然後選擇“設定”。 3.進入帳號管理:在設定選單中,找到「帳號管理」或「帳號助理」選項,點

開源!超越ZoeDepth! DepthFM:快速且精確的單目深度估計! 開源!超越ZoeDepth! DepthFM:快速且精確的單目深度估計! Apr 03, 2024 pm 12:04 PM

0.這篇文章乾了啥?提出了DepthFM:一個多功能且快速的最先進的生成式單目深度估計模型。除了傳統的深度估計任務外,DepthFM還展示了在深度修復等下游任務中的最先進能力。 DepthFM效率高,可以在少數推理步驟內合成深度圖。以下一起來閱讀這項工作~1.論文資訊標題:DepthFM:FastMonocularDepthEstimationwithFlowMatching作者:MingGui,JohannesS.Fischer,UlrichPrestel,PingchuanMa,Dmytr

BTCC教學:如何在BTCC交易所綁定使用MetaMask錢包? BTCC教學:如何在BTCC交易所綁定使用MetaMask錢包? Apr 26, 2024 am 09:40 AM

MetaMask(中文也叫小狐狸錢包)是一款免費的、廣受好評的加密錢包軟體。目前,BTCC已支援綁定MetaMask錢包,綁定後可使用MetaMask錢包進行快速登錄,儲值、買幣等,且首次綁定還可獲得20USDT體驗金。在BTCCMetaMask錢包教學中,我們將詳細介紹如何註冊和使用MetaMask,以及如何在BTCC綁定並使用小狐狸錢包。 MetaMask錢包是什麼? MetaMask小狐狸錢包擁有超過3,000萬用戶,是當今最受歡迎的加密貨幣錢包之一。它可免費使用,可作為擴充功能安裝在網絡

iPhone上的蜂窩數據網路速度慢:修復 iPhone上的蜂窩數據網路速度慢:修復 May 03, 2024 pm 09:01 PM

在iPhone上面臨滯後,緩慢的行動數據連線?通常,手機上蜂窩互聯網的強度取決於幾個因素,例如區域、蜂窩網絡類型、漫遊類型等。您可以採取一些措施來獲得更快、更可靠的蜂窩網路連線。修復1–強制重啟iPhone有時,強制重啟設備只會重置許多內容,包括蜂窩網路連線。步驟1–只需按一次音量調高鍵並放開即可。接下來,按降低音量鍵並再次釋放它。步驟2–過程的下一部分是按住右側的按鈕。讓iPhone完成重啟。啟用蜂窩數據並檢查網路速度。再次檢查修復2–更改資料模式雖然5G提供了更好的網路速度,但在訊號較弱

Google狂喜:JAX性能超越Pytorch、TensorFlow!或成GPU推理訓練最快選擇 Google狂喜:JAX性能超越Pytorch、TensorFlow!或成GPU推理訓練最快選擇 Apr 01, 2024 pm 07:46 PM

谷歌力推的JAX在最近的基準測試中表現已經超過Pytorch和TensorFlow,7項指標排名第一。而且測試並不是JAX性能表現最好的TPU上完成的。雖然現在在開發者中,Pytorch依然比Tensorflow更受歡迎。但未來,也許有更多的大型模型會基於JAX平台進行訓練和運行。模型最近,Keras團隊為三個後端(TensorFlow、JAX、PyTorch)與原生PyTorch實作以及搭配TensorFlow的Keras2進行了基準測試。首先,他們為生成式和非生成式人工智慧任務選擇了一組主流

特斯拉機器人進廠打工,馬斯克:手的自由度今年將達到22個! 特斯拉機器人進廠打工,馬斯克:手的自由度今年將達到22個! May 06, 2024 pm 04:13 PM

特斯拉機器人Optimus最新影片出爐,已經可以在工廠裡打工了。正常速度下,它分揀電池(特斯拉的4680電池)是這樣的:官方還放出了20倍速下的樣子——在小小的「工位」上,揀啊揀啊揀:這次放出的影片亮點之一在於Optimus在廠子裡完成這項工作,是完全自主的,全程沒有人為的干預。而且在Optimus的視角之下,它還可以把放歪了的電池重新撿起來放置,主打一個自動糾錯:對於Optimus的手,英偉達科學家JimFan給出了高度的評價:Optimus的手是全球五指機器人裡最靈巧的之一。它的手不僅有觸覺

自媒體到底是什麼?它的主要特點和功能有哪些? 自媒體到底是什麼?它的主要特點和功能有哪些? Mar 21, 2024 pm 08:21 PM

隨著網路的快速發展,自媒體這個概念已經深入人心。那麼,自媒體到底是什麼呢?它有哪些主要特點和功能呢?接下來,我們將一一探討這些問題。一、自媒體到底是什麼?自媒體,顧名思義,就是自己就是媒體。它是指透過網路平台,個人或團隊可以自主創建、編輯、發布和傳播內容的資訊載體。不同於傳統媒體,如報紙、電視、電台等,自媒體具有更強的互動性和個人化,讓每個人都能成為訊息的生產者和傳播者。二、自媒體的主要特色和功能有哪些? 1.低門檻:自媒體的崛起降低了進入媒體產業的門檻,不再需要繁瑣的設備和專業的團隊,一部手

See all articles