[关闭]
@tangchao 2018-02-06T17:11:34.000000Z 字数 2360 阅读 932

avalon 源码

学习笔记


阅读 avalon 1.46 版本

阅读经验

关注点:

技巧:

编码经验

纯函数,可以抽出来

思路整理

注册 vm

  1. source 中普通属性生成 accessor,并将属性转化为访问器属性, getsetaccessor 对应的代码。 合并到 $vmodel
  2. 方法直接并到 $vmodel
  3. 其它的 $id, $model, $events, $watch, $unwatch, $fire
  4. 遍历所有计算属性,通过执行一次 get 收集生成相应的依赖

扫描文档

  1. 默认从 <html> 开始扫描
  2. 如果一个元素有 ms-controller,提取 vm, 组成一个 vmodels 列表
  3. 提取元素的 attributes,遍历,筛出含有 ms 的属性
  4. 每个属性生成一个 binding,包含 element, type, value,将对应值存上去
  5. 将该元素的所有 binding 增加 handler,根据 type 分配方法。
  6. bindings 存入到该 vm 上的 $event[keyName] 中。
  7. 执行一次 handler 刷新视图。
  8. 扫描子节点。

第7步,是如何收集依赖注入的呢?

  1. 全局创建一个闭包 dependencyDetection,其中有一个空数组 outerFrames
  2. executeBindings:
  3. injectBinding: 开始执行 begin 将一个含 callback(参数 vmodel, accessor) 的对象 pushouterFrames
  4. 对该属性进行一次取值,执行 collectDependency
  5. 会调用 callback,将会把这个 binding 添加到 $event[accessor._name]
  6. endpop 这个 outerFrames

改变 vm

  1. vm 上某一个属性进行了赋值操作,则调用 set
  2. 更新 vmvm.$model 的值
  3. 遍历 $event[keyName],新的 valueitem.el 为参数,执行其 handler
  4. 触发($fire)该 vm$watch 的方法

$watch 的绑定与触发

绑定:其实就是把回调函数 push 到 $event[keyName]。如果没有就手动创建一个。
触发:当 vm 改变的时候,会 $fire。而这个方法中,会遍历 $event[keyName],是函数,则执行它。

计算属性

定义 vm 时,会执行 $reinitialize,将 accessor.digest (即执行一次 accessor) 注入依赖的 $event[dependencyKeyName]

扫描文档的 7.4 步,该计算属性访问器执行时 -> 调用 get -> 对依赖的简单属性进行求值 -> 执行 collectDependency -> 7.5 中 callback 接收的 accessor._name 就会是这个简单属性的

每一次被触发 accessor 时,如果值发生了改变,则会执行自己的 $event 来触发自己的 watch 的内容。

监控数组

数据结构:
vm.$event.keyName 是数组本身操作触发
vm.keyName.proxies 上是各子项操作触发

更新:
长度不一样,先新增 add 或者删除 splice,再对剩下想同位置的元素进行 set
proxies 对应子项作为 binding 去触发。

新增:
先在 proxies 生成 vm 上的数据,以及插入新的标签到 dom,
再对该 dom 进行 scan。

各种指令

组件

组件的使用:

注册一个组件 avalon.ui[widget]=function(){},其中内容主要有:
获取可配置的 options,组成 vm 或组件必须用的数据
定义 vm
有模板的,使用 avalon.parseHTML 生成元素,并插入到 DOM 中 element 相关的位置
$init 方法中 avalon.scan(element, [vm].concat(vmodels)),对新加入的元素一次扫描

源码原理:

执行组件的定义 avalon.ui[widget](elem, data, vmodels)
执行组件的 $init

事件

通过解析表达式,生成 data.evaluator,中将执行 vm 上的函数,并把参数带上 vm 传入
data.argsvmodels
bindingExecutors.on 中:通过 avalon.bind 方法,给元素绑定一个回调,回调把 data.args 作为参数,执行 data.evaluator

备忘

avalon.bindingHandlers
avalon.bindingExecutors
avalon.vmodels

核心方法:modelFactory

avalon.define
-> modelFactory
-> 遍历所有属性,每一个属性 makeSimpleAccessor 生成 accessor
-> accessor.updateValueglobalUpdateValue, accessor.notifyglobalNotify
-> globalNotifyfireDependenciesEventBus.$fire.call
……> defineProperties
……> 添加: EventBus[i], $model, $events

核心方法:扫描

avalon.scan
-> scanTag
-> scanAttr
-> 循环所有属性生成 binding 对象,然后添加到数组 bindings
-> executeBindings 循环 bindings
-> bindingHandlers[data.type](data, vmodels)

执行

fireDependencies
-> fn.handler

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注