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