自定义高阶函数组件,实现组件或插槽内容的加载状态,错误,及结果的自动显示,此版本由原来的Vue2改写而来,因为工作实在太忙,没太多时间写具体思路,只给大家参考吧,有不清楚的可以评论留言,我给大家解释,具体用法如下:
hoc.js
/*自定义高阶函数组件,实现组件或插槽内容的加载状态,错误,及结果的自动显示,用法如下:1、数据获取请求定义:_request为返回的Promise对象const _request = (params) => { return api.get(`api/v3/trade/market`, {showError:false, showLoading:false})}2、组装高阶函数,只有1个参数时,传数据请求函数,2个参数时,位置1为定义的vue组件let hoc = new Hoc(_request)或let hoc = new Hoc(About, _request)3、将组装的高阶函数定义为组件components: { hoc,}4、组件传参:fixed 为加载状态及错误结果是否全屏显示4.1、无组件参数时,暴露默认数据插槽 #default="{data}" 获取数据<hoc :params="params" #default="{data}" fixed>...</hoc>@:params 为默认插槽时,为请求函数_request传参,展示的内容为声明的高阶函数组件内部插槽内容4.2、有组件传参时,例如组件为About,展示的内容为组件内容,需在About内用如下形式传参和接收数据,组件内有插槽时,可在hoc内设置插槽内容<hoc fixed>...</hoc>About组件内部:export default { props: ['data'], setup(){ const params = ref('zh-CN') return { params } },}*/import FLoading from '@/components/FLoading'import ErrorMC from './hoc_error'import ViewState from './view_state.js'import {SUCCESS} from '@/api'import { getCurrentInstance, onMounted, ref, watch, h } from 'vue'import { useI18n } from 'vue-i18n'export default function(WrappedComponent, promiseFn) { if(!promiseFn){ promiseFn = WrappedComponent WrappedComponent = null } return { props: { params: { default: null }, fixed: { type: Boolean, default: false } }, setup(props, ctx){ const self = getCurrentInstance() const {t} = useI18n() const viewState = ref(ViewState.busy) const message = ref('') const data = ref(null) const reqParams = ref(null) async function request() { viewState.value = ViewState.busy const result = await promiseFn(reqParams.value) if (result.rst != SUCCESS) { message.value = `${result.code||''} ${t('error_code.'+result.msg).replace('error_code.','')}` if (result.path) { message.value = `path: ${result.path}<br/>${message.value}` } viewState.value = ViewState.error } else { data.value = result.data viewState.value = ViewState.idle } } onMounted(()=>{ // 立刻发送请求,并且监听参数变化重新请求 reqParams.value = WrappedComponent && self.refs.wrapped.params || props.params watch(reqParams, ()=>request(), { immediate: true, deep:true }) }) return { viewState, message, data, request } }, render() { const slots = {...this.$slots} slots.default = ()=> this.$slots.default({data:this.data}) const args = { ref: 'wrapped', data: this.data, ...this.$attrs, } const wrapped = WrappedComponent || "div" const wrapper = h('div', { style: this.viewState != ViewState.idle?'position:relative; min-height: 2.1rem;':'' }, [ this.viewState == ViewState.busy ? h(FLoading, { color: '#c9c9c9', size: 30, fixed: this.fixed, bgColor: 'rgba(0, 0, 0, 0)', }) : (this.viewState == ViewState.error ? h(ErrorMC, { message: this.message, fixed: this.fixed, onRetry:()=> this.request() }) : null), this.viewState != ViewState.idle? h('div', {style:'visibility: hidden;'}, h(wrapped, args, null)): h(wrapped, args, slots), ]) return wrapper }, }}
view_state.js
export default class ViewState { static idle = 0 static busy = 1 static empty = 2 static error = 3 static unAuthorized = 4}
hoc_error.vue
<template> <div class="error-mask" :class="{fixed:fixed}"> <section> <div class="content"> <p v-html="message"></p> <div class="pt10"> <van-button type="danger" size="small" block @click="retry">{{$t(`重试`)}}</van-button> </div> </div> </section> </div></template><script>export default { props: { message:String, fixed:{ type:Boolean, default:false } }, setup(props, ctx){ function retry(){ ctx.emit('retry') } return { retry } }}</script><style lang="less" scoped>.error-mask{ position: absolute; left: 0; top: 0; right:0; bottom:0; background-color:rgba(0,0,0,.32); z-index:1; &.fixed { position: fixed; } section { margin: 0.2rem; height: calc(100% - 0.4rem;); overflow-y: auto; line-height: 1.5; color: #FFF; font-size: 12px; display: flex; flex-direction: column; justify-content: center; p {word-break: break-all;} }}</style>