用原生js实现Vue单向数据绑定

2020-03-08  本文已影响0人  本一和他的朋友们

问题:Vue的单项数据是如何绑定的

为了了解vue的的单向数据绑定原理,看了官方文档

发现Object.defineProperty是其核心,又查看了MDN文档,以下是自己参考文档和其他文章,使用原生js写出的代码,首先让代码跑起来,有个直观的感受,然后再深入解析。

示例代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            margin: 0;
            padding: 0;
            height: 100vh;
        }

        .main{
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
        }
        
    </style>
    <title>用原生js实现单向数据绑定</title>
</head>
<body>
    <div class="main">
        <input type="text" id="model">
        
        <div id="modelText"></div>
    </div>
    <script>
        var model = document.querySelector("#model")
        var modelText = document.querySelector("#modelText")

        var defaultName = 'hello world'
        var userInfo = {}
        model.value = defaultName

        Object.defineProperty(userInfo, 'name', {
            get: function() {
                return defaultName
            },
            set: function(newValue) {
                model.value = newValue;
                console.log("newValue is ===>>>", newValue)
                modelText.textContent = newValue
            }
        })

        userInfo.name = defaultName
        var isEnd = true 

        model.addEventListener('keyup', function() {
            if (isEnd) {
                userInfo.name = this.value
            }
        }, false)

        // 监听中文输入法切换
        model.addEventListener('compositionstart', function() {
            console.log('开始中文输入')
            isEnd = false
        })

        model.addEventListener('compositionend', function() {
            isEnd = true 
            console.log("结束中文输入")
        })
    </script>
</body>
</html>

代码解析

Object.defineProperty() 方法直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。

用法如下:

Object.definProperty(
    obj,  // 要在其上定义的对象
    prop, // 要定义或修改的属性的名称
    descriptor  // 将被定义或修改的属性描述符
)

例子中通过Object.definProperty将userInfo.name的值利用get来获取值,利用set来监听值的变化。

    var userInfo = {}

    Object.defineProperty(userInfo, 'name', {
        get: function() {
        },
        set: function(newValue) {
        }
    })

回头看Vue中的实现

  1. 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。
  2. 这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在属性被访问和修改时通知变更。
  3. 每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

同时官方文档有图,更加直观的展示了数据变化过程


image
上一篇下一篇

猜你喜欢

热点阅读