前言

       我们都知道,Vue是一个构建数据驱动的web界面的渐进式框架。Vue.js的目标是通过尽可能简单的API实现响应的数据绑定和组合的视图组件。(摘自百度百科)这段Vue的定义明确了Vue的几大特点:数据驱动、渐进式、响应式、组件化、声明式渲染。
       对于Vue的渐进式和组件化这里不作赘述,本文具体看看Vue的数据驱动、响应式的原理,文末还会试着实现一个简单的双向绑定。

什么是数据驱动和双向绑定?

       所谓数据驱动,就是当数据发生变化的时候,用户界面发生相应的变化,开发者不需要手动的去修改dom,Vue会自动的根据数据渲染页面。这就是声明式渲染的概念,开发者借助Vue提供的API,只需要关注结果而不用关注具体是怎么实现的(与命令式渲染的区别),同时这也是Vue响应式的基础。我们都知道Vue是一个MVVM模式的框架,model和view的变化会通过viewmodel实时的反映在对方上(也就是我们常说的双向绑定),这样以来开发人员就不必过多关注dom操作而专注于业务逻辑,同时不触碰dom使得我们的代码易于维护。那么,Vue是怎么做到这一点的呢?

Vue响应式和双向绑定的原理

       Vue的双向绑定是采用“数据劫持结合发布-订阅者”模式实现的。我们结合官方文档的图来具体看一下Vue双向绑定的原理。
在这里插入图片描述
       Vue实例在初始化时,遍历在Observer(观察者)中所有属性通过Object.defineProperty()来实现他们的存取描述符(getter和setter),这样以来给任何对象的任意属性赋值都会触发该属性的setter,那么就能监听到数据变化。同时每个属性都会设置一个Dep(消息订阅器),他内部维护了一个数组,用来记录所有Watcher(订阅者)。
       然后Vue通过Compile(解析器)编译模板,将模板中的变量替换成对应的数据并渲染页面视图。此时Watcher会将自己添加到Dep中,到这里一个Vue实例的初始化完毕。
       当属性值发生改变时,触发setter函数,setter会调用Dep.notify()通知每一个订阅该属性的Watcher,Watcher会调用自身的update()函数对视图进行更新。这样一来双向绑定就实现了。

关于Object.defineProperty(obj,prop,descriptor)

       在使用js实现简单的双向绑定之前,我们要先来看一下这个不可或缺的函数,Object.defineProperty(obj,prop,descriptor)可以定义或修改对象的一个属性,并对这个属性的描述符进行设置。
       对于该函数的参数,obj是需要进行定义或修改的属性所属于的对象。prop是需要进行定义或修改的属性。descriptor是prop属性的描述符,它是以对象的形式传入的,有六个选项:value是该属性的值、writable表示该属性是否可写、enumerable表示该属性是否可以被遍历获得、configurable表示该属性是否可删除以及writable以外的描述符是否可改、set是该属性值被设置时执行的回调函数(默认是undefined)、get是该属性值被获得时执行的回调函数(默认是undefined)。在descriptor的六个选项中,数据描述符(value和writable)和存取描述符(get和set)是不可共存的。

js手撸一个简单的双向绑定

       废话不多说,先上代码。

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>双向绑定demo</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <div id="app">
            <div>双向绑定demo</div>
            <input type="text" id="input">
            <div>
				<span>input:</span>
				<span id="output"></span>
			</div>
        </div>
    </body>
    <script>
        var obj={}
        Object.defineProperty(obj,'input',{
            get:function(){
                return obj.input
            },
            set:function(value){
                document.getElementById('input').value = value
                document.getElementById('output').innerHTML = value
            }
        })
        document.addEventListener('keyup',function(e){
            obj.input = e.target.value
        })
    </script>
</html>

       这里我摆了一个输入框和一个span,span的文本、输入框的值和obj的属性input实现双向绑定。直接看js部分,定义了一个对象obj,用Object.defineProperty()给obj添加了一个属性input,并给该属性设置了get和set。给文本添加监听,当按键弹起时,修改obj对象的input属性,这时触发input属性的setter修改span内的文本。效果如下:
在这里插入图片描述
       当直接修改obj的input属性时,触发input的setter,修改输入框的值和span内的文本,效果如下:
在这里插入图片描述
       这样一个简单的双向绑定demo就完成了。


       以上是我对Vue响应式和双向绑定的理解,如有错误还请大牛指正,如有不同意见也欢迎质疑,希望对大家有所帮助,也希望同样在准备春招的朋友一切顺利。

Logo

前往低代码交流专区

更多推荐