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

news2025/4/6 23:26:07

 

 接上,

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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/190077.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

最全总结 | 聊聊 Selenium 隐藏浏览器指纹特征的几种方式!

大家好&#xff0c;我是安果&#xff01;我们使用 Selenium 对网页进行爬虫时&#xff0c;如果不做任何处理直接进行爬取&#xff0c;会导致很多特征是暴露的对一些做了反爬的网站&#xff0c;做了特征检测&#xff0c;用来阻止一些恶意爬虫本篇文章将介绍几种常用的隐藏浏览器…

第九层(9):STL之map/multimap

文章目录前情回顾map/multimap概念差别构造函数赋值操作大小操作函数交换函数插入函数删除函数查找函数统计函数排序规则下一座石碑&#x1f389;welcome&#x1f389; ✒️博主介绍&#xff1a;一名大一的智能制造专业学生&#xff0c;在学习C/C的路上会越走越远&#xff0c;后…

三线金叉选股公式,均线、成交量、MACD共振

均线、成交量、MACD三线金叉共振选股公式思路还是比较简单的&#xff0c;分别写出均线金叉、成交量的均量线金叉、MACD的快线和慢线金叉&#xff0c;最后用AND连接这三个条件。 一、编写选股公式所需通达信函数 1、EXIST函数 含义&#xff1a;是否存在 用法&#xff1a;EXIST…

OpenGL | 搭建OpenGL 画画框架

一、搭建OpenGL 画画框架3D场景初始化&#xff08;1&#xff09; 代码void Init() {glMatrixMode(GL_PROJECTION); //将当前矩阵指定为投影矩阵,对投影矩阵操作gluPerspective(50.0f, 800.0f / 600.0f, 0.1f, 1000.0f);//创建一个对称的透视投影矩阵&#xff0c;并且用这个…

世界上最大型的 Demo Drop DJ 比赛来到元宇宙!

简要介绍 WBDD 于 2023 年 1 月 26 日至 2 月 8 日进入元宇宙。 认识世界上最大型的 DJ 比赛获胜者&#xff0c;并在元宇宙中伴随着他们的音乐跳舞。 该体验将是线下活动的延伸&#xff0c;由 Mike Williams 担任活动大使。 体验将对所有人开放。 完成 80% 的任务&#xff…

51单片机简易出租车计费系统仿真设计( proteus仿真+程序+报告+讲解视频)

51单片机简易出租车计费系统仿真设计( proteus仿真程序报告讲解视频&#xff09; 仿真图proteus 8.9及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0036 51单片机简易出租车计费系统仿真设计讲解视频1.主要功能&#xff1a;…

MXNet实现图片的样式风格迁移(Style Transfer)

样式迁移就是将一个样式&#xff08;风格&#xff09;应用到一张主图上&#xff0c;改变这张图片的风格&#xff0c;比如说拍摄了一张夜晚的图片&#xff0c;我们可以拿梵高的"星月夜"图片做样式&#xff0c;应用到拍摄的图片上&#xff0c;两者合成后的新图片&#…

linux基本功系列之uptime命令实战

文章目录一. uptime命令介绍二. 语法格式及常用选项三. 参考案例3.1 显示当前系统运行负载情况3.2 显示机器正常运行的时间3.3 显示机器启动时间3.4 关于平均负载的介绍总结前言&#x1f680;&#x1f680;&#x1f680; 想要学好Linux&#xff0c;命令是基本功&#xff0c;企业…

推荐 5 个实用 GitHub 项目

本期推荐开源项目目录&#xff1a;1. AI-For-Beginners2. 一个小巧轻便的 PDF 阅读器3. 开源的智能手表4. 开源内容管理系统5. 程序员海外工作/英文面试手册01AI-For-Beginners之前推荐过 Microsoft 出品的 Web 技术栈课程&#xff0c;本开源项目同样是 Microsoft 的 Azure Clo…

go runtime

go 运行时&#xff0c;也称为 go runtime&#xff0c;类似Java中的JVM虚拟机&#xff0c;不过runtime并非是虚拟机。其本身就是每个 go 程序的一部分&#xff0c;它会跟源码一起编译并链接到目标程序中&#xff0c;即便只写了一个 hello world 程序&#xff0c;这个程序中也包含…

day15 二叉树 | 104、二叉树的最大深度 111、二叉树的最小深度 222、完全二叉树的节点个数

题目 104、二叉树的最大深度 递归法&#xff08;后序&#xff09;&#xff08;必须会&#xff09; // 定义&#xff1a;输入根节点&#xff0c;返回这棵二叉树的最大深度 int maxDepth(TreeNode root) {if (root null) {return 0;}// 利用定义&#xff0c;计算左右子树的最大…

论文笔记:Graph WaveNet for Deep Spatial-Temporal Graph Modeling

IJCAI 2019 1 abstract & intro 时空数据挖掘问题大多数使用邻接矩阵来建模节点之间的属性关系&#xff0c;这种思路的一个基本假设是&#xff1a;节点信息取决于自身和邻居的历史信息。 但这类模型的假设存在着一些问题&#xff1a; 未能充分建模节点之间的依赖关…

宝塔部署springboot,vue,node.js项目

宝塔部署springboot项目&#xff1a; 先将命令转移到jar包所属文件夹中 分为短暂部署和永久部署 短暂部署&#xff1a;java -jar xxx.jar 永久部署&#xff1a;nohup java -jar demo-1.0.0.jar logs_mark.txt 2>&1 & nohup:linux的命令,代表关闭但持续运行 查看898…

52.Isaac教程--操纵杆

操纵杆 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录操纵杆使用游戏机操纵杆使用其他操纵杆使用 Playstation 操纵杆很容易控制运行 Isaac SDK 的机器人&#xff0c;但也可以使用其他控制器。 使用游戏机操纵杆 按照以下步骤校准您的…

微信小程序018小说在线阅读系统书城

管理员的主要功能有&#xff1a; 1.管理员输入账户登陆后台 2.个人中心&#xff1a;管理员修改密码和账户信息 3.用户管理&#xff1a;对注册的用户信息进行删除&#xff0c;查询&#xff0c;添加&#xff0c;修改 4.小说信息管理&#xff1a;对小说信息进行添加&#xff0c;修…

TCP/IP第六章笔记ICMP协议

文章目录6.1 引言6.2 ICMP报文分组格式和类型6.3 ICMP地址掩码请求与应答6.4 ICMP时间戳请求与应答6.5 ICMP端口不可达差错6.6 ICMP的处理&#xff08;4.4BSD系统下&#xff09;6.1 引言 第三章在IP选择路由时&#xff0c;如果一个报文最后限制转发次数用完后还传输不到目的地…

【高并发】- 不可不知道的RPC框架服务通信

前言 前面章节讲解了高并发系统中相关指标、为什么要学习高并发设计思想、高并发系统中每个环节的流量处理等思想。本章节讲解服务通信&#xff0c;来帮助大家更好理解系统间通信过程。 1 RPC框架介绍 RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff0…

Win10家庭版和Win10专业版有什么区别?

win10操作系统拥有7个不同的版本&#xff0c;其中win10家庭版和专业版被人们广泛的应用&#xff0c;很多用户都不知道如何区分win10家庭版和专业版&#xff0c;接下来把win10家庭版和专业版有什么不同的地方告诉大家。我们一起来看看吧。 win10家庭版和专业版的区别&#xff1a…

java服务框架高级之微服务保护 Sentinel 限制规则,流控模式,流控效果

初识Sentinel 雪崩问题&#xff1a; 解决雪崩问题的常见方式有四种&#xff1a; 1.超时处理&#xff1a;设定超时时间&#xff0c;请求超过一定时间没有响应就返回错误信息&#xff0c;不会无休止等待 2.舱壁模式&#xff1a;限定每个业务能使用的线程数&#xff0c;避免耗尽…

2023外企还香吗?2022届计算机谈谈入职外企的感受和经历

互联网寒冬&#xff0c;大规模“毕业”的环境下&#xff0c;2023年外企又香了吗&#xff1f; 大家好&#xff0c;我是2022届计算机应届毕业生&#xff0c;毕业入职了一家大型非互联网外企&#xff0c;2022年由于只上了半年班&#xff0c;所以只有半年工资&#xff0c;总收入在1…