IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue 源码理解分解之数据绑定 -> 正文阅读

[JavaScript知识库]vue 源码理解分解之数据绑定

Observer , dep , watcher 是vue双向绑定的关键组成部分

observer

方法、类作用
toggleObserving (value: boolean)控制变量“shouldObserve”,间接控制调用observer时是否为对象创建__ob__
class Observer(value:object | any[])创建 {value,dep,vmCount}
observe (value: any, asRootData: ?boolean): Observer | void为value创建ob
defineReactive(obj: any,key: string,val?: any,customSetter?: Function,shallow?: boolean)将obj中的key定义为响应式
set(target: any[] | any, key: string | number, val: any) :any为对象设值,如果是reactiveObj则触发通知
del(target:any | any[], key: any)删除属性触发修改
// 控制着observer是否能生成 ob 对象
export function toggleObserving (value: boolean) {
  shouldObserve = value
}

// 为value 新增__ob__ ,每个ob关联一个dep 
// value为数组时会修改其原型链上的方法,使其某些方法可以触发更新,并为其每个元素进行 observer
// value是对象则会针对每个值 defineReactive
export class Observer {
  value: any;
  dep: Dep;
  vmCount: number; // number of vms that have this object as root $data
  constructor (value: any) {}
  
  walk (obj: Object) {}
  observeArray (items: Array<any>) {}
}

// 由shouldObserve 与类型判断控制是否生成 ob , 如果生成或已有ob,则返回
export function observe (value: any, asRootData: ?boolean): Observer | void {}

/**
 * Define a reactive property on an Object.
 * 配置obj[key]属性为响应式,会获取其原本的 getter, setter
 * 响应式的属性当被取值时(getter),会检查全局target,如果当前被watch了,则会收集watcher,如果val是数组则会让每个元素都一并收集
 * 响应式的属性当被赋值时(setter(val))会通知所有收集的watcher 
 * 注:当对obj不存在的key进行响应式时,将会没有getter,setter,只改闭包中的值
 */
export function defineReactive(
  obj: any,
  key: string,
  val?: any,
  customSetter?: Function,
  shallow?: boolean
) {}

/**
 * Set a property on an object. Adds the new property and
 * triggers change notification if the property doesn't
 * already exist.
 * 更改obj/arr或新增响应式属性
*/
export function set(target: any[] | any, key: string | number, val: any) :any {}

/**
 * Delete a property and trigger change if necessary.
 */
export function del(target:any | any[], key: any) {}

Dep

方法/类作用
class Dep依赖收集器,收集watcher
pushTargetwatcher 入栈
popTargetwacher出栈
let uid = 0
export default class Dep {
  static target: WatcherInstance | null;
  id: number;
  subs: Array<WatcherInstance>;
  constructor() {
    this.id = uid++
    this.subs = []
  }
  addSub(sub: WatcherInstance) {
    this.subs.push(sub)
  }
  removeSub(sub: WatcherInstance) {
    remove(this.subs, sub)
  }
  depend() {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }
  // 为subs中的wacher根据ID排序(dev), 触发所有wacher的update()
  notify () {}
}

Dep.target = null
// watcher 栈
const targetStack = <WatcherInstance[]>[];
export function pushTarget(target: WatcherInstance | null) {}
export function popTarget() {}

Watcher

方法/类作用
class Watcher观察者,掌握着触发的回调
let uid = 0
export default class Watcher {
  vm: Component;
  expression: string;
  cb: (value?: any, oldValue?: any) => void;
  id: number;
  // options
  deep: boolean;
  user: boolean;
  lazy: boolean;
  sync: boolean;
  dirty: boolean;
  //状态
  active: boolean;
  // 记录着被哪些依赖收集
  deps: Array<Dep>;
  newDeps: Array<Dep>;
  depIds: SimpleSet;
  newDepIds: SimpleSet;
  before?: Function;
  getter: () => any;
  value: any;
  constructor(
    vm: Component,
    expOrFn: string | Function,
    cb: (value?: any, oldValue?: any) => void,
    options?: WatcherOption | void,
    isRenderWatcher?: boolean
  ) {
 	// ...
  	this.value = this.lazy
      ? undefined
      : this.get()
  }
  /**
   * Evaluate the getter, and re-collect dependencies.
   * 当前watcher入栈,获取expOrFn 对应的值,并且让其内部的响应式属性收集当前watcher,形成绑定关系
   */
  get(): any {
  	pushTarget(this);
  	value = this.getter.call(vm, vm)
  	if (this.deep) {
        traverse(value)
    }
    popTarget()
    this.cleanupDeps()
    return value
  }
	
  /**
   * Add a dependency to this directive.
   */
  addDep(dep: DepInstance) {}
  
  /**
   * Clean up for dependency collection.
   * 清除久依赖,将新依赖转为旧依赖
   */
  cleanupDeps() {}
  
  /**
   * Subscriber interface.
   * Will be called when a dependency changes.
   * 三种情况更新
   */
  update() {
	/* istanbul ignore else */
    if (this.lazy) {
      this.dirty = true;
    } else if (this.sync) {
      this.run();
    } else {
      queueWatcher(this);
    }
  }
	
  /**
   * Scheduler job interface.
   * Will be called by the scheduler.
   * 触发 get() 更新 value , 并触发 cb.call(vm,val,oval) (cb对于RenderWatcher无意义)
   */
  run() {}
	
 /**
  * Evaluate the value of the watcher.
  * This only gets called for lazy watchers.
  */
  evaluate() {
    this.value = this.get()
    this.dirty = false
  }
	
  /**
   * Depend on all deps collected by this watcher.
   */
  depend() {
    let i = this.deps.length
    while (i--) {
      this.deps[i].depend()
    }
  }
  
  /**
  * Remove self from all dependencies' subscriber list.
  */
  teardown() {
	if (this.active) {
      // remove self from vm's watcher list
      // this is a somewhat expensive operation so we skip it
      // if the vm is being destroyed.
      if (!this.vm._isBeingDestroyed) {
        remove(this.vm._watchers, this)
      }
      let i = this.deps.length
      while (i--) {
        this.deps[i].removeSub(this)
      }
      this.active = false
    }
  }
}

traverse

方法/类作用
traverse(val: any)遍历对象(收集当前target),如果存在ob,则将其ob.dep.id记录,防止死循环

scheduler

方法/类作用
queueWatcher(watcher: WatcherInstance)将watcher加入队列中,下个周期开始触发watcher.run
flushSchedulerQueue ()排序并触发watcher队列
let waiting = false;
let flushing = false;
let index = 0;
let has: { [key: number]: boolean } = {};
// 循环 watcher 的id记录
let circular: { [key: number]: number } = {}
export function queueWatcher(watcher: WatcherInstance) {}
//如果a,b两个watcher 互相影响,则会造成死循环,用circular计数,防止崩溃
function flushSchedulerQueue()

array

const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]
// 
// 修改数组原生方法,当使用以上方法时,若果是插入数据则会触发ob.observeArray(inserted),然后 this.__ob__.dep.notify();以达到触发数组绑定的目的
methodsToPatch.forEach(function (method: string) {
})
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-23 16:34:41  更:2021-08-23 16:37:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:22:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码