深入了解Vue中双向数据绑定原理
作者:几何心凉 发布时间:2024-05-13 09:38:25
标签:Vue,双向,数据,绑定,原理
数据的变化反应到视图
前面我们了解到数据劫持之后,我们可以在数据发生修改之后做任何我们想要做的事情,操作视图当然也是OK的
命令式操作视图
目标:我们通过原始的操作dom的方式让每一次的name的最新值都能显示到p元素内部
<div id="app">
<p></p>
</div>
<script>
let data = {
name: '小兰同学',
age: 18,
height:180
}
// 遍历每一个属性
Object.keys(data).forEach((key)=>{
// key 属性名
// data[key] 属性值
defineReactive(data,key,data[key])
})
function defineReactive(data,key,value){
Object.defineProperty(data,key,{
get(){
return value
},
set(newVal){
value = newVal
// 数据发生变化,操作dom进行更新
document.querySelector('#app p').innerHTML = data.name
}
})
}
// 首次渲染
document.querySelector('#app p').innerHTML = data.name
</script>
声明式操作视图
目标:我们将data中name属性的值作为文本渲染到标记了v-text的p标签内部,在vue中,我们把这种标记式的声明式渲染叫做指令
<div id="app">
<p v-text="name"></p>
</div>
<script>
let data = {
name: '小兰同学',
age: 18,
height: 180
}
// 遍历每一个属性
Object.keys(data).forEach((key) => {
// key 属性名
// data[key] 属性值
// data 原对象
defineReactive(data, key, data[key])
})
function defineReactive(data, key, value) {
Object.defineProperty(data, key, {
get() {
return value
},
set(newVal) {
value = newVal
// 数据发生变化,操作dom进行更新
compile()
}
})
}
//
function compile() {
let app = document.getElementById('app')
// 1.拿到app下所有的子元素
const nodes = app.childNodes // [text, input, text]
//2.遍历所有的子元素
nodes.forEach(node => {
// nodeType为1为元素节点
if (node.nodeType === 1) {
const attrs = node.attributes
// 遍历所有的attrubites找到 v-model
Array.from(attrs).forEach(attr => {
const dirName = attr.nodeName
const dataProp = attr.nodeValue
if (dirName === 'v-text') {
node.innerText = data[dataProp]
}
})
}
})
}
// 首次渲染
compile()
</script>
小结
不管是指令也好,插值表达式也好,这些都是将数据反应到视图的标记而已,通过标记我们可以把数据的变化响应式的反应到对应的dom位置上去
找标记,把数据绑定到dom的过程,我们称之为binding
视图的变化反应到数据
目标:将data中的message属性对应的值渲染到input上面,同时input值发生修改之后,可以反向修改message的值,在vue系统中,v-model指令就是干这个事情的,下面我们就实现一下v-model的功能
<div id="app">
<input v-model="name" />
</div>
<script>
let data = {
name: '小兰同学',
age: 18,
height: 170
}
// 遍历每一个属性
Object.keys(data).forEach((key) => {
// key 属性名
// data[key] 属性值
// data 原对象
defineReactive(data, key, data[key])
})
function defineReactive(data, key, value) {
Object.defineProperty(data, key, {
get() {
return value
},
set(newVal) {
// 数据发生变化,操作dom进行更新
if (newVal === value) {
return
}
value = newVal
compile()
}
})
}
// 编译函数
function compile() {
let app = document.getElementById('app')
// 1.拿到app下所有的子元素
const nodes = app.childNodes // [text, input, text]
//2.遍历所有的子元素
nodes.forEach(node => {
// nodeType为1为元素节点
if (node.nodeType === 1) {
const attrs = node.attributes
// 遍历所有的attrubites找到 v-model
Array.from(attrs).forEach(attr => {
const dirName = attr.nodeName
const dataProp = attr.nodeValue
if (dirName === 'v-model') {
node.value = data[dataProp]
// 视图变化反应到数据 无非是事件监听反向修改
node.addEventListener('input', (e) => {
data[dataProp] = e.target.value
})
}
})
}
})
}
// 首次渲染
compile()
</script>
现存的问题
无法做到精准更新
<div id="app">
<p v-text="name"></p>
<p v-text="age"></p>
<p v-text="name"></p>
</div>
<script>
let data = {
name: '小兰同学',
age: 18,
height: 180
}
// 遍历每一个属性
Object.keys(data).forEach((key) => {
// key 属性名
// data[key] 属性值
// data 原对象
defineReactive(data, key, data[key])
})
function defineReactive(data, key, value) {
Object.defineProperty(data, key, {
get() {
return value
},
set(newVal) {
// 数据发生变化,操作dom进行更新
if (newVal === value) {
return
}
value = newVal
compile()
}
})
}
// 编译函数
function compile() {
let app = document.getElementById('app')
// 1.拿到app下所有的子元素
const nodes = app.childNodes // [text, input, text]
//2.遍历所有的子元素
nodes.forEach(node => {
// nodeType为1为元素节点
if (node.nodeType === 1) {
const attrs = node.attributes
Array.from(attrs).forEach(attr => {
const dirName = attr.nodeName
const dataProp = attr.nodeValue
console.log( dirName,dataProp)
if (dirName === 'v-text') {
console.log(`更新了${dirName}指令,需要更新的属性为${dataProp}`)
node.innerText = data[dataProp]
}
})
}
})
}
// 首次渲染
compile()
</script>
来源:https://blog.csdn.net/JHXL_/article/details/124842265
0
投稿
猜你喜欢
- 如下所示:#获取模型权重for k, v in model_2.state_dict().iteritems(): print("
- Python可以使用 xml.etree.ElementTree 模块从简单的XML文档中提取数据。 为了演示,假设你想解析Planet P
- 安装一些必要的环境1.下载go sdk (本人装的是1.9) 2.下载golang3.下载git 因为有些依赖 要用 go get 去git
- 本文实例为大家分享了python3.6.1安装教程,供大家参考,具体内容如下1、安装编译环境所需包#yum install zlib-dev
- 上一篇文章介绍了并发和多线程的概念,这次就来向大家上一个实战来讲解一下如何真正的运用上多线程这个概念。有需要的可以看看我之前这篇文章:Pyt
- python的版本经过了python2.x和python3.x等版本,无论哪种版本,关于python爬虫相关的知识是融会贯通的,脚本之家关于
- 昨天,系统管理员告诉我,我们一个内部应用数据库所在的磁盘空间不足了。我注意到数据库事件日志文件XXX_Data.ldf文件已经增长到了3GB
- 日期和时间类型MySQL有多个表示各种日期和时间值的数据类型, 比如YEAR和DATE. MySQL存储时间的最精确粒度是秒。 然而, 能做
- 以前跟同事开玩笑时说过,我们遇到的用户在访谈测试过程中的表现基本上就三种类型,发泄型,赞美型和实话实说型。发泄型用户通常是在产品的使用过程中
- 本文实例讲述了Symfony2之session与cookie用法。分享给大家供大家参考,具体如下:session操作:1. Set Sess
- Form介绍在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。与此同时我们在好多
- 本文实例讲述了Python实现基本数据结构中栈的操作。分享给大家供大家参考,具体如下:#! /usr/bin/env python#codi
- PHP convert_cyr_string() 函数实例把字符串由一种字符集转换成另一种:<?php $str = "He
- 每日凌晨2:00进行dump对相应数据库进行备份,同时对相应数据库进行binlog日志文件更新。如果发现数据库错误,只需要先恢复上一个dum
- 测试需求 为了更好的测试你的ASP程序,你首先需要决定你的程序将来需要面对多大的压力。简单的说,压力或负载可以分解成以下数字:· 最低用户数
- 为了测试一组网页是否能够访问,采取python中的requests包进行批量的访问测试,并输出访问结果。一、requests包的安装 打开命
- 1.因为oracle 10g暂时没有与win7兼容的版本,我们可以通过对安装软件中某些文件的修改达到安装的目地。 a)打开“\ORACLE1
- 测试题defer有一些规则,如果不了解,代码实现的最终结果会与预期不一致。对于这些规则,你了解吗?这是关于defer使用的代码,可以先考虑一
- 当然,第一反应是用存储过程。判断原来这个字段值,然后UPDATE。 网上粗粗找了一下没找到方案。自己一动手,居然有个很有趣的结果,连WHER
- 重现如下: <!doctype html> <html> <head> <title>设置i