Vue源码 - 2.数据劫持
程序员文章站
2022-04-15 19:54:48
新建src/index.jsimport { initMixin } from "./init"function Vue(options) { // 运行 Vue 的初始化操作 this._init(options)}// 通过引入文件的方式给 Vue 原型上添加方法initMixin(Vue)export default Vue新建src/init.jsimport { initState } from './state';// 在原型上添加一个 init 的方....
- 新建src/index.js
import { initMixin } from "./init"
function Vue(options) {
// 运行 Vue 的初始化操作
this._init(options)
}
// 通过引入文件的方式给 Vue 原型上添加方法
initMixin(Vue)
export default Vue
- 新建src/init.js
import { initState } from './state';
// 在原型上添加一个 init 的方法
export function initMixin(Vue) {
// 初始化方法
Vue.prototype._init = function(options) {
// 数据的劫持
const vm = this; // vue 中使用的 this.$options 指的就是用户传递的属性
vm.$options = options
// 初始化状态
initState(vm)
}
}
- 新建 src/state.js
import { observe } from "./observer/index"
export const initState = function(vm) {
let opts = vm.$options
console.log(opts);
// vue 数据的来源 属性 、 方法 、 数据 、 计算属性 、 watch
if(opts.props) {
initProps(vm)
}
if(opts.methods) {
initMethods(vm)
}
if(opts.data) {
initData(vm)
}
if(opts.computed) {
initComputed(vm)
}
if(opts.watch) {
initWatch(vm)
}
}
function initData(vm) {
// 数据的初始化工作
let data = vm.$options.data // 用户传递的 data
/**
* 1. data._data 是希望用户也能拿到 data 属性
* 2. 如果 data 返回的是一个方法的话立即执行 data()
*/
data = vm._data = typeof data == 'function' ? data.call(vm) : data
// 对象劫持 用户改变了数据,我希望可以得到通知 - 刷新页面
// MVVM 模式 数据改变可以驱动视图的变化
// 核心方法 object.defineProperty() 给属性增加 get 、set 方法
observe(data) // 响应式原理
}
- 新建 src/observer/index.js
/**
* 1. 把 data 中的数据,都使用 Object.defineProperty 重新定义 es5 的方法
* 2. Object.defineProperty 不能兼容 ie8 及其以下,所以 vue2 无法兼容 ie8 版本
*/
import { isObject, def } from '../utils/index';
import { arrayMethods } from './array.js'
class Observer {
constructor(value) {
// vue 如果数据的层次过多,需要递归的去解析对象中的属性,依次增加 set 和 get 方法
// 所以 vue3.0 中使用 proxy 方法,proxy不需要递归,也不需要给属性添加 get 和 set 方法,所以性能提升2-3倍
def(value, '__ob__', this)
if(Array.isArray(value)) {
// 如果是数组的话并不会对索引进行观测,因为会导致性能问题
// 前端开发很少去操作索引 push shift unshift
// 如果数组里放的是对象我再监控
value.__proto__ = arrayMethods // 重写数组的原型方法
this.observerArray(value)
} else {
this.walk(value)
}
}
observerArray(data) {
data.forEach(item => {
observe(item)
})
}
walk(data) {
let keys = Object.keys(data)
keys.forEach(key => {
defineReactive(data, key, data[key]) // 定义响应式数据
});
}
}
function defineReactive(data, key, value) {
observe(value) // 递归实现深度检测
Object.defineProperty(data, key, {
get() { // 获取值的时候做一些操作
return value
},
set(newValue) { // 设置值的时候也可以做一些操作
if(newValue === value) return
observe(newValue) // 继续劫持用户设置的值,因为有可能用户设置的值是一个对象
value = newValue
}
})
}
export function observe(data) {
let isObj = isObject(data)
if(!isObj) {
return
}
// 如果是对象的话就需要 观测数据
return new Observer(data)
}
- 新建 src/utils/index.js
// 判断是否是对象
export function isObject(data) {
return typeof data === 'object' && data !== null
}
// 不可枚举的响应式方法
export function def(data, key, value) {
Object.defineProperty(data, key, {
enumerable: false,
configurable: false,
value
})
}
本文地址:https://blog.csdn.net/qq_35432512/article/details/107320531