深入了解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>
以上就是深入了解Vue中双向数据绑定原理的详细内容,更多关于Vue双向数据绑定的资料请关注脚本之家其它相关文章!
相关文章
el-table表头根据内容自适应完美解决表头错位和固定列错位
这篇文章主要介绍了el-table表头根据内容自适应完美解决表头错位和固定列错位,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2021-01-01
Vue 2源码解析HTMLParserOptions.start函数方法
这篇文章主要为大家介绍了Vue 2源码解析HTMLParserOptions.start函数方法,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2022-08-08
Vue项目中new Vue()和export default{}的区别说明
这篇文章主要介绍了Vue项目中new Vue()和export default{}的区别说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2022-03-03


最新评论