【模拟实现】v-text

3/30/2021 面试vue模拟实现

# 面试题

模拟实现 v-text 指令,模拟数据驱动视图层更新。给定代码模版如下:

<div id="app">
  <h1 v-text="title"></h1>
  <p>当前时间戳:<span v-text="time"></span></p>
</div>
1
2
3
4
class ViewBind {
  constructor ({ el = 'body', data = {}} = {}) {
    // 此处实现代码
  }
}
/**
 * 调用方式类似 Vue 初始化,
 * el 代表根元素,data 中的字段会自动和 DOM 中 v-text 属性对应元素内容绑定
 **/
const app = new ViewBind({
  el: '#app',
  data: {
    title: '这是标题',
    time: +new Date()
  }
})
/**
 * 初始化之后页面#app显示效果如下:
  <div id="app">
    <h1 v-text="title">这是标题</h1>
    <p>当前时间戳:<span v-text="time">1522070099060</span></p>
  </div>
 * 类似于 Vue,初始化之后 app 内部有一个 data 对象,
 * 通过修改 data 对象的属性来间接修改 DOM 中挂载了对应 v-text 属性的元素内容
 **/
setInterval(() => {
  // 定时修改页面上<span v-text="time">元素中的内容
  app.data.time = +new Date()
  console.log('[data]:', app.data.time)
}, 1000)
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

# ViewBind类实现

实现步骤

  1. 数据劫持,劫持 data 的 setter 方法
  2. 更新视图
class ViewBind {
  constructor ({ el = 'body', data = {}} = {}) {
    this.dom = document.querySelectorAll(el)
    this.data = data
    this.observe(data)
  }
  // 数据劫持
  observe(data) {
    const self = this
    Object.keys(data).forEach(function (key) {
      self.defineReactive(data, key, data[key])
    })
  }
  defineReactive(data, key, value) {
    const self = this
    Object.defineProperty(data, key, {
      enumerable : true,
      configurable : true,
      set (newVal) {
        value = newVal
        self.updateDom()
      },
      get () {
        return value
      },
    })
  }
  // 更新视图
  updateDom() {
    const self = this
    const queue = [...this.dom]
    while (queue.length > 0) {
      const node = queue.shift()
      if (node.children) {
        queue.push(...node.children)
      }
      if (node.attributes['v-text']) {
        const key = node.attributes['v-text'].value
        node.innerText = self.data[key]
      }
    }
  }
}
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
42
43

# 测试一下

点击跳转 (opens new window)

Last Updated: 3/31/2021, 1:05:35 PM