Vue高阶组件

2021/3/26

# Heading

参考列表: Vue 高阶组件 (opens new window)

# 高阶组件介绍

vue 高阶组件的认识,在 React 中组件是以复用代码实现的,而 Vue 中是以 mixins 实现,并且官方文档中也缺少一些高阶组件的概念,因为在 vue 中实现高阶组很困难,并不像 React 简单

所谓高阶组件其实就是一个高阶函数, 即返回一个组件函数的函数,Vue 中怎么实现呢? 注意 高阶组件有如下特点

  1. 高阶组件(HOC)应该是无副作用的纯函数,且不应该修改原组件,即原组件不能有变动
  2. 高阶组件(HOC)不关心你传递的数据(props)是什么,并且新生成组件不关心数据来源
  3. 高阶组件(HOC)接收到的 props 应该透传给被包装组件即直接将原组件 prop 传给包装组件
  4. 高阶组件完全可以添加、删除、修改 props

# 高阶组件举例

Base.vue

<template>
  <div>
    <p @click="Click">props: {{ test }}</p>
  </div>
</template>
<script>
export default {
  name: "Base",
  props: {
    test: Number,
  },
  methods: {
    Click() {
      this.$emit("Base-click");
    },
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Vue 组件主要就是三点:propsevent 以及 slots。对于 Base 组件 组件而言,它接收一个数字类型的 props 即 test,并触发一个自定义事件,事件的名称是:Base-click,没有 slots。我们会这样使用该组件:

<Base @Base-click="xxxx" :test="100" /></Base>
1

现在我们需要 base-component 组件每次挂载完成的时候都打印一句话:haha,同时这也许是很多组件的需求,

# 使用 mixin 实现

所以按照 mixins 的方式,我们可以这样做: consoleMixin.js:

export default consoleMixin {
  mounted () {
    console.log('haha')
  }
}
1
2
3
4
5

然后在 Base 组件中将 consoleMixin 混入: mixins: [ consoleMixin ]

# 使用高阶组件(HOC)实现

function Console(WrappedComponent) {
  return {
    mounted() {
      console.log("haha");
    },
    props: WrappedComponent.props,
    render(h) {
      const slots = Object.keys(this.$slots)
        .reduce((arr, key) => arr.concat(this.$slots[key]), [])
        // 手动更正 context
        .map((vnode) => {
          // Vue要求以下等式成立
          // this.$vnode.context === this.$vnode.componentOptions.children[0].context
          // 强制把slot的归属权给高阶组件 而不是 父组件 通过当前实例 _self 属性访问当实例本身,而不是直接使用 this,因为 this 是一个代理对象
          vnode.context = this._self; //绑定到高阶组件上
          return vnode;
        });

      return h(
        WrappedComponent,
        {
          on: this.$listeners,
          props: this.$props,
          attrs: this.$attrs,
        },
        slots
      );
    },
  };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30