手写vue2响应式

思路:

1、使用Object.defineProperty()实现

Object.defineProperty直接在一个对象上定义一个新属性,或者修改一个已经存在的属性

Object.defineProperty(对象名,属性名,{配置项})

2、目标对象中的每一个数据都要监听,所以需要遍历目标对象,操作覆盖所有数据

3、数据和view需要关联,获取所有标签节点后使用attributes得到v-text/v-modal对应的属性名,使用innerHTML(文本)或者value(input)实现M->V,监听input事件实现V->M

4、为了精确更新,将对应的属性和相关操作在V->M时收集起来,下一次修改对应属性时精确更新此属性的相关回调,即把值放入dom中展示的语句

<!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>手写响应式</title>
</head>

<body>
    <div id="app">
        <div v-text="name"></div>
        <input type="text" v-modal="age">
    </div>
</body>

</html>
<script>
    let data = {
        name: '123',
        age: 18,
        sex: '女'
    }

    //处理data中每一个数据
    Object.keys(data).forEach(prop => {
        defineReactive(data, prop, data[prop])
    })

    function defineReactive(data, prop, value) {
        //使用Object.defineProperty实现
        Object.defineProperty(data, prop, {
            get() {
                //get获取值
                return value
            },
            set(newVal) {
                //set修改值
                if (value === newVal) return //若修改前后值没变 不做操作
                value = newVal //更新值
                Dep.trigger(prop) //执行收集的使用到当前属性的所有依赖的回调函数
            }
        })
    }
    let Dep = {
        _dep: {}, //存放属性以及对应的回调函数
        collect(event, fn) {
            //收集
            if (!this._dep[event]) { this._dep[event] = [] }
            this._dep[event].push(fn)
        },
        trigger(event) {
            //执行
            this._dep[event].forEach(fn => {
                fn()
            })
        }
    }
    function compile() {
        //M->v   v-> M 的实现
        let childNodes = document.querySelector('#app').childNodes
        childNodes.forEach(node => {
            if (node.nodeType == '1') {
                //nodeType 1 -> 节点类型为标签
                let attr = node.attributes
                Array.from(attr).forEach(attrItem => {
                    let nodeName = attrItem.nodeName
                    let nodeVal = attrItem.nodeValue
                    if (nodeName === 'v-text') {
                        node.innerHTML = data[nodeVal]
                        Dep.collect(nodeVal, () => {
                            node.innerHTML = data[nodeVal]
                        })
                    }
                    if (nodeName === 'v-modal') {
                        node.value = data[nodeVal]
                        Dep.collect(nodeVal, () => {
                            node.value = data[nodeVal]
                        })
                        node.addEventListener('input', (e) => {
                            data[nodeVal] = e.target.value
                        })
                    }
                })

            }
        })
    }
    compile()


</script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值