Vue做出Observer有哪些方法

作者&投稿:宏震 (若有异议请与网页底部的电邮联系)
~
这次给大家带来Vue做出Observer有哪些方法,Vue做出Observer的注意事项有哪些,下面就是实战案例,一起来看一下。
导语:
本文是对 Vue 官方文档深入响应式原理(https://cn.vuejs.org/v2/guide/reactivity.html)的理解,并通过源码还原实现过程。
响应式原理可分为两步,依赖收集的过程与触发-重新渲染的过程。依赖收集的过程,有三个很重要的类,分别是 Watcher、Dep、Observer。本文主要解读 Observer 。
这篇文章讲解上篇文章没有覆盖到的 Observer 部分的内容,还是先看官网这张图:
Observer 最主要的作用就是实现了上图中touch -Data(getter) - Collect as Dependency这段过程,也就是依赖收集的过程。
还是以下面的代码为例子进行梳理:
(注:左右滑动即可查看完整代码,下同)
varvm = newVue({
el: '#demo',
data: {
firstName: 'Hello',
fullName: ''
},
watch: {
firstName(val) {
this.fullName = val + 'TalkingData';
},
}
})在源码中,通过还原Vue 进行实例化的过程,从开始一步一步到Observer 类的源码依次为(省略了很多不在本篇文章讨论的代码):
// src/core/instance/index.js
functionVue(options) {
if(process.env.NODE_ENV !== 'production'&&
!(thisinstanceofVue)
) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
// src/core/instance/init.js
Vue.prototype._init = function(options?: Object) {
constvm: Component = this
// ...
initState(vm)
// ...
}
// src/core/instance/state.js
exportfunctioninitState(vm: Component) {
// ...
constopts = vm.$options
if(opts.data) {
initData(vm)
}
// ...
}
functioninitData(vm: Component) {
letdata = vm.$options.data
data = vm._data = typeofdata === 'function'
? getData(data, vm)
: data || {}
// ...
// observe data
observe(data, true/* asRootData */)
}在initData 方法中,开始了对data 项中的数据进行“观察”,会将所有数据的变成observable 的。接下来看observe 方法的代码:
// src/core/observer/index.js
functionobserve(value: any, asRootData: ?boolean): Observer| void{
// 如果不是对象,直接返回
if(!isObject(value) || value instanceofVNode) {
return
}
letob: Observer | void
if(hasOwn(value, '__ob__') && value.__ob__ instanceofObserver) {
// 如果有实例则返回实例
ob = value.__ob__
} elseif(
// 确保value是单纯的对象,而不是函数或者是Regexp等情况
observerState.shouldConvert &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
// 实例化一个 Observer
ob = newObserver(value)
}
if(asRootData && ob) {
ob.vmCount++
}
returnob
}observe 方法的作用是给data 创建一个Observer 实例并返回,如果data 有ob属性了,说明已经有Observer 实例了,则返回现有的实例。Vue 的响应式数据都会有一个ob的属性,里面存放了该属性的Observer 实例,防止重复绑定。再来看new Observer(value) 过程中发生了什么:
exportclassObserver{
value: any;
dep: Dep;
vmCount: number; // number of vms that has this object as root $data
constructor(value: any) {
this.value = value
this.dep = newDep()
this.vmCount = 0
def(value, '__ob__', this)
if(Array.isArray(value)) {
// ...
this.observeArray(value)
} else{
this.walk(value)
}
}
walk (obj: Object) {
constkeys = Object.keys(obj)
for(leti = 0; i < keys.length; i++) {
defineReactive(obj, keys[i], obj[keys[i]])
}
}
observeArray (items: Array<any>) {
for(leti = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
}通过源码可以看到,实例化Observer 过程中主要是做了两个判断。如果是数组,则对数组里面的每一项再次调用oberser 方法进行观察;如果是非数组的对象,遍历对象的每一个属性,对其调用defineReactive 方法。这里的defineReactive 方法就是核心!通过使用Object.defineProperty 方法对每一个需要被观察的属性添加get/set,完成依赖收集。依赖收集过后,每个属性都会有一个Dep 来保存所有Watcher 对象。按照文章最开始的例子来讲,就是对firstName和fullName分别添加了get/set,并且它们各自有一个Dep 实例来保存各自观察它们的所有Watcher 对象。下面是defineReactive 的源码:
exportfunctiondefineReactive(
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean
) {
constdep = newDep()
// 获取属性的自身描述符
constproperty = Object.getOwnPropertyDeor(obj, key)
if(property && property.configurable === false) {
return
}
// cater for pre-defined getter/setters
// 检查属性之前是否设置了 getter/setter
// 如果设置了,则在之后的 get/set 方法中执行设置了的 getter/setter
constgetter = property && property.get
constsetter = property && property.set
// 通过对属性再次调用 observe 方法来判断是否有子对象
// 如果有子对象,对子对象也进行依赖搜集
letchildOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: functionreactiveGetter() {
// 如果属性原本拥有getter方法则执行
constvalue = getter ? getter.call(obj) : val
if(Dep.target) {
// 进行依赖收集
dep.depend()
if(childOb) {
// 如果有子对象,对子对象也进行依赖搜集
childOb.dep.depend()
// 如果属性是数组,则对每一个项都进行依赖收集
// 如果某一项还是数组,则递归
if(Array.isArray(value)) {
dependArray(value)
}
}
}
returnvalue
},
set: functionreactiveSetter(newVal) {
// 如果属性原本拥有getter方法则执行
// 通过getter方法获取当前值,与新值进行比较
// 如果新旧值一样则不需要执行下面的操作
constvalue = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if(newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if(process.env.NODE_ENV !== 'production'&& customSetter) {
customSetter()
}
if(setter) {
// 如果属性原本拥有setter方法则执行
setter.call(obj, newVal)
} else{
// 如果原本没有setter则直接赋新值
val = newVal
}
// 判断新的值是否有子对象,有的话继续观察子对象
childOb = !shallow && observe(newVal)
// 通知所有的观察者,更新状态
dep.notify()
}
})
}相信看了本文案例你已经掌握了方法,更多精彩请关注Gxl网其它相关文章!
推荐阅读:
怎样对webpack4.0进行打包优化

做出json与数组键值大小写转换


武强县17568374984: vue watch用法需要自己写吗 -
悟珊林青: Observer, Watcher, vm 可谓 Vue 中比较重要的部分,检测数据变动后视图更新的重要环节.下面我们来看看 如何实现一个简单的 $watch 功能,当然Vue 中使用了很多优化手段,在本文中暂不一一讨论.例子: // 创建 vm let vm = new Vue({ data: '...

武强县17568374984: 如何用vue.js中的index -
悟珊林青: 写了个2113DEMO代码5261:<p class="text-success" v-on:click="getIndex($index)">Text:{{option.text}}--Vlue:{{option.value}}</p> 给参4102数值1653版($index)就可以.权<ul> <li v-for="(index,item) in items" data-index="{{index}}" v-...

武强县17568374984: 认识Vue.js+Vue.js的优缺点+和与其他前端框架的区别 -
悟珊林青: 首先,我们先了解什么是MVX框架模式?MVX框架模式:MVC+MVP+MVVM1.MVC:Model(模型)+View(视图)+controller(控制器),主要是基于分层的目的,让彼此的职责分开.View通过Controller来和Model联系,Controller是View和...

武强县17568374984: vue.js 本地 怎么做服务器渲染 -
悟珊林青: 从官方给出的渲染方案能看出,后端只是在页面硬塞了数据及数据状态进去,就效果而论渲染的工作还是前端负责,所以其他后端也能做到.具体看例子写script标签到页面那段.vue的服务端渲染,目前发现下面两个包可以实现nodejs向其他服务器请求数据.我现在用的是axios,因为我看到axios同时支持nodejs和浏览器.

武强县17568374984: vue.js做前台,后台的框架怎么选择 -
悟珊林青: 前后台交互其实都是通过servlet来实现的. 即servlet写数据给前台,前台展示.前台提交数据,servlet处理. 框架只是封装了servlet,提供了更加简便,更加好维护的集成模式.如果你很感兴趣框架的实现方式的话,你可以看看nutz的源代码. nutz是国产的,有非常好的文档和注释.

武强县17568374984: Vue.js要学什么知识? -
悟珊林青: 数据驱动视图、响应式数据、模板语法、指令、生命周期、组件化、组件通信、组件插槽、异步组件Vue-cli 脚手架、vue-router 、 vuex.我是在广州蓝景技术交流群自学的,大家有兴趣可以一起学.

武强县17568374984: vue.js怎样构建后台管理界面 -
悟珊林青: 介绍: 这是一个用vuejs2.0和element搭建的后台管理界面.相关技术: vuejs2.0:渐进式JavaScript框架,易用、灵活、高效,似乎任何规模的应用都适用. element:基于vuejs2.0的ui组件库. vue-router:一般单页面应用spa都要用到的前端路由. vuex:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.

武强县17568374984: 如何制作vue,怎么调滤镜 -
悟珊林青: 1、vue是一个视频剪辑软件.2、用法:在我们制作(自行拍摄之前)可以来设置拍摄时候的色调滤镜,拍摄的时长,这些拍摄的视频,可以直接用到我们要制作的剪辑小视屏当中.调用手机里的小视屏、可以给视频加上LOGO、在发送前进行...

武强县17568374984: 如何制作并使用Vue波纹按钮组件 -
悟珊林青: 使用vue.js构造modal组件的方法是使用 v-model 指令: v-model 指令在表单控件元素上创建双向数据绑定.根据控件类型它自动选取正确的方法更新元素. 比如,多个勾选框,绑定到同一个数组: <input type="checkbox" id="jack" value=...

武强县17568374984: vue使用中的内存泄漏推荐 -- vue.js
悟珊林青: 内存泄露是指new了一块内存,但无法被释放或者被垃圾回收.这篇文章主要介绍了vue使用中的内存泄漏,需要的朋友可以参考下什么是内存泄露?内存泄露是指new了一...

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网