ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

vue双向数据绑定原理

2021-06-04 11:30:37  阅读:187  来源: 互联网

标签:node vue 绑定 value 视图 key 双向 data newValue


vue响应式原理

数据驱动

数据响应式:据模型仅仅是普通的JavaScript对象,而当我们修改数据时,视图会进行更新,避免了频繁的DOM操作,提高开发效率,这与Jquery不一样,Jquery是频繁的操作Dom

双向绑定:

数据改变,视图改变,视图改变,数据也随之改变( 双向绑定中是包含了数据响应式的内容)

我们可以使用`v-model` 在表单元素上创建双向数据绑定

数据驱动是Vue最独特的特性之一

 开发过程中仅仅需要关注数据本身,不需要关心数据是如何渲染到视图中的。主流的`MVVM`框架都已经实现了数据响应式与双向绑定,所以可以将数据绑定到`DOM`上。

响应式核心原理

vue2原理

官方文档:https://cn.vuejs.org/v2/guide/reactivity.html

Vue2.x中响应式的实现是通过Object.defineProperty来完成的,注意该属性无法降级(shim)处理,所以Vue不支持IE8以及更低版本的浏览器的原因。

数据变化反应到导视图

声明式改变视图:

将data中name属性的值作为文本渲染到标记了v-text的p标签内部,在vue中,我们把这种标记式的声明式渲染叫做指令

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

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <p v-text='name'></p>
    <p v-text='age'></p>
  </div>
  <script>

    let data = { name: '李白', age: 12 }

    Object.keys(data).forEach(key => {
      define(data, key, data[key])

    });
    function define(data, key, value) {

      Object.defineProperty(data, key, {
        get() {
          return value
        },
        set(newValue) {
          value = newValue
          compile()
        }
      })
    }

    function compile() {
      let app = document.querySelector('#app')
      let nodes = app.childNodes
      // console.log(nodes);
      nodes.forEach(item => {
        if (item.nodeType === 1) {
          let arr = item.attributes
          console.log(arr);
          Array.from(arr).forEach(node => {
            let name = node.nodeName
            let value = node.nodeValue
            if (name === 'v-text') {
              item.innerHTML = data[value]
            }
          })
        }
      })
    }
    compile()
  </script>
</body>

</html>

命令式改变视图:

通过原始的操作dom的方式让每一次的name的最新值都能显示到p元素内部

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

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <p></p>
  </div>
  <script>
    let p = document.querySelector("#app p")
    let data = { name: '李白', age: 12 }
    // console.log(Object.keys(data));

    Object.keys(data).forEach(key => {
      console.log(data);
      console.log(key);
      define(data, key, data[key])

    });
    function define(data, key, value) {
      // console.log(data, key, value);
      Object.defineProperty(data, key, {
        get() {
          return value
        },
        set(newValue) {
          value = newValue
          p.innerHTML = value
        }
      })
    }
    p.innerHTML = data.name
  </script>
</body>

</html>

视图变化反应到数据

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

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <input type="text" v-model="name">
  </div>
  <script>
    let data = {
      name: '李白',
      age: 18
    }
    Object.keys(data).forEach(key => {
      defineReactiveProperty(data, key, data[key])
    })
    function defineReactiveProperty(data, key, value) {
      console.log();
      Object.defineProperty(data, key, {
        get() {
          return value
        },
        set(newValue) {
          if (newValue === value) {
            return
          }
          value = newValue
          // 使用声明式渲染,就要便利所有节点,看哪个节点有我们的自定义绑定属性
          compile()
        }
      })
    }
    function compile() {
      let app = document.querySelector('#app')
      // 拿到 app 下所有子元素
      const nodes = app.childNodes
      nodes.forEach(node => {
        if (node.nodeType === 1) {
          const attrs = node.attributes
          Array.from(attrs).forEach(attr => {
            const nodeName = attr.nodeName
            const nodeValue = attr.nodeValue
            if (nodeName === 'v-model') {
              // 当data中数据发生变化时,改变文本框的value属性,以更新文本框的值
              node.value = data[nodeValue]
              // 当文本框的内容发生变化时,更新 data 中属性的值
              node.addEventListener('input', e => {
                data[nodeValue] = e.target.value
              })
            }
          })
        }
      })
    }
    compile()
  </script>

</html>

Vue3响应式原理

Vue3的响应式原理是通过Proxy来完成的。

Proxy直接监听对象,而非属性,所以将多个属性转换成getter/setter的时候,不需要使用循环。

ProxyES6课程中新增的,IE不支持

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Proxy</title>
  </head>
  <body>
    <div id="app">hello</div>
    <script>
      //模拟Vue中的data选项
      let data = {
        msg: "hello",
        count: 0,
      };
      //模拟Vue实例
      //为data创建一个代理对象vm,这样就可以通过vm.msg来获取data中的msg属性的值,而这时候会执行get方法
      let vm = new Proxy(data, {
        // 当访问vm的成员时会执行
        //target表示代理的对象(这里为data对象),key表示所代理的对象中的属性
        get(target, key) {
          console.log("get key:", key, target[key]);
          return target[key];
        },
        //当设置vm的成员时会执行
        set(target, key, newValue) {
          console.log("set key:", key, newValue);
          if (target[key] === newValue) {
            return;
          }
          target[key] = newValue;
          document.querySelector("#app").textContent = target[key];
        },
      });
      //测试
      vm.msg = "aaaa";
      console.log(vm.msg);
    </script>
  </body>
</html>

双向数据绑定

双向数据绑定包含两部分内容,数据变化更新视图,视图变化更新数据。

实现双向数据绑定

基本的思路就是,我们可以给文本框(第一个文本框)添加一个input事件,在输入完数据后触发该事件,同时将用户在文本框中输入的数据赋值给data中的属性(视图变化,更新数据,而当数据变化后,会执行行observer.js中的set方法,更新视图,也就是触发了响应式的机制)。

//处理v-model
  modelUpdater(node, value, key) {
    //v-model是文本框的属性,给文本框赋值需要通过value属性
    node.value = value;
    new Watcher(this.vm, key, (newValue) => {
      node.value = newValue;
    });
    //实现双向绑定
    node.addEventListener("input", () => {
      this.vm[key] = node.value;
    });
  }

为当前的文本框节点添加了input事件,当在文本框中输入内容的时候会触发该事件,同时,将用户在文本框节点中输入的值重新赋值给了data中对应的属性。

在文本框中输入值,对应的差值表达式和v-text中的内容都会发生改变。同时在控制台中输出vm.msg的值会发现数据也发生了变化。

当给data中的属性赋值后,会执行observer.js中的set方法,更新视图,也就是触发了响应式的机制。

标签:node,vue,绑定,value,视图,key,双向,data,newValue
来源: https://blog.csdn.net/weixin_50613714/article/details/117553938

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有