简单模拟vue实现数据劫持-视图更新双向绑定-2

 

 接上,

new一个实例对象,vc,构造函数动态绑定一个空对象,并在构造函数上绑定静态方法

$on进行事件的注册,$emit抛出执行事件


        function observe() {
            // 利用策略模式-可以快速根据特定的事件,执行多个函数
            this.strategy = {

            }
        }
        //    在observe构造函数的原型上添加两个静态方法$on和$emit
        // $emit调用传入参数,通过属性名找到方法,执行所有事件(被发布的事件,订阅者获取将执行所有事件)
        observe.prototype.$emit = function (eventName) {
            this.strategy[eventName].forEach(fn => fn())
        }
        // $on调用传入两个参数,第一个事件名,第二个事件执行函数--会被push到对象中
        observe.prototype.$on = function (eventName, callback) {
            // 判断里面有没有这个事件名,没有就添加键值
            if (!this.strategy[eventName]) {
                this.strategy[eventName] = []
            }
            this.strategy[eventName].push(callback)
        }

        const vc = new observe()

        // 理解为在methods中定义执行函数
        function doclick() {
            console.log("起身");
        }
        //  定义一个事件,执行函数----发布了一个事件
        vc.$on('qisheng', doclick)

 抛出执行事件

 使用$on添加事件,$emit抛出执行事件

 接上次目标

数据修改,视图更新--和模拟实现v-model的双向绑定

先实现v-html的数据改动视图更新---

 当订阅者关注发生改变的时候执行事件更新视图

(之前的错误,写死了,写data.name的话只会data.name会更新数据,应该改为key)

 修改后试试确定没问题

 更新视图

 

 实现演示

 实现v-model双向--从视图到数据

首先数据更新视图也更新和上面v-html一样添加一个$on

 前面set方法里已经使用$emit更新视图了,这样就可以了实现数据变化绑定v-model的input数据变化

监听input事件,事件对象e,的target的value有input框输入的值,并把值赋值给实例对象里的key(age或name)

 实现双向绑定演示

 实现效果完整代码

<body>
    <div id="app">
        <h1 v-html="name"></h1>
        <input v-model="name" type="text">
        <h2 v-html="name" data-html="name"></h2>
        <input v-model="age" data-html="name"></input>
        <h3 v-html="age"></h3>
    </div>
    <script>

        // // 观察者
        // function observe() {

        // }

        function observe() {
            // 利用策略模式-可以快速根据特定的事件,执行多个函数
            this.strategy = {

            }
        }
        //    在observe构造函数的原型上添加两个静态方法$on和$emit
        // $emit调用传入参数,通过属性名找到方法,执行所有事件(被发布的事件,订阅者获取将执行所有事件)
        observe.prototype.$emit = function (eventName) {
            this.strategy[eventName].forEach(fn => fn())
        }
        // $on调用传入两个参数,第一个事件名,第二个事件执行函数--会被push到对象中
        observe.prototype.$on = function (eventName, callback) {
            // 判断里面有没有这个事件名,没有就添加键值
            if (!this.strategy[eventName]) {
                this.strategy[eventName] = []
            }
            this.strategy[eventName].push(callback)
        }

        // const vc = new observe()

        // // 理解为在methods中定义执行函数
        // function doclick() {
        //     console.log("起身");
        // }
        // //  定义一个事件,执行函数----发布了一个事件
        // vc.$on('qisheng', doclick)
    </script>

    <script>

        const vc = new observe()

        function MVVM(options) {
            const { el, data } = options
            console.log(el);
            console.log(data);
            for (let key in data) {
                console.log(key);
                Object.defineProperty(this, key, {
                    get: function () {
                        return data[key]
                    },
                    set: function (newVal) {
                        console.log(newVal, '修改了值');
                        // 修改值和原先值不同才会触发
                        if (data[key] !== newVal) {
                            data[key] = newVal
                            vc.$emit(key)
                        }
                    }
                })
            }
            // 显示数据//挂载的节点,下的所有元素---得到伪数组
            const domArr = document.querySelector(el).children
            //    转换为真数组
            console.log(Array.from(domArr), '转换');
            Array.from(domArr).forEach(domNode => {
                console.log(domNode);
                console.log(domNode.dataset.html, 'dataset取自定义属性值');
                // console.log(domNode.hasAttribute('v-html'));
                if (domNode.hasAttribute('v-html')) {
                    console.log(domNode.getAttribute('v-html'));
                    const key = domNode.getAttribute('v-html')
                    domNode.innerHTML = this[key]//this指向实例化对象
                    // ------------
                    // 发布一个事件
                    vc.$on(key, () => { domNode.innerHTML = this[key] })
                }

                if (domNode.hasAttribute('v-model')) {
                    // console.log(domNode.getAttribute('v-html'));
                    const key = domNode.getAttribute('v-model')
                    domNode.value = this[key]//this指向实例化对象
                    vc.$on(key, () => { domNode.value = this[key] })
                    // 监听input事件,事件对象e,的target的value有input框输入的值,并把值赋值给实例对象里的key(age或name)
                    domNode.addEventListener('input', (e) => { 
                        this[key]= e.target.value 
                    })
                }

            })

        }
        // 语法 dataset 也可以取自定义属性值,但是标签绑定固定语法 data-自定义名="值",取出标签元素.dataset.自定义名,返回自定义属性值
        // 语法getAttribute,返回自定义属性值,元素.hasAttribute('自定义属性名'),返回自定义属性值
        // 语法hasAttribute,返回布尔值,元素.hasAttribute('自定义属性'),判断节点是是否存在此自定义属性
        const vm = new MVVM({
            el: '#app',
            data: {
                name: "张三",
                age:18
            },
        })

        console.dir(vm)
    </script>
</body>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值