手写vue2.0响应式中原理的mini版本
文章类型:Vue
发布者:hp
发布时间:2023-05-25
vue中,改变了数据,就会自动更新页面,为什么会这样呢,其实,本质上是数据的改变引起了相关函数的一个重新调用,导致了浏览器重新渲染页面,
1:传统中,我们对html进行读取值和设置值,都需要重新进行调用
<div>
<p>姓:<span class="firstName"></span></p>
<p>名:<span class="lastName"></span></p>
<p>年龄:<span class="age"></span></p>
<input type="text" oninput="obj.name=this.value"/>
</div>
var obj={
name:'张三',
age:18
}
function firstName(){
document.getElementsByClassName("firstName")[0].innerHTML=obj.name.substring(0,1)
}
function lastName(){
document.getElementsByClassName("lastName")[0].textContent=obj.name.substring(1,obj.name.length)
}
function age(){
document.getElementsByClassName("age")[0].innerHTML=obj.age
}2:更改了某个值,那么我们就需要重新调用这个函数,去触发,才能实现页面的更新,那么,本质上还是改变了数据,触发了跟它相关的函数
obj.name="李四"
// firstName()
// lastName()
setTimeout(()=>{
obj.name='王五'
},5000)3:正是因为这个原理,才产生了vue的一个数据驱动视图更新,那么,我们首先要做的是,数据怎么才能知道有变化
var obj={
name:'张三',
age:18
}
oberseve(obj)
function oberseve(obj){
//把传进来的obj进行遍历添加属性和方法
console.log(obj)
for(let key in obj){
let initVal=obj[key]
/*采用new Set的目的是去重,
如果对一个属性进行多次修改,
那么方法会有多个,避免掉性能浪费
最后统一做一次数据更新
*/
let funList=new Set()
Object.defineProperty(obj,key,{
get(){
//读取的时候,进行把使用的函数进行收集
//为后面修改数据做准备,如果修改数据
//那么就找到这个依赖里面的数据进行修改
window.__fun && funList.add(window.__fun)
console.log(funList)
console.log('触发get')
return initVal
},
set(val){
console.log('触发set')
initVal=val
//改变了数据 要怎么进行方法的自动更新,
//怎么知道是谁,更新哪些方法
console.log(funList)
console.log(funList.length)
/*
改变数据的时候,进行通知更新(派发更新)
*/
for (let fun of funList) {
fun()
}
}
})
}
}4:我们通过js原本的一个api,通过读取进入get方法,改变值进入set方法,那么我们就知道数据的一个变化,这也是vue2的一个数据劫持方案,接下来,我们就要思考,数据变化后,怎么让视图进行更新,
要明白谁在改变我,是在用我,说白了就是那个函数读取或者修改了我,好对应触发更新重新渲染
function autoRunFunction(fun){
/*
做一种类似代理调用方式
*/
window.__fun=fun
fun()
window.__fun=null
}5:我们在调用方法的时候,采取代理模式,说白了就是,你要调用,我帮你调用,类似中介模式,那么,我肯定知道谁在调用,把调用人记录下来,等调用完我在清空,
let funList=new Set()
get(){
//读取的时候,进行把使用的函数进行收集
//为后面修改数据做准备,如果修改数据
//那么就找到这个依赖里面的数据进行修改
window.__fun && funList.add(window.__fun)
console.log(funList)
console.log('触发get')
return initVal
},
6:读取的时候,我就记录下来,这也是vue中的所谓依赖,就是数据跟函数发生关系时候,那么,如果修改数据,我就知道谁改了,我就通知谁去更新,也叫派发更新
set(val){
console.log('触发set')
initVal=val
//改变了数据 要怎么进行方法的自动更新,
//怎么知道是谁,更新哪些方法
console.log(funList)
console.log(funList.length)
/*
改变数据的时候,进行通知更新(派发更新)
*/
for (let fun of funList) {
fun()
}
}<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div>
<p>姓:<span class="firstName"></span></p>
<p>名:<span class="lastName"></span></p>
<p>年龄:<span class="age"></span></p>
<input type="text" oninput="obj.name=this.value"/>
</div>
</body>
</html>
<script src="js/myvue.js"></script>
<script>
var obj={
name:'张三',
age:18
}
function firstName(){
document.getElementsByClassName("firstName")[0].innerHTML=obj.name.substring(0,1)
}
function lastName(){
document.getElementsByClassName("lastName")[0].textContent=obj.name.substring(1,obj.name.length)
}
function age(){
document.getElementsByClassName("age")[0].innerHTML=obj.age
}
oberseve(obj)
/*
只能从调用处进行想办法
说白了就是代理代用,
我帮你去实现这个方法的调用
*/
autoRunFunction(firstName)
autoRunFunction(lastName)
autoRunFunction(age)
//改变数据
obj.name="李四"
// firstName()
// lastName()
setTimeout(()=>{
obj.name='王五'
},5000)
</script>/*
本质是,数据改变的时候,进行自动触发相关函数的调用
*/
function oberseve(obj){
//把传进来的obj进行遍历添加属性和方法
console.log(obj)
for(let key in obj){
let initVal=obj[key]
/*采用new Set的目的是去重,
如果对一个属性进行多次修改,
那么方法会有多个,避免掉性能浪费
最后统一做一次数据更新
*/
let funList=new Set()
Object.defineProperty(obj,key,{
get(){
//读取的时候,进行把使用的函数进行收集
//为后面修改数据做准备,如果修改数据
//那么就找到这个依赖里面的数据进行修改
window.__fun && funList.add(window.__fun)
console.log(funList)
console.log('触发get')
return initVal
},
set(val){
console.log('触发set')
initVal=val
//改变了数据 要怎么进行方法的自动更新,
//怎么知道是谁,更新哪些方法
console.log(funList)
console.log(funList.length)
/*
改变数据的时候,进行通知更新(派发更新)
*/
for (let fun of funList) {
fun()
}
}
})
}
}
function autoRunFunction(fun){
/*
做一种类似代理调用方式
*/
window.__fun=fun
fun()
window.__fun=null
}1:响应式本质是数据改变,自动的触发了相关函数的一个调用
2:找到了一个能让对象数据读取和修改自动触发函数的一个api,(Object.defineProperty),才能实现
3:设计上通过改版调用者的一个代理方式,,采用一个读取记录关系,修改后沿着这个记录的关系进行重新调用渲染
暂无评论,快来发表第一条评论吧~