本文最后更新于836 天前,其中的信息可能已经过时,如有错误请评论留言
使用过 vue 朋友都知道 vue 是数据驱动视图,实现双向数据绑定,数据变化界面也跟着变化,今天我们来浅浅地当一下小小的尤雨溪,回到那个没有 vue 的时候,用原生 js 实现一下 vue 响应式
材料准备
先简单写个页面和样式
// index.html
<!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>Vue响应式</title>
<link rel="stylesheet" href="./index.css" />
<script src="./yyx.js"></script>
</head>
<body>
<div class="card">
<p id="lastName"></p>
<p id="firstName"></p>
<p id="age"></p>
</div>
<input type="text" oninput="user.name = this.value" />
<input type="date" onchange="user.birth = this.value" />
<script src="./index.js"></script>
</body>
</html>
// index.css
.card {
width: 300px;
border: 2px solid rgb(74, 125, 142);
border-radius: 10px;
font-size: 2em;
padding: 0 20px;
margin: 0 auto;
background: lightblue;
color: #333;
}
input[type="text"] {
margin-left: 600px;
}
实现响应式
我们创建一个 js 文件,模拟 vue 的 js 源代码文件,就起名叫 yyx.js
详细代码如下,详细了解过 vue 的朋友肯定听过依赖收集和派发更新
// yyx.js
/**
* 实现响应式的函数,在对应的值的 get 和 set 中拿到依赖属性的函数并执行
* @param {Object} obj
*/
function respond(obj) {
for (const key in obj) {
let internalValue = obj[key]
let funcs = new Set()
Object.defineProperty(obj, key, {
get: function () {
// 依赖收集:收集该属性被哪些函数依赖
if (window.__func) {
funcs.add(window.__func)
}
return internalValue
},
set: function (value) {
// 派发更新:当属性值发生变化时,通知所有依赖该属性的函数执行
internalValue = value
funcs.forEach(func => func())
}
})
}
}
/**
* 使用一个大全局变量接收调用的函数,以便在 get 中知道是哪个函数依赖对应属性调用,并在 set 中执行该函数
* @param {function} fn
*/
function autoRunFunc(fn) {
window.__func = fn
fn()
window.__func = null
}
题外话:这里的 window.__func 有点 PHP 的超全局变量的意味,难怪都说“PHP是世界上最好的语言”(笑)
有了我们手写的框架文件,我们就可以在自己要写的 js 里使用了,最后看一下效果
// index.js
let user = {
name: '世风至',
birth: '2000-01-01',
}
/* 传入对象,使其变为响应式 */
respond(user)
// 显示姓氏
function showLastName() {
document.querySelector('#lastName').textContent = '姓:' + user.name[0]
}
// 显示名字
function showFirstName() {
document.querySelector('#firstName').textContent = '名:' + user.name.slice(1)
}
// 显示年龄
function showAge() {
let birthday = new Date(user.birth)
let today = new Date()
today.setHours(0), today.setMinutes(0), today.setMilliseconds(0)
let thisYearBirthday = new Date(
today.getFullYear(),
birthday.getMonth(),
birthday.getDate()
)
let age = today.getFullYear() - birthday.getFullYear()
if (today.getTime() < thisYearBirthday.getTime()) {
age--
}
document.querySelector('#age').textContent = '年龄:' + age
}
// showLastName()
// showFirstName()
// showAge()
/* 调用autoRunFunc函数,以便获得要执行的函数 */
autoRunFunc(showFirstName)
autoRunFunc(showLastName)
autoRunFunc(showAge)
这里年龄函数是用日期算出来的,不用在意,你也可以直接用输入框输入年龄,看懂了也去动手实现一下吧



