找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 48|回复: 0

Qt-Waterfall 模板替换原理

[复制链接]

14

主题

3

回帖

80

积分

注册会员

积分
80
发表于 2026-3-24 09:38:40 | 显示全部楼层 |阅读模式
  1. 核心概念

  2.   这是 Hippy/quicktvui 框架的一个数据驱动模板渲染机制,将 Vue 组件作为模板,通过 ${prop} 占位符实现数据绑定。

  3.   ---

  4.   1. 模板定义

  5.   在 Vue 组件中使用 ${prop} 语法定义占位符:

  6.    <!-- packages/quicktvui/src/waterfall/item/card-item.vue -->
  7.    <es-card-container
  8.      layout="${layout}"
  9.      flexStyle="${style}"
  10.      cardId="${cardId}"
  11.      focusScale="${cardPlaceHolder.focusScale}"
  12.      text="${title}"
  13.    />

  14.   语法特点:
  15.    - ${propName} - 直接属性引用
  16.    - ${obj.subProp} - 支持嵌套路径
  17.    - ${prop==true} - 支持表达式

  18.   ---

  19.   2. 数据结构

  20.   数据通过 JavaScript 对象传入,与占位符一一对应:

  21.    // 数据项定义
  22.    const item: QTWaterfallCardItem = {
  23.      _id: '1',
  24.      type: QTWaterfallItemType.QT_WATERFALL_ITEM_TYPE_CARD,
  25.      cardId: '1717748409857474561',
  26.      style: { width: 850, height: 400 },
  27.      cardPlaceHolder: { enable: true, radius: 100, focusScale: 1.2 },
  28.      decoration: { left: 90, top: 40 }
  29.    }

  30.   ---

  31.   3. 渲染流程

  32.    ┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
  33.    │  Vue 模板组件    │ ──▶ │  数据绑定引擎    │ ──▶ │  最终 DOM 元素   │
  34.    │  ${prop} 占位符  │     │  replacePlaceholders│     │  实际属性值      │
  35.    └─────────────────┘     └─────────────────┘     └─────────────────┘

  36.   Web 平台实现(QtFastListView.js):

  37.    // 1. 捕获子组件作为模板
  38.    insertChild(view, index) {
  39.      this._templateChildren.push({
  40.        dom: view.dom,
  41.        component: view,
  42.        type: view.props.type
  43.      })
  44.      view.dom.style.display = 'none' // 隐藏模板
  45.    }

  46.    // 2. 数据驱动渲染
  47.    _createItemFromData(itemData, index) {
  48.      // 克隆模板
  49.      const clonedNode = matchingTemplate.dom.cloneNode(true)

  50.      // 绑定数据
  51.      this._bindDataToNode(clonedNode, itemData)

  52.      return clonedNode
  53.    }

  54.    // 3. 占位符替换核心算法
  55.    _replacePlaceholders(str, data) {
  56.      return str.replace(/\$\{([^}]+)\}/g, (match, propPath) => {
  57.        // 支持嵌套路径: "style.fontSize" → data.style.fontSize
  58.        let value = propPath.split('.').reduce((obj, key) => {
  59.          return obj?.[key]
  60.        }, data)

  61.        return value !== undefined ? String(value) : match
  62.      })
  63.    }

  64.   ---

  65.   4. 特殊属性处理


  66.   ┌───────────────┬───────────────────────────────┐
  67.   │ 属性          │ 处理方式                      │
  68.   ├───────────────┼───────────────────────────────┤
  69.   │ flexStyle     │ 对象展开为 CSS 样式           │
  70.   │ list/listData │ 递归渲染子列表                │
  71.   │ textSize      │ 转换为 fontSize 样式          │
  72.   │ src           │ 支持 {url, uri, src} 对象解构 │
  73.   │ showIf        │ 条件渲染控制                  │
  74.   └───────────────┴───────────────────────────────┘

  75.    // flexStyle 处理示例
  76.    if (keyLower === 'flexstyle') {
  77.      const styleObj = this._extractValue(attrValue, data)
  78.      this._applyFlexStyleToElement(node, styleObj)
  79.      // { width: 850, height: 400 } → style="width:850px;height:400px"
  80.    }

  81.   ---

  82.   5. 类型匹配机制

  83.   通过 type 属性实现模板与数据的匹配:

  84.    <!-- 模板定义 -->
  85.    <qt-poster :type="10001" />    <!-- 海报类型 -->
  86.    <card-item :type="10003" />    <!-- 卡片类型 -->

  87.    // 数据项
  88.    const item = { type: 10003, ... } // 匹配 card-item 模板

  89.    // 匹配逻辑
  90.    let template = this._templateChildren.find(t => t.type === itemData.type)

  91.   ---

  92.   6. 单例模板

  93.   singleton 属性标记只渲染一次的模板:

  94.    <!-- 单例模板:只匹配一条数据,不克隆 -->
  95.    <header-view singleton :type="100" />

  96.    if (hasSingleton) {
  97.      this._singletonTemplates.push({ dom: node, type })
  98.      // 直接显示,不克隆
  99.    }

  100.   ---

  101.   架构图

  102.    ┌──────────────────────────────────────────────────────────────────┐
  103.    │                        QtWaterfall                               │
  104.    ├──────────────────────────────────────────────────────────────────┤
  105.    │  setSectionList([section1, section2, ...])                       │
  106.    │                                                                   │
  107.    │  ┌─────────────────────────────────────────────────────────────┐ │
  108.    │  │ Section (type: FLEX/CARD/PLUGIN...)                         │ │
  109.    │  │  ├── titleStyle: { fontSize: 50 }                           │ │
  110.    │  │  ├── itemList: [item1, item2, ...]                          │ │
  111.    │  │  └── cardId: "模板ID"                                        │ │
  112.    │  └─────────────────────────────────────────────────────────────┘ │
  113.    │                            │                                      │
  114.    │                            ▼                                      │
  115.    │  ┌─────────────────────────────────────────────────────────────┐ │
  116.    │  │ QtFastListView / tv-flex                                    │ │
  117.    │  │  ├── Template Children (隐藏)                               │ │
  118.    │  │  │    ├── <qt-poster type="10001"/>                        │ │
  119.    │  │  │    └── <card-item type="10003"/>                        │ │
  120.    │  │  └── Rendered Items (数据驱动克隆)                          │ │
  121.    │  │       ├── Item[0] → clone(template) + bind(data[0])        │ │
  122.    │  │       └── Item[1] → clone(template) + bind(data[1])        │ │
  123.    │  └─────────────────────────────────────────────────────────────┘ │
  124.    └──────────────────────────────────────────────────────────────────┘

  125.   ---

  126.   总结


  127.   ┌───────────┬───────────────────────────────────┐
  128.   │ 概念      │ 说明                              │
  129.   ├───────────┼───────────────────────────────────┤
  130.   │ 模板      │ Vue 组件,使用 ${prop} 定义占位符 │
  131.   │ 数据      │ JS 对象,属性路径与占位符对应     │
  132.   │ type      │ 匹配模板与数据的标识              │
  133.   │ 渲染      │ 克隆模板 → 替换占位符 → 插入 DOM  │
  134.   │ singleton │ 单例模板,不克隆,直接绑定数据    │
  135.   └───────────┴───────────────────────────────────┘


  136. ✦ 这种设计让 UI 模板可以完全复用,只需传入不同数据即可生成列表项,是典型的数据驱动视图模式。
复制代码




您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|QuickTVUI论坛

GMT+8, 2026-4-19 19:05 , Processed in 0.125349 second(s), 30 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表