007-双向绑定原理

双向绑定原理

  • 双向绑定
  • 思考:
  • 一句话描述原理
  • DocuemntFragment(碎片化文档)
  • Object.defineProperty(数据劫持)
  • 发布订阅者模式
  • Vue 双向绑定图示
  • Vue 双向绑定完整实现代码

双向绑定

vue中 data定义的数据会添加双向绑定的功能,即数据更新后,页面内容会同步更新;页面内容更新后,数据也会同步更新。

思考:

  1. 初始化,如何将 data 中的数据更新到DOM模板中? - 碎片化文档
  2. 页面更新,如何更新数据? - input事件监听
  3. 数据变了更新页面,那如何知道数据变了呢? - 数据劫持,Object.defineProperty()
  4. 已知数据变了(发布者),如何更新跟这个数据相关的页面内容 {{}}、属性绑定、v-model(订阅者)呢? - 发布订阅者模式

一句话描述原理

Vue 数据双向绑定是通过数据劫持结合发布订阅者模式的方式来实现的。使用 DocuemntFragment(碎片化文档)获取所有子节点,将 v-model {{}} 类似语法的值进行填充,监听页面元素的 input 事件,当 val 变更时,更新 data 中的数据,给 data 通过 object.defineProperty 添加响应监听,当 val 变化时,会触发 set 方法,通过发布订阅模式,触发订阅者的更新方法,更新视图。

DocuemntFragment(碎片化文档)

在这里插入图片描述

function nodeToFragment(node){var fragment = document.createDocumentFragment();var child = null;while(child = node.firstChild){fragment.appendChild(child)}return fragment
}

Object.defineProperty(数据劫持)

在这里插入图片描述

var obj = {};  // 定义一个空对象
Object.defineProperty(obj, 'val', { // 定义要修改对象的属性get: function () {console.log('获取对象的值')},set: function (newVal) { console.log('设置对象的值:最新的值是'+newVal);}
});
obj.hello = 'hello world'

js通过Object.defineProperty方法简单的实现双向绑定:

<!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><input type="text" id="app"><span id="childSpan"></span>
</body>
<script>var obj = {}var initValue='初始值'Object.defineProperty(obj,'initValue',{get(){console.log('获取obj最新的值');return initValue},set(newVal){initValue = newValconsole.log('设置最新的值');// 获取到最新的值  然后将最新的值赋值给我们的spandocument.getElementById('childSpan').innerHTML = initValueconsole.log(obj.initValue);}})document.addEventListener('keyup', function (e) {obj.initValue = e.target.value; //监听文本框里面的值 获取最新的值 然后赋值给obj })</script>
</html>

发布订阅者模式

发布订阅者模式又叫 观察者模式,他定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得将得到通知。

// 实现发布订阅模式// 事件容器:
let handlers = {}// 添加事件:
handlers['onmsg'].push(fn1)// 触发事件:
this.handlers['onmsg'].forEach(handler => { handler(...params) })

学习参考:JavaScript设计模式 -发布订阅者模式

Vue 双向绑定图示

在这里插入图片描述

Vue 双向绑定完整实现代码

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title></head><body><div id="app">测试双向绑定demo<input type="text" v-model="text" /> {{text}}</div></body><script type="text/javascript">//编译函数function compile(node, vm) {var reg = /\{\{(.*)\}\}/; // 来匹配{{xxx}}中的xxx//如果是元素节点if(node.nodeType === 1) {var attr = node.attributes;//解析元素节点的所有属性for(let i = 0; i < attr.length; i++) {if(attr[i].nodeName == 'v-model') {var name = attr[i].nodeValue //看看是与哪一个数据相关node.addEventListener('input', function(e) { //将与其相关的数据改为最新值vm[name] = e.target.value})node.value = vm.data[name]; //将data中的值赋予给该nodenode.removeAttribute('v-model')}}}//如果是文本节点if(node.nodeType === 3) {if(reg.test(node.nodeValue)) {var name = RegExp.$1; //获取到匹配的字符串name = name.trim();node.nodeValue = vm[name]; //将data中的值赋予给该nodenew Watcher(vm, node, name) //绑定一个订阅者}}}// 在向碎片化文档中添加节点时,每个节点都处理一下function nodeToFragment(node, vm) {var fragment = document.createDocumentFragment();var child;while(child = node.firstChild) {compile(child, vm);fragment.appendChild(child);}return fragment}//  Vue构造函数     //   观察data中的所有属性值,注意增添了observefunction Vue(options) {this.data = options.data;observe(this.data, this)var id = options.el;var dom = nodeToFragment(document.getElementById(id), this)//处理完所有节点后,重新把内容添加回去document.getElementById(id).appendChild(dom)}//实现一个响应式监听属性的函数。一旦有赋新值就发生变化 function defineReactive(obj, key, val) {var dep = new Dep(); //观察者实例Object.defineProperty(obj, key, {get: function() {if(Dep.target) { //每一个观察着都是唯一的dep.addSub(Dep.target)}return val},set: function(newVal) {if(newVal === val) {return}val = newVal;console.log('新值' + val);//一旦更新立马通知dep.notify();}})}//实现一个观察者,对于一个实例 每一个属性值都进行观察。function observe(obj, vm) {for(let key of Object.keys(obj)) {defineReactive(vm, key, obj[key]);}}// Watcher监听者function Watcher(vm, node, name) {Dep.target = this;this.vm = vm;this.node = node;this.name = name;this.update();Dep.target = null;}Watcher.prototype = {update() {this.get();this.node.nodeValue = this.value //更改节点内容的关键},get() {this.value = this.vm[this.name] //触发相应的get}}//dep构造函数function Dep() {this.subs = [] // 观察主题添加订阅者}Dep.prototype = {// 添加订阅者addSub(sub) {this.subs.push(sub)},// 发布通知notify() {this.subs.forEach(function(sub) {sub.update();})}}var vm = new Vue({el: 'app',data: {text: '赵刚'}})</script></html>

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

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

相关文章

照片坐标 | 使用EXCEL批量读取照片GPS坐标并标注拍摄地图

一 前言 7、8月是旅游的季节&#xff0c;旅途过程我们经常使用手机拍摄记录美好的瞬间&#xff0c;整个旅途使用手机拍摄已成为用户高频的出行习惯&#xff0c;无论是小孩、年轻人、老年人&#xff0c;只要手机在手&#xff0c;都会频频举起手机进行拍摄&#xff0c;贯穿整个旅…

网工内推 | 网络工程师,IE认证优先,最高15K,有项目绩效奖金

01 重庆并联网络科技有限公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、负责集成项目的相关实施工作&#xff08;设备上架安装、网络设备配置、服务器相关系统配置安装、相关软件环境搭建及配置等&#xff09; 2、负责项目现场技术维护与技术支持&#xff1b;…

透视B站财报:从前景看“钱景”

3月7日晚&#xff0c;哔哩哔哩发布了2023年度及第四季度财报。 财报显示&#xff0c;哔哩哔哩2023年总营收225亿元&#xff0c;净亏损同比大幅收窄49%&#xff0c;其中第四季度总营收达63.5亿元。 在后续电话会议上&#xff0c;哔哩哔哩管理层对市场上重点关注的“B站2024年能…

史上最全AP/mAP通用代码实现(yolov5 txt版本)-下

提示&#xff1a;通用map指标框架代码介绍&#xff0c;直接使用yolov5数据格式&#xff0c;实现论文map指标计算代码解读 文章目录 前言该版本是直接使用yolo数据格式实现map计算&#xff0c;集成txt转json格式内容。 一、map模块整体认识二、map计算应用代码解读三、通用map计…

egg如何写单元测试

优秀的代码需要有单元测试进行质量保证&#xff0c;每个测试用例都给应用的稳定性提供了一层保障。 测试目录结构 我们约定 test 目录为存放所有测试脚本的目录&#xff0c;测试所使用到的 fixtures 和相关辅助脚本都应该放在此目录下。 测试文件的目录和我们需要测试的文件目…

Redis进阶(三):主从复制

为了解决单点问题&#xff0c;实现多服务器部署redis&#xff0c;有几种解决方案可以实现&#xff1a;主从复制&#xff0c;主从哨兵还有集群。 何为主从复制 简单来说有三个服务器分别部署了redis-server程序&#xff0c;选中一个服务器当作主节点&#xff0c;其他的就是从节…

机器学习笔记 计算机视觉中的测距任务常见技术路线

一、计算机视觉中的测距任务 测距是计算机视觉中的一项关键任务,涉及测量物体和相机之间的距离。这些信息可用于多种应用,包括机器人、自动驾驶汽车和增强现实。测距技术有很多种,包括主动式和被动式,每种技术都有自己的优点和局限性。主动测距技术,例如飞行时间、结构光和…

动态规划DP之背包问题3---多重背包问题

目录 DP分析&#xff1a; 优化&#xff1a; 二进制优化 例题&#xff1a; 01背包是每个物品只有一个&#xff0c;完全背包问题是每个物品有无限个。 那么多重背包问题就是 每个物品有有限个。 有 N 种物品和一个容量是 V 的背包。 第 i 种物品最多有 si 件&#xff0c;每件体…

Softmax 回归 + 损失函数 + 图片分类数据集【动手学深度学习v2】李沐动手学深度学习课程笔记

目录 Softmax回归 损失函数 图片分类数据集 Softmax回归从零开始实现 Softmax回归简洁实现 Softmax回归 回归和分类的区别 回归问题举例上节课的预测房价问题&#xff0c;分类问题就是对样本进行分类 回归和分类的具体区别 假设真实的类别为第i个类别&#xff08;值为1&#x…

js【详解】event loop(事件循环/事件轮询)

event loop 是异步回调的实现原理 js 代码的执行过程 从前到后&#xff0c;一行一行执行如果某一行执行报错&#xff0c;则停止下面代码的执行先把同步代码执行完&#xff0c;再执行异步 event loop 图解 以下方代码为例&#xff1a; 第1步 将第 1 行代码放入调用栈 将要执行第…

JavaScript极速入门(2)

JQuery W3C标准给我们提供了一系列函数,让我们可以操作: 网页内容 网页结构 网页样式 但是原生的JavaScript提供的API操作DOM元素时,代码比较繁琐,冗长.我们学习使用JQuery来操作页面对象. JQuery是一个快速,简洁且功能丰富的JavaScript框架,于2006年发布.它封装JavaScript常…

Linux运维:实现光盘开机自动挂载、配置本地yum源教程

Linux运维&#xff1a;实现光盘开机自动挂载、配置本地yum源教程 一、光盘开机自动挂载1、检查光驱设备2、创建挂载点3、编辑/etc/fstab文件4、测试挂载 二、配置本地yum源(挂载光盘或ISO文件)1、挂载ISO文件2、创建YUM仓库配置文件3、清理YUM缓存并测试 &#x1f496;The Begi…

【netty系列-02】深入理解socket本质和BIO底层实现

Netty系列整体栏目 内容链接地址【一】深入理解网络通信基本原理和tcp/ip协议https://zhenghuisheng.blog.csdn.net/article/details/136359640【二】深入理解Socket本质和BIOhttps://zhenghuisheng.blog.csdn.net/article/details/136549478 深入理解socket本质和bio底层实现 …

找出单身狗1,2

目录 1. 单身狗12. 单身狗2 1. 单身狗1 题目如下&#xff1a; 思路&#xff1a;一部分人可能会使用对数组排序&#xff0c;遍历数组的方式去找出只出现一次的数字&#xff0c;但这种方法的时间复杂度过高&#xff0c;有时候可能会不满足要求。 有一种十分简便的方法是使用异或…

DEAP:利用生理信号进行情绪分析的数据库【DEAP数据集】

文章目录 摘要引言刺激选择实验环境参与者步骤参与者自我评估 主观评价分析EEG频率与参与者评分之间的相关性单次试验分类结果 结论 点击下载原文 摘要 ● DEAP&#xff1a;用于分析人类情感状态的多模态数据集。 ● 32名参与者观看了40个一分钟长的音乐视频。 ● 参与者根据唤…

Programming Abstractions in C阅读笔记:p312-p326

《Programming Abstractions in C》学习第77天&#xff0c;p312-p326&#xff0c;总计15页&#xff0c;第7章完结。 一、技术总结 第7章主要讲算法分析——引入时间复杂度这一概念来评估算法的快慢。时间复杂度使用大O符号来表示。 第7章以排序算法为示例&#xff0c;包含&a…

[PTA] 分解质因子

输入一个正整数n&#xff08;1≤n≤1e15&#xff09;&#xff0c;编程将其分解成若干个质因子&#xff08;素数因子&#xff09;积的形式。 输入格式: 任意给定一个正整数n&#xff08;1≤n≤1e15&#xff09;。 输出格式: 将输入的正整数分解成若干个质因子积的形式&#…

ubuntu 卸载miniconda3

一开始安装路径错了&#xff0c;需要重新安一次&#xff0c;就一起记录了。 前提是这种方式安装&#xff1a; ubuntu安装miniconda3管理python版本-CSDN博客 删除Miniconda的安装目录 这目录就是你选择安装的时候指定的&#xff0c;如果记不得了,可以这样查看 which conda 这…

数据库压力测试方法概述

一、前言 在前面的压力测试过程中&#xff0c;主要关注的是对接口以及服务器硬件性能进行压力测试&#xff0c;评估请求接口和硬件性能对服务的影响。但是对于多数Web应用来说&#xff0c;整个系统的瓶颈在于数据库。 原因很简单&#xff1a;Web应用中的其他因素&#xff0c;…

Chrome安装Axure插件

打开原型目录/resources/chrome&#xff0c;重命名axure-chrome-extension.crx&#xff0c;修改后缀为rar&#xff0c;axure-chrome-extension.rar 解压到axure-chrome-extension目录打开Chrome&#xff0c;更多工具->扩展程序&#xff0c;打开开发者模式&#xff0c;选择加…