1.引入咱們手寫的Vue 拿到配置數據vue
import Vue from '../source/src/index'; let vm = new Vue({ el: '#app', data() { return { msg: 'hello', school: { name: 'zf', age: 10 }, arr: [1, 2, 3] } }, computed: { }, watch: { } }) console.log(vm) // setTimeout(() => { // vm.arr[0].push(100) // console.log(vm) // }, 1000)
2. 新建文件 source/src/index 數組
在這個文件中 咱們利用 ——init 這個方法 對 用戶傳入的數據進行初始化 傳入配置信息app
function Vue(options) { // console.log(options) // 初始化vue this._init(options) }
3. 在_init 方法中 咱們能夠先將 options 掛載到實例 再進行初始化數據操做 函數
Vue.prototype._init = function (options) { // vue 的初始化 let vm = this; // 將 options 掛載到實例 vm.$options = options; //須要數據從新初始化 initState(vm) }
5. 新建 文件 observe/index 編寫 initState 方法而且導出測試
export function initState(vm) {
console.log(vm)
}
在這裏咱們能夠拿到 vue 的整個實例方法 this
6. 在initState 方法中 咱們進行初始化 好比初始化 數據 初始化 計算屬性 初始化 watch spa
export function initState(vm) { // 拿到option 存儲起來 let options = vm.$options; if (options.data) { // 初始化數據 initData(vm) } if (options.computed) { // 初始化計算屬性 initComputed() } if (options.watch) { // 初始化watch initWatch() } }
7. 初始化數據 在 initData 方法中 咱們經過 傳入實例的option 拿到數據 再判斷 數據 是 函數 仍是 對象 若是是函數 調用call 方法 拿到函數 返回值 如何不是直接返回數據 或者 空數據 prototype
let data = vm.$options.data // 判斷是不是函數 取返回值 data = vm._data = typeof data === 'function' ? data.call(vm) : data || {}
8. 拿到數據後 咱們要對數據進行 監聽 編寫 observe 方法 監聽數據 、3d
function initData(vm) { let data = vm.$options.data // 判斷是不是函數 取返回值 data = vm._data = typeof data === 'function' ? data.call(vm) : data || {} observe(vm._data) }
10 在 observe 方法中 要進行判斷 看看數據是否是對象或者爲空 若是不是 直接返回 若是是 返回一個 Observe 對象 代理
export function observe(data) { // 不是對象或者是null if (typeof data !== 'object' || data === null) { return } return new Observe(data) }
11. 編寫這個 Observe 對象 新建文件 Observe.js
這個文件裏面最主要的是 Object.defineProperty 方法 裏面傳入 data , 還有key key 表明屬性 因此 咱們須要遍歷數據 拿到 全部的 key value 傳入
class Observe { constructor(data) { // 數組 重寫push 方法 if (Array.isArray()) { } else { // 對象 // data 就是咱們 定義的 vm._data 的數據 this.walk(data) } } //將對象的數據使用 defineProperty 從新定義 walk(data) { let keys = Object.keys(data); for (let i = 0; i < keys.length; i++) { let key = keys[i]; // key let value = data[keys[i]]; // value defineReactive(data, key, value) } } } export function defineReactive(data, key, value) { Object.defineProperty(data, key, { get() { // 有值 return value; }, set(newValue) { if (newValue !== value) return; value = newValue } }) } export default Observe;
11. 由於 數據裏面 的對象 可能嵌套 一個對象 因此咱們應該在 數據裏面的對象再進行 深度監聽
export function defineReactive(data, key, value) { observe(value); Object.defineProperty(data, key, { get() { // 有值 return value; }, set(newValue) { if (newValue !== value) return; value = newValue } }) }
12. 測試代碼
import Vue from '../source/src/index'; let vm = new Vue({ el: '#app', data() { return { msg: 'hello', school: { name: 'zf', age: 10 }, arr: [1, 2, 3] } }, computed: { }, watch: { } }) console.log(vm._data.msg) // hello
打印出100
13. 這裏每次取值都須要 掛在 _data 上 很 不方便 好比
function initData(vm) { let data = vm.$options.data // 判斷是不是函數 取返回值 data = vm._data = typeof data === 'function' ? data.call(vm) : data || {} for (let key in data) { proxy(vm, "_data", key) } observe(vm._data) }
14, 編寫 proxy 方法
function proxy(vm, source, key) { Object.defineProperty(vm, key, { get() { return vm[source][key] }, set(newValue) { vm[source][key] = newValue } }) }
15。測試成功
import Vue from '../source/src/index'; let vm = new Vue({ el: '#app', data() { return { msg: 'hello', school: { name: 'zf', age: 10 }, arr: [1, 2, 3] } }, computed: { }, watch: { } }) console.log(vm.msg) // hello