1. 程式人生 > 實用技巧 >實現一個最小版本vue(二)之observer

實現一個最小版本vue(二)之observer

Vue

  • 功能
    • 負責接收初始化的引數
    • 負責把data中的屬性注入到vue例項,轉化稱getter,setter
    • 負責呼叫observer監聽data中所有屬性的變化
    • 負責呼叫compiler解析指令/差值表示式
    • 結構

observer

  • 功能
    • 負責把data選項中的屬性轉換成響應式資料
    • data中的某個屬性也是物件,把該屬性轉換成響應式資料
    • 資料變化發出通知
  • 結構
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>mini vue</title>
</head>
<body>
<div id="app">
  <h1>差值表示式</h1>
  <h3>{{msg}}</h3>
  <h3>{{count}}</h3>
  <h1>v-text</h1>
  <div v-text="msg"></div>
  <h1>v-model</h1>
  <input type="text" v-model="msg" />
  <input type="text" v-model="count" />
</div>
<script src="js/observer.js"></script>
<script src="js/vue.js"></script>
<script>
let vm = new Vue({
  el: '#app',
  data: {
    msg: 'hello vue',
    count: 28,
  },
})
console.log(vm.msg)
</script>
</body>
</html>
// observer.js
class Observer {
  constructor (data) {
    this.walk(data)
  }

  walk (data) {
    // 1.判斷data是否時物件
    if (!data || typeof data !== 'object') {
      return
    }
    // 2.遍歷data物件所有屬性
    Object.keys(data).forEach(key => {
      this.defineReactive(data, key, data[key])
    })
  }

  defineReactive (obj, key, val) {
    Object.defineProperty(obj, key, {
      enumerable: true,
      configurable: true,
      get () {
        // 如果使用obj[key],會發生堆疊溢位錯誤
        // return obj[key]
        return val
      },
      set (newValue) {
        if (newValue === val) {
          return
        }
        val = newValue
        // 傳送通知
      },
    })
  }
}
// vue.js
class Vue {
  constructor (options) {
    // 1.通過屬性儲存選項的資料
    this.$options = options || {}
    this.$data = options.data || {}
    this.$el = typeof options.el === 'string' ? document.querySelector(options.el) : options.el
    // 2.把data中的成員轉化稱getter和setter,注入到vue例項
    this._proxyData(this.$data)
    // 3. 呼叫observer物件,監聽資料變化
    new Observer(this.$data)
    // 4.呼叫compiler物件,解析指令和差值表示式
  }


  _proxyData (data) {
    // 遍歷data中所有屬性
    Object.keys(data).forEach(key => {
      Object.defineProperty(this, key, {
        enumerable: true,
        configurable: true,
        get () {
          return data[key]
        },
        set (newValue) {
          if (newValue === data[key]) {
            return
          }
          data[key] = newValue
        },
      })
    })
    // 把data的屬性注入到vue例項


  }
}