这是我参与更文挑战的第3天,活动详情查看: 更文挑战
此系列文章只是对自己学习做个总结与复盘,后面会将学到的vue2相关复盘文章链接更新到此处。感谢村长!
-
此处没有涉及到vue,只是学习前对defineProperty的一个了解 —— 修改数据后程序怎么知道,在哪里更新视图。
-
思考:vue2中怎么对data中的数据进行响应式处理,怎么对模板进行编译,将数据初始化到数据对应的视图中,此处是全量更新,怎么在数据变化后精准更新相应的视图?
-
后续文章1:vue2学习之记录一个简版vue的实现
<!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>vue2.6使用defineProperty方式简单实现数据响应式-即数据驱动视图变化</title>
</head>
<body>
<div id="app">
<div id="time"></div>
<div id="arr"></div>
<div>
<label>数组操作</label>
<div id="arr1"></div>
<button onclick="myPush()">push</button>
<button onclick="myPop()">pop</button>
<button onclick="myUnshift()">unshift</button>
<button onclick="myShift()">shift</button>
<button onclick="myReverse()">reverse</button>
<button onclick="mySplice()">splice</button>
<button onclick="mySort()">sort</button>
</div>
</div>
<script>
// 数组响应式
// 1、找到数组原型
// 2、覆盖数组的7大方法,使其可以通知更新
// 3、将新原型设置到数组的实例原型上
const oldProto = Array.prototype;
// 在备份后修改备份
const newProto = Object.create(oldProto);
['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort'].forEach(method => {
newProto[method] = function () {
// 进行原始操作
oldProto[method].apply(this, arguments);
// 覆盖操作,通知更新
console.log('数组执行' + method + '操作');
}
})
let obj = {
arr1: [8,1,0,-1,6,41]
}
// 对象响应式
function defineReactive(obj, key, val) {
// 递归对树形结构进行处理
observe(val)
// 对数据进行拦截
Object.defineProperty(obj, key, {
get () {
// console.log(`get: ${key} : ${val}`)
return val
},
set (newVal) {
if (val !== newVal) {
// 在此处要对新增的属性是对象的情况做下响应式处理,eg: obj.data = { a: 1 }
observe(newVal)
// console.log('set: ' + key)
// 此处不能使用obj[key] = newVal
// 以上方式其实是在set方法中无限重复执行obj.key = 'xxx',即会重复触发set方法
val = newVal
update() // 自己先写个更新函数,在vue中其实是编译器对模板进行处理渲染的一个过程
}
}
})
}
function set (obj, key, val) {
// 对新增加的属性做响应式处理
defineReactive(obj, key, val)
}
// 对某个对象进行遍历,对其中所有的属性做响应式处理,如果有嵌套对象,需要递归
function observe (obj) {
if (typeof obj !== 'object' || obj === null) {
// 值不是对象的就出去走下一步-对数据进行拦截的步骤吧
// 注意typeof null === 'object',所以要区分下null
return obj
}
if (Array.isArray(obj)) {
// 覆盖原型,替换7个方法
obj.__proto__ = newProto
// 对数组中可能存在的对象或数组执行响应化
// const keys = Object.keys(obj)
for (let i = 0; i < obj.length; i++) {
observe(obj[i])
}
} else {
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
}
}
function update () {
document.getElementById('time').innerText = obj.testSet.time
document.getElementById('arr').innerHTML = obj.arr
document.getElementById('arr1').innerHTML = obj.arr1
}
// 手动新增属性,值为对象
set(obj, 'testSet', { time: new Date().toLocaleTimeString() })
set(obj, 'arr', [])
var i = 0
setInterval(() => {
obj.testSet.time = new Date().toLocaleTimeString()
if (i < 10) {
obj.arr.push(i++)
}
}, 1000)
// 对整个obj不管存在的还是新来的,都做响应式处理
observe(obj)
function myPush () {
obj.arr1.push(666)
}
function myPop () {
if (obj.arr1.length) {
obj.arr1.pop()
} else {
console.log('没有啦~');
}
}
function myUnshift () {
obj.arr1.unshift(666)
}
function myShift () {
if (obj.arr1.length) {
obj.arr1.shift()
} else {
console.log('没有啦~');
}
}
function myReverse () {
obj.arr1.reverse()
}
function mySplice () {
obj.arr1.splice(1, 0, 13)
}
function mySort () {
obj.arr1.sort((a, b) => { return a - b })
}
</script>
</body>
</html>