详解vue的数据binding绑定原理

发布时间 - 2026-01-11 00:37:57    点击率:

自从angular火了以后,各种mvc框架喷涌而出,angular虽然比较火,但是他的坑还是蛮多的,还有许多性能问题被人们吐槽。比如检查机制,数据binding是受人喜爱的,脏检查就有点…性能低下了。有时候改了一个地方,脏循环要循环多次来保证数据是不是真的变了和是否停止变化了。这样性能就很低了。于是人们开始钻研新的双向数据binding的方法。尤大的vue binding就是本人蛮喜欢的一种实现方式,本文跟随尤大的一个例子来详解vue的数据binding的原理。

数据binding,一般也就是正则匹配到元素中的模板,然后代码切换为程序员给的data。双向binding除了脏检查机制,尤大用es5的defineProperty来实现的双向数据binding,拦截了对象的set和get方法,这个就比较有效了。同样的avalon也是此方法,用正美的话说:“我只是在var data = 1的时候拦截了’=‘“。原理都是一样的。我们直接上例子:(这里跟随尤大的脚步)(复制可用)

<!DOCTYPE html>
<html>
  <head>
    <title>ideal</title>
    <meta charset="utf-8">
  </head>
  <body>
    <div id="test">
      <p>{{msg}}</p>
      <p>{{msg}}</p>
      <p>{{msg}}</p>
      <p>{{what}}</p>
      <p>{{hey}}</p>
    </div>
    <script>
      var bindingMark = 'data-element-binding'
      function Element (id, initData) {
        var self   = this,
          el     = self.el = document.getElementById(id)
          bindings = {} //内部暂存绑定数据及dom
          data   = self.data = {} //存储bingding数据并实现监控
          content = el.innerHTML.replace(/\{\{(.*)\}\}/g, markToken)
          el.innerHTML = content
         
        for (var variable in bindings) {
          bind(variable); //将每个数据的名称比如'msg'绑定到data
        }
        if (initData) {
          for (var variable in initData) {
            data[variable] = initData[variable]
          }
        }
        function markToken (match, variable) {
          bindings[variable] = {} //bindings里存储了数据来源的字段比如bindings['msg']
          return '<span ' + bindingMark + '="' + variable +'"></span>'
        }
        function bind (variable) {
          bindings[variable].els = el.querySelectorAll('[' + bindingMark + '="' + variable + '"]')//bindings里再存储msg绑定的元素
          ;[].forEach.call(bindings[variable].els, function (e) { //删除data-element-binding属性
            e.removeAttribute(bindingMark)
          })
          Object.defineProperty(data, variable, { //es5观察属性
            set: function (newVal) {
              [].forEach.call(bindings[variable].els, function (e) {
                bindings[variable].value = e.textContent = newVal //=>这里才是实现的绑定,更新数据到dom并更新内部暂存数据
              })
            },
            get: function () {
              return bindings[variable].value //取数据仅仅是内部暂存的数据
            }
          })
        }
      }
      
      var app = new Element('test', {
        msg: 'hello',
        what: 'hi'
      })

    </script>
  </body>
</html>

这应该就是vue数据binding的原理了。一些地方都写在注释了。

这个数据binding的流程是怎样的?

开始弄一个属性占位符data-element-binding,正则把原元素的内容加个标签再加上此属性,属性的值是绑定的值的key,比如msg是hello,则data-element-binding=”msg“,同时在匹配的时候把这个key存到bindings对象里面,bindings暂存绑定数据。

遍历bindings对象,再把每个存在data-element-binding的元素以它的key(比如msg)存到bindings里面,然后删除dom中的data-element-binding属性。

最重要的是:它维护了一个data对象,这个data对象是binding的关键,他是m和v的接口。他循环定义属性key(比如msg),然后在set的时候更新dom的数据,完成的binding,也就是”=“的操作,并且把这个值存到bindings里暂存。set的时候返回的是bindings里面的暂存数据。这样的好处就是我始终是使用js的原生方法,我改变data就会实现双向的绑定。v=>m的binding只需要一个onchange事件就可以,避免了循环的检查。

vue的单项绑定就是这样了,有趣的地方是你在控制台修改data的属性,p标签的内容也会相应改变,这正是es5 set方法的特点,这样的双向绑定是好维护并且没有副作用的,而且性能还是很强大的。

那见识过vue的数据绑定以后我们实现一个input的双向数据绑定(跟源码不一样的说)

其实input的双向binding很简单,因为vue已经帮我们做好了data属性,那么我在操作data的时候实际上已经完成了m到v的双向绑定。那么原理很简单,onkey的时候就修改data数据就好了。先上代码:(复制可用)

<!DOCTYPE html>
<html>
  <head>
    <title>ideal</title>
    <meta charset="utf-8">
  </head>
  <body>
    <input class="test" type="text" name="asd" onkeyup ="handleChange()" v-model="hey">
    <input class="test" type="" name="" onkeyup ="handleChange()" v-model="msg">
    <script>
      var bindingMark = 'data-element-binding'
      function Element (classa, initData) {
        var self   = this,
          el     = self.el = document.getElementsByClassName(classa),//多个input改为class
          bindings = {} 
          data   = self.data = {} 
          for (var i = 0; i < el.length; i++) {
            content = el[i].outerHTML.replace(/v-model=\"(.*)\"/g, markToken);
            el[i].outerHTML = content
          }
        for (var variable in bindings) {
          bind(variable); 
        }
        if (initData) {
          for (var variable in initData) {
            data[variable] = initData[variable]
          }
        }
        function markToken (match, variable) {
          bindings[variable] = {} 
          return bindingMark + '="' + variable +'"' //内填一个span变为只改它的元素
        }
        function bind (variable) {

          bindings[variable].els = document.querySelectorAll('[' + bindingMark + '="' + variable + '"]')//document获取binding元素
          ;
          Object.defineProperty(data, variable, { 
            set: function (newVal) {
              [].forEach.call(bindings[variable].els, function (e) {
                bindings[variable].value = e.value = newVal //=>textContent改为input的value
              })
            },
            get: function () {
              return bindings[variable].value 
            }
          })
        }
      }
      
      var app = new Element('test', {
        msg: 'hello',
        hey:'aaa'
      })
      function handleChange(e){ //增加v=>m的绑定
        e = e || window.event
        var key = e.target.outerHTML.match(/data-element-binding=\"(.*)\"/)[1];
        data[key] = e.target.value
        console.log(data.hey,data.msg);
      }
    </script>
  </body>
</html>

修改的地方也注释了,结果会看到当我打开的时候,input已经被binding了msg和hey:

当我有输入的时候:

当操作data的时候:

双向binding已经ok,么么哒。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# vue binding  # vue binding.value  # vue数据绑定  # 绑定  # 很简单  # 的是  # 就会  # 是在  # 我在  # 也会  # 他是  # 多个  # 才是  # 的说  # 我有  # 我只  # 被人  # 你在  # 遍历  # 当我  # 下了  # 再加上  # 是怎样 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 高配服务器限时抢购:企业级配置与回收服务一站式优惠方案  通义万相免费版怎么用_通义万相免费版使用方法详细指南【教程】  网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?  iOS验证手机号的正则表达式  HTML5打空格有哪些误区_新手常犯的空格使用错误【技巧】  Win11怎么关闭资讯和兴趣_Windows11任务栏设置隐藏小组件  laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法  如何利用DOS批处理实现定时关机操作详解  如何用PHP快速搭建高效网站?分步指南  如何在云虚拟主机上快速搭建个人网站?  使用豆包 AI 辅助进行简单网页 HTML 结构设计  Laravel如何创建自定义中间件?(Middleware代码示例)  JS中页面与页面之间超链接跳转中文乱码问题的解决办法  如何用PHP工具快速搭建高效网站?  Laravel如何记录自定义日志?(Log频道配置)  再谈Python中的字符串与字符编码(推荐)  详解CentOS6.5 安装 MySQL5.1.71的方法  html如何与html链接_实现多个HTML页面互相链接【互相】  Zeus浏览器网页版官网入口 宙斯浏览器官网在线通道  如何挑选高效建站主机与优质域名?  Laravel怎么导出Excel文件_Laravel Excel插件使用教程  Python3.6正式版新特性预览  如何在万网自助建站平台快速创建网站?  如何用y主机助手快速搭建网站?  Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives  详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)  Laravel如何实现全文搜索_Laravel Scout集成Algolia或Meilisearch教程  laravel怎么实现图片的压缩和裁剪_laravel图片压缩与裁剪方法  Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程  佛山企业网站制作公司有哪些,沟通100网上服务官网?  VIVO手机上del键无效OnKeyListener不响应的原因及解决方法  如何在橙子建站中快速调整背景颜色?  高端企业智能建站程序:SEO优化与响应式模板定制开发  Thinkphp 中 distinct 的用法解析  Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】  Laravel怎么使用Intervention Image库处理图片上传和缩放  深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?  使用PHP下载CSS文件中的所有图片【几行代码即可实现】  合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?  MySQL查询结果复制到新表的方法(更新、插入)  北京企业网站设计制作公司,北京铁路集团官方网站?  Win11关机界面怎么改_Win11自定义关机画面设置【工具】  如何在 Telegram Web View(iOS)中防止键盘遮挡底部输入框  大连网站制作公司哪家好一点,大连买房网站哪个好?  今日头条微视频如何找选题 今日头条微视频找选题技巧【指南】  JS碰撞运动实现方法详解  Laravel如何升级到最新版本?(升级指南和步骤)  如何实现javascript表单验证_正则表达式有哪些实用技巧  移动端脚本框架Hammer.js  专业商城网站制作公司有哪些,pi商城官网是哪个?