第9章 组件系统设计原理

9.1 组件注册机制

9.1.1 全局组件注册流程

// 全局组件注册源码核心
Vue.options.components = Object.create(null)

Vue.component = function(id, definition) {
  // 标准化组件选项
  if (isObject(definition)) {
    definition = Vue.extend(definition)
  }
  
  // 存储到全局组件库
  this.options.components[id] = definition
  return definition
}

// 组件构造器生成
Vue.cid = 0
Vue.extend = function(extendOptions) {
  const Super = this
  const Sub = function VueComponent(options) {
    this._init(options)
  }
  
  Sub.cid = Vue.cid++
  Sub.prototype = Object.create(Super.prototype)
  Sub.prototype.constructor = Sub
  Sub.options = mergeOptions(Super.options, extendOptions)
  
  return Sub
}

注册过程解析

  1. 选项标准化:将组件配置转换为构造器
  2. 原型继承:继承Vue基类能力
  3. 全局存储:注册到Vue.options.components

9.1.2 局部组件注册实现

// 组件合并策略
function mergeAssets(parentVal, childVal) {
  const res = Object.create(parentVal || null)
  return childVal
    ? extend(res, childVal)
    : res
}

// 组件选项合并
const strats = {
  components: function(parentVal, childVal) {
    return mergeAssets(parentVal, childVal)
  }
}

合并规则

  • 局部组件优先于全局组件
  • 同名组件会被覆盖

9.2 组件生命周期管理

9.2.1 组件生命周期全景图

父beforeCreate
子初始化
子beforeCreate
子created
子beforeMount
子mounted
父mounted

9.2.2 组件挂载流程

// 组件VNode创建
function createComponent(Ctor, data, context, children) {
  // 安装组件钩子
  installComponentHooks(data)
  
  return new VNode(
    `vue-component-${Ctor.cid}`,
    data, undefined, undefined, undefined, context,
    { Ctor, children }
  )
}

// 组件钩子安装
const componentVNodeHooks = {
  init(vnode) {
    const child = vnode.componentInstance = new vnode.componentOptions.Ctor()
    child.$mount(undefined) // 不指定el
  },
  
  prepatch(oldVnode, vnode) {
    // 更新组件props等
  },
  
  insert(vnode) {
    if (!vnode.componentInstance._isMounted) {
      vnode.componentInstance._isMounted = true
      callHook(vnode.componentInstance, 'mounted')
    }
  }
}

9.3 组件通信机制

9.3.1 Props传递原理

// Props标准化处理
function normalizeProps(options) {
  const props = options.props
  if (!props) return
  const res = {}
  if (Array.isArray(props)) {
    props.forEach(key => {
      res[key] = { type: null }
    })
  } else {
    for (const key in props) {
      res[key] = isObject(props[key])
        ? props[key]
        : { type: props[key] }
    }
  }
  options.props = res
}

// Props响应化处理
function initProps(vm, propsOptions) {
  const propsData = vm.$options.propsData || {}
  const props = vm._props = {}
  
  for (const key in propsOptions) {
    defineReactive(props, key, propsData[key])
    if (!(key in vm)) {
      proxy(vm, '_props', key)
    }
  }
}

9.3.2 自定义事件实现

// 事件中心实现
function eventsMixin(Vue) {
  Vue.prototype.$on = function(event, fn) {
    const vm = this
    ;(vm._events[event] || (vm._events[event] = [])).push(fn)
    return vm
  }

  Vue.prototype.$emit = function(event) {
    const vm = this
    let cbs = vm._events[event]
    if (cbs) {
      const args = Array.prototype.slice.call(arguments, 1)
      for (let i = 0; i < cbs.length; i++) {
        cbs[i].apply(vm, args)
      }
    }
    return vm
  }
}

// 组件v-on处理
function updateComponentListeners(vm, listeners) {
  for (const name in listeners) {
    const handler = listeners[name]
    if (!handler) continue
    vm.$on(name, handler)
  }
}

9.4 高阶组件模式

9.4.1 函数式组件实现

Vue.component('smart-list', {
  functional: true,
  props: ['items'],
  render(h, context) {
    return h('ul', context.data, 
      context.props.items.map(item => 
        h('li', item.name)
      )
    )
  }
})

性能优势

  • 无实例化开销
  • 无状态组件快速渲染

9.4.2 异步组件加载

Vue.component('async-component', (resolve, reject) => {
  setTimeout(() => {
    resolve({
      template: '
Loaded!
'
}) }, 1000) }) // 结合Webpack代码分割 Vue.component('async-webpack', () => import('./AsyncComponent.vue'))

加载阶段生命周期

const AsyncComponent = () => ({
  component: import('./MyComponent.vue'),
  loading: LoadingComponent,
  error: ErrorComponent,
  delay: 200,
  timeout: 3000
})

9.5 组件系统优化策略

9.5.1 组件缓存机制

// keep-alive实现原理
export default {
  name: 'keep-alive',
  abstract: true,

  created() {
    this.cache = Object.create(null)
  },

  render() {
    const slot = this.$slots.default
    const vnode = slot[0]
    const key = vnode.key
    if (this.cache[key]) {
      vnode.componentInstance = this.cache[key].componentInstance
    } else {
      this.cache[key] = vnode
    }
    vnode.data.keepAlive = true
    return vnode
  }
}

9.5.2 组件懒加载优化

// 结合路由的懒加载方案
const router = new VueRouter({
  routes: [
    {
      path: '/heavy',
      component: () => import(
        /* webpackChunkName: "heavy" */ 
        './HeavyComponent.vue'
      )
    }
  ]
})

本章重点总结:

  1. 组件注册机制:全局与局部组件的存储与合并策略
  2. 生命周期管理:嵌套组件的挂载顺序控制
  3. 通信原理:Props的响应式处理与事件系统实现
  4. 高阶模式:函数式组件与异步加载的优化实践

深度实践建议

  1. 实现自定义组件合并策略
  2. 开发包含完整生命周期的嵌套组件
  3. 对比不同组件加载方式的性能差异
// 组件注册调试示例
Vue.component('global-comp', { template: '
Global
'
}) new Vue({ components: { 'local-comp': { template: '
Local
'
} }, mounted() { console.log(this.$options.components) } })

你可能感兴趣的:(javascript,vue.js,开发语言,前端,算法,ecmascript)