大家好,又见面了,我是你们的朋友全栈君。
一、高阶组件概念
何谓高阶组件?类比高阶函数的定义:将函数作为参数的函数就是高阶函数,那么,将组件作为参数的组件就是高阶组件。
二、目标
假如我们有一个组件,我们希望通过某个函数,去扩展它,得到一个新的组件,新的组件有完全的参数组件的行为,如果这点可以满足,那么其他扩展就可以针对性的进行处理了。组件最重要的三个功能就是事件、属性以及插槽,通过函数得到新的组件如果能完全复制参数组件的这三项能力,那么这个函数就是一个合格的高阶组件。
三、思路
通过组件的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