简单实现vue框架中的双向数据绑定(v-model)

前言

最近学到了proxy和reflet就想着做一个小案例,这就想到了可以用这个实现vue框架里面的v-model双向数据绑定

实现思路:

  • 创建一个 Proxy 对象,用于监听数据对象属性的读取和赋值操作。

  • 在数据对象对应的属性被访问时,会触发 Proxy 对象的 get() 方法,我们可以在这个方法中添加必要的逻辑,如:如果是获取属性值,则将该属性值返回,如果是设置属性值,则需要将新值同步到输入框中。

  • 在输入框的输入事件中,将输入框的值同步到数据对象中,这里需要注意的是,在数据对象的属性被赋值时,会触发 Proxy 对象的 set() 方法,我们可以在这个方法中添加必要的逻辑,如:更新属性值,并将新值同步到输入框中。

  • 还需要注意的是,在使用 Proxy 监听对象的读取和赋值操作时,需要注意对象的嵌套层数,如果是多层嵌套,则需要递归创建 Proxy 对象,以达到监听所有属性和属性值的目的。

<body>

    <div>
        <label>姓名:</label>
        <input type="text" id="inputName" cameel-bind="name">
        <p cameel-bind="name">姓名:{{}}</p>
    </div>
    <div>
        <label>年龄:</label>
        <input type="text" id="inputAge" cameel-bind="age">
        <p cameel-bind="age">年龄:{{data.age}}</p>
    </div>

<script>
    const data = {
        name: "小明",
        age: 18
    };

    const handler = {
        get(target, key, receiver) {
            return Reflect.get(target, key, receiver)
        },
        set(target, key, value, receiver) {
            console.log(`set ${key} = ${value}`)
            Reflect.set(target, key, value, receiver);
            render();
            return true;
        }
    };

    const proxy = new Proxy(data, handler);

    const inputName = document.getElementById("inputName")
    const inputAge = document.getElementById("inputAge")

    inputName.addEventListener('input', function (e) {
        proxy.name = e.target.value;
    })

    inputAge.addEventListener('input', function (e) {
        proxy.age = e.target.value;
    })

    function render() {
        const elList = document.querySelectorAll('[cameel-bind]')
        elList.forEach(el => {
            const key = el.getAttribute('cameel-bind')
            console.log(el.getAttribute('cameel-bind'))
            const value = proxy[key]
            el.innerText = value
            el.value = value;

        });
    }
    render();

</script>


</body>

render函数:

   function render() {
        const elList = document.querySelectorAll('[cameel-bind]')
        elList.forEach(el => {
            const key = el.getAttribute('cameel-bind')
            console.log(el.getAttribute('cameel-bind'))
            const value = proxy[key]
            el.innerText = value
            el.value = value;

        });
    }

这里详细解析一下上述函数:

首先我们看到的这个函数名字叫render,显然它是用来渲染页面的,所以它的作用就是用来更新页面上那些被绑定了某个key值的元素的内容。

接下来我们看里面的代码,首先获取了所有带有cameel-bind属性的元素,这里用到了querySelectorAll方法,它是用来获取页面上所有符合指定选择器的元素的列表,这个方法是基于CSS选择器实现的,相信你已经非常熟悉它了,因为这是前端开发必备的知识点啊。而cameel-bind是这里自定义的一个属性,用来绑定元素的内容和数据源。

接着我们来看forEach方法,这是一个用来遍历数组的方法,对于每一个元素执行指定的回调函数。里面的回调函数包含两部分,第一部分是获取这个元素的cameel-bind的属性值,即key。第二部分是用获取到的key去代理对象(proxy)中获取对应的值(value),然后将这个值赋给元素的innerText属性,也就是元素的文本内容。这里用到了innerText属性,它是用来获取或设置元素的文本内容的。

接下来我们看render()函数的执行,它没有任何的参数,这表示它靠的是闭包的机制来获取所有需要渲染的元素。当闭包中的数据发生变化时,我们就需要再次调用这个函数来实现渲染。

render 函数实现解析总结:

  • 获取所有带有cameel-bind属性的元素
  • 对于每个元素,获取它绑定的key值
  • 到代理对象(proxy)中查找这个key对应的value值
  • 将value赋给这个元素的innerText属性,更新它的内容
  • 执行render()函数,渲染页面,并且可以反复调用它来实现数据的动态更新。

注意事项:

  • 修改代理对象的属性时,需要使用Reflect.set()方法,否则代理对象的属性不会被更新。

  • 双向绑定的数据必须在data对象中定义。

  • 使用Proxy需要判断浏览器是否支持该API。

  • 给页面元素绑定cameel-bind属性时,属性值必须是data对象中已定义的属性名,否则页面不会渲染该属性。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值