🎨 自定义模板开发规范说明

📋 目录

1. 概述

自定义模板是MyCardPlus插件的核心功能,允许开发者创建完全自定义的卡片展示效果。本文档提供了详细的开发规范,确保模板的质量、可维护性和兼容性。

📖 文档目标

  • 提供标准化的开发流程
  • 确保模板的兼容性和稳定性
  • 提高开发效率和代码质量
  • 便于团队协作和代码维护

2. 开发原则

2.1 设计原则

2.2 技术原则

3. 模板结构规范

3.1 基本结构

基础模板结构
<!-- 卡片容器 --> <div class="custom-card"> <!-- 图片区域 --> <div class="card-image"> <img src="{{imageUrl}}" alt="{{title}}" /> <div class="card-badge">{{badgeText}}</div> </div> <!-- 内容区域 --> <div class="card-content"> <h3 class="card-title">{{title}}</h3> <p class="card-description">{{description}}</p> <div class="card-meta"> <span class="meta-item">{{meta1}}</span> <span class="meta-item">{{meta2}}</span> </div> </div> <!-- 操作区域 --> <div class="card-actions"> <button class="action-btn" onclick="handleAction('{{id}}')">操作</button> </div> </div>

3.2 区域划分

4. 命名规范

4.1 CSS类名规范

CSS类名规范示例
/* 卡片容器 */ .custom-card { } /* 图片区域 */ .card-image { } .card-image img { } .card-badge { } /* 内容区域 */ .card-content { } .card-title { } .card-description { } .card-meta { } .meta-item { } /* 操作区域 */ .card-actions { } .action-btn { } /* 状态区域 */ .card-status { } .status-badge { } /* 响应式类名 */ .card-image--mobile { } .card-content--tablet { }

4.2 变量命名规范

5. 数据绑定规范

5.1 模板变量语法

模板变量使用规范
<!-- 基础变量绑定 --> <div class="title">{{productName}}</div> <!-- 条件渲染 --> {{#if hasDiscount}} <div class="discount">{{discountText}}</div> {{/if}} <!-- 循环渲染 --> {{#each tags}} <span class="tag">{{this}}</span> {{/each}} <!-- 嵌套对象 --> <div class="user-info"> <span>{{user.name}}</span> <span>{{user.email}}</span> </div> <!-- 默认值 --> <div class="price">{{price || '暂无价格'}}</div>

5.2 字段映射配置

字段名 数据类型 格式设置 说明
productImage 文本 文本 商品图片URL
productName 文本 文本 商品名称
currentPrice 数字 货币 当前价格
ratingScore 数字 数字 评分分数
tags 文本 文本 标签数组(JSON格式)

6. 表单组件规范

🎯 表单组件功能概述

MyCardPlus插件支持在自定义模板中添加各种表单组件,用户输入的数据会自动收集并传递给活字格命令。支持所有卡片交互事件(单击、双击、右键、鼠标进入/离开、操作按钮)。

6.1 支持的输入组件类型

组件类型 HTML标签 数据类型 说明
文本输入框 <input type="text"> 字符串 单行文本输入
数字输入框 <input type="number"> 字符串 数字输入,可转换为数字类型
邮箱输入框 <input type="email"> 字符串 邮箱格式输入
多行文本域 <textarea> 字符串 多行文本输入
下拉选择框 <select> 字符串 从选项列表中选择
复选框 <input type="checkbox"> 布尔值 选中返回true,未选中返回false
单选框 <input type="radio"> 字符串 返回选中选项的value值

6.2 表单组件使用规范

⚠️ 重要:必须添加 data-field 属性

所有需要收集数据的表单组件都必须添加 data-field 属性,这是插件识别和收集数据的唯一标识。

表单组件使用示例
<!-- 文本输入框 --> <div class="form-group"> <label class="form-label">姓名:</label> <input type="text" class="form-input" data-field="userName" value="{{userName}}" placeholder="请输入姓名"> </div> <!-- 数字输入框 --> <div class="form-group"> <label class="form-label">年龄:</label> <input type="number" class="form-input" data-field="userAge" value="{{userAge}}" placeholder="请输入年龄"> </div> <!-- 邮箱输入框 --> <div class="form-group"> <label class="form-label">邮箱:</label> <input type="email" class="form-input" data-field="userEmail" value="{{userEmail}}" placeholder="请输入邮箱"> </div> <!-- 多行文本域 --> <div class="form-group"> <label class="form-label">备注:</label> <textarea class="form-textarea" data-field="userRemark" placeholder="请输入备注">{{userRemark}}</textarea> </div> <!-- 下拉选择框 --> <div class="form-group"> <label class="form-label">性别:</label> <select class="form-select" data-field="userGender"> <option value="">请选择性别</option> <option value="男" {{#if userGender == "男"}}selected{{/if}}>男</option> <option value="女" {{#if userGender == "女"}}selected{{/if}}>女</option> </select> </div> <!-- 复选框组 --> <div class="form-group"> <label class="form-label">爱好:</label> <div class="checkbox-group"> <div class="checkbox-item"> <input type="checkbox" data-field="hobby_reading" {{#if hobby_reading}}checked{{/if}}> <span>阅读</span> </div> <div class="checkbox-item"> <input type="checkbox" data-field="hobby_sports" {{#if hobby_sports}}checked{{/if}}> <span>运动</span> </div> <div class="checkbox-item"> <input type="checkbox" data-field="hobby_music" {{#if hobby_music}}checked{{/if}}> <span>音乐</span> </div> </div> </div> <!-- 单选框组 --> <div class="form-group"> <label class="form-label">学历:</label> <div class="radio-group"> <div class="radio-item"> <input type="radio" data-field="education" value="高中" name="education" {{#if education == "高中"}}checked{{/if}}> <span>高中</span> </div> <div class="radio-item"> <input type="radio" data-field="education" value="大专" name="education" {{#if education == "大专"}}checked{{/if}}> <span>大专</span> </div> <div class="radio-item"> <input type="radio" data-field="education" value="本科" name="education" {{#if education == "本科"}}checked{{/if}}> <span>本科</span> </div> </div> </div>

6.3 表单组件CSS样式规范

表单组件CSS样式
/* 表单组样式 */ .form-group { margin-bottom: 16px; } .form-label { display: block; font-size: 14px; font-weight: 500; color: #333; margin-bottom: 6px; } /* 输入框样式 */ .form-input, .form-select, .form-textarea { width: 100%; padding: 10px 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; transition: border-color 0.3s, box-shadow 0.3s; box-sizing: border-box; } .form-input:focus, .form-select:focus, .form-textarea:focus { outline: none; border-color: #007bff; box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.1); } .form-textarea { resize: vertical; min-height: 80px; } /* 复选框和单选框组样式 */ .checkbox-group, .radio-group { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 6px; } .checkbox-item, .radio-item { display: flex; align-items: center; gap: 6px; font-size: 14px; color: #555; } .checkbox-item input[type="checkbox"], .radio-item input[type="radio"] { margin: 0; width: 16px; height: 16px; } /* 响应式设计 */ @media (max-width: 768px) { .checkbox-group, .radio-group { flex-direction: column; gap: 8px; } .form-input, .form-select, .form-textarea { padding: 8px 10px; font-size: 16px; /* 移动端避免缩放 */ } }

6.4 数据收集和传递机制

✅ 自动数据收集

插件会自动收集所有带有 data-field 属性的表单组件数据,无需额外JavaScript代码。

6.4.1 支持的事件类型

⚠️ 重要:事件冲突处理

当同时设置了卡片的单击命令和按钮的操作命令时,点击操作按钮会同时触发两个命令。

这是因为按钮位于卡片内部,点击按钮时会冒泡到卡片,导致同时触发按钮的操作命令和卡片的单击命令。

解决方案:
  1. 在按钮上阻止事件冒泡:在按钮的HTML中添加 onclick="event.stopPropagation();"
  2. 在活字格命令中区分事件来源:通过 action 参数判断是按钮点击还是卡片点击
  3. 避免同时设置冲突的命令:如果不需要卡片单击功能,可以不设置卡片单击命令

6.4.2 在活字格命令中获取数据

活字格命令中使用表单数据(包含事件冲突处理)
// 获取表单数据 const formData = Forguncy.Helper.SpecialName.getSpecialNameValue("formData"); const action = Forguncy.Helper.SpecialName.getSpecialNameValue("action"); const cardArray = Forguncy.Helper.SpecialName.getSpecialNameValue("cardArray"); const cardIndex = Forguncy.Helper.SpecialName.getSpecialNameValue("cardIndex"); // 事件冲突处理:通过action参数区分事件来源 if (action && action !== "") { // 这是按钮操作事件 console.log("按钮操作事件:", action); switch (action) { case "save": console.log("保存用户信息:", { name: formData.userName, age: formData.userAge, email: formData.userEmail, remark: formData.userRemark, gender: formData.userGender, hobbies: { reading: formData.hobby_reading, sports: formData.hobby_sports, music: formData.hobby_music }, education: formData.education }); // 合并原始数据和用户输入数据 const mergedData = { ...cardArray, ...formData }; console.log("完整数据:", mergedData); // 执行保存逻辑... break; case "preview": console.log("预览数据:", formData); // 执行预览逻辑... break; case "cancel": console.log("取消操作"); // 执行取消逻辑... break; default: console.log("未知按钮操作:", action); break; } } else { // 这是卡片点击事件(action为空或undefined) console.log("卡片点击事件"); console.log("当前表单数据:", formData); console.log("卡片数据:", cardArray); console.log("卡片索引:", cardIndex); // 执行卡片点击逻辑... // 例如:显示详情、编辑模式等 }

6.5 表单组件最佳实践

  • 字段命名规范:使用有意义的字段名,如 userNameproductPrice
  • 默认值设置:使用模板变量为输入组件设置默认值,如 value="{{userName}}"
  • 占位符文本:为输入组件添加 placeholder 属性,提供用户输入提示
  • 表单验证:在活字格命令中进行数据验证,确保数据完整性
  • 错误处理:处理表单数据为空或格式不正确的情况
  • 用户体验:使用合适的输入类型和样式,提高用户输入体验
  • ⚠️ 注意事项

    • 字段名唯一性:确保每个 data-field 的值在卡片内是唯一的
    • 数据类型:复选框返回布尔值,其他组件返回字符串
    • 单选框组:同一组的单选框必须使用相同的 name 属性
    • 数据安全:在活字格命令中验证和清理用户输入数据
    • 兼容性:确保表单组件在不同浏览器中正常工作
    • 事件冲突:点击操作按钮会同时触发按钮命令和卡片单击命令,需要在按钮上添加 onclick="event.stopPropagation();" 或在命令中区分事件来源

    6.6 完整表单模板示例

    用户信息编辑卡片模板

    完整表单模板示例
    <!-- 用户信息编辑卡片 --> <div class="user-edit-card"> <!-- 头像区域 --> <div class="avatar-section"> <img src="{{userAvatar}}" alt="用户头像" class="user-avatar"> <div class="edit-badge">编辑模式</div> </div> <!-- 表单区域 --> <div class="form-section"> <h3 class="form-title">用户信息编辑</h3> <!-- 基本信息 --> <div class="form-group"> <label class="form-label">姓名:</label> <input type="text" class="form-input" data-field="userName" value="{{userName}}" placeholder="请输入姓名"> </div> <div class="form-group"> <label class="form-label">年龄:</label> <input type="number" class="form-input" data-field="userAge" value="{{userAge}}" placeholder="请输入年龄"> </div> <div class="form-group"> <label class="form-label">邮箱:</label> <input type="email" class="form-input" data-field="userEmail" value="{{userEmail}}" placeholder="请输入邮箱"> </div> <div class="form-group"> <label class="form-label">性别:</label> <select class="form-select" data-field="userGender"> <option value="">请选择性别</option> <option value="男" {{#if userGender == "男"}}selected{{/if}}>男</option> <option value="女" {{#if userGender == "女"}}selected{{/if}}>女</option> </select> </div> <div class="form-group"> <label class="form-label">学历:</label> <div class="radio-group"> <div class="radio-item"> <input type="radio" data-field="education" value="高中" name="education" {{#if education == "高中"}}checked{{/if}}> <span>高中</span> </div> <div class="radio-item"> <input type="radio" data-field="education" value="大专" name="education" {{#if education == "大专"}}checked{{/if}}> <span>大专</span> </div> <div class="radio-item"> <input type="radio" data-field="education" value="本科" name="education" {{#if education == "本科"}}checked{{/if}}> <span>本科</span> </div> </div> </div> <div class="form-group"> <label class="form-label">爱好:</label> <div class="checkbox-group"> <div class="checkbox-item"> <input type="checkbox" data-field="hobby_reading" {{#if hobby_reading}}checked{{/if}}> <span>阅读</span> </div> <div class="checkbox-item"> <input type="checkbox" data-field="hobby_sports" {{#if hobby_sports}}checked{{/if}}> <span>运动</span> </div> <div class="checkbox-item"> <input type="checkbox" data-field="hobby_music" {{#if hobby_music}}checked{{/if}}> <span>音乐</span> </div> </div> </div> <div class="form-group"> <label class="form-label">备注:</label> <textarea class="form-textarea" data-field="userRemark" placeholder="请输入备注信息">{{userRemark}}</textarea> </div> <!-- 操作按钮 --> <div class="action-buttons"> <button class="btn btn-success" data-action="save" onclick="event.stopPropagation();">保存</button> <button class="btn btn-secondary" data-action="preview" onclick="event.stopPropagation();">预览</button> <button class="btn btn-primary" data-action="publish" onclick="event.stopPropagation();">发布</button> </div> </div> </div>

    7. 图片处理规范

    7.1 图片显示方式

    图片处理最佳实践
    <!-- 推荐方式:手动编写img标签 --> <div class="card-image"> <img src="{{productImage}}" alt="{{productName}}" style="max-width: 100%; height: auto; display: block;" /> <div class="card-badge">{{badgeText}}</div> </div> <!-- 背景图片方式 --> <div class="card-image" style="background-image: url('{{productImage}}'); background-size: cover; background-position: center;"> <div class="card-badge">{{badgeText}}</div> </div> <!-- 响应式图片 --> <img src="{{productImage}}" alt="{{productName}}" style="width: 100%; height: 200px; object-fit: cover;" />

    7.2 支持的图片格式

    ⚠️ 注意事项

    • 图片字段建议设置为"文本"格式,在模板中手动编写img标签
    • 确保图片路径正确,避免404错误
    • 使用alt属性提供图片描述,提高可访问性
    • 考虑图片加载失败的情况,提供备用方案

    8. CSS样式规范

    8.1 基础样式规范

    CSS样式规范示例
    /* 卡片容器 */ .custom-card { background: white; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 12px rgba(0,0,0,0.08); transition: all 0.3s ease; border: 1px solid #f0f0f0; margin-bottom: 16px; } /* 悬停效果 */ .custom-card:hover { transform: translateY(-4px); box-shadow: 0 8px 25px rgba(0,0,0,0.15); } /* 图片区域 */ .card-image { position: relative; height: 200px; overflow: hidden; background: #f8f8f8; } .card-image img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.3s ease; } /* 内容区域 */ .card-content { padding: 16px; } .card-title { font-size: 16px; font-weight: 600; color: #333; margin-bottom: 8px; line-height: 1.4; } /* 响应式设计 */ @media (max-width: 768px) { .card-image { height: 150px; } .card-content { padding: 12px; } .card-title { font-size: 14px; } }

    8.2 样式最佳实践

    9. 交互功能规范

    9.1 事件处理

    交互功能示例
    <!-- 按钮点击事件 --> <button class="action-btn" onclick="handleAction('{{productId}}')"> 添加到购物车 </button> <!-- 卡片点击事件 --> <div class="custom-card" onclick="handleCardClick('{{productId}}')"> <!-- 卡片内容 --> </div> <!-- 图片点击事件 --> <img src="{{productImage}}" onclick="handleImageClick('{{productId}}')" style="cursor: pointer;" /> <!-- JavaScript函数 --> <script> function handleAction(productId) { console.log('处理操作:', productId); // 实现具体逻辑 } function handleCardClick(productId) { console.log('卡片点击:', productId); // 实现具体逻辑 } function handleImageClick(productId) { console.log('图片点击:', productId); // 实现具体逻辑 } </script>

    9.2 交互设计原则

    9.3 事件冲突处理

    ⚠️ 重要:事件冒泡冲突

    当卡片内部包含可点击元素(如按钮、链接)时,点击这些元素会同时触发元素自身的点击事件和卡片的点击事件,导致事件冲突。

    常见冲突场景:
    • 卡片设置了单击命令,内部按钮也设置了操作命令
    • 卡片设置了双击命令,内部元素设置了单击命令
    • 多个嵌套的可点击元素
    解决方案:
    事件冲突处理示例
    <!-- 方案1:在按钮上阻止事件冒泡 --> <div class="card" onclick="handleCardClick()"> <h3>{{title}}</h3> <p>{{description}}</p> <button onclick="event.stopPropagation(); handleButtonClick()"> 操作按钮 </button> </div> <!-- 方案2:在活字格命令中区分事件来源 --> <div class="card"> <h3>{{title}}</h3> <p>{{description}}</p> <button data-action="save">保存</button> <button data-action="delete">删除</button> </div> <!-- JavaScript处理 --> <script> // 在活字格命令中 const action = Forguncy.Helper.SpecialName.getSpecialNameValue("action"); if (action && action !== "") { // 按钮操作事件 console.log("按钮操作:", action); } else { // 卡片点击事件 console.log("卡片点击"); } </script> <!-- 方案3:使用事件委托 --> <div class="card" onclick="handleCardEvent(event)"> <h3>{{title}}</h3> <p>{{description}}</p> <button data-action="save">保存</button> <button data-action="delete">删除</button> </div> <script> function handleCardEvent(event) { const target = event.target; if (target.tagName === 'BUTTON') { // 按钮点击 const action = target.getAttribute('data-action'); console.log("按钮操作:", action); event.stopPropagation(); } else { // 卡片点击 console.log("卡片点击"); } } </script>

    10. 性能优化规范

    10.1 性能优化策略

    10.2 代码优化示例

    性能优化代码示例
    /* 使用transform代替top/left */ .card-badge { position: absolute; top: 8px; left: 8px; transform: translateZ(0); /* 启用硬件加速 */ } /* 使用will-change优化动画 */ .custom-card { will-change: transform; transition: transform 0.3s ease; } /* 图片懒加载 */ <img src="{{productImage}}" loading="lazy" alt="{{productName}}" /> /* 防抖处理 */ function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } const debouncedHandleAction = debounce(handleAction, 300);

    11. 测试规范

    11.1 测试检查清单

  • 模板在不同数据情况下正常显示
  • 图片正确加载和显示
  • 响应式布局在不同屏幕尺寸下正常
  • 交互功能正常工作
  • 错误数据得到正确处理
  • 性能表现良好
  • 浏览器兼容性测试通过
  • 无障碍访问功能正常
  • 11.2 测试数据准备

    测试数据示例
    // 正常数据测试 const normalData = { productImage: "https://example.com/image.jpg", productName: "测试商品", currentPrice: 99.99, ratingScore: 4.5 }; // 边界数据测试 const edgeData = { productImage: "", // 空图片 productName: "", // 空标题 currentPrice: 0, // 零价格 ratingScore: null // 空评分 }; // 异常数据测试 const errorData = { productImage: "invalid-url", productName: null, currentPrice: "invalid-price", ratingScore: "invalid-score" };

    12. 完整示例

    12.1 商品卡片模板示例

    完整模板代码

    商品卡片完整示例
    <!-- 商品卡片模板 --> <div class="product-card"> <!-- 图片区域 --> <div class="product-image"> <img src="{{productImage}}" alt="{{productName}}" style="max-width: 100%; height: auto; display: block;" /> {{#if badgeText}} <div class="product-badge">{{badgeText}}</div> {{/if}} <button class="add-to-cart" onclick="addToCart('{{productId}}')">+</button> </div> <!-- 内容区域 --> <div class="product-content"> <h3 class="product-title">{{productName}}</h3> {{#if ratingScore}} <div class="product-rating"> <span class="rating-stars">{{ratingStars}}</span> <span class="rating-score">{{ratingScore}}</span> {{#if ratingCount}} <span class="rating-count">({{ratingCount}}条评价)</span> {{/if}} </div> {{/if}} {{#if tags}} <div class="product-tags"> {{#each tags}} <span class="product-tag">{{this}}</span> {{/each}} </div> {{/if}} <div class="product-price-section"> <div class="product-price"> <span class="current-price">¥{{currentPrice}}</span> {{#if originalPrice}} <span class="original-price">¥{{originalPrice}}</span> {{/if}} </div> {{#if discount}} <span class="discount">{{discount}}</span> {{/if}} </div> {{#if deliveryTime}} <div class="delivery-info"> <div class="delivery-time"> <span>🕐</span> <span>{{deliveryTime}}</span> </div> {{#if deliveryFee}} <div class="delivery-fee"> <span>🚚</span> <span>配送费¥{{deliveryFee}}</span> </div> {{/if}} </div> {{/if}} </div> </div> <!-- CSS样式 --> <style> .product-card { background: white; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 12px rgba(0,0,0,0.08); transition: all 0.3s ease; border: 1px solid #f0f0f0; margin-bottom: 16px; } .product-card:hover { transform: translateY(-4px); box-shadow: 0 8px 25px rgba(0,0,0,0.15); } .product-image { position: relative; height: 200px; overflow: hidden; background: #f8f8f8; } .product-image img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.3s ease; } .product-card:hover .product-image img { transform: scale(1.05); } .product-badge { position: absolute; top: 8px; left: 8px; background: #ff6b35; color: white; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: 500; } .add-to-cart { position: absolute; bottom: 8px; right: 8px; background: #ff6b35; color: white; border: none; border-radius: 50%; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; cursor: pointer; font-size: 18px; transition: all 0.3s ease; } .add-to-cart:hover { background: #e55a2b; transform: scale(1.1); } .product-content { padding: 16px; } .product-title { font-size: 16px; font-weight: 600; color: #333; margin-bottom: 8px; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .product-rating { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; } .rating-stars { color: #ff6b35; font-size: 14px; } .rating-score { color: #666; font-size: 14px; } .rating-count { color: #999; font-size: 12px; } .product-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; } .product-tag { background: #f8f8f8; color: #666; padding: 2px 6px; border-radius: 3px; font-size: 11px; } .product-price-section { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .product-price { display: flex; align-items: baseline; gap: 4px; } .current-price { font-size: 18px; font-weight: 700; color: #ff6b35; } .original-price { font-size: 14px; color: #999; text-decoration: line-through; } .discount { background: #ff6b35; color: white; padding: 2px 6px; border-radius: 3px; font-size: 11px; font-weight: 500; } .delivery-info { display: flex; justify-content: space-between; align-items: center; font-size: 12px; color: #666; padding-top: 12px; border-top: 1px solid #f0f0f0; } .delivery-time, .delivery-fee { display: flex; align-items: center; gap: 4px; } /* 响应式设计 */ @media (max-width: 768px) { .product-image { height: 150px; } .product-content { padding: 12px; } .product-title { font-size: 14px; } .current-price { font-size: 16px; } } </style> <!-- JavaScript功能 --> <script> function addToCart(productId) { console.log('添加到购物车:', productId); // 实现购物车逻辑 showToast(`商品 ${productId} 已添加到购物车!`); } function showToast(message) { const toast = document.createElement('div'); toast.textContent = message; toast.style.cssText = ` position: fixed; top: 20px; right: 20px; background: #28a745; color: white; padding: 12px 20px; border-radius: 6px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 1000; font-size: 14px; transition: all 0.3s ease; `; document.body.appendChild(toast); setTimeout(() => { toast.style.opacity = '0'; toast.style.transform = 'translateX(100%)'; setTimeout(() => { document.body.removeChild(toast); }, 300); }, 2000); } </script>

    12.2 字段映射配置

    字段名 数据类型 格式设置 是否必填 说明
    productImage 文本 文本 商品图片URL
    productName 文本 文本 商品名称
    productId 文本 文本 商品ID
    badgeText 文本 文本 商品标签
    ratingStars 文本 文本 星级评分
    ratingScore 数字 数字 评分分数
    ratingCount 数字 数字 评价数量
    tags 文本 文本 标签数组
    currentPrice 数字 货币 当前价格
    originalPrice 数字 货币 原价
    discount 文本 文本 折扣信息
    deliveryTime 文本 文本 配送时间
    deliveryFee 数字 货币 配送费

    🎉 开发完成

    恭喜!您已经了解了自定义模板的完整开发规范。按照这些规范开发模板,将确保代码质量、可维护性和用户体验。