Vue核心思想-数据驱动的实现分析

数据驱动
  • 数据驱动是Vue的核心思想之一,指视图由数据驱动生成,通过修改数据来实现了对视图的修改,而非直接操作DOM。
  • DOM变成了数据的映射,我们把重点放在了数据的逻辑处理上,提高了开发效率。
  • VirtualDOM就是一个js对象去描述一个DOM节点,在Vue中是用VNode这个class去描述。
Vue的挂载过程

挂载的目标就是把模板渲染成为最终的DOM。
主要是分为 render 和 update 两个过程。
$mount () -> mountComponent () -> vm._render () + vm._uptate ()

1、Render

Vue的_render方法是vue实例的一个私有方法,作用是生成一个VNode。
(src/core/instance/render.js)
在 initRender () 中定义了两种方法,vm._c ⽅法,它是被模板编译成的 render 函数使⽤,⽽vm.$createElement 是⽤户⼿写 render ⽅法使⽤的, 这俩个⽅法⽀持的参数相同, 并且内部都调⽤了 createElement ⽅法

export function initRender (vm: Component) {
   
  // bind the createElement fn to this instance
  // so that we get proper render context inside it.
  // args order: tag, data, children, normalizationType, alwaysNormalize
  // internal version is used by render functions compiled from templates
  vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
  // normalization is always applied for the public version, used in
  // user-written render functions.
  vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
  }
}

_createElement ()
1、参数

export function _createElement (
  context: Component, //VNode的上下文环境
  tag?: string | Class<Component> | Function | Object, //标签 字符串类型、Component类型/
  data?: VNodeData, //VNode的数据
  children?: any,//VNode的子节点,为任意类型
  normalizationType?: number//规范化类型
): VNode | Array<VNode> {
    ....  }

2、重点流程

  1. 子节点的规范化
  • 由于Virtual DOM是树状结构,一个VNode都可能有很多个子节点,这些子节点也应该是VNode类型。 要将类型为any的 children 规范为VNode类型。
  • 根据 normalizationType 的不同分别调用 normalizeChildren 和 simpleNormalizeChildren。
  • 其中simpleNormalizeChildren 是用Array.prototype.concat 将数组拉平为一维数组,深度只有一层。
// 1. When the children contains components - because a functional component
// 返回的是一个数组而不是一个根节点
// normalization is needed - if any child is an Array, we flatten the whole 返回的是一个数组而不是一个根节点
// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep  
// because functional components already normalize their own children.
export function simpleNormalizeChildren (children: any) {
   
  for (let i = 0; i < children.length; i++) {
   
    if (Array.isArray(children[i])) {
   
      return Array.prototype.concat.apply([], children)
    }
  }
  return children
}
  • 当子节点包含生成嵌套数组的构造函数时
  • 当编译 template, slot, v-for 这些标签或者是用户自定义的render函数
// 2. When the children contains constructs that always generated nested Arrays,
// e.g. <template>, <slot>, v-for, or when the children is provided by user   
// with hand-written render functions / JSX. In such cases a full normalization
// is needed to cater to all possible types of children values.
export function normalizeChildren (children: any): ?Array<VNode> {
   
  return isPrimitive(children)
    ? [createTextVNode(children)]
    : Array.isArray(children)
      ? normalizeArrayChildren(children)
      : undefined
}

如果是子节点一个基础类型,就调用createTextVNode 创建一个文本节点的VNode。如是一个数组类型就调用 normalizeArrayChildren

normalizeArrayChildren()

  • 参数是子节点 和 嵌套的索引
  • 该方法的主要逻辑就是遍历子节点,取到单个节点 c ,接着判断 c 的类型,如果是数组就递归处理这个节点;如果是一个基础类型,则通过createTextVNode方法转换为VNode类型;否则就是VNode类型。
  • 经过对子节点的规范化处理, 原来类型为any的children就成了一个VNode节点集合。
function normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNode> {
   
  const res = []
  let i, c
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值