Vue 响应式原理
cooljser 2022-01-10  vue
vue2 中的响应式是结合数据劫持 + 发布订阅模式实现的,最简单的实现如下:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="box-1"></div>
    <div class="box-2"></div>
  </body>
  <script src="index.js"></script>
  <script>
    let obj = {};
    Vue({
      data: obj,
      tag: 'box1',
      dataKey: 'one',
      selector: '.box-1'
    });
    obj.one = 'one';
  </script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// @ts-nocheck
const Dep = {
  clientList: {},
  listen: function (key, fn) {
    (this.clientList[key] || (this.clientList[key] = [])).push(fn);
  },
  trigger: function () {
    // 提取 key, 并把剩下的参数传给 fn
    let key = Array.prototype.shift.call(arguments),
      fns = this.clientList[key];
    if (!fns || fns.length === 0) {
      return false;
    }
    for (let i = 0, fn; fn = fns[i++];) {
      fn.apply(this, arguments);
    }
  }
};
const Vue = function({data, tag, dataKey, selector}) {
  let value = '',
      el = document.querySelector(selector);
  Object.defineProperty(data, dataKey, {
    get: function() {
      console.log('取值');
      return value;
    },
    set: function(val) {
      console.log('设置值');
      value = val;
      Dep.trigger(tag, val);
    }
  })
  Dep.listen(tag, function(text) {
    el.innerHTML = text;
  });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
