Stories

Detail Return Return

js實現數據雙向綁定 - Stories Detail

接上一篇文章《js實現數據單向綁定》
上篇文章中用原生js實現了數據的單向綁定。本篇文章繼續介紹如何用js實現數據的雙向綁定。綁定的方式模仿vue中的v-model指令。

創建標籤

<div id="div1">
  <input type="text" v-model="name">
  <br> 姓名:{{name}}
</div>

創建一個輸入框,使用v-model屬性綁定變量name,注意這裏只是模仿vue綁定的形式,代碼中並沒有引入任何vue依賴。完全靠原生js實現。

單向綁定

let el = document.getElementById('app');
let template = el.innerHTML;
let _data = {
  name: '_BuzzLy'
};

let data = new Proxy(_data, {
  set(obj, name, value) {
    obj[name] = value;
    render();
  }
});

render();

function render() {
  el.innerHTML = template.replace(/\{\{\w+\}\}/g, str => {
    str = str.substring(2, str.length - 2);
    return _data[str];
  });
}

到這我們又實現了一遍單向綁定,想要實現數據的雙向綁定其實很簡單,只需稍微修改我們的render函數。

雙向綁定

function render() {
  el.innerHTML = template.replace(/\{\{\w+\}\}/g, str => {
    str = str.substring(2, str.length - 2);
    return _data[str];
  });

  // 找到所有input標籤
  Array.from(el.getElementsByTagName('input'))
   // 過濾得到其中帶有v-model屬性的標籤 
   .filter(ele => ele.getAttribute('v-model'))
   // 遍歷這些input標籤
   .forEach(input => {
      // 獲取到v-model中綁定的key,從數據中找到key對應的value賦給input
      // 這一步就相當於數據=>視圖的綁定
      let name = input.getAttribute('v-model');
      input.value = _data[name];
    
      // 為input綁定輸入事件
      input.oninput = function () {
        // 當input修改時,將修改後的值賦給暴露在外的data對象
        // 這一步就實現了視圖=>數據的綁定
        data[name] = this.value;
      };
  });
}

修改後的render函數通過過濾、遍歷得到每一個擁有v-model屬性的input標籤,然後將數據綁定到視圖上,並且視圖修改也會觸發數據的更新,這樣就實現了數據的雙向綁定。
看似複雜的綁定機制其實就是通過我們熟悉的js一些基礎的操作來實現的。


完整代碼

<!DOCTYPE html>
<html lang="en" dir="ltr">

<head>
  <meta charset="utf-8">
  <title></title>
</head>

<body>
  <div id="div1">
    <input type="text" v-model="name">
    <br> 姓名:{{name}}
  </div>
</body>
<script>
  let el = document.getElementById('div1');
  let template = el.innerHTML;
  let _data = {
    name: '_BuzzLy'
  };

  let data = new Proxy(_data, {
    set(obj, name, value) {
      obj[name] = value;
      render();
    }
  });

  render();

  function render() {
    el.innerHTML = template.replace(/\{\{\w+\}\}/g, str => {
      str = str.substring(2, str.length - 2);
      return _data[str];
    });

    Array.from(el.getElementsByTagName('input'))
     .filter(ele => ele.getAttribute('v-model'))
     .forEach(input => {
       let name = input.getAttribute('v-model');
       input.value = _data[name];

       input.oninput = function () {
         data[name] = this.value;
       };
    });
  }
</script>

</html>
user avatar tianmiaogongzuoshi_5ca47d59bef41 Avatar honwhy Avatar alibabawenyujishu Avatar haoqidewukong Avatar smalike Avatar linlinma Avatar zs_staria Avatar freeman_tian Avatar front_yue Avatar kobe_fans_zxc Avatar littlelyon Avatar 6fafa Avatar
Favorites 187 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.