前端系统学习 10. Vue高级用法

2022-02-22  本文已影响0人  stanf1l

Vue 高级用法

动画特效

  1. transition 实现路由切换动画

插槽 - Slot

当某些组件或页面的宏观布局确定,局部子组件需要经常变化的时候,十分适合使用 Slot

父组件和子组件的变量作用域都是创建时的作用域,但是父组件可以向 slot 子组件传递数据

  1. slot 实现原理

slot 本质上是一个返回 VNode 的函数,一般情况下,Vue 中的组件要渲染到页面上需要经过 template -> render function -> VNode -> DOM 的过程

比如一个带 slot 的组件

Vue.component('button-counter', {
  template: '<div> <slot>我是默认内容</slot></div>'
})
 
new Vue({
    el: '#app',
    template: '<button-counter><span>我是slot传入内容</span></button-counter>',
    components:{buttonCounter}
})

经过 vue 编译,组件渲染函数会变成

(function anonymous(
) {
with(this){
  return _c('div',[_t("default",[_v("我是默认内容")])],2)}
})

而这个_t就是 slot 渲染函数

function resolveSlots (
    children,
    context
  ) {
    if (!children || !children.length) {
      return {}
    }
    var slots = {};
    for (var i = 0, l = children.length; i < l; i++) {
      var child = children[i];
      var data = child.data;
      // remove slot attribute if the node is resolved as a Vue slot node
      if (data && data.attrs && data.attrs.slot) {
        delete data.attrs.slot;
      }
      // named slots should only be respected if the vnode was rendered in the
      // same context.
      if ((child.context === context || child.fnContext === context) &&
        data && data.slot != null
      ) {
        // 如果slot存在(slot="header") 则拿对应的值作为key
        var name = data.slot;
        var slot = (slots[name] || (slots[name] = []));
        // 如果是tempalte元素 则把template的children添加进数组中,这也就是为什么你写的template标签并不会渲染成另一个标签到页面
        if (child.tag === 'template') {
          slot.push.apply(slot, child.children || []);
        } else {
          slot.push(child);
        }
      } else {
        // 如果没有就默认是default
        (slots.default || (slots.default = [])).push(child);
      }
    }
    // ignore slots that contains only whitespace
    for (var name$1 in slots) {
      if (slots[name$1].every(isWhitespace)) {
        delete slots[name$1];
      }
    }
    return slots
}

Mixin

本质就是一个 js 对象,它可以包含我们组件中任意功能选项,如 data、components、methods、created、computed等等

我们只要将公用的功能以对象的方式传入 mixins 选项中是,当组件使用 mixins 对象时所有 mixins 对象的选项都将被混入该组件本身的选项中来

在 Vue 中我们可以局部混入和全局混入,全局混入常用来编写插件。

  1. mixin 实战
  2. mixin 实现原理
export function mergeOption (
  parent: Object,
  child: Object,
  vm?: Component
): Object {
  // 判断有有没有 mixin 也就是 mixin里面挂 mixin 的情况,有的化递归合并
  if (child.mixins) {
    for (let i = 0, l = child.mixins.length; i < l; i++) {
      parent = mergeOptions(parent, child.mixins[i], vm)
    }
  }

  const options = {}
  let key
  for (key in parent) {
    // 先遍历 parent 的 key 调对应的 strats[xxx]方法进行合并
    mergeField(key)
  }

  for (key in child) {
    if (!hasOwn(parent, key)) {
      处理 parent 没有处理的 key
      mergeField(key)
    }
  }

  function mergeField (key) {
    const strat = strats[key] || defaultStrat
    options[key] = strat(parent[key], child[key], vm, key)
  }

  return options
}

其主要逻辑就是合并 mixin 和当前组件的各种数据,细分为四种策略:

插件

插件就是指对 Vue 的功能的增强或补充

  1. 什么是插件?如何编写一个插件
MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或 property
  Vue.myGlobalMethod = function () {}

  // 2. 添加全局资源
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVNode) {}
  })

  // 3. 注入组件选项
  Vue.mixin({
    created: function () {}
  })

  // 4. 添加实例方法
  Vue.prototype.$myMethod = function (options) {

  }

}

Vue.use(plugin, options)
  1. Vue.use做了什么
Vue.use = function (plugin, options) {
  const installedPlugins = this._installedPlugins || (this._installedPlugins = [])

  if (installedPlugins.indexOf(plugin) > -1) return this

  // init plugin.install()
  const args = Array.prototype.slice.call(arguments, 1)
  args.unshift(this)

  if (typeof plugin.install === 'function') {
    plugin.install.apply(plugin, args)
  } else if (typeof plugin === 'function') {
    plugin.apply(null, args)
  }

  installedPlugins.push(plugin)
  return this
}
上一篇 下一篇

猜你喜欢

热点阅读