跟随大师课简单学习vue响应式
首先定义一个简单的页面
<body>
<div class="card">
<p id="firstName"></p>
<p id="lastName"></p>
<p id="age"></p>
</div>
<script src="./index.js"></script>
</body>
js文件
var user={
name:'尤雨溪',
birth:'2002-05-14'
}
// 显示姓
function showFirstName(){
document.querySelector('#firstName').
textContent='姓:'+user.name[0];
}
// 显示名字
function showLastName(){
document.querySelector('#lastName').
textContent='名:'+user.name.slice(1);
}
showFirstName()
showLastName()
此时页面上显示为
此时如果我们在js文件或控制台中直接修改user.name的话,虽然数据变化了,但是页面却没有发生变化,导致数据与界面不一致
如果想让页面变化的话则需要运行他所依赖的函数,
所以需要让数据发生变化时自动的调用他所依赖的函数
使用Object.defineProperty来自动调用函数
var user={
name:'尤雨溪',
birth:'2002-05-14'
}
// observe(user) //观察数据
// 显示姓
function showFirstName(){
document.querySelector('#firstName').
textContent='姓:'+user.name[0];
}
// 显示名字
function showLastName(){
document.querySelector('#lastName').
textContent='名:'+user.name.slice(1);
}
showFirstName()
showLastName()
var internalName=user.name
Object.defineProperty(user,'name',{
get:function(){
console.log('有人读取了name属性');
return internalName;
},
set:function(val){
internalName=val;
showFirstName()
showLastName()
console.log('有人再给name属性赋值,赋的值是'+val);
}
})
user.name='奥特曼'
但是这样是一个写死的,实际情况肯定是不能这样写,所以新建一个通用的js文件,用来在数据变化时自动的运行依赖的函数
// 观察某个对象的所有属性
function observe(obj){
for(const key in obj){
let internalValue=obj[key]; //存储
Object.defineProperty(obj,ley,{
get:function(){
return internalValue;
},
set:function(val){
internalValue=val
// 自动调用依赖该属性的函数???
},
})
}
}
但是此时因为变成了一个公共的库,所以并不知道有哪些函数,所以可以声明一个空数组通过Object.defineProperty的get来存储用我的函数,
// 观察某个对象的所有属性
function observe(obj){
for(const key in obj){
let internalValue=obj[key]; //存储
let foncs=[] //新建一个空数组用来存储用我的函数
Object.defineProperty(obj,ley,{
get:function(){
// 记录是哪个函数在用我,vue里叫做依赖收集
foncs.push(abc) //还是不知道函数叫什么
return internalValue;
},
set:function(val){
internalValue=val
// 执行用我的函数,vue里叫做派发更新
for(var i=0;i<foncs.length;i++){
foncs[i];
}
},
})
}
}
但是此时还有一个问题是如果一个函数改变了多次数据的话会push多次,所以通过判断或者net Set()来避免重复
// 观察某个对象的所有属性
function observe(obj){
for(const key in obj){
let internalValue=obj[key]; //存储
let funcs=[] //新建一个空数组用来存储用我的函数
Object.defineProperty(obj,ley,{
get:function(){
// 记录是哪个函数在用我,vue里叫做依赖收集
if(!funcs.includes(abc)){
funcs.push(abc)//还是不知道函数叫什么
}
return internalValue;
},
set:function(val){
internalValue=val
// 执行用我的函数,vue里叫做派发更新
for(var i=0;i<funcs.length;i++){
funcs[i]();
}
},
})
}
}
但是此时此刻我们还是不知道有哪些函数在用我,vue中用了一个非常巧妙的方法来解决这个问题,不直接运行函数,而是在他运行之前把他交给另外一个东西,比如给他声明一个全局变量,在他运行之前window.__func=showFirstName 将函数赋给变量,在函数运行完后在设为空,这样在Object.defineProperty的get中就可以获取到这个全局变量将他push到我们准备好的数组中
var user={
name:'尤雨溪',
birth:'2002-05-14'
}
observe(user) //观察数据
// 显示姓
function showFirstName(){
document.querySelector('#firstName').
textContent='姓:'+user.name[0];
}
// 显示名字
function showLastName(){
document.querySelector('#lastName').
textContent='名:'+user.name.slice(1);
}
window.__func=showFirstName
showFirstName()
window.__func=null
window.__func=showLastName
showLastName()
window.__func=null
// 观察某个对象的所有属性
function observe(obj) {
for (const key in obj) {
let internalValue = obj[key]; //存储
let funcs = [] //新建一个空数组用来存储用我的函数
Object.defineProperty(obj, key, {
get: function () {
// 记录是哪个函数在用我,vue里叫做依赖收集
if (window.__func && !funcs.includes(window.__func)) {
funcs.push(window.__func)
}
return internalValue;
},
set: function (val) {
internalValue = val
// 执行用我的函数,vue里叫做派发更新
for (var i = 0; i < funcs.length; i++) {
funcs[i]();
}
},
})
}
}
此时再修改user中的数据的话页面也会随之改变,但是这个一直重复赋值在给空比较麻烦,所以可以在公共的js中写一个函数autorun
function autorun(fn){
window.__func=fn
fn()
window.__func=null
}
autorun(showFirstName)
autorun(showLastName)
可以设置一个input框试一下效果
<!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>
<div class="card">
<p id="firstName"></p>
<p id="lastName"></p>
<p id="age"></p>
</div>
<input type="text" oninput="user.name=this.value"/>
<script src="./eve.js"></script>
<script src="./index.js"></script>
</body>
</html>
var user={
name:'尤雨溪',
birth:'2002-05-14'
}
observe(user) //观察数据
// 显示姓
function showFirstName(){
document.querySelector('#firstName').
textContent='姓:'+user.name[0];
}
// 显示名字
function showLastName(){
document.querySelector('#lastName').
textContent='名:'+user.name.slice(1);
}
autorun(showFirstName)
autorun(showLastName)
// 观察某个对象的所有属性
function observe(obj) {
for (const key in obj) {
let internalValue = obj[key]; //存储
let funcs = [] //新建一个空数组用来存储用我的函数
Object.defineProperty(obj, key, {
get: function () {
// 记录是哪个函数在用我,vue里叫做依赖收集
if (window.__func && !funcs.includes(window.__func)) {
funcs.push(window.__func)
}
return internalValue;
},
set: function (val) {
internalValue = val
// 执行用我的函数,vue里叫做派发更新
for (var i = 0; i < funcs.length; i++) {
funcs[i]();
}
},
})
}
}
function autorun(fn){
window.__func=fn
fn()
window.__func=null
}
此时数据发生变化页面也会随之变化,代码已经写完,肯定会有很多bug,但算知道了一个大概的脉络