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
表示组件名称
动态组件实现示例
秉持着数据驱动试图的理念,动态组件的实现有如下步骤:
- 生成一份组件的配置
- 利用配置对象+
<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>
以上就是动态组件渲染机制的全部内容,在此感谢**《哲玄课堂-大前端全栈实践课》**的大力支持!