利用 Object.defineProperty 來實現(xiàn) vue 的雙向綁定.

先說一下,我們需要達到的目標.

  • modeldata 發(fā)生變化時,dom元素的value要發(fā)生變化.
  • dom元素的value,發(fā)生變化時,modeldata 要發(fā)生變化.
目標過程

核心思想即是:

  • 我們需要監(jiān)控到 model.dataset,當執(zhí)行set 的時候,改變對應的dom.value
  • 我們需要監(jiān)控到 dom.valueset,當執(zhí)行到 set 的時候,改變對應的 model.value

1.Object.defineProperty 設(shè)置自定義對象的 set

由于,我們需要監(jiān)控到model.valueset.
常規(guī)做法,一般是不能做到了.

let model = {}
model.value = 'value' // 這里設(shè)置上了就設(shè)置上了,沒有辦法獲取到設(shè)置到的動作.

使用 Object.defineProperty來監(jiān)聽model.value屬性的set行為.

let value = undefined
  let model = {}
  Object.defineProperty(model, 'value', {
    set: function (newVal) {
      // 在這檢控到了model.value值的set設(shè)置時機
      value = newVal
      console.log('model.value setted!!!')
    },
    get: function () {
      return value
    }
  })
model.value='aaaaa'
model.value setted!!!

可以正常監(jiān)控到 model.value 屬性的 set 時機.


2.dom是HTMLElement對象,能用 Object.defineProperty來設(shè)置某個屬性的set嗎?

由于 dom 元素,本質(zhì)也是一個 HTMLElement對象.
所以,如果.value 屬性內(nèi)部設(shè)置的configurable:true 的話,我們是可以利用Object.defineProperty 來重新設(shè)置 .valueset ,拿到dom.value 修改時機的.

按照一樣的邏輯,使用Object.defineProperty來設(shè)置dom元素的value的set時機

 // 拿到input的dom對象
  let defaultInputVal = undefined
  let input = document.querySelector('#input')
  Object.defineProperty(input, 'value', {
    set: function (newVal) {
      defaultInputVal = newVal
      console.log('input.dom.value setted!')
    },
    get: function () {
      return defaultInputVal
    }
  })
dom對象無法使用Object.defineProperty來設(shè)置屬性

結(jié)果發(fā)現(xiàn),使用同樣的辦法,在dom上無法使用 Object.defineProperty拿到屬性.
如果其內(nèi)部定義 value 屬性設(shè)置的 configurable:false 的話,那么在我這里再次定義,也沒有報錯誤:

Cannot redefine property:value

反正不管怎么樣,自定義對象的那套 Object.defineProperty 想利用 set 方式拿到 DOM 對象某個屬性的 set 時機是拿不到了.


3.利用事件拿到 dom 對象屬性的 set 時機

那么,就退而求其次的使用事件吧.
(反正最終是要拿到dom對象的.value屬性賦值的那個時機)

let input = document.querySelector('#input')
  input.addEventListener('keyup', function (e) {
    console.log(e.target.value)
  }, false)
利用事件拿到dom對象的屬性set.gif

實現(xiàn)數(shù)據(jù)的雙向綁定.

現(xiàn)在我們有的:

  • 利用 Object.defineProperty拿到的了model.valueset 時機
  • 利用 事件 拿到了 dom 元素的 .valueset 時機.
  • 接下來的就簡單了,在 model.value.set 內(nèi)部同時修改 dom.value
  • dom.value.set 內(nèi)部修改 model.value

代碼如下:

<!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>Object.defineProperty</title>
</head>

<body>
  <h3>利用Object.defineProperty & dom.event 實現(xiàn)數(shù)據(jù)雙向綁定</h3>
  <input type="text" id="input">
  <div id="contentText"></div>
</body>

<script>
  let value = undefined
  let contentText = document.querySelector('#contentText')
  let model = {}
  Object.defineProperty(model, 'value', {

    set: function (newVal) {

      // 在這檢控到了model.value值的set設(shè)置時機
      value = newVal
      // 把model的新值賦值給dom
      input.value = newVal
      contentText.textContent = newVal

    },
    get: function () {
      return value
    }
  })

  let input = document.querySelector('#input')
  input.addEventListener('keyup', function (e) {
    // console.log(e.target.value)
    // 在這里拿到了dom的value更新值
    // 把dom的新值賦值給model
    model.value = e.target.value
    console.log(`input的數(shù)據(jù)改變了,model.value=${model.value}`)
  }, false)
</script>

</html>

效果:

Object.defineProperty&DOM.EVENT

4.補充

ES6.Proxy & DOM.EVENT

其實本質(zhì)上,只要拿到了model.valueset設(shè)置時機,在結(jié)合dom本身支持的事件機制,就能實現(xiàn)數(shù)據(jù)的雙向綁定.

ES6 新推出的 Proxy 也能監(jiān)控到 Objset,所以也能完成這樣的雙向綁定.

<!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>利用 Proxy 來實現(xiàn)數(shù)據(jù)的雙向綁定</title>
</head>

<body>
  <h3>利用ES6提供的Proxy來實現(xiàn)數(shù)據(jù)屬性雙向綁定</h3>
  <input type="text" id="input">
  <div id="textContent"></div>
</body>
<script>
  let input = document.querySelector('#input')
  let textContent = document.querySelector('#textContent')
  input.addEventListener('keyup', function (e) {
    proxyModel.value = e.target.value
    console.log(`model.value=${proxyModel.value}`)
  }, false)
  let model = {
    value: undefined
  }

  let proxyModel = new Proxy(model, {
    get: function (obj, prop) {
      return obj[prop]
    },
    set: function (obj, prop, val) {
      obj[prop] = val
      input.value = val
      textContent.textContent = val
    }
  })
</script>

</html>

結(jié)果:


總結(jié)

雙向綁定實現(xiàn)起來其實非常簡單.無非就下面三步.

  • 利用 Proxy 或者 Object.defineProperty 都能設(shè)置屬性的set
  • 利用 Event 機制,拿到 dom 元素設(shè)置值的時機.
  • 在雙方對應的 set 時機里來實現(xiàn)數(shù)據(jù)的雙向綁定.
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • vue理解淺談 一 理解vue的核心理念 使用vue會讓人感到身心愉悅,它同時具備angular和react的優(yōu)點...
    ndxs2008閱讀 24,388評論 2 18
  • 本文是lhyt本人原創(chuàng),希望用通俗易懂的方法來理解一些細節(jié)和難點。轉(zhuǎn)載時請注明出處。文章最早出現(xiàn)于本人github...
    lhyt閱讀 2,295評論 0 4
  • 雙向綁定如何實現(xiàn): 1、我們需要一個方法來識別視圖中哪個元素被設(shè)置了雙向綁定。 2、我們需要監(jiān)視視圖和數(shù)據(jù)的變化。...
    LoveBugs_King閱讀 1,638評論 1 3
  • 緣起 前幾天在看一些流行的迷你mvvm框架(比如avalon.js、 vue.js 這種較輕的框架,而非Angul...
    880d91446f17閱讀 369評論 0 0
  • 有一群弟子要出去朝圣。師父拿出一個苦瓜,對弟子們說:“隨身帶著這個苦瓜,記得把它浸泡在每一條你們經(jīng)過的圣河,并...
    羽悅開心閱讀 361評論 0 0

友情鏈接更多精彩內(nèi)容