需求
最近碰到一个需求,web 界面本身是基于配置动态渲染出来,页面里面某个位置的组件是一个特殊节点 slot,该节点本⾝不会被渲染,用户自定义了一个组件,该组件的定义保存成 json 格式文件,特殊节点加载这个配置文件后渲染出该组件,界面里会有多个这种特殊节点加载多个用户自定义组件
这个需求 json2render 动态界面组件正好可以实现这个功能,json2render 是一个 web 界面动态渲染库,可以根据 json 数据动态渲染界面,是根据动态表单组件 vjform 设计思想的重构版本,采用 proxy 重写了表达式数据关联关系的逻辑,分离了表达式关联关系的转换实现与渲染框架(vue、react)的依赖,最新版本引入了 dependency injection 机制,使扩展新的功能更加科学合理,目前 json2render 渲染方式提供 vue3 支持
效果
具体效果如下

示例中主界面是通过 json 数据动态呈现,里面有个地方选择组件,在选择组件后加载组件的 json 数据,动态呈现到下面的特殊节点区域
实现
json2render 作为动态呈现组件本身内部也可以渲染 json2render实现嵌套渲染
首先安装 @json2render/vue-full 和 element-plus 并在项目中引用,@json2render/vue-full 包含了对 vue3 的完整支持
npm i @json2render/vue-full element-plus
复制代码
import { createApp } from 'vue'
import App from './App'
import Element from 'element-plus'
import JRender from '@json2render/vue-full'
import 'element-plus/lib/theme-chalk/index.css'
createApp(App)
.use(Element)
.use(JRender)
.mount('#app')
复制代码
实现一个 vue 界面, App.js
<script>
import { defineComponent } from "vue"
export default defineComponent({
setup() {
return {
// 主界面的配置,可以写死也可以远程读 json 文件
// 常规的网络请求资源问题,这里就不实现怎么读了
config: {}
}
}
})
</script>
<template>
<v-jrender
:fields="config.fields"
:datasource="config.datasource"
:listeners="config.listeners"
/>
</template>
复制代码
主界面的实现 json 数据如下
{
"datasource": {
"template": {
// fetch 类型数据源用于读取远程资源
"type": "fetch",
// 根据选择的组件名称读取对应json文件数据
// 资源存储在 /data/components 目录下
"url": "#:/data/components/${model.name}.json",
"auto": false,
"props": { "method": "GET", "params": {} },
"defaultData": false
}
},
"listeners": [
{
// 定义一个监听,在选择的组件名称变化后数据源重新请求自定义组件json数据
"watch": "$:model.name",
"actions": [{ "handler": "@:template.request()" }]
}
],
"fields": [
{
"component": "h1",
"text": "加载模板组件"
},
{
"component": "el-select",
"model": "model.name",
"children": [
{
"component": "el-option",
"props": { "label": "组件1", "value": "cmp1" }
},
{
"component": "el-option",
"props": { "label": "组件2", "value": "cmp2" }
},
{
"component": "el-option",
"props": { "label": "监听触发", "value": "listeners" }
}
]
},
{
"component": "div",
"props": {
"style": {
"border": "1px dashed silver",
"padding": "1.25rem",
"marginTop": "0.75rem"
}
},
"children": [
{
"component": "p",
"condition": "$:!template.data",
"text": "加载自定义组件",
"props": { "style": { "textAlign": "center" } }
},
{
"component": "v-jrender",
"condition": "$:template.data",
"props": "$:template.data"
}
]
}
]
}
复制代码
在 /data/components 目录下实现三个自定义模板组件
cmp1.json
{
"fields": [{ "component": "p", "text": "段落文本" }]
}
复制代码
cmp2.json
{
"modelValue": {},
"fields": [
{ "component": "el-input", "model": "model.text" },
{ "component": "p", "text": "#:输入了: ${model.text||''}" }
]
}
复制代码
listeners.json
{
"listeners": [
{
"watch": "$:model.on",
"actions": [
{
"condition": "$:!!model.on",
"handler": "@model.value:model.value + 1"
},
{
"condition": "$:!model.on",
"handler": "@model.value:0"
}
]
},
{
"watch": "$:model.value",
"actions": [
{
"condition": "$:!!model.on && model.value < 100",
"timeout": "$:model.num * 100",
"handler": "@model.value:model.value + 1"
}
]
}
],
"fields": [
{
"component": "el-input-number",
"model": "model.num",
"props": { "min": 0, "max": 5 }
},
{
"component": "el-button",
"text": "Go",
"props": { "onClick": "@model.on:true" }
},
{
"component": "el-button",
"text": "Reset",
"props": { "onClick": "@model.on:false" }
},
{
"component": "el-progress",
"props": {
"strokeWidth": 24,
"textInside": true,
"percentage": "$:model.value"
}
}
],
"modelValue": { "num": 0, "value": 0 }
}
复制代码
具体的代码可以看 json2render 项目 templateload 的示例
国内网慢可看 国内镜像






















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)