开始前,请先完成首页的开发,详见
【微信小程序-原生开发】实用教程05-首页(含自定义调试模式、插入图片、图文排版、底部留白、添加本地图片)
https://blog.csdn.net/weixin_41192489/article/details/128729732
需求描述
今天整个稍微复杂点的,效果如下:
但在开始前,我们需要做几项其他的准备
升级到最新版的 Tdesign 组件库
按教程01 默认模板创建的项目的 Tdesign 组件不是最新版的,需手动升级一下,操作流程如下:
- 打开终端,执行命令
cnpm i tdesign-miniprogram -S --production
未安装 cnpm 的朋友,先执行 npm i cnpm 安装 cnpm
2. 执行 npm 构建
切换为最新版的调试基础库
默认的调试基础库版本比较低,请按下图进行切换
调整全局样式
通过 app.wxss 可以设置全局样式,以便所有页面共享,现将 app.wxss 里的代码全部替换为下方代码:
/* app.wxss 定义全局样式 */ page { /* 默认页面底色设置为白色 */ background: white; /* 底部留白的高度需与底部导航的高度相同 */ padding-bottom: 100rpx; }
有了全局样式后,便可删除首页中底部的占位区间啦!
pages\index\index.wxml
<view class="blankBar"> </view>
pages\index\index.wxss
.blankBar { /* 底部留白的高度需与底部导航的高度相同 */ height: 100rpx; }
配置组件按需注入
修改全局配置文件 app.json
- 删除 usingComponents 配置
- 添加 lazyCodeLoading 配置
"lazyCodeLoading": "requiredComponents",
这两项配置的改变,都是为了实现组件按需注入
,从而提升微信小程序的加载和渲染速度。
添加网络图片素材
因微信小程序的限制,图片视频等媒体素材总大小不能超过200k,所以图片需先上传到 CDN 后引入其网址使用。
让我们将图片的网址整理存到 assets文件夹中(无相关路径的文件夹或文件,请自行创建)
assets\images\美女\data.js
export default { '1':'https://ucc.alicdn.com/images/user-upload-01/6dca0e87288a4c37b76e7d26e016e299.jpeg', '2':'https://ucc.alicdn.com/images/user-upload-01/8dd7ab28ae6246b69a1722b3ad18d506.jpeg' }
assets\images\帅哥\data.js
export default { '1':'https://ucc.alicdn.com/images/user-upload-01/de253e12408f4133adf8f82982e22ce5.jpeg', '2':'https://ucc.alicdn.com/images/user-upload-01/e9fb6f4e461744e593ca305440760e16.jpeg', '3':'https://ucc.alicdn.com/images/user-upload-01/63926e3235434cd8bd30285f5612d303.jpeg', '4':'https://ucc.alicdn.com/images/user-upload-01/601a29123c17471dac01e358dce8e1fe.jpeg', }
代码实现
准备工作完毕,终于可以开始开发啦!
我先给出最终的总代码,然后分别解析各部分的核心实现哈:
pages\member\index.json
{ "usingComponents": { "t-swiper": "tdesign-miniprogram/swiper/swiper", "t-tabs": "tdesign-miniprogram/tabs/tabs", "t-tab-panel": "tdesign-miniprogram/tab-panel/tab-panel", "t-avatar": "tdesign-miniprogram/avatar/avatar" } }
pages\member\index.wxml
<!-- 轮播图 --> <view class="swiperBox"> <t-swiper image-props="{{imageProps}}" current="{{current}}" autoplay="{{autoplay}}" duration="{{duration}}" interval="{{interval}}" list="{{swiperList}}" navigation="{{ { type: 'dots-bar' } }}" /> </view> <!-- 分类页签 tab --> <t-tabs defaultValue="{{defaultTab}}" theme="card" bindchange='tabChange'> <t-tab-panel wx:for="{{tabList}}" wx:key="index" label="{{item.label}}" value="{{item.index}}" /> </t-tabs> <!-- 成员列表 --> <view wx:for="{{filteredMemberList}}" wx:key="index" class="memberBox"> <t-avatar class="avatar-example" shape="round" image="{{item.imgURL}}" /> <view class="memberName"> {{item.name}} </view> <view class="memberStaus"> {{item.status}} ing </view> </view>
pages\member\index.wxss
.swiperBox{ padding: 30rpx; } .memberBox{ padding: 20rpx; display: flex; align-items: center; border-bottom: 1rpx solid rgb(223, 217, 217); background-color: #ffffff; } .memberName{ font-weight: bold; font-size: 40rpx; padding-left: 30rpx; } .memberStaus{ padding-left: 40rpx; }
pages\member\index.js
// 导入图片素材 import girlImgDic from '../../assets/images/美女/data' import boyImgDic from '../../assets/images/帅哥/data' Page({ data: { // 添加轮播图片的属性 imageProps: { // 图片按宽度自适应 mode: 'widthFix' }, // 轮播从下标为 0 的图片开始 current: 0, // 自动轮播 autoplay: true, // 每张图片的停留时间 duration: 500, // 轮播时间间隔 interval: 5000, // 轮播图的图片列表 swiperList: [ girlImgDic['1'], girlImgDic['2'], boyImgDic['4'], ], // 默认 tab 页签的 index defaultTab: '0', // 分类页签 tab 列表 tabList: [{ index: '0', label: '全部' }, { index: '1', label: '男' }, { index: '2', label: '女' }, ], // 过滤后的成员列表 filteredMemberList: [], // 总成员列表,其中 gender '1'为男,'2'为女 allMemberList: [{ imgURL: girlImgDic['1'], name: '小霞', gender: '2', status: '筹备婚礼' }, { imgURL: girlImgDic['2'], name: '若依', gender: '2', status: '享受泡澡' }, { imgURL: boyImgDic['1'], name: '约翰', gender: '1', status: '忧郁' }, { imgURL: boyImgDic['2'], name: '陈翔', gender: '1', status: '思考' }, { imgURL: boyImgDic['4'], name: '李阳', gender: '1', status: '沉醉' }, ] }, // 切换页签时触发 tabChange: function (e) { let gender = e.detail.value if (gender !== '0') { this.setData({ filteredMemberList: this.data.allMemberList.filter(item => item.gender === gender) }) } else { this.setData({ filteredMemberList: this.data.allMemberList }) } }, // 生命周期--页面加载时执行 onLoad(options) { this.setData({ filteredMemberList: this.data.allMemberList }) }, onShow() { this.getTabBar().init(); }, })
轮播图
组件文档见
https://tdesign.tencent.com/miniprogram/components/swiper
<!-- 轮播图 --> <view class="swiperBox"> <t-swiper image-props="{{imageProps}}" current="{{current}}" autoplay="{{autoplay}}" duration="{{duration}}" interval="{{interval}}" list="{{swiperList}}" navigation="{{ { type: 'dots-bar' } }}" /> </view>
.swiperBox{ padding: 30rpx; }
// 添加轮播图片的属性 imageProps: { // 图片按宽度自适应 mode: 'widthFix' }, // 轮播从下标为 0 的图片开始 current: 0, // 自动轮播 autoplay: true, // 每张图片的停留时间 duration: 500, // 轮播时间间隔 interval: 5000, // 轮播图的图片列表 swiperList: [ girlImgDic['1'], girlImgDic['2'], boyImgDic['4'], ],
重点留意:
- 需设置 padding,因默认效果轮播图是圆角的,直接紧挨手机边缘不美观
- 需设置轮播图片的适配模式
widthFix
,以便按手机宽度自适应。
分类页签 tab
<!-- 分类页签 tab --> <t-tabs defaultValue="{{defaultTab}}" theme="card" bindchange='tabChange'> <t-tab-panel wx:for="{{tabList}}" wx:key="index" label="{{item.label}}" value="{{item.index}}" /> </t-tabs>
// 默认 tab 页签的 index defaultTab: '0', // 分类页签 tab 列表 tabList: [{ index: '0', label: '全部' }, { index: '1', label: '男' }, { index: '2', label: '女' }, ],
重点留意:页签的切换事件
// 切换页签时触发 tabChange: function (e) { let gender = e.detail.value if (gender !== '0') { this.setData({ filteredMemberList: this.data.allMemberList.filter(item => item.gender === gender) }) } else { this.setData({ filteredMemberList: this.data.allMemberList }) } },
此处因未访问接口,只是前端按性别字段,对成员列表进行了过滤。
成员列表
<!-- 成员列表 --> <view wx:for="{{filteredMemberList}}" wx:key="index" class="memberBox"> <t-avatar class="avatar-example" shape="round" image="{{item.imgURL}}" /> <view class="memberName"> {{item.name}} </view> <view class="memberStaus"> {{item.status}} ing </view> </view>
.memberBox{ padding: 20rpx; display: flex; align-items: center; border-bottom: 1rpx solid rgb(223, 217, 217); background-color: #ffffff; } .memberName{ font-weight: bold; font-size: 40rpx; padding-left: 30rpx; } .memberStaus{ padding-left: 40rpx; }
样式部分即最基础的 flex 布局,注意提一下 wxml 中的新语法 wx:for
wx:for
类似 vue 中的 v-for,用于循环遍历渲染列表,注意其书写格式
- 无需在 wx:for 中声明,index 即下标
- 无需在 wx:for 中声明,item 即被遍历的每一项
wx:for="{{filteredMemberList}}" wx:key="index"
<view class="memberName"> {{item.name}} </view>
生命周期 onLoad
本例中,最终渲染的成员列表是 filteredMemberList,但其在最开始是空的,需在页面加载时,赋予初始值 allMemberList,故需使用页面加载时的生命周期 onLoad
// 生命周期--页面加载时执行 onLoad(options) { this.setData({ filteredMemberList: this.data.allMemberList }) },