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>

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

相关推荐
Q26433650232 分钟前
【有源码】基于SpringBoot+Vue的博物馆展览与服务一体化平台-java博物馆数字化展品展示与交互平台设计
java·vue.js·spring boot·spring·毕业设计·javaweb·课程设计
Dawson Zhu15 分钟前
《Agentic Design Patterns》第 2 章导读:路由(Routing)
人工智能·语言模型·架构·aigc·agi
এ慕ོ冬℘゜26 分钟前
es6基础
前端·javascript·es6
ym hyd 1111 小时前
汽车零部件缺陷管理系统源码 Java+SpringBoot+Vue3 前后分离
java·vue.js·spring boot·汽车·毕设
传奇开心果编程1 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
可乐鸡翅yeah_2 小时前
hls.js 缓冲区参数 maxBufferLength、maxBufferSize 通俗讲解与业务调参
开发语言·javascript·ios·音视频·safari·m3u8
梦帮科技2 小时前
【3.0修订版】 RNS 代币架构:ERC20 五件套扩展与六钱包分配
数据结构·后端·算法·架构·node.js·区块链·php
一隅论数智2 小时前
RDF(Resource Description Framework)介绍和使用举例(二)
大数据·人工智能·经验分享·笔记·学习·架构·政务
paopaokaka_luck2 小时前
高校社团管理(AI辅助任务分配、协同过滤算法推荐、ECharts数据可视化、活动参与闭环、校园交流与反馈、器材借还管理)
java·前端·javascript·spring boot·数据分析·echarts
vx_Biye_Design2 小时前
springboot小区管理系统68491-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·spring·课程设计·express