vue双向绑定原理(数据响应式原理)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        /* 
            1.首先实现一个整体的VUE类,Watcher类
            2.实现MVVM中的M到V,把模型里的数据绑定到视图
            3.(1)最后实现从V-M,当文本框输入的时候,由文本事件触发更新模型中的数据
              (2)同时更新相应的视图
        */

        // 发布者
        class Vue {
            constructor(options) {
                this.options = options
                this.$data = options.data   // 获取数据
                this.$el = document.querySelector(options.el)
                this._directive = {}    // 容器,存放数据
                this.Observer(this.$data)
                this.Compile(this.$el)
            }

            // 数据劫持
            Observer (data) {
                for (let key in data) {
                    this._directive[key] = []
                    let Val = data[key]
                    let watch = this._directive[key]
                    // this.$data 对象里面的每一个属性发生变化,都要更新视图
                    Object.defineProperty(this.$data, key, {
                        get: function () {
                            return Val
                        },

                        set: function(newVal) {
                            if (newVal !== Val) {   // 当新值不等于老值时,将老值赋给新值
                                Val = newVal
                                watch.forEach(item => {
                                    item.update()
                                })
                            }
                        }
                    })
                }    
            }

            // 解析指令
            Compile (el) {
                let nodes = el.children
                for (let i = 0; i < nodes.length; i++) {
                    if (nodes[i].children.length) {
                        // 递归循环
                        this.Compile(nodes[i])
                    }

                    // 判断是否含有指令v-text
                    if (nodes[i].hasAttribute('v-text')) {
                        let attrVal = nodes[i].getAttribute('v-text')
                        this._directive[attrVal].push(new Watcher(nodes[i], this, attrVal, "innerHTML"))
                    }
                    // 判断是否含有指令v-model
                    if (nodes[i].hasAttribute('v-model')) {
                        let attrVal = nodes[i].getAttribute('v-model')
                        this._directive[attrVal].push(new Watcher(nodes[i], this, attrVal, "value"))

                        // 监听input输入框事件
                        nodes[i].addEventListener('input',()=>{
                            this.$data[attrVal] = nodes[i].value
                        })
                    }
                }
            }
        }

        // 订阅者
        class Watcher {
            constructor(el, vm, exp, attr) {
                this.el = el
                this.vm = vm
                this.exp = exp
                this.attr = attr
                this.update()   // 初始化视图
            }

            update () {
                this.el[this.attr] = this.vm.$data[this.exp]
            }
        }
    </script>
</head>
<body>
    <div id="app">
        <h1>数据响应式原理</h1>
        <div>
            <div v-text="myText"></div>
            <div v-text="myBox"></div>
            <input type="text" v-model="myText">
        </div>
    </div>

    <script>
        const app = new Vue({
            el: "#app",
            data: {
                myText: '大吉大利,今晚吃鸡',
                myBox: '落地成盒'
            }
        })
    </script>
</body>
</html>

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值