简单手撕实现vue的响应式
本文最后更新于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)

这里年龄函数是用日期算出来的,不用在意,你也可以直接用输入框输入年龄,看懂了也去动手实现一下吧

山水有相逢,我们江湖再见!じゃな~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇