vue的雙向數據綁定原理


實現vue的雙向數據綁定

前言

在日常生活中,很多求職者都會遇到面試問題就是vue雙向數據綁定的原理。很多同學的回答大體一致:Object.defineProperty和觀察者模式,再往下問就說不清楚了。接下來我會詳細解析vue雙向數據綁定原理,用最簡單的方式給大家呈現,所以實現的過程我們會以思路為主,不會考慮更多的性能問題。

雙向數據含義

  • 關於雙向數據綁定,主要分為兩個方向:
    1. model(數據層) --> view(視圖層) 數據層改變視圖層自動更新
    2. view(視圖層) --> model(數據層) 視圖層改變(比如input和textarea等)數據層數據也會變化
  • 對於早期框架以backbone為例來說,實現的是單向數據綁定,也就是數據層變化視圖層更新,視圖層變化只能通過controller(行為層,事件層)來手動修改數據。比如說用戶修改了input的值,我們可以在controller層監聽用戶的輸入事件,手動修改model層數據。目前的react個人認為應該是屬於單向數據流。
  • 最早的雙向數據綁定提出據我使用應該是angularJs,此處實現會再以下詳細講述,此處不做介紹。目前最火的框架vue使用的就是雙向數據流。

單向數據流

  • 我們實現vue雙向數據流會從單向數據流開始,實現的思路頁面首次渲染綁定數據 --> 數據變化視圖更新
    1. 實現首次渲染數據
      • 此處使用的是面向對象的封裝模式,定義構造函數Vue,要求傳入參數是一個對象,對象包含el和data兩個key,el對應是根元素選擇器,data對應頁面渲染的數據。
      • 封裝庫文件vue.js
          class Vue {
              constructor (opts){
                  // 獲取根元素
                  this.el = document.querySelector(opts.el)
                  // 獲取數據源
                  this.data = opts.data
                  // 解析html
                  this.compile(this.el)
              }
              compile(el){
                  /* 
                      獲取html里面所有的插值表達式{{}}
                      獲取根元素下面所有的子節點,判斷子節點的類型
                          1. 如果子節點也是一個元素節點
                              - 繼續執行編譯函數,找到他們下面的子節點 此處使用了遞歸語法
                          2. 如果子節點就是一個文本節點
                              - 判斷文本節點里面是否包含插值表達式  此處使用正則表達式判斷
                                  + 包含插值表達式,找到正則表達式里面的變量名
                  */
                  // 獲取所有的子節點
                  let childNodes = el.childNodes
                  let reg = /\{\{(.*)\}\}/
                  childNodes.forEach(node => {
                      //  區分節點類型
                      let text = node.textContent
                      if(node.nodeType === 1){
                          // 元素節點
                          this.compile(node)
                      }else if(node.nodeType === 3 && reg.test(text)){
                          // 文本節點
                          let exp = reg.exec(text)[1]
                          console.warn('獲取的變量名', exp)
                          // 渲染數據到頁面
                          this.bindData(node, exp)
                      }
                  })
              }
              bindData(node, exp){
                  node.textContent = this.data[exp]
              }
          }
      
      • html使用測試
          <!-- 引入庫文件 -->
          <script src="vue.js"></script>
          <!-- html結構 -->
          <div id="app">
              {{name}}
              <ul>
                  <li>{{title}}</li>
              </ul>
              <p>{{msg}}</p>
          </div>
          <!-- 創建實例 -->
          <script>
              new Vue({
                  el: "#app",
                  data: {
                      name: '張三',
                      title: '標題',
                      msg: '消息'
                  }
              })
          </script>
      

未完,不想寫了。有心情再寫✍🏻


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM