createRenderer 函数详解
createRenderer
是 VTJ 渲染系统的核心函数,用于根据 DSL (Domain Specific Language) 创建 Vue 组件渲染器。
作用
- 组件渲染器创建:基于 DSL 配置生成可复用的 Vue 组件
- 上下文管理:创建并维护组件运行时上下文(Context)
- 响应式系统集成:处理状态(state)、计算属性(computed)和方法(methods)
- 生命周期管理:集成 DSL 定义的生命周期钩子
- 跨框架支持:通过抽象层支持不同版本的 Vue
工作原理
输入参数 (CreateRendererOptions
)
typescript
interface CreateRendererOptions {
Vue?: any; // Vue 实例 (默认为全局 Vue)
mode?: ContextMode; // 上下文模式 (默认 Runtime)
dsl?: BlockSchema; // 块定义 DSL
components?: Record<string, any>; // 可用组件
libs?: Record<string, any>; // 第三方库
apis?: Record<string, any>; // API 集合
loader?: BlockLoader; // 块加载器
window?: Window; // 目标窗口对象
}
核心工作流程
初始化上下文:
typescriptconst context = new Context({ mode, dsl: dsl.value, attrs: { $components, $libs, $apis } });
创建 Vue 组件:
- 使用
Vue.defineComponent
定义组件 - 处理 props、setup、render 等核心选项
- 使用
响应式系统集成:
typescriptcontext.state = createState(Vue, dsl.value.state, context); const computed = createComputed(Vue, dsl.value.computed, context); const methods = createMethods(dsl.value.methods, context);
依赖注入处理:
typescriptconst injects = createInject(Vue, dsl.value.inject, context);
数据源初始化:
typescriptconst dataSources = createDataSources(dsl.value.dataSources, context);
生命周期管理:
typescript...createLifeCycles(dsl.value.lifeCycles, context)
渲染逻辑:
typescriptrender() { const nodes: NodeSchema[] = dsl.value.nodes || []; // 单节点渲染 if (nodes.length === 1) return nodeRender(nodes[0], context, Vue, loader, nodes); // 多节点渲染 return nodes.map(child => nodeRender(child, context, Vue, loader, nodes)); }
关键辅助函数
createProps()
- 处理组件 props- 支持字符串和对象形式定义
- 自动解析 JS 表达式默认值
typescriptconst propsDef = createProps(dsl.value.props, context);
createState()
- 创建响应式状态- 使用
Vue.reactive
创建响应式对象 - 自动解析 JS 表达式和函数
- 使用
createComputed()
- 创建计算属性- 使用
Vue.computed
包装计算逻辑
- 使用
createDataSources()
- 初始化数据源- 支持 mock 和 API 两种类型
- 自动处理数据转换
setWatches()
- 设置侦听器typescriptVue.watch( context.__parseExpression(n.source), context.__parseFunction(n.handler), { deep, immediate } );
使用方法
基本使用
typescript
import { createRenderer } from '@vtj/renderer';
const { renderer, context } = createRenderer({
Vue, // 可选 Vue 实例
dsl: blockSchema, // 块定义 DSL
components: { Button, Input }, // 注册组件
apis: { fetchData } // 注册 API
});
// 在 Vue 应用中作为组件使用
app.component('BlockRenderer', renderer);
DSL 配置示例
json
{
"name": "MyBlock",
"state": {
"count": {
"type": "JSExpression",
"value": "0"
},
"message": {
"type": "JSExpression",
"value": "'Hello VTJ'"
}
},
"methods": {
"increment": {
"type": "JSFunction",
"value": "() => {\n this.state.count++\n}"
}
},
"nodes": [
{
"name": "div",
"children": {
"type": "JSExpression",
"value": "`${this.state.message}(${this.state.count})`"
}
},
{
"id": "473bdbbv",
"name": "ElButton",
"from": "element-plus",
"children": "按钮",
"props": {
"type": "primary"
},
"events": {
"click": {
"name": "click",
"handler": {
"type": "JSFunction",
"value": "this.increment"
},
"modifiers": {}
}
}
}
]
}
高级功能
依赖注入:
json"inject": [ { "name": "theme", "from": "THEME_PROVIDER", "default": "light" } ]
数据源配置:
json"dataSources": { "userData": { "type": "api", "ref": "getUserInfo", "transform": { "type": "JSFunction", "value": "function(data) { return data.user }" } } }
生命周期钩子:
json"lifeCycles": { "mounted": { "type": "JSFunction", "value": "function() { console.log('组件挂载') }" } }
最佳实践
- 组件拆分:复杂 UI 拆分为多个 block
- 状态管理:优先使用块级 state,复杂场景考虑外部状态管理
- 性能优化:
- 使用
Vue.markRaw
避免不必要的响应式转换 - 合理使用计算属性缓存复杂运算
- 使用
- 样式隔离:利用
adoptedStyleSheets
实现 CSS 隔离 - 错误处理:在数据源中添加错误处理逻辑
注意事项
- 确保 DSL 中的 JS 表达式/函数可安全执行
- 跨窗口渲染时提供正确的 window 对象
- 生产环境移除调试用的 mock 数据源
- 避免在 render 函数中进行复杂计算