分类页面预览图:
分类页面次要代码
index.js
// pages/category/index.js
import {request} from "../../request/index.js"
Page({
/**
* 页面的初始数据
*/
data: {
// 左侧菜单数据
leftMenuList: [],
// 右侧的商品数据
rightContent: [],
// 被点击的左侧菜单
currentIndex: 0,
// 右侧间隔顶部间隔
scrollTop:0,
},
// 接口返回数据
Cates: [],
/**
* 生命周期函数 -- 监听页面加载
*/
onLoad: function (options) {
/**
* 1, 先判断本地贮存中有没有旧的缓存数据
* 本地存储数据格式:* {time.Data.now(),data:[.....]}
* 2,没有数据就发送申请,* 3,有旧数据且旧数据没有过期,间接应用本地贮存中的旧数据
*/
const Cates = wx.getStorageSync("cates");
if (!Cates) {
// 不存在,获取数据
this.getCates();} else {
// 本地有缓存
if (Date.now() - Cates.time > 1000 * 10) {
// 超过 10s 就从新发送申请
this.getCates();} else {
// 能够应用本地缓存数据
this.Cates = Cates.data;
// 结构左侧菜单数据
let leftMenuList = this.Cates.map(v => v.cat_name);
// 结构右侧商品数据
let rightContent = this.Cates[0].children;
this.setData({
leftMenuList,
rightContent,
})
}
}
},
// 获取分类数据
getCates() {
request({url: "/categories"}).then(res => {
this.Cates = res.data.message;
// 把构造数据存入本地缓存
wx.setStorageSync('cates', {time: Date.now(),
data: this.Cates
});
// 结构左侧菜单数据
let leftMenuList = this.Cates.map(v => v.cat_name);
// 结构右侧商品数据
let rightContent = this.Cates[0].children;
this.setData({
leftMenuList,
rightContent,
})
})
},
// 左侧菜单的点击事件
handleItemTap(e) {
/*
1, 获取被点击菜单的索引
2,给 data 中的 currentIndex 赋值
3, 依据不同索引渲染右侧内容
*/
const {index} = e.currentTarget.dataset;
let rightContent = this.Cates[index].children;
this.setData({
currentIndex: index,
rightContent,
// 设置右侧间隔顶部间隔
scrollTop:0,
});
},
/**
* 生命周期函数 -- 监听页面首次渲染实现
*/
onReady: function () {},
/**
* 生命周期函数 -- 监听页面显示
*/
onShow: function () {},
/**
* 生命周期函数 -- 监听页面暗藏
*/
onHide: function () {},
/**
* 生命周期函数 -- 监听页面卸载
*/
onUnload: function () {},
/**
* 页面相干事件处理函数 -- 监听用户下拉动作
*/
onPullDownRefresh: function () {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {}
})
index.json
{
"usingComponents": {"SearchInput":"../../components/SearchInput/SearchInput"},
"navigationBarTitleText": "商品分类"
}
index.less
vscode 的 easyless 插件会主动生成 index.wxss
/* pages/category/index.wxss */
page {height: 100%;}
.cates {
height: 100%;
.cates_container {
// less 中应用 calc 留神
height: ~'calc(100vh - 90rpx)';
display: flex;
.left_menu {
flex: 2;
.menu_item {
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 30rpx;
}
.active {color: var(--themeColor);
border-left: 5rpx solid currentColor;
}
}
.right_content {
flex: 5;
.good_group {
.good_title {
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
.delimiter {
color: #cccccc;
padding: 0 10rpx;
}
.title {}}
.good_list {
display: flex;
flex-wrap: wrap;
navigator {
width: 33.33%;
text-align: center;
image {width: 50%;}
.goods_name {}}
}
}
}
}
}
index.wxml
<view class="cates">
<SearchInput></SearchInput>
<view class="cates_container">
<!-- 左侧菜单 -->
<scroll-view scroll-y="{{true}}" class="left_menu">
<view class="menu_item {{index===currentIndex?'active':''}}"wx:for="{{leftMenuList}}"wx:key="*this"bindtap="handleItemTap"data-index="{{index}}"
>
{{item}}
</view>
</scroll-view>
<!-- 右侧菜单 -->
<scroll-view scroll-top="{{scrollTop}}" scroll-y="{{true}}" class="right_content">
<view class="good_group"
wx:for="{{rightContent}}"
wx:for-index="index1"
wx:for-item="item1"
>
<view class="good_title">
<text class="delimiter">/</text>
<text class="title">{{item1.cat_name}}</text>
<text class="delimiter">/</text>
</view>
<view class="good_list">
<navigator class=""target="" url="/pages/goods_list/index?cid={{item2.cat_id}}" hover-class="navigator-hover" open-type="navigate"
wx:for="{{item1.children}}"
wx:for-index="index2"
wx:for-item="item2"
wx:key="cat_id"
>
<image class=""src="{{item2.cat_icon}}"mode="widthFix"lazy-load="false"binderror="" bindload="" />
<view class="goods_name">{{item2.cat_name}}</view>
</navigator>
</view>
</view>
</scroll-view>
</view>
</view>
分类页面难点记录
次要是布局文件 index.less 的编写,留神 less 语法。
商品列表页面预览
商品列表页性能:反对上拉加载更多,下拉刷新等
商品列表页次要代码:
index.js
// pages/goods_list/index.js
import {request} from "../../request/index.js"
Page({
/**
* 页面的初始数据
*/
data: {
tabs: [{
id: 0,
value: "综合",
isActive: true,
},
{
id: 1,
value: "销量",
isActive: false,
},
{
id: 0,
value: "价格",
isActive: false,
},
],
// 商品列表数据
goodsList: [],},
// 接口要的参数
QueryParams: {
query: "",
cid: "",
pagenum: 1,
pagesize: 10
},
// 总页数
totalPages: 1,
/**
* 生命周期函数 -- 监听页面加载
*/
onLoad: function (options) {
this.QueryParams.cid = options.cid;
this.getGoodsList();},
// 获取商品列表页数据
getGoodsList() {
request({
url: "/goods/search",
data: this.QueryParams,
}).then(res => {//console.log(res);
// 数据总条数
const total = res.data.message.total;
// 计算总页数
this.totalPages = Math.ceil(total/this.QueryParams.pagesize);
//console.log(this.totalPages);
this.setData({goodsList:[...this.data.goodsList,... res.data.message.goods],
});
// 手动敞开下拉刷新界面, 首次进入也不会报错,无需解决
wx.stopPullDownRefresh();})
},
// 题目点击事件 从子组件 Tabs 传递过去的
handleTabsItemChange(e) {
// 获取被点击的题目索引
const {index} = e.detail;
// 批改源数组
let {tabs} = this.data;
tabs.forEach((v, i) => i === index ? v.isActive = true : v.isActive = false);
// 赋值到 data 中
this.setData({tabs});
},
/**
* 生命周期函数 -- 监听页面首次渲染实现
*/
onReady: function () {},
/**
* 生命周期函数 -- 监听页面显示
*/
onShow: function () {},
/**
* 生命周期函数 -- 监听页面暗藏
*/
onHide: function () {},
/**
* 生命周期函数 -- 监听页面卸载
*/
onUnload: function () {},
/**
* 页面相干事件处理函数 -- 监听用户下拉动作
*/
onPullDownRefresh: function () {//console.log('下拉了');
// 重置数组
this.setData({goodsList:[],
});
// 重置页码
this.QueryParams.pagenum=1;
// 从新发送申请
this.getGoodsList();},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {//console.log('页面触底了~~');
// 判断还有没有下一页数据
if(this.QueryParams.pagenum>=this.totalPages){
// 没有下一页数据了
wx.showToast({title: '没有更多数据了',});
}else{
this.QueryParams.pagenum++;
this.getGoodsList();}
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {}
})
index.json
{
"usingComponents": {
"SearchInput":"../../components/SearchInput/SearchInput",
"Tabs":"../../components/Tabs/Tabs"
},
"navigationBarTitleText": "商品列表页",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark"
}
index.less
/* pages/goods_list/index.wxss */
.first_tab {
.goods_item {
display: flex;
border-bottom: 1px solid #cccccc;
.goods_img_wrap {
flex: 2;
display: flex;
justify-content: center;
align-items: center;
image {width: 70%;}
}
.goods_info_wrap {
flex: 3;
display: flex;
flex-direction: column;
justify-content: space-around;
.goods_name {
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.goods_price {color: var(--themeColor);
font-size: 32rpx;
}
}
}
}
index.wxml
<SearchInput></SearchInput>
<!-- 监听自定义事件 -->
<Tabs tabs="{{tabs}}" bindtabsItemChange="handleTabsItemChange">
<block wx:if="{{tabs[0].isActive}}">
<view class="first_tab">
<navigator class="goods_item"
wx:for="{{goodsList}}"
wx:key="goods_id"
>
<!-- 左侧的图片容器 -->
<view class="goods_img_wrap">
<image class=""src="{{item.goods_small_logo}}"mode="widthFix"lazy-load="false"binderror="" bindload="" />
</view>
<!-- 左边的商品信息 -->
<view class="goods_info_wrap">
<view class="goods_name">{{item.goods_name}}</view>
<view class="goods_price">¥{{item.goods_price}}</view>
</view>
</navigator>
</view>
</block>
<block wx:elif="{{tabs[1].isActive}}">1</block>
<block wx:elif="{{tabs[2].isActive}}">2</block>
</Tabs>
商品列表页援用的组件 Tabs 次要代码
Tabs.js
// components/Tabs/Tabs.js
Component({
/**
* 组件的属性列表
*/
properties: {
// 接管父组件的传值
tabs:{
type:Array,
value:[],}
},
/**
* 组件的初始数据
*/
data: { },
/**
* 组件的办法列表
*/
methods: {handleItemTap(e){
// 获取点击索引
const {index} = e.currentTarget.dataset;
// 触发父组件的事件
this.triggerEvent("tabsItemChange",{index})
},
}
})
Tabs.less
.tabs{
.tabs_title{
display: flex;
.title_item{
display: flex;
padding: 15rpx 0;
justify-content: center;
align-items: center;
flex: 1;
}
}
.tabs_content{}}
.active{color: var(--themeColor);
border-bottom: 5rpx solid currentColor;
}
Tabs.wxml
<view class="tabs">
<view class="tabs_title">
<view class="title_item {{item.isActive?'active':''}}"wx:for="{{tabs}}"wx:key="id"bindtap="handleItemTap"data-index="{{index}}">
{{item.value}}
</view>
</view>
<view class="tabs_content">
<slot></slot>
</view>
</view>
商品列表页及 Tabs 组件次要技术点记录
1,父组件(商品列表页)和子组件 (Tabs 组件) 互相传递数据问题
2, 上拉加载更多、下拉刷新实现的逻辑