// 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 () {
}
})
{
"usingComponents": {
"SearchInput":"../../components/SearchInput/SearchInput"
},
"navigationBarTitleText": "商品分类"
}
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 {}
}
}
}
}
}
}
<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语法。
// 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 () {
}
})
{
"usingComponents": {
"SearchInput":"../../components/SearchInput/SearchInput",
"Tabs":"../../components/Tabs/Tabs"
},
"navigationBarTitleText": "商品列表页",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark"
}
/* 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;
}
}
}
}
<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}}">1block>
<block wx:elif="{{tabs[2].isActive}}">2block>
Tabs>
// components/Tabs/Tabs.js
Component({
/**
* 组件的属性列表
*/
properties: {
//接收父组件的传值
tabs:{
type:Array,
value:[],
}
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
handleItemTap(e){
//获取点击索引
const {index} = e.currentTarget.dataset;
//触发父组件的事件
this.triggerEvent("tabsItemChange",{index})
},
}
})
.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;
}
<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>
1,父组件(商品列表页)和子组件(Tabs组件)相互传递数据问题
2,上拉加载更多、下拉刷新实现的逻辑