Vue高阶组件_高阶组件的承上启下

2022-11-18 11:33:57 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。


一、高阶组件概念

何谓高阶组件?类比高阶函数的定义:将函数作为参数的函数就是高阶函数,那么,将组件作为参数的组件就是高阶组件。

二、目标

假如我们有一个组件,我们希望通过某个函数,去扩展它,得到一个新的组件,新的组件有完全的参数组件的行为,如果这点可以满足,那么其他扩展就可以针对性的进行处理了。组件最重要的三个功能就是事件、属性以及插槽,通过函数得到新的组件如果能完全复制参数组件的这三项能力,那么这个函数就是一个合格的高阶组件。

三、思路

通过组件的render函数基于参数组件的模板进行属性、事件乃至插槽的捆绑

四、准备

我们先定义一个baseComp,一个函数hoc.js,将baseComp传入得到wrapperComp

baseComp.vue

代码语言:javascript复制
<template>
  <div>
    <button @click="$emit('handle-click')">点击事件</button><br>
    <!--  --> props[p] =======> {
  
  {p}} <br>
    <!--  --> data[myProp] =======> {
  
  {myProp}}<br><br>
    <slot /> --------------------插槽分割线-------------------- <br>
    <slot name="sname" />
  </div>
</template>
<script>
export default {
  props: ['p'],
  components: {},
  data() {
    return {
      myProp: "baseProp1",
    };
  },
  created() {},
  methods: {},
  mounted() {},
  computed: {}
};
</script>

hoc.js

代码语言:javascript复制
export default function Wrapper(baseComp) {
 return {
  data() {
   return {};
  },
  mounted() {},
  render(h) {
   return h(baseComp, {})
  }
 }
}

app.vue

代码语言:javascript复制
<style>
.app {
  padding: 20px;
}
</style>
<template>
  <div class="app">
    /********************** baseComp start **********************/
    <br />
    <baseComp @handle-click="handle" p="baseApp">
      <div>我是一个默认插槽:base默认slot</div>
      <template v-slot:sname>
        <div>我是一个具名插槽:base具名slot</div>
      </template>
    </baseComp>
    <br />
    /********************** baseComp end **********************/
    <br />
    <br />
    /********************** wrapperComp start **********************/
    <br />
    <wrapperComp @handle-click="handle" p="wrapperApp">
      <div>我是一个默认插槽:wrapper默认slot</div>
      <template v-slot:sname>
        <div>我是一个具名插槽:wrapper具名slot</div>
      </template>
    </wrapperComp>
    /********************** wrapperComp end **********************/
  </div>
</template>
<script>
import baseComp from "./baseComp.vue";
import hoc from "./hoc";
const wrapperComp = hoc(baseComp);
export default {
  components: { baseComp, wrapperComp },
  created() {},
  methods: {
    handle() {
      alert("handle success");
    }
  },
  mounted() {},
  computed: {}
};
</script>

我们通过将baseComp传递给hoc.js得到wrapperComp组件,目前只是将模板进行复制,我们来看看效果:

如图我们已经完成一个组件生成另一个组件了,但是你会发现,属性、插槽以及事件都不能正确传递,接下来我们依次实现

五、实现

1、属性、事件

hoc.js

代码语言:javascript复制
...
render(h) {
   return h(baseComp, {
    on: this.$listeners,
    attrs: this.$attrs,
    props: this.$props
   })
  }
...

点击下方按钮也能触发事件了

2、插槽

hoc.js

代码语言:javascript复制
...
  render(h) {
   let scopedSlots = {};
   let $slots = this.$slots;
   Object.keys($slots).map((key) => (scopedSlots[key] = () => $slots[key]))
   return h(baseComp, {
    on: this.$listeners,
    attrs: this.$attrs,
    props: this.$props,
    scopedSlots
   })
  }
...

插槽内容也能传递

六、难点

1、忽略 props 使得声明的属性没有传递

2、使用this.slots绑定插槽:插槽内容无法按照插槽顺序渲染(因为只是简单的模板列表的平铺,不涉及作用域属性)

Reference

1、Discussion: Best way to create a HOC

https://github.com/vuejs/vue/issues/6201

2、探索Vue高阶组件

http://hcysun.me/2018/01/05/探索Vue高阶组件/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/210116.html原文链接:https://javaforall.cn

0 人点赞