看了B站上一个老师的课,简单记录下。
一,响应式原理:
前端有命令式与声明式两种开发模式。
命令式框架关注过程,声明式框架关注结果。
命令式框架
命令式框架一般说的jquery, 操作dom获取dom。
思考一个问题:有个按钮,点击文案改成英文文字。
如果是原生js和jQuery,方法是button 绑定 click 修改文案
const div = document.getElementsByTagName('div')[0]
const btn = document.getElementsByTagName('button')[0]
btn.onclick = function(){
div.innerText = '好'
}
声明式框架
现在,vue、react出来了以后,由命令式转换为声明式,如果使用vue方法是,绑定一个click事件,定义一个初始数据,修改这个数据就行。
<div>
{{text}}
</div>
<button @click="()=>{text='好'}">button</button>
<script>
export default {
data() {
return {
text: 'hello'
}
}
}
</script>
相比来说,声明式没有对dom的操作,只是对数据的修改,不用关注底层怎么实现的。不过声明式的底层还是命令式。
二,双向绑定
输入input数据,引起一个data变化。改变data,input中数据也变化,叫做双向绑定。
点击按钮,都改变为’hao‘
底层实现
<div id="app">
<input type="text">
<h1></h1>
<button>button</button>
</div>
<script>
const input = document.getElementsByTagName('input')[0]
const h1 = document.getElementsByTagName('h1')[0]
const btn = document.getElementsByTagName('button')[0]
let data = {
text: ''
}
input.addEventListener('input', function(e) {
data.text = e.target.value
})
btn.onclick = function() {
data.text = 'hao'
}
Object.defineProperty(data, 'text', {
get: function() {
return data['text']
},
set: function(newValue) {
h1.innerText = newValue
input.value = newValue
}
})
</script>
双向绑定抽象出来就是响应式页面的实现。
三,vue2和vue3响应式数据的区别
vue3使用proxy代理,使用ref或reactive将数据转化为响应式数据。
vue3传递的是对象,没有指定具体监听的属性,所以无论修改或者添加属性,都不会触发getter和setter。
vue2缺点:不能给数组或者对象直接修改数值,不能给对象赋一个新的属性。
是因为defineProperty这个方法有局限性,当定义Object.defineProperty(data, ‘text’,
{get: },{ set: }),已经确定要给属性‘text‘进行双向绑定,后来再添加其他属性时,就没有响应式了。
vue3底层大致是这
<script>
const btn = document.getElementsByTagName('button')[0]
const data = {
text: ''
}
function effect() {
document.body.innerText = data.text
}
const obj = new proxy(data, {
get(target, key) {
return target[key]
},
set(target, key, newvalue) {
target[key] = newvalue
effect()
return true
}
})
btn.onclick = function() {
obj.text = 'hao'
}
</script>
四,用vue3官网中的例子简单看下:
一个经常被拿来当作典型例子的用例即是 Excel 表格:
这里单元格 A2 中的值是通过公式 = A0 + A1 来定义的 (你可以在 A2 上点击来查看或编辑该公式),因此最终得到的值为 3,正如所料。但如果你试着更改 A0 或 A1,你会注意到 A2 也随即自动更新了。
我们可以用真正的 Vue API 改写上面的例子:
import { ref, watchEffect } from 'vue'
const A0 = ref(0)
const A1 = ref(1)
const A2 = ref()
watchEffect(() => {
// 追踪 A0 和 A1
A2.value = A0.value + A1.value
})
// 将触发副作用
A0.value = 2
使用一个响应式副作用来更改一个 ref 并不是最优解,事实上使用计算属性会更直观简洁:
import { ref, computed } from 'vue'
const A0 = ref(0)
const A1 = ref(1)
const A2 = computed(() => A0.value + A1.value)
A0.value = 2
在内部,computed 会使用响应式副作用来管理失效与重新计算的过程。
那么,常见的响应式副作用的用例是什么呢?自然是更新 DOM!我们可以像下面这样实现一个简单的“响应式渲染”:
import { ref, watchEffect } from 'vue'
const count = ref(0)
watchEffect(() => {
document.body.innerHTML = `计数:${count.value}`
})
// 更新 DOM
count.value++