commit 13a770d56d0fd87170f61a79929c1098cde15161 Author: yumoqing Date: Tue May 19 01:17:14 2026 +0800 Initial bricks miniprogram implementation diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..d32a8fe --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,34 @@ +# Bricks 微信小程序 - 设计文档 + +## 架构 +JSON → BricksParser → setData → WXML 递归模板 → 小程序原生渲染 + +## 核心文件 +- `utils/parser.js` - JSON 解析引擎 +- `utils/http.js` - wx.request 封装 +- `utils/renderer.js` - 事件分发 +- `components/brick/brick.wxml` - 递归模板 (template is="brick") +- `pages/bricks/bricks.js` - 页面入口 + +## 组件映射 +| Bricks Widget | 小程序组件 | +|--------------|----------| +| Text/Title1-6 | `` | +| HBox/VBox | `` | +| Filler | `` | +| KeyinText/Input | `` | +| Image | `` | +| Running | `` | +| VScrollPanel/HScrollPanel | `` | +| Modal/Popup | `` | + +## 事件系统 +- urlwidget → wx.navigateTo +- method → Page 方法调用 +- event → bindtap/catchtap +- script → wx.request 服务端 RPC + +## 限制 +- 包体积 2MB → 分包加载 +- WXML 不支持 innerHTML → 用 template 递归 +- Markdown/Html → 需引入 mp-html 插件 diff --git a/app.js b/app.js new file mode 100644 index 0000000..6985418 --- /dev/null +++ b/app.js @@ -0,0 +1,36 @@ +App({ + globalData: { + baseUrl: '', + authToken: '', + bricks: null + }, + onLaunch() { + // 加载 bricks 解析引擎 + const { BricksParser } = require('./utils/parser') + this.globalData.bricks = new BricksParser() + }, + // 工具函数: 对应 JS 版 bricks.extend + extend(target, source) { + for (let key in source) { + if (source.hasOwnProperty(key)) { + if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) { + target[key] = this.extend(target[key] || {}, source[key]) + } else { + target[key] = source[key] + } + } + } + return target + }, + // 模板变量替换: 对应 bricks.obj_fmtstr + fmt(str, data) { + return str.replace(/\{\{([^}]+)\}\}/g, (match, key) => { + return data[key] !== undefined ? data[key] : match + }) + }, + // entire_url: 拼接 baseUrl + entireUrl(path) { + const base = this.globalData.baseUrl || '' + return base.replace(/\/$/, '') + '/' + path.replace(/^\//, '') + } +}) diff --git a/app.json b/app.json new file mode 100644 index 0000000..d2308a6 --- /dev/null +++ b/app.json @@ -0,0 +1,11 @@ +{ + "pages": [ + "pages/bricks/bricks" + ], + "window": { + "navigationBarTitleText": "Bricks", + "navigationBarBackgroundColor": "#ffffff" + }, + "style": "v2", + "sitemapLocation": "sitemap.json" +} diff --git a/app.wxss b/app.wxss new file mode 100644 index 0000000..a3ec8b2 --- /dev/null +++ b/app.wxss @@ -0,0 +1,84 @@ +page { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + font-size: 28rpx; + color: #333; +} + +/* Flex 布局 - 对应 HBox/VBox */ +.flex-row { + display: flex; + flex-direction: row; + align-items: flex-start; +} +.flex-col { + display: flex; + flex-direction: column; +} +.flex-fill { + flex: 1; +} +.flex-center { + justify-content: center; + align-items: center; +} +.flex-between { + justify-content: space-between; +} + +/* 标题 - 对应 Title1-6 */ +.title-1 { font-size: 64rpx; font-weight: bold; } +.title-2 { font-size: 56rpx; font-weight: bold; } +.title-3 { font-size: 48rpx; font-weight: semi-bold; } +.title-4 { font-size: 40rpx; font-weight: medium; } +.title-5 { font-size: 36rpx; font-weight: medium; } +.title-6 { font-size: 32rpx; font-weight: medium; } + +/* 文本 */ +.text-content { padding: 16rpx 32rpx; line-height: 1.6; } + +/* 输入框 */ +.input-field { + border: 1rpx solid #ddd; + border-radius: 8rpx; + padding: 16rpx 24rpx; + margin: 16rpx 32rpx; + font-size: 28rpx; +} + +/* Loading - 对应 Running */ +.loading { + display: flex; + justify-content: center; + align-items: center; + padding: 40rpx; +} + +/* 图片 */ +.image-content { width: 100%; height: auto; } +.icon-content { width: 48rpx; height: 48rpx; } + +/* 滚动面板 */ +.scroll-panel { width: 100%; height: 100%; } + +/* Modal */ +.modal-overlay { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + background: rgba(0,0,0,0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 999; +} +.modal-content { + background: #fff; + border-radius: 16rpx; + padding: 32rpx; + max-width: 80%; +} + +/* Menu */ +.menu-item { + padding: 24rpx 32rpx; + border-bottom: 1rpx solid #eee; +} diff --git a/components/brick/brick.js b/components/brick/brick.js new file mode 100644 index 0000000..ff94caf --- /dev/null +++ b/components/brick/brick.js @@ -0,0 +1,27 @@ +/** + * Bricks 递归组件逻辑 + */ +Component({ + properties: { + item: { + type: Object, + value: {} + } + }, + methods: { + onEvent(e) { + const dataset = e.currentTarget.dataset + const { actiontype, target, methodname, url, script } = dataset + this.triggerEvent('bricksaction', { actiontype, target, methodname, url, script, event: e }) + }, + onInput(e) { + this.triggerEvent('inputchange', { value: e.detail.value, widget: this.data.item }) + }, + onCloseModal(e) { + this.triggerEvent('modalclose') + }, + stopPropagation() { + // 阻止冒泡 + } + } +}) diff --git a/components/brick/brick.json b/components/brick/brick.json new file mode 100644 index 0000000..a89ef4d --- /dev/null +++ b/components/brick/brick.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} diff --git a/components/brick/brick.wxml b/components/brick/brick.wxml new file mode 100644 index 0000000..727c942 --- /dev/null +++ b/components/brick/brick.wxml @@ -0,0 +1,117 @@ + +