vue-json-engine
v0.2.1
Published
A pure JSON engine framework based on Vue.js reactivity system
Downloads
197
Readme
Vue JSON Engine
基于 Vue.js 的纯 JSON 驱动 UI 引擎框架
概述
Vue JSON Engine 是一个创新的 UI 开发框架,它允许你完全使用 JSON 配置来构建 Vue 应用程序。通过声明式的 JSON 结构描述应用的状态、视图和交互逻辑,实现前端应用的配置化开发。
核心特性
| 特性 | 描述 | |------|------| | 🎯 零代码开发 | 通过 JSON 配置构建完整 UI 界面 | | 📦 响应式状态管理 | 内置 Store 系统,基于 Vue 3 响应式 | | 🧩 组件化架构 | 支持自定义组件和第三方组件库 | | 🔌 插件系统 | 统一的插件接口,支持第三方库集成 | | 🔗 路由系统 | 内置路由管理,支持动态路由 | | 🌐 HTTP 客户端 | 内置 HTTP 请求封装 | | ⚡ 事件系统 | 完整的事件处理和修饰符支持 | | 🌐 Messaging | 纯 JSON 配置的实时消息路由 | | 📡 远程配置 | 远程加载和热更新 JSON 配置 | | ⚡ 表达式缓存 | 提升表达式求值性能 | | 🔥 HMR 支持 | 开发时代码热更新 | | 🎨 样式处理 | 自动转换 CSS 字符串为对象 | | 📝 表达式求值 | 动态表达式计算和绑定 | | 🔄 条件/列表渲染 | 支持 if/for 指令 | | 🔌 组件注册 | 灵活的组件库注册机制 | | 🎮 Action DSL | 15 种结构化动作类型,替代 JS 字符串 | | 💾 Storage 操作 | 支持 localStorage/sessionStorage 持久化 |
目录
核心原理
架构图
┌─────────────────────────────────────────────────────────────────┐
│ JSON App Config │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌─────────────────┐ │
│ │ Stores │ │Components │ │ Router │ │ Root │ │
│ │ (状态管理) │ │(组件定义) │ │ (路由) │ │ (UI 树结构) │ │
│ └───────────┘ └───────────┘ └───────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ JSON App Engine │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌─────────────────┐ │
│ │ Parser │ │ Compiler │ │ Renderer │ │ Reactivity │ │
│ │ (解析JSON) │ │(编译组件) │ │(渲染VNode)│ │ (响应式系统) │ │
│ └───────────┘ └───────────┘ └───────────┘ └─────────────────┘ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌─────────────────┐ │
│ │ Events │ │ Router │ │ HTTP │ │ Registry │ │
│ │ (事件处理) │ │ (路由管理) │ │(HTTP请求) │ │ (组件注册) │ │
│ └───────────┘ └───────────┘ └───────────┘ └─────────────────┘ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌─────────────────┐ │
│ │ Channel │ │ Remote │ │ Cache │ │ HMR │ │
│ │ (消息路由) │ │(远程配置) │ │(表达式缓存)│ │ (热更新) │ │
│ └───────────┘ └───────────┘ └───────────┘ └─────────────────┘ │
│ ┌───────────┐ ┌───────────┐ │
│ │ Plugin │ │ Action │ │
│ │ Manager │ │ Registry │ │
│ │ (插件管理) │ │(动作注册) │ │
│ └───────────┘ └───────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Vue 3 Runtime │
│ (虚拟 DOM + 响应式系统) │
└─────────────────────────────────────────────────────────────────┘模块职责
| 模块 | 路径 | 职责 |
|------|------|------|
| App | core/app.ts | 应用核心,协调各模块 |
| Store | stores/store.ts | 状态管理,响应式数据 |
| ActionDispatcher | stores/action-dispatcher.ts | Action DSL 执行引擎 |
| StoreManager | stores/store-manager.ts | Store 管理器 |
| Compiler | core/compiler.ts | JSON 编译为 Vue 组件 |
| Renderer | engine/renderer.ts | 统一渲染器 |
| Parser | core/parser.ts | JSON 解析和验证 |
| Events | core/events.ts | 事件处理和修饰符 |
| Router | router/router.ts | 路由管理 |
| RouterView | router/components/router-view.ts | 路由视图组件 |
| RouterLink | router/components/router-link.ts | 路由链接组件 |
| HTTP | http/client.ts | HTTP 请求封装 |
| Interceptors | http/interceptors.ts | HTTP 拦截器 |
| Registry | registry/registry.ts | 组件注册和管理 |
| Plugin | plugins/plugin-manager.ts | 插件管理和生命周期 |
| ActionRegistry | stores/action-registry.ts | 自定义 Action 注册 |
| Messaging | messaging/ws-engine.ts | WebSocket 消息引擎 |
| Remote | remote/loader.ts | 远程配置加载 |
| ExpressionCache | engine/expression-cache.ts | 表达式缓存 (LRU/FIFO/LFU/TTL) |
| Evaluator | core/evaluator.ts | 表达式求值引擎 |
| HMR | hmr/client.ts | 热模块替换支持 |
| Filters | engine/filters/ | 内置过滤器 (10+ 类别) |
| SFCConverter | converters/sfc-converter.ts | Vue SFC → JSON 转换 |
| Schema | schema/ | JSON Schema 验证驱动 |
| AppBuilder | app/builder.ts | 应用构建器 |
| Plugin | app/plugin.ts | 插件系统 |
快速开始
安装
npm install vue-json-engine基础示例
import { createApp } from 'vue'
import { createJSONApp } from 'vue-json-engine'
const config = {
stores: [
{
id: 'counter',
state: { count: 0 },
getters: { doubled: 'count * 2' },
actions: { increment: 'count++', decrement: 'count--' }
}
],
root: {
type: 'element',
tag: 'div',
children: [
{
type: 'element',
tag: 'p',
children: [
{ type: 'text', content: { type: 'expression', value: 'counter.count' } }
]
},
{
type: 'element',
tag: 'button',
events: { onClick: { type: 'handler', action: 'counter.increment' } },
children: [{ type: 'text', content: '+' }]
}
]
}
}
const jsonApp = createJSONApp(config)
createApp(jsonApp.toVueComponent()).mount('#app')功能模块
1. 状态管理 (Store)
Store 是框架的核心状态管理系统,基于 Vue 3 响应式系统实现。
1.1 Store 定义
interface JSONStore {
id: string
state: Record<string, unknown> // 响应式状态
getters: Record<string, unknown> // 计算属性
actions: Record<string, Function> // 操作方法
$patch: (partial) => void // 批量更新
$reset: () => void // 重置状态
$subscribe: (callback) => void // 状态订阅
}1.2 JSON 配置
{
"stores": [
{
"id": "user",
"state": {
"name": "",
"email": "",
"isLoggedIn": false
},
"getters": {
"displayName": "name || 'Guest'",
"isAdmin": "email.includes('admin')"
},
"actions": {
"login": "isLoggedIn = true",
"logout": "isLoggedIn = false; name = ''; email = ''",
"updateProfile": "name = args[0]; email = args[1]"
}
}
]
}1.3 Store API
| API | 描述 |
|-----|------|
| createStore(definition) | 创建 Store 实例 |
| useStore(id) | 获取已存在的 Store |
| resetStores() | 清空所有 Store |
| getAllStores() | 获取所有 Store |
2. UI 节点
框架定义了 8 种核心节点类型:
2.1 Element (HTML 元素)
{
"type": "element",
"tag": "div",
"props": {
"class": "container",
"style": "padding: 20px; background: #fff"
},
"events": {
"onClick": { "type": "handler", "action": "handleClick" }
},
"children": [...]
}支持的 HTML 标签:所有标准 HTML 标签
2.2 Text (文本)
// 静态文本
{ "type": "text", "content": "Hello World" }
// 动态文本
{ "type": "text", "content": { "type": "expression", "value": "user.name" } }2.3 Component (自定义组件)
定义组件:
{
"components": [
{
"name": "Counter",
"props": ["initialValue"],
"state": { "count": 0 },
"methods": {
"increment": "count++",
"decrement": "count--"
},
"template": {
"type": "element",
"tag": "div",
"children": [
{ "type": "text", "content": { "type": "expression", "value": "count" } },
{
"type": "element",
"tag": "button",
"events": { "onClick": { "type": "handler", "action": "increment" } },
"children": [{ "type": "text", "content": "+" }]
}
]
}
}
]
}使用组件:
{
"type": "component",
"name": "Counter",
"props": { "initialValue": 10 },
"events": {
"onChange": { "type": "handler", "action": "handleCounterChange" }
}
}2.4 UI Component (第三方组件库)
{
"type": "ui-component",
"library": "antd",
"component": "Button",
"props": {
"type": "primary",
"size": "large",
"loading": { "type": "expression", "value": "form.submitting" }
},
"events": {
"onClick": { "type": "handler", "action": "form.submit" }
},
"children": [{ "type": "text", "content": "Submit" }]
}2.5 If (条件渲染)
{
"type": "if",
"condition": "user.isLoggedIn",
"then": {
"type": "element",
"tag": "div",
"children": [{ "type": "text", "content": "Welcome!" }]
},
"else": {
"type": "element",
"tag": "button",
"children": [{ "type": "text", "content": "Login" }]
}
}2.6 For (列表渲染)
{
"type": "for",
"each": "item",
"of": "todos.items",
"indexAlias": "index",
"children": [
{
"type": "element",
"tag": "li",
"children": [
{ "type": "text", "content": { "type": "expression", "value": "index" } },
{ "type": "text", "content": ". " },
{ "type": "text", "content": { "type": "expression", "value": "item.text" } }
]
}
]
}2.7 Slot (插槽定义)
{
"type": "slot",
"name": "default",
"props": { "user": "currentUser" }
}2.8 Slot Outlet (插槽出口)
{
"type": "slot-outlet",
"name": "default",
"props": { "user": { "type": "expression", "value": "user" } }
}3. 事件系统
3.1 基本事件
{
"events": {
"onClick": { "type": "handler", "action": "counter.increment" },
"onInput": { "type": "handler", "action": "form.value = $event" },
"onChange": { "type": "handler", "action": "handleChange" }
}
}3.2 事件修饰符
{
"events": {
"onClick": {
"type": "handler",
"action": "submit",
"modifiers": ["prevent", "stop", "self"]
}
}
}可用修饰符:
| 修饰符 | 描述 |
|--------|------|
| prevent | 调用 event.preventDefault() |
| stop | 调用 event.stopPropagation() |
| self | 只当事件从绑定元素触发时才触发 |
| once | 只触发一次 |
| capture | 使用捕获模式 |
| passive | 提升 touch 事件性能 |
3.3 $event 对象
Ant Design Vue 的 onUpdate:value 直接传递值:
{
"events": {
"onUpdate:value": { "type": "handler", "action": "form.username = $event" }
}
}原生 input 的 $event.target.value:
{
"events": {
"onInput": { "type": "handler", "action": "form.value = $event.target.value" }
}
}3.4 事件参数
{
"events": {
"onClick": {
"type": "handler",
"action": "todos.removeTodo(todo.id)"
}
}
}3.5 键盘事件别名
支持按键别名:
{
"events": {
"onKeydown": { "type": "handler", "action": "submit()" }
}
}按键别名:enter, tab, esc, space, up, down, left, right, delete
4. 路由系统
4.1 路由配置
{
"router": {
"mode": "hash",
"base": "/",
"routes": [
{
"path": "/",
"name": "home",
"component": "HomePage"
},
{
"path": "/users/:id",
"name": "user-detail",
"component": "UserDetail",
"children": [
{
"path": "posts",
"component": "UserPosts"
}
]
},
{
"path": "/admin",
"component": "AdminLayout",
"meta": { "requiresAuth": true },
"children": [
{ "path": "", "redirect": "/admin/dashboard" },
{ "path": "dashboard", "component": "AdminDashboard" }
]
},
{
"path": "/:pathMatch(.*)*",
"redirect": "/"
}
]
}
}4.2 路由配置示例
{
"router": {
"mode": "hash",
"routes": [
{ "path": "/", "name": "home", "component": "HomePage" },
{ "path": "/users/:id", "name": "user-detail", "component": "UserDetail" }
]
}
}在组件中使用路由:
{
"type": "component",
"name": "RouterLink",
"props": { "to": "/users/123" },
"children": [{ "type": "text", "content": "User Details" }]
}路由跳转通过事件触发:
{
"type": "element",
"tag": "button",
"events": {
"onClick": { "type": "navigate", "path": "/next-page" }
}
7. 插件系统
框架提供统一的插件接口,用于集成第三方库和扩展功能。
7.1 插件接口
interface JSONPlugin {
name: string // 插件名称(必需)
version?: string // 版本号
dependencies?: string[] // 依赖的其他插件
hooks?: JSONPluginHooks // 生命周期钩子
extend?: JSONPluginExtensionPoints // 扩展点
install?: (context, options?) => void // 安装函数
}7.2 内置插件
| 插件名 | 功能 | 提供内容 |
|--------|------|----------|
| echarts | 图表可视化 | LineChart, BarChart, PieChart 组件 |
| date | 日期处理 | date, timestamp, timeago 过滤器 |
| validation | 表单验证 | validate action, trim/lowercase/uppercase 过滤器 |
| auth | 用户认证 | auth/login, auth/logout, auth/check actions |
7.3 使用插件
import { createJSONApp, createEChartsPlugin, createDatePlugin } from 'vue-json-engine'
const jsonApp = createJSONApp(config)
.use(createEChartsPlugin({ theme: 'light' }))
.use(createDatePlugin({ defaultFormat: 'YYYY-MM-DD' }))
.use(createAuthPlugin({ loginUrl: '/api/auth/login' }))
await jsonApp.initializePlugins()7.4 在 JSON 中使用插件提供的组件
{
"type": "ui-component",
"library": "echarts",
"component": "PieChart",
"props": {
"data": { "type": "expression", "value": "dashboard.chartData" },
"nameField": "name",
"valueField": "value",
"height": 300
}
}7.5 使用插件提供的过滤器
{
"type": "text",
"content": { "type": "expression", "value": "createdAt | date:'YYYY-MM-DD HH:mm'" }
}7.6 ECharts 插件详解
ECharts 插件提供以下快捷图表组件:
| 组件 | 说明 | 快捷属性 |
|------|------|----------|
| ECharts | 通用图表 | option (完整配置) |
| LineChart | 折线图 | xField, yField, smooth, areaStyle |
| BarChart | 柱状图 | xField, yField |
| PieChart | 饼图 | nameField, valueField, radius |
使用示例:
{
"type": "ui-component",
"library": "echarts",
"component": "LineChart",
"props": {
"title": "销售趋势",
"data": { "type": "expression", "value": "sales.monthlyData" },
"xField": "month",
"yField": "value",
"smooth": true,
"areaStyle": true,
"height": 300,
"color": ["#1890ff"]
}
}7.7 创建自定义插件
import type { JSONPlugin, JSONPluginContext } from 'vue-json-engine'
export interface MyPluginOptions {
apiKey?: string
}
export function createMyPlugin(options: MyPluginOptions = {}): JSONPlugin {
return {
name: 'my-plugin',
version: '1.0.0',
extend: {
// 注册过滤器
filters: {
myFilter: (value: unknown) => String(value).toUpperCase()
},
// 注册组件库
libraries: [{
name: 'my-lib',
components: { MyComponent: { /* Vue 组件 */ } }
}],
// 注册 Action
actions: {
'my/action': async (context, ...args) => {
return { success: true }
}
}
},
install(context: JSONPluginContext) {
console.log('[MyPlugin] Installed')
}
}
}7.8 生命周期钩子
interface JSONPluginHooks {
beforeCreate?: (config) => JSONAppConfig | void // 创建前
created?: (context) => void // 创建后
beforeMount?: (context) => void // 挂载前
mounted?: (context) => void // 挂载后
beforeDestroy?: (context) => void // 销毁前
destroyed?: () => void // 销毁后
}8. 响应式系统
框架基于 Vue 3 响应式系统,Store 的 state 和 getters 自动支持响应式。
8.1 Store 响应式
{
"stores": [
{
"id": "counter",
"state": { "count": 0 },
"getters": { "doubled": "count * 2" }
}
]
}9. JSON 解析器
框架自动解析 JSON 配置,无需手动调用解析器。
{
"type": "element",
"tag": "div",
"children": [
{ "type": "text", "content": "Hello" }
]
}框架内部将上述 JSON 解析为内部节点结构。
10. 编译器
编译器将 JSON 配置编译为 Vue 渲染函数,框架自动处理。
{
"stores": [
{
"id": "counter",
"state": { "count": 0 },
"actions": { "increment": "count++" }
}
],
"root": {
"type": "element",
"tag": "button",
"events": {
"onClick": { "type": "handler", "action": "counter.increment" }
}
}
}框架自动编译上述配置为可执行的 Vue 组件。
11. 渲染器
渲染器根据 JSON 配置生成 Vue VNode,框架自动处理。
{
"type": "element",
"tag": "div",
"props": { "class": "container" },
"children": [
{ "type": "text", "content": "Hello World" }
]
}12. Messaging
Messaging 模块提供基于纯 JSON 配置的实时消息路由能力,完全由 JSON 配置驱动,无需任何 JS API 调用。
11.1 配置格式
{
"stores": [
{
"id": "chat",
"state": { "messages": [] },
"actions": {
"addMessage": "messages.push($event.payload)"
},
"messaging": {
"connection": "chat-ws",
"subscribe": "messages",
"action": "addMessage"
}
}
],
"messaging": {
"connections": {
"chat-ws": {
"url": "wss://api.example.com/ws",
"reconnect": true
}
}
}
}11.2 配置说明
messaging.connections:定义所有 WebSocket 连接
| 属性 | 类型 | 说明 |
|------|------|------|
| url | string | WebSocket 连接地址 |
| reconnect | boolean | object | 自动重连配置 |
Store.messaging:将 Store 绑定到消息通道
| 属性 | 类型 | 说明 |
|------|------|------|
| connection | string | 引用 messaging.connections 中的连接 ID |
| subscribe | string | string[] | 要订阅的频道 |
| action | string | 收到消息时调用的 action(默认 onMessage) |
11.3 工作原理
1. 框架读取 messaging.connections 配置
2. 自动建立所有 WebSocket 连接
3. 读取 Store.messaging 配置
4. 自动订阅对应频道
5. 收到消息 → 自动路由到 Store action11.4 重连配置
{
"messaging": {
"connections": {
"chat-ws": {
"url": "wss://api.example.com/ws",
"reconnect": {
"enabled": true,
"maxAttempts": 10,
"initialDelay": 1000,
"maxDelay": 30000,
"jitter": 0.3
}
}
}
}
}11.5 完整示例
{
"stores": [
{
"id": "notification",
"state": { "items": [] },
"actions": {
"add": "items.unshift($event.payload)",
"remove": "items = items.filter(i => i.id !== $event.payload.id)"
},
"messaging": {
"connection": "ws-server",
"subscribe": ["notification", "alert"]
}
},
{
"id": "presence",
"state": { "users": {} },
"actions": {
"update": "users[$event.payload.userId] = $event.payload"
},
"messaging": {
"connection": "ws-server",
"subscribe": "presence",
"action": "update"
}
}
],
"messaging": {
"connections": {
"ws-server": {
"url": "wss://api.example.com/ws",
"reconnect": true
}
}
}
}13. 远程配置
远程配置模块支持从远程服务器加载 JSON 配置。
12.1 配置格式
{
"remote": {
"baseURL": "https://cdn.example.com/config",
"endpoints": {
"app": "/app.json",
"pages": "/pages/{name}.json",
"components": "/components/{name}.json"
},
"cache": {
"enabled": true,
"ttl": 60000
}
}
}12.2 在应用中使用
{
"id": "my-app",
"remote": {
"baseURL": "https://cdn.example.com"
},
"stores": [...],
"root": { ... }
}框架自动从远程加载配置并缓存。
12.3 缓存行为
| 配置 | 说明 |
|------|------|
| enabled: true | 启用缓存 |
| ttl: 60000 | 缓存有效期(毫秒) |
14. 表达式缓存
表达式缓存自动优化性能,无需手动配置。
框架内部自动缓存已编译的表达式:
{
"stores": [
{
"id": "counter",
"state": { "count": 0 },
"getters": { "doubled": "count * 2" }
}
]
}框架自动缓存 count * 2 的编译结果。
15. HMR 支持
框架内置 HMR 支持,在开发模式下自动启用。
16. Action DSL
Action DSL 是结构化的 JSON 动作格式,支持 15 种动作类型,完全替代传统的 JavaScript 字符串动作。
16.1 为什么使用 Action DSL?
| 特性 | 字符串动作 | DSL 动作 |
|------|-----------|----------|
| 类型安全 | ❌ 无类型检查 | ✅ TypeScript 类型检查 |
| 可读性 | ⚠️ count++ | ✅ { type: 'increment', target: 'count' } |
| 模板支持 | ❌ 需手动拼接 | ✅ {{expr}} 语法 |
| 组合能力 | ⚠️ ; 分隔多语句 | ✅ sequence 嵌套 |
| 可调试性 | ⚠️ 运行时错误 | ✅ 编译时警告 |
| 代码生成 | ⚠️ 字符串解析困难 | ✅ AST 结构易于生成 |
16.2 15 种动作类型
数据操作
| 类型 | 用途 | 语法 |
|------|------|------|
| set | 设置属性值 | { type: 'set', target: 'prop', value: 0 } |
| increment | 递增数值 | { type: 'increment', target: 'count', by: 1 } |
| decrement | 递减数值 | { type: 'decrement', target: 'count', by: 1 } |
| push | 数组添加 | { type: 'push', target: 'items', value: { id: 1 } } |
| remove | 数组移除 | { type: 'remove', target: 'items', by: { key: 'id', value: 1 } } |
| update | 按 key 更新 | { type: 'update', target: 'items', by: { key: 'id', value: 1 }, updates: { name: 'new' } } |
| toggle | 布尔翻转 | { type: 'toggle', target: 'isOpen' } |
控制流
| 类型 | 用途 | 语法 |
|------|------|------|
| if | 条件执行 | { type: 'if', condition: '{{count > 0}}', then: [...], else?: [...] } |
| switch | 分支执行 | { type: 'switch', on: 'status', cases: { '200': [...], '404': [...] } } |
| sequence | 顺序执行 | { type: 'sequence', steps: [...] } |
异步/外部
| 类型 | 用途 | 语法 |
|------|------|------|
| http | HTTP 请求 | { type: 'http', method: 'GET', url: '/api', onSuccess: [...], onError?: [...] } |
| call | 调用其他 action | { type: 'call', action: 'otherAction', args: [1, 2] } |
| delay | 延迟执行 | { type: 'delay', ms: 1000, then: { type: 'set', target: 'loading', value: false } } |
其他
| 类型 | 用途 | 语法 |
|------|------|------|
| reset | 重置状态 | { type: 'reset', target: 'count' } 或 { type: 'reset' } (重置整个 store) |
| log | 日志输出 | { type: 'log', message: 'Count: {{count}}', data: '{{items}}' } |
| emit | 触发事件 | { type: 'emit', event: 'custom', payload: '{{data}}' } |
数据持久化
| 类型 | 用途 | 语法 |
|------|------|------|
| storage | 存储操作 | { type: 'storage', operation: 'get/set/remove/clear', key: 'key', value: {}, target: 'state' } |
16.3 模板语法
使用 {{expr}} 语法在 DSL 值中进行插值:
{ "type": "set", "target": "name", "value": "Hello {{userName}}" }
{ "type": "set", "target": "count", "value": "{{count + 1}}" }
{ "type": "push", "target": "items", "value": { "id": "{{Date.now()}}", "text": "{{newTodo.trim()}}" } }模板变量表
| 变量 | 来源 | 说明 |
|------|------|------|
| $event | 事件触发 | 事件传递的值或 Event 对象 |
| args[0], args[1], ... | action 参数 | 调用 action 时传入的参数 |
| record | 表格行数据 | {{record.id}} 获取当前行 ID |
| index | 循环索引 | {{index}} 获取当前项索引 |
| response | HTTP 响应 | {{response.data}} 获取响应数据 |
| error | 错误对象 | {{error.message}} 获取错误信息 |
16.4 嵌套路径更新
支持深层属性更新:
{ "type": "set", "target": "products.currentProduct.name", "value": "{{$event}}" }
{ "type": "set", "target": "form.errors.username", "value": "太短" }16.5 UI 事件中的 DSL 格式
UI 事件使用 handler 类型包装 DSL action:
{
"events": {
"onClick": { "type": "handler", "action": { "type": "call", "action": "counter.increment" } },
"onUpdate:value": { "type": "handler", "action": { "type": "set", "target": "form.username", "value": "{{$event}}" } },
"onPressEnter": { "type": "handler", "action": { "type": "call", "action": "todos.addTodo" } }
}
}16.6 完整示例
计数器
{
"stores": [
{
"id": "counter",
"state": { "count": 0 },
"actions": {
"increment": { "type": "increment", "target": "count" },
"decrement": { "type": "decrement", "target": "count" },
"reset": { "type": "reset", "target": "count" }
}
}
],
"root": {
"type": "element",
"tag": "button",
"events": {
"onClick": { "type": "handler", "action": { "type": "call", "action": "counter.increment" } }
}
}
}Todo 列表
{
"stores": [
{
"id": "todos",
"state": { "items": [], "newTodo": "" },
"actions": {
"addTodo": {
"type": "if",
"condition": "{{newTodo.trim()}}",
"then": [
{ "type": "push", "target": "items", "value": { "id": "{{Date.now()}}", "text": "{{newTodo.trim()}}", "completed": false } },
{ "type": "set", "target": "newTodo", "value": "" }
]
},
"removeTodo": {
"type": "remove",
"target": "items",
"by": { "key": "id", "value": "{{args[0]}}" }
},
"toggleTodo": {
"type": "update",
"target": "items",
"by": { "key": "id", "value": "{{args[0]}}" },
"updates": { "completed": "{{!items.find(t => t.id === args[0]).completed}}" }
}
}
}
],
"root": {
"type": "element",
"tag": "div",
"children": [
{
"type": "element",
"tag": "input",
"events": {
"onUpdate:value": { "type": "handler", "action": { "type": "set", "target": "todos.newTodo", "value": "{{$event}}" } }
}
},
{
"type": "element",
"tag": "button",
"events": { "onClick": { "type": "handler", "action": { "type": "call", "action": "todos.addTodo" } } }
}
]
}
}表单验证
{
"stores": [
{
"id": "form",
"state": { "username": "", "email": "", "errors": {}, "message": "" },
"getters": { "isValid": "username.length >= 3 && email.includes('@')" },
"actions": {
"validateAndSubmit": {
"type": "sequence",
"steps": [
{ "type": "set", "target": "errors", "value": {} },
{ "type": "if", "condition": "{{username.length < 3}}", "then": [{ "type": "set", "target": "errors.username", "value": "用户名至少需要3个字符" }] },
{ "type": "if", "condition": "{{!email.includes('@')}}", "then": [{ "type": "set", "target": "errors.email", "value": "请输入有效的邮箱地址" }] },
{ "type": "if", "condition": "{{Object.keys(errors).length === 0}}", "then": [{ "type": "set", "target": "message", "value": "提交成功!" }] }
]
}
}
}
]
}HTTP 请求
{
"stores": [
{
"id": "api",
"state": { "list": [], "loading": false, "error": null },
"actions": {
"loadData": {
"type": "http",
"method": "GET",
"url": "/api/data",
"params": { "page": "{{pagination.current}}", "pageSize": "{{pagination.pageSize}}" },
"onSuccess": [
{ "type": "set", "target": "list", "value": "{{response.data.list}}" },
{ "type": "set", "target": "loading", "value": false }
],
"onError": [
{ "type": "set", "target": "error", "value": "{{error.message}}" },
{ "type": "set", "target": "loading", "value": false }
]
},
"deleteItem": {
"type": "http",
"method": "DELETE",
"url": "/api/data/{{args[0]}}",
"onSuccess": [{ "type": "call", "action": "loadData" }]
}
}
}
]
}16.7 字符串动作对比表
| 功能需求 | 字符串动作 | DSL 动作 |
|---------|-----------|----------|
| 计数器+1 | "count++" | { type: 'increment', target: 'count' } |
| 计数器-1 | "count--" | { type: 'decrement', target: 'count' } |
| 设置值 | "count = 0" | { type: 'set', target: 'count', value: 0 } |
| 添加到数组 | "items.push(newItem)" | { type: 'push', target: 'items', value: '{{newItem}}' } |
| 按 ID 删除 | "items = items.filter(i => i.id !== id)" | { type: 'remove', target: 'items', by: { key: 'id', value: '{{args[0]}}' } } |
| 条件执行 | "if (count > 0) count--" | { type: 'if', condition: '{{count > 0}}', then: [{ type: 'decrement', target: 'count' }] } |
| 加载数据 | "fetch('/api').then(r => r.json())..." | { type: 'http', method: 'GET', url: '/api', onSuccess: [...] } |
| 调用其他 | "doSomething()" | { type: 'call', action: 'doSomething' } |
| 多步操作 | "a(); b(); c()" | { type: 'sequence', steps: [{ type: 'call', action: 'a' }, { type: 'call', action: 'b' }, { type: 'call', action: 'c' }] } |
| 存储数据 | "localStorage.setItem('k', JSON.stringify(v))" | { type: 'storage', operation: 'set', key: 'k', value: '{{v}}' } |
| 读取存储 | "JSON.parse(localStorage.getItem('k'))" | { type: 'storage', operation: 'get', key: 'k', target: 'data' } |
17. Storage 操作
Storage 模块提供浏览器本地存储的操作能力,支持 localStorage 和 sessionStorage。
17.1 配置格式
{
"actions": {
"saveUser": {
"type": "storage",
"operation": "set",
"storage": "local",
"key": "user_info",
"value": { "username": "{{username}}", "token": "{{token}}" }
},
"loadUser": {
"type": "storage",
"operation": "get",
"key": "user_info",
"target": "userData"
},
"logout": {
"type": "storage",
"operation": "remove",
"key": "user_info"
},
"clearAll": {
"type": "storage",
"operation": "clear"
}
}
}17.2 操作类型
| 操作 | 描述 | 必需参数 |
|------|------|----------|
| get | 从存储读取数据,自动 JSON 解析 | key, target |
| set | 写入数据到存储,自动 JSON 序列化 | key, value |
| remove | 删除指定 key | key |
| clear | 清空整个存储 | 无 |
17.3 存储类型
| 类型 | 配置值 | 说明 |
|------|--------|------|
| localStorage | "storage": "local" 或省略 | 持久化存储,关闭浏览器后仍保留 |
| sessionStorage | "storage": "session" | 会话级存储,关闭标签页后清除 |
17.4 模板支持
key 和 value 都支持模板语法:
{
"type": "storage",
"operation": "set",
"key": "user_{{userId}}",
"value": { "name": "{{user.name}}", "role": "{{user.role}}" }
}17.5 完整示例:登录认证
{
"stores": [
{
"id": "user",
"state": {
"isLoggedIn": false,
"username": "",
"token": ""
},
"getters": {
"displayName": "username || 'Guest'"
},
"actions": {
"login": {
"type": "sequence",
"steps": [
{ "type": "set", "target": "isLoggedIn", "value": true },
{ "type": "set", "target": "username", "value": "{{args[0].username}}" },
{ "type": "set", "target": "token", "value": "{{args[0].token}}" },
{
"type": "storage",
"operation": "set",
"key": "user_info",
"value": { "username": "{{username}}", "token": "{{token}}" }
}
]
},
"logout": {
"type": "sequence",
"steps": [
{ "type": "storage", "operation": "remove", "key": "user_info" },
{ "type": "set", "target": "isLoggedIn", "value": false },
{ "type": "set", "target": "username", "value": "" },
{ "type": "set", "target": "token", "value": "" }
]
}
}
}
]
}路由守卫配置(main.ts):
const router = jsonApp.getRouter()
const userStore = jsonApp.getStore('user')
// 恢复登录状态
const stored = localStorage.getItem('user_info')
if (stored) {
const user = JSON.parse(stored)
userStore.state.isLoggedIn = true
userStore.state.username = user.username
}
// 路由守卫
router.beforeEach((to) => {
if (to.path !== '/login' && !userStore.state.isLoggedIn) {
return '/login'
}
return true
})
// 监听登出跳转
userStore.$subscribe((state) => {
if (!state.isLoggedIn) {
router.push('/login')
}
})17.6 useStorage Composable
在 TypeScript 中使用响应式存储:
import { useStorage, useLocalStorage, useSessionStorage } from 'vue-json-engine'
// 响应式 localStorage
const theme = useLocalStorage('theme', 'light')
// 响应式 sessionStorage
const token = useSessionStorage('token', '')
// 完整配置
const data = useStorage('key', defaultValue, {
storage: 'local',
listenToStorageEvents: true // 跨标签页同步
})特性:
- 自动 JSON 序列化/反序列化
- 响应式更新,修改值自动同步到存储
- 支持跨标签页同步(通过 storage event)
- 支持默认值
API 参考
创建应用
{
"id": "my-app",
"stores": [...],
"http": { "baseURL": "https://api.example.com" },
"messaging": { "connections": {...} },
"root": { ... }
}完整配置示例:
{
"id": "demo-app",
"stores": [
{
"id": "counter",
"state": { "count": 0 },
"actions": {
"increment": { "type": "increment", "target": "count" },
"decrement": { "type": "decrement", "target": "count" },
"reset": { "type": "reset", "target": "count" }
}
}
],
"http": { "baseURL": "" },
"components": [
{
"name": "MyComponent",
"props": ["title"],
"template": { "type": "element", "tag": "div", "children": [{ "type": "text", "content": { "type": "expression", "value": "title" } }] }
}
],
"router": { "mode": "hash", "routes": [...] },
"messaging": { "connections": { "ws": { "url": "wss://..." } } },
"root": { "type": "element", "tag": "div" }
}完整示例
计数器 + Todo + 表单
{
"id": "demo-app",
"stores": [
{
"id": "counter",
"state": { "count": 0 },
"getters": { "doubled": "count * 2" },
"actions": {
"increment": { "type": "increment", "target": "count" },
"decrement": { "type": "decrement", "target": "count" },
"reset": { "type": "reset", "target": "count" }
}
},
{
"id": "todos",
"state": {
"items": [],
"newTodo": ""
},
"getters": {
"remaining": "items.filter(t => !t.completed).length"
},
"actions": {
"addTodo": {
"type": "if",
"condition": "{{newTodo.trim()}}",
"then": [
{ "type": "push", "target": "items", "value": { "id": "{{Date.now()}}", "text": "{{newTodo.trim()}}", "completed": false } },
{ "type": "set", "target": "newTodo", "value": "" }
]
},
"removeTodo": {
"type": "remove",
"target": "items",
"by": { "key": "id", "value": "{{args[0]}}" }
},
"toggleTodo": "const t = items.find(x => x.id === args[0]); if (t) t.completed = !t.completed"
}
},
{
"id": "form",
"state": { "username": "", "email": "", "errors": {}, "message": "" },
"getters": { "isValid": "username.length >= 3 && email.includes('@')" },
"actions": {
"validateAndSubmit": {
"type": "sequence",
"steps": [
{ "type": "set", "target": "errors", "value": {} },
{ "type": "if", "condition": "{{username.length < 3}}", "then": [{ "type": "set", "target": "errors.username", "value": "用户名至少需要3个字符" }] },
{ "type": "if", "condition": "{{!email.includes('@')}}", "then": [{ "type": "set", "target": "errors.email", "value": "请输入有效的邮箱地址" }] },
{
"type": "if",
"condition": "{{Object.keys(errors).length === 0}}",
"then": [{ "type": "set", "target": "message", "value": "提交成功!用户名: {{username}}, 邮箱: {{email}}" }]
}
]
}
}
}
],
"root": {
"type": "element",
"tag": "div",
"props": { "class": "app" },
"children": [
{
"type": "element",
"tag": "h1",
"children": [{ "type": "text", "content": "Vue JSON Engine Demo" }]
},
{
"type": "element",
"tag": "section",
"children": [
{ "type": "element", "tag": "h2", "children": [{ "type": "text", "content": "计数器" }] },
{
"type": "element", "tag": "p",
"children": [
{ "type": "text", "content": "Count: " },
{ "type": "text", "content": { "type": "expression", "value": "counter.count" } }
]
},
{
"type": "element", "tag": "button",
"events": { "onClick": { "type": "handler", "action": "counter.increment" } },
"children": [{ "type": "text", "content": "+" }]
}
]
}
]
}
}开发指南
项目结构
vue-json-engine/
├── src/
│ ├── core/ # 核心引擎 (Vue 集成层)
│ │ ├── app.ts # 应用核心
│ │ ├── compiler.ts # JSON 编译器
│ │ ├── evaluator.ts # 表达式求值引擎
│ │ ├── events.ts # 事件处理
│ │ ├── parser.ts # JSON 解析器
│ │ ├── registry.ts # 组件注册
│ │ ├── renderer.ts # 渲染器
│ │ ├── sfc-converter.ts # Vue SFC → JSON 转换
│ │ └── reactivity.ts # 响应式工具
│ ├── app/ # 应用构建系统
│ │ ├── app.ts # 应用类
│ │ ├── builder.ts # 构建器
│ │ └── plugin.ts # 插件系统
│ ├── engine/ # 引擎核心
│ │ ├── expression-cache.ts # 表达式缓存 (LRU/FIFO/LFU/TTL)
│ │ ├── renderer.ts # 统一渲染器
│ │ └── filters/ # 内置过滤器 (10+ 类别)
│ ├── stores/ # 状态管理
│ │ ├── store.ts # Store 实现
│ │ ├── action-dispatcher.ts # Action DSL 执行器
│ │ └── store-manager.ts # Store 管理器
│ ├── router/ # 路由系统
│ │ ├── router.ts # 路由核心
│ │ └── components/ # 路由组件
│ ├── http/ # HTTP 客户端
│ │ ├── client.ts # HTTP 客户端
│ │ └── interceptors.ts # 拦截器
│ ├── messaging/ # 消息系统
│ │ └── ws-engine.ts # WebSocket 引擎
│ ├── remote/ # 远程配置
│ │ └── loader.ts # 配置加载器
│ ├── hmr/ # 热更新
│ │ └── client.ts # HMR 客户端
│ ├── converters/ # 转换器
│ │ └── sfc-converter.ts # SFC 转换器
│ ├── schema/ # Schema 驱动
│ │ ├── schema.json # JSON Schema 定义
│ │ ├── types.ts # Schema 类型
│ │ └── validator.ts # Schema 验证器
│ ├── components/ # Vue 组件
│ ├── composables/ # Vue Composables
│ ├── registry/ # 组件注册表
│ │ └── libraries/antd.ts # Ant Design 库
│ ├── types/ # 类型定义
│ └── index.ts # 入口文件
├── tests/
│ ├── core/ # 核心模块测试
│ ├── engine/ # 引擎测试
│ └── schema/ # Schema 测试
├── examples/
├── openspec/
├── package.json
├── tsconfig.json
└── vite.config.ts开发命令
# 开发模式
npm run dev
# 构建
npm run build
# 测试
npm run test
npm run test:watch
npm run test:coverage
# 类型检查
npm run typecheck
# 代码检查
npm run lint
npm run lint:fix类型定义
完整类型定义见 src/types/index.ts,主要包括:
- 节点类型:
JSONNode,JSONElement,JSONText,JSONComponent,JSONUIComponent,JSONIf,JSONFor - 表达式:
JSONExpression,JSONRef,JSONComputed - 事件:
JSONEventHandler,JSONEventModifier,JSONEventAction - Store:
JSONStore,JSONStoreDefinition,JSONStoreState,JSONStoreGetters,JSONStoreActions - Action DSL:
Action,ActionObject,SetAction,IncrementAction,PushAction,IfAction,HttpAction等 15 种动作类型 - 路由:
JSONRouter,JSONRoute,JSONRouterConfig,JSONRouteLocation - HTTP:
HTTPMethod,HTTPRequestConfig,HTTPResponse,HTTPError,JSONHTTPConfig - 组件:
JSONComponentDefinition,JSONComponentLibrary,ComponentRegistry - 插件:
JSONPlugin,JSONPluginHooks,JSONPluginExtensionPoints,ActionHandler
最佳实践
1. 状态设计
- 相关状态组织在同一 Store
- 避免过深嵌套
- 使用 getters 派生复杂计算
2. 组件拆分
- 复用逻辑封装为自定义组件
- 使用 UI 组件库加速开发
- 保持组件职责单一
3. 性能优化
- 大列表使用虚拟滚动
- 避免在 getters 中做重计算
- 合理使用表达式求值
4. 事件处理
- 使用修饰符简化代码
- 避免在事件中写复杂逻辑
- 复杂操作封装为 action
5. 插件使用
- 按需加载插件,避免引入不必要的依赖
- 自定义插件遵循命名规范(小写字母+连字符)
- 使用生命周期钩子处理初始化逻辑
- 将第三方库封装为插件提高复用性
