|
|
- 核心概念
- 这是 Hippy/quicktvui 框架的一个数据驱动模板渲染机制,将 Vue 组件作为模板,通过 ${prop} 占位符实现数据绑定。
- ---
- 1. 模板定义
- 在 Vue 组件中使用 ${prop} 语法定义占位符:
- <!-- packages/quicktvui/src/waterfall/item/card-item.vue -->
- <es-card-container
- layout="${layout}"
- flexStyle="${style}"
- cardId="${cardId}"
- focusScale="${cardPlaceHolder.focusScale}"
- text="${title}"
- />
- 语法特点:
- - ${propName} - 直接属性引用
- - ${obj.subProp} - 支持嵌套路径
- - ${prop==true} - 支持表达式
- ---
- 2. 数据结构
- 数据通过 JavaScript 对象传入,与占位符一一对应:
- // 数据项定义
- const item: QTWaterfallCardItem = {
- _id: '1',
- type: QTWaterfallItemType.QT_WATERFALL_ITEM_TYPE_CARD,
- cardId: '1717748409857474561',
- style: { width: 850, height: 400 },
- cardPlaceHolder: { enable: true, radius: 100, focusScale: 1.2 },
- decoration: { left: 90, top: 40 }
- }
- ---
- 3. 渲染流程
- ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
- │ Vue 模板组件 │ ──▶ │ 数据绑定引擎 │ ──▶ │ 最终 DOM 元素 │
- │ ${prop} 占位符 │ │ replacePlaceholders│ │ 实际属性值 │
- └─────────────────┘ └─────────────────┘ └─────────────────┘
- Web 平台实现(QtFastListView.js):
- // 1. 捕获子组件作为模板
- insertChild(view, index) {
- this._templateChildren.push({
- dom: view.dom,
- component: view,
- type: view.props.type
- })
- view.dom.style.display = 'none' // 隐藏模板
- }
- // 2. 数据驱动渲染
- _createItemFromData(itemData, index) {
- // 克隆模板
- const clonedNode = matchingTemplate.dom.cloneNode(true)
- // 绑定数据
- this._bindDataToNode(clonedNode, itemData)
- return clonedNode
- }
- // 3. 占位符替换核心算法
- _replacePlaceholders(str, data) {
- return str.replace(/\$\{([^}]+)\}/g, (match, propPath) => {
- // 支持嵌套路径: "style.fontSize" → data.style.fontSize
- let value = propPath.split('.').reduce((obj, key) => {
- return obj?.[key]
- }, data)
- return value !== undefined ? String(value) : match
- })
- }
- ---
- 4. 特殊属性处理
- ┌───────────────┬───────────────────────────────┐
- │ 属性 │ 处理方式 │
- ├───────────────┼───────────────────────────────┤
- │ flexStyle │ 对象展开为 CSS 样式 │
- │ list/listData │ 递归渲染子列表 │
- │ textSize │ 转换为 fontSize 样式 │
- │ src │ 支持 {url, uri, src} 对象解构 │
- │ showIf │ 条件渲染控制 │
- └───────────────┴───────────────────────────────┘
- // flexStyle 处理示例
- if (keyLower === 'flexstyle') {
- const styleObj = this._extractValue(attrValue, data)
- this._applyFlexStyleToElement(node, styleObj)
- // { width: 850, height: 400 } → style="width:850px;height:400px"
- }
- ---
- 5. 类型匹配机制
- 通过 type 属性实现模板与数据的匹配:
- <!-- 模板定义 -->
- <qt-poster :type="10001" /> <!-- 海报类型 -->
- <card-item :type="10003" /> <!-- 卡片类型 -->
- // 数据项
- const item = { type: 10003, ... } // 匹配 card-item 模板
- // 匹配逻辑
- let template = this._templateChildren.find(t => t.type === itemData.type)
- ---
- 6. 单例模板
- singleton 属性标记只渲染一次的模板:
- <!-- 单例模板:只匹配一条数据,不克隆 -->
- <header-view singleton :type="100" />
- if (hasSingleton) {
- this._singletonTemplates.push({ dom: node, type })
- // 直接显示,不克隆
- }
- ---
- 架构图
- ┌──────────────────────────────────────────────────────────────────┐
- │ QtWaterfall │
- ├──────────────────────────────────────────────────────────────────┤
- │ setSectionList([section1, section2, ...]) │
- │ │
- │ ┌─────────────────────────────────────────────────────────────┐ │
- │ │ Section (type: FLEX/CARD/PLUGIN...) │ │
- │ │ ├── titleStyle: { fontSize: 50 } │ │
- │ │ ├── itemList: [item1, item2, ...] │ │
- │ │ └── cardId: "模板ID" │ │
- │ └─────────────────────────────────────────────────────────────┘ │
- │ │ │
- │ ▼ │
- │ ┌─────────────────────────────────────────────────────────────┐ │
- │ │ QtFastListView / tv-flex │ │
- │ │ ├── Template Children (隐藏) │ │
- │ │ │ ├── <qt-poster type="10001"/> │ │
- │ │ │ └── <card-item type="10003"/> │ │
- │ │ └── Rendered Items (数据驱动克隆) │ │
- │ │ ├── Item[0] → clone(template) + bind(data[0]) │ │
- │ │ └── Item[1] → clone(template) + bind(data[1]) │ │
- │ └─────────────────────────────────────────────────────────────┘ │
- └──────────────────────────────────────────────────────────────────┘
- ---
- 总结
- ┌───────────┬───────────────────────────────────┐
- │ 概念 │ 说明 │
- ├───────────┼───────────────────────────────────┤
- │ 模板 │ Vue 组件,使用 ${prop} 定义占位符 │
- │ 数据 │ JS 对象,属性路径与占位符对应 │
- │ type │ 匹配模板与数据的标识 │
- │ 渲染 │ 克隆模板 → 替换占位符 → 插入 DOM │
- │ singleton │ 单例模板,不克隆,直接绑定数据 │
- └───────────┴───────────────────────────────────┘
- ✦ 这种设计让 UI 模板可以完全复用,只需传入不同数据即可生成列表项,是典型的数据驱动视图模式。
复制代码
|
|