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