手写简易vue响应式

39 篇文章 0 订阅
12 篇文章 0 订阅

1.vue 2.0

html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id='app'>
        订阅1<span class="box-1">1111</span>
        订阅2<span class="box-2">2222</span>
    </div>
    <script src="./index.js"></script>
    <script>
        // 开始执行数据劫持
        let dataObj = {};
        dataHijack({
            data: dataObj, //劫持的对象
            tag: 'view-1', // 唯一id,类似vue节点上的key
            datakey: 'one', // 挂载到对象的属性,类似data中的属性名
            selector: '.box-1', // 类名
        })
        dataHijack({
            data: dataObj,
            tag: 'view-2',
            datakey: 'two',
            selector: '.box-2',
        })
        // 修改数据
        dataObj.one = '测试1'
        dataObj.two = '测试2'
    </script>
</body>

</html>

js

// 订阅器模式
let Dep = {
    clientList: {}, //订阅者集合
    // 添加订阅
    listen: function (key, fn) { //key:唯一id,fn:回调函数,可能有多个
        // 如果该项没有订阅,设置初始存储集合,然后添加回调函数
        (this.clientList[key] || (this.clientList[key] = [])).push(fn)
    },
    // 推送方法
    trigger: function () {
        // 这里的arguments指的下面的set方法传过来的[tag, val],数组格式
        // key对应的就是tag,即唯一id
        let key = Array.prototype.shift.call(arguments)
        // 拿到当前的函数,为什么能拿到,是因为初始化时执行Dep.listen已经存储到clientList了
        // fns其实就是里面的回调函数
        let fns = this.clientList[key]
        if (!fns || fns.length === 0) {
            return false
        }
        // 执行节点对应的函数,即初始化挂载的回调
        for (let i = 0, fn; i < fns.length; i++) {
            fn = fns[i]
            fn.call(this, ...arguments)
        }
    }
}

// 数据劫持
let dataHijack = function ({ data, tag, datakey, selector }) {
    let value = ''
    // 对对象的各个属性进行劫持
    Object.defineProperty(data, datakey, {
        get: function () {
            console.log('取值')
            return value
        },
        set: function (val) {
            // 修改dataObj后会进入这里
            console.log('设置值')
            value = val
            // 数据变化
            Dep.trigger(tag, val)
        }
    })
    // 添加订阅者,这里指的是将订阅者1,2分别添加到clientList中,
    // 此时clientList的格式为:{view-1: [ƒ],view-2: [ƒ]},f是这里传过去的函数
    Dep.listen(tag, function (text) {
        document.querySelector(selector).innerHTML = text
    })
}

2.vue 3.0

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id='app'>
        proxy的使用
    </div>
    <script>
        let obj = {
            name: '小明',
            age: '18',
        }
        // 代理
        const p = new Proxy(obj, {
            // 查属性
            get(target, propName) {
                return target[propName]
            },
            // 新增修改属性
            set(target, propName, value) {
                target[propName] = value
            },
            // 删除属性
            deleteProperty(target, propName) {
            },
        })
    </script>
</body>
</html>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值