elpis之动态组件机制

elpis之动态组件机制

动态组件设计

经过上文对于DSL领域模型的理解,我们可以通过一份DSL配置渲染出我们所需要的组件,具体配置如下:

json 复制代码
{
    "schemaConfig": {
        "schema": {
            "type": "",
            "properties": {
                "key": {
                    "createFormOption": {
                        "comType": ""
                    },
                    "editFormOption": {
                        "comType": ""
                    },
                    "detailPanelOption": {
                        "comType": ""
                    }
                }
            }
        }
    },
    "componentConfig": {
        "createForm": {
            "title": "",
            "saveText": ""
        },
        "editForm": {
            "title": "",
            "saveText": ""
        },
        "detailPanel": {
            "mainKey": "",
            "title": ""
        }
    }
}

通过上文,我们可以拿到一份完成的schemaConfig配置对象,因为动态组件用于当菜单的moduleType=schema时,页面渲染出对应的schemaView,因此我们在schemaView这个页面结合自定义hook完成对于动态组件DSL->配置对象的转换,具体代码如下:

js 复制代码
import { ref, watch, onMounted, nextTick } from 'vue'
import { useRoute } from 'vue-router'
import { useMenuStore } from '$elpisStore/menu'

export const useSchema = () => {
    const route = useRoute()
    const menuStore = useMenuStore()
    const api = ref('')
    const tableSchema = ref({})
    const tableConfig = ref()

    const searchConfig = ref()
    const searchSchema = ref({})

    const components = ref({})

    // 通用构建方法(清除噪音)
    const buildDtoSchema = (_schema, comName) => {
        if (!_schema?.properties) return
        const dtoSchema = {
            type: 'object',
            properties: {}
        }

        // 提取有效 schema 字段信息

        for (const key in _schema.properties) {
            const props = _schema.properties[key]
            const option = props[`${comName}Option`]
            if (option) {
                let dtoProps = {}
                // 提取props中非 option 的部分, 存放到dtoProps
                for (const pKey in props) {
                    if (pKey.indexOf('Option') < 0) {
                        dtoProps[pKey] = props[pKey]
                    }
                }
                // 处理 comName Option
                dtoProps = Object.assign({}, dtoProps, { option })
                // 处理 required
                const { required } = _schema
                const isRequired = required && required.find(pKey => pKey === key)
                if (isRequired) {
                    dtoProps.option.required = true
                }
                dtoSchema.properties[key] = dtoProps
            }
        }

        return dtoSchema
    }

    // 构造schemaConfig 相关配置,传输给schemaView
    const buildData = () => {
        const { key, sider_key: siderKey } = route.query
        const mItem = menuStore.findMenuItem({
            key: 'key',
            value: siderKey ?? key
        })
        if (mItem && mItem.schemaConfig) {
            const { schemaConfig: sConfig } = mItem
            const configSchema = JSON.parse(JSON.stringify(sConfig.schema))
            api.value = sConfig.api ?? ''

            tableSchema.value = {}
            tableConfig.value = undefined
            searchConfig.value = undefined
            searchSchema.value = {}
            components.value = {}

            nextTick(() => {
                // 构建tableSchema 和 tableConfig
                tableSchema.value = buildDtoSchema(configSchema, 'table')
                tableConfig.value = sConfig.tableConfig
                // 构建searchConfig 和 searchSchema
                searchConfig.value = sConfig.searchConfig
                const dtoSearchSchema = buildDtoSchema(configSchema, 'search')
                for (const key in dtoSearchSchema.properties) {
                    if (route.query[key] !== undefined) {
                        dtoSearchSchema.properties[key].option.default = route.query[key]
                    }
                }
                searchSchema.value = dtoSearchSchema
                // 构造components = { comKey: { schema: {}, config: {} } }
                const { componentConfig } = sConfig
                if (componentConfig && Object.keys(componentConfig).length > 0) {
                    const dtoComponents = {}
                    for (const comName in componentConfig) {
                        dtoComponents[comName] = {
                            schema: buildDtoSchema(configSchema, comName),
                            config: componentConfig[comName]
                        }
                    }
                    components.value = dtoComponents
                }
            })
        }
    }

    onMounted(() => {
        buildData()
    })

    watch(
        [() => route.query.key, () => route.query.sider_key, () => menuStore.menuList],
        () => {
            buildData()
        },
        { deep: true }
    )

    return {
        api,
        tableSchema,
        tableConfig,
        searchSchema,
        searchConfig,
        components
    }
}

通过以上代码,我们可以构造出动态组件{ comKey: { schema: {}, config: {} } }的数据结构,comKey表示组件名称

动态组件实现示例

秉持着数据驱动试图的理念,动态组件的实现有如下步骤:

  1. 生成一份组件的配置
  2. 利用配置对象+<component />动态组件完成组件的渲染工作
js 复制代码
import CreateForm from './create-form/create-form.vue'
// 编写动态组件配置
const ComponentConfig = {
    createForm: {
        component: CreateForm
    }
}
export default ComponentConfig
vue 复制代码
<script setup>
import ComponentConfig from './components/component-config'
// 获取动态组件对应的配置对象
const { components } = useSchema()
</script>
<template>
<!-- 完成动态组件的渲染 -->
<component
    :is="ComponentConfig[key].component"
    v-for="(item, key) in components"
    :key="key"
/>
</template>

以上就是动态组件渲染机制的全部内容,在此感谢**《哲玄课堂-大前端全栈实践课》**的大力支持!

相关推荐
井柏然2 小时前
从 npm 包实战深入理解 external 及实例唯一性
前端·javascript·前端工程化
羊锦磊3 小时前
[ vue 前端框架 ] 基本用法和vue.cli脚手架搭建
前端·vue.js·前端框架
brzhang3 小时前
高通把Arduino买了,你的“小破板”要变“AI核弹”了?
前端·后端·架构
我星期八休息3 小时前
C++异常处理全面解析:从基础到应用
java·开发语言·c++·人工智能·python·架构
xjf77114 小时前
Nx项目中使用Vitest对原生JS组件进行单元测试
javascript·单元测试·前端框架·nx·vitest·前端测试
new_daimond4 小时前
微服务网关技术详细介绍
微服务·云原生·架构
Light604 小时前
领码方案|微服务与SOA的世纪对话(4):迁移与避坑——从 SOA 到微服务的演进路线图
微服务·云原生·架构·自动化运维·容器化·服务治理·渐进式迁移
Roadinforest4 小时前
水墨风鼠标效果实现
前端·javascript·vue.js
XYiFfang4 小时前
【Docker】解决Docker中“exec format error”错误:架构不匹配的完整指南
docker·容器·架构