前言
在小程序开发中,经常会遇到页面多处重复展示相同结构的 UI,比如列表卡片、信息条目。如果重复写多份相同 wxml 代码,代码冗余、后期维护麻烦。小程序提供<template>模板,可以把重复 UI 结构封装,一处定义,多处复用。
本篇是课堂案例 3.9,基础需求:封装学生、教师模板;拓展作业:新增奥运冠军模板,展示冠军姓名与参赛项目,完整演示模板定义、导入、传参、动态渲染。
官方文档参考:模板片段 | 微信开放文档
项目预览效果
页面标题:模板的定义和引用 依次渲染:
- 3 条学生信息卡片
- 3 条教师信息卡片
- 3 条奥运冠军信息卡片(作业新增部分) 每一条信息之间使用分割线隔开,结构统一,数据各自独立。
项目目录结构
模板
├─ template
│ └─ template.wxml # 存放student、teacher、champion三个模板定义
├─ pages
│ └─ index
│ ├─ index.js
│ ├─ index.wxml
│ ├─ index.wxss
│ └─ index.json
├─ app.js
├─ app.json
└─ app.wxss
一、模板定义 template/template.wxml
使用<template name="模板名">封装 UI 结构,name 是模板唯一标识,后续引用时靠这个名字匹配。
<!--template.wxml-->
<template name="student">
<view>姓名:{{name}}</view>
<view>年龄:{{age}}</view>
<view>所学专业:{{major}}</view>
</template>
<template name="teacher">
<view>姓名:{{name}}</view>
<view>年龄:{{age}}</view>
<view>讲授课程:{{course}}</view>
</template>
<!--作业拓展:奥运冠军模板-->
<template name="champion">
<view>奥运冠军姓名:{{name}}</view>
<view>项目:{{sport}}</view>
</template>
重点:模板内部只能使用传入的数据,不能直接读取页面 Page 的 data。
二、页面视图 pages/index/index.wxml
- <import src="相对路径"/>:导入外部 wxml 模板文件,只引入 template 片段
- <template is="模板名" data="{{...对象}}"/>:使用模板,...为对象展开语法
- is属性既可以写固定字符串,也可以绑定变量动态切换模板
<!--index.wxml-->
<view class="box">
<view class="title">模板的定义和引用</view>
<!--导入外部模板文件,重点:pages/index下,向上两层找到template文件夹-->
<import src="../../template/template.wxml" />
<!--动态指定模板-->
<template is="{{temp01}}" data="{{...student01}}" />
<view>------------------------------</view>
<template is="student" data="{{...student02}}" />
<view>------------------------------</view>
<!--直接字面量传参,不借助data对象-->
<template is="student" data="{{name:'杨同学', age:21, major:'人工智能'}}" />
<view>------------------------------</view>
<template is="{{temp02}}" data="{{...teacher01}}" />
<view>------------------------------</view>
<template is="teacher" data="{{...teacher02}}" />
<view>------------------------------</view>
<template is="teacher" data="{{name:'薛老师', age:38, course:'线性代数'}}" />
<view>------------------------------</view>
<!--作业新增:奥运冠军模板渲染-->
<template is="champion" data="{{...champion01}}" />
<view>------------------------------</view>
<template is="champion" data="{{...champion02}}" />
<view>------------------------------</view>
<template is="champion" data="{{...champion03}}" />
</view>
⚠️踩坑重点:import路径!index.wxml 在pages/index/,需要../../回到项目根目录,很多同学直接写/template/template.wxml会出现Template not found模板找不到警告。
三、页面逻辑 pages/index/index.js
Page 的 data 存放所有需要渲染的数据对象,通过...展开传递给模板。
// index.js
Page({
data: {
temp01: 'student',
temp02: 'teacher',
student01: {
name: '张同学',
age: 19,
major: '软件工程'
},
student02: {
name: '李同学',
age: 20,
major: '计算机科学与技术'
},
teacher01: {
name: '王老师',
age: 40,
course: '智能终端开发技术'
},
teacher02: {
name: '刘老师',
age: 42,
course: '物联网识别技术'
},
//作业:奥运冠军数据
champion01:{
name:'许海峰',
sport:'男子自选手枪慢射'
},
champion02:{
name:'刘翔',
sport:'男子110米栏'
},
champion03:{
name:'全红婵',
sport:'女子10米跳台'
}
}
})
四、样式文件
pages/index/index.wxss
/**index.wxss**/
page {
height: 100vh;
display: flex;
flex-direction: column;
}
app.wxss(全局样式)
/**app.wxss**/
.box {
margin: 20rpx;
padding: 20rpx;
border: 2rpx solid silver;
}
.title {
font-size: 40rpx;
font-weight: bold;
text-align: center;
margin-bottom: 30rpx;
color: red;
}
view {
font-size: 30rpx;
}
五、app.json 项目配置(关闭 Skyline,防止页面空白)
{
"pages": [
"pages/index/index"
],
"window": {
"navigationBarTitleText": "模板",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle":"black"
},
"sitemapLocation": "sitemap.json"
}
六、核心知识点总结
- template 定义:<template name="xxx">,name 是模板唯一标识,一个 wxml 文件内可以定义多个模板。
- import 导入:只导入目标文件里的 template 模板,不会递归导入其他 import。
- 模板引用
- is:指定使用哪一个模板,可以写固定字符串,也可以绑定变量动态切换模板。
- data="{{...obj}}":对象展开语法,把 obj 里面的属性直接传递给模板,模板内直接使用{{name}}取值。
- 模板作用域:模板是孤立作用域,模板里面不能直接访问页面 data,所有数据必须通过data属性传入。
- import 和 include 的区别
- import:只引入<template>模板片段,适合 UI 卡片复用。
- include:直接拷贝整个文件的 wxml 代码(排除 template/wxs),适合公共页头页脚。
七、高频踩坑排错
- Template 'xxx' not found最常见!import路径错误。index 在 pages/index,要用../../template/template.wxml,不要直接写/template/template.wxml。同时检查模板 name 拼写,大小写不能错。
- 模板内文字空白,没有数据 忘记写...展开对象,写成data="{{student01}}",模板拿不到字段,必须写data="{{...student01}}"。
- 页面空白 app.json 中删除 skyline 相关配置,使用传统 webview 渲染,清理缓存后重新编译。
- 基础库内部报错 Cannot read property '__subPageFrameEndTime__' of null 属于微信开发者工具灰度基础库 3.17.3 内部 bug,不是你的代码问题,切换基础库到稳定版本 3.11.3 即可消除。
八、模板的使用场景
适合页面中大量重复结构的 UI:列表条目、信息卡片、商品卡片、用户信息卡片。把重复 UI 抽成模板,一处修改,所有引用位置同步更新,减少重复代码,提升可维护性。
完整代码复制后,修改 import 路径、清缓存,即可正常运行,满足课堂作业要求。