scroll-view
scroll-view
该接口数据返回格式为:
{
"message":[
{
"cat_id":1,
"cat_name":"大家电",
"cat_pid":0,
"cat_level":0,
"cat_deleted":false,
"cat_icon":"/full/none.jpg",
"children":[
{
"cat_id":3,
"cat_name":"电视",
"cat_pid":1,
"cat_level":1,
"cat_deleted":false,
"cat_icon":"/full/none.jpg",
"children":[
{
"cat_id":5,
"cat_name":"曲面电视",
"cat_pid":3,
"cat_level":2,
"cat_deleted":false,
"cat_icon":"https://api-hmugo-web.itheima.net/full/2fb113b32f7a2b161f5ee4096c319afedc3fd5a1.jpg"
},
{
"cat_id":6,
"cat_name":"海信",
"cat_pid":3,
"cat_level":2,
"cat_deleted":false,
"cat_icon":"https://api-hmugo-web.itheima.net/full/5e38cf9e6e7c46a17fe1c597a883ae627977b296.jpg"
}
]
}
]
}
]
}
此处message
中为三套循环,第一层为左侧分类列表,第二层为分类中小类,第三层为详细产品。
在category/index.js
中,声明所需数据:
/**
* 页面的初始数据
*/
data: {
// 左侧菜单数组
leftMenuList: [],
// 右侧商品数组
rightContent: []
},
// 定义变量接受server返回整体数据
Cates: [],
引入之前设计的request
import { request } from "../../request/index.js"
发送网络请求并处理数据:
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.getCates();
},
/*
加载分类数据
*/
getCates() {
request({
url: "https://api-hmugo-web.itheima.net/api/public/v1/categories"
}).then(result => {
console.log(result)
this.Cates = result.data.message;
// 构造左侧大菜单数据
let leftMenuList = this.Cates.map(v => v.cat_name);
// 构造右侧商品数据
let rightContent = this.Cates[0].children;
this.setData({
leftMenuList,
rightContent
})
})
},
分类页面头部是一个搜索框,这个组件在上一节中已经做了处理,那在这里直接引用即可。
在category/index.json
中,引入组件:
{
"usingComponents": {
"SearchInput":"../../components/SearchInput/SearchInput"
},
"navigationBarTitleText": "商品分类"
}
在category/index.wxml
中,使用组件:
<view class="cates">
<SearchInput></SearchInput>
</view>
首先,将页面左右分开布局,
在category/index.wxml
中,编写布局
<view class="cates_container">
<!-- 左侧菜单 -->
<scroll-view class="left_menu" scroll-y>
</scroll-view>
<!-- 右侧商品内容 -->
<scroll-view class="right_content" scroll-y>
</scroll-view>
</view>
在category/index.less
文件中,编写样式文件:
page {
height: 100%;
}
.cates {
height: 100%;
.cates_container {
/* 在less中使用calc时要注意 */
height : ~'calc(100vh - 90rpx)';
display: flex;
.left_menu {
flex: 2;
background-color: hotpink;
}
.right_content {
flex: 5;
background-color: gold;
}
}
}
左侧菜单,需要对leftMenuList
进行循环,并先完成简单样式。
在category/index.wxml
中,编写菜单遍历代码:
<!-- 左侧菜单 -->
<scroll-view class="left_menu" scroll-y>
<view class="menu_item" wx:for="{{leftMenuList}}" wx:key="*this">{{item}}</view>
</scroll-view>
在category/index.less
文件中,编写样式代码:
.cates {
height: 100%;
.cates_container {
/* 在less中使用calc时要注意 */
height : ~'calc(100vh - 90rpx)';
display: flex;
.left_menu {
flex: 2;
.menu_item {
height : 80rpx;
justify-content: center;
align-items : center;
font-size : 30rpx;
display : flex;
}
}
}
}
这里,主要两个循环,第一层为子分类标题,第二层为子分类列表内容。
在category/index.wxml
中,编写UI,代码如下:
<!-- 右侧商品内容 -->
<scroll-view class="right_content" scroll-y>
<view class="goods_group" wx:for="{{rightContent}}" wx:for-index="cate_index" wx:key="cat_id" wx:for-item="cate_item">
<!-- 商品标题 -->
<view class="goods_title">
<text class="delimiter">/</text>
<text class="title">{{cate_item.cat_name}}</text>
<text class="delimiter">/</text>
</view>
<!-- 商品分类 -->
<view class="goods_list">
<navigator wx:for="{{cate_item.children}}" wx:for-item="good_item" wx:for-index="good_index" wx:key="cat_id">
<image mode="widthFix" src="{{good_item.cat_icon}}" />
<view class="goods_name">{{good_item.cat_name}}</view>
</navigator>
</view>
</view>
</scroll-view>
在catrgory/index.less
中编写样式,如下:
.right_content {
flex: 5;
.goods_group {
.goods_title {
height : 80rpx;
display : flex;
justify-content: center;
align-items : center;
.delimiter {
color : #ccc;
padding: 0 10rpx;
}
.title {}
}
}
.goods_list {
display : flex;
flex-wrap: wrap;
navigator {
width : 33.33%;
text-align: center;
image {
width: 50%;
}
.goods_name {
padding-bottom: 8rpx;
}
}
}
}
接下来,需要实现,点击左侧菜单,出现选中样式,并且,右侧商品内容同步更新。
active
样式首先需要在点击左侧菜单时,样式更新。
在categry/index.less
中,编写选中样式文件:
.left_menu {
flex: 2;
.menu_item {
height : 80rpx;
justify-content: center;
align-items : center;
font-size : 30rpx;
display : flex;
}
.active{
color: var(--themeColor);
border-left: 5rpx solid currentColor;
}
}
在category/index.js
中,记录当前索引值:
data: {
// 左侧菜单数组
leftMenuList: [],
// 右侧商品数组
rightContent: [],
// 选择菜单索引
currentIndex: 0
},
在category/index.wxml
中,判断索引,添加样式:
<!-- 左侧菜单 -->
<scroll-view class="left_menu" scroll-y>
<view class="menu_item {{currentIndex===index?'active':''}}" wx:for="{{leftMenuList}}" wx:key="*this">{{item}}</view>
</scroll-view>
此时,仅有第一个是选中样式,当点击菜单是没有效果的,因为还没设置点击事件,接下来添加一下吧。
在category/index.wxml
中,给左侧菜单添加点击事件,并把当前索引传入。
<!-- 左侧菜单 -->
<scroll-view class="left_menu" scroll-y>
<view class="menu_item {{currentIndex===index?'active':''}}" wx:for="{{leftMenuList}}" wx:key="*this" bind:tap="handItemTab" data-index="{{index}}">{{item}}</view>
</scroll-view>
在category/index.js
中,添加处理函数,并更新currentIndex
:
// 菜单点击事件
handItemTab(e){
console.log(e);
// 获取索引
const {index} = e.currentTarget.dataset;
this.setData({
currentIndex: index
})
},
这样,即完成菜单点击效果的切换。
根据点击菜单,更新右侧商品内容,只需要通过index
获取商品数据即可
// 菜单点击事件
handItemTab(e){
console.log(e);
// 获取索引
const {index} = e.currentTarget.dataset;
// 更新右侧商品数据
let rightContent = this.Cates[index].children;
this.setData({
currentIndex: index,
rightContent
})
},
如上,就完成了右侧内容的动态切换。
以商品分类接口为例,其返回数据较多,在网络不好的情况较慢,无论是在用户体验还是技术角度都是不好的,实际项目中,需要对这种变化频率不高、数据量较大的接口增加缓存。
实现方案如下:
将更新UI代码操作,抽取独立方法,如下:
/* 更新UI */
updateUI() {
// 构造左侧大菜单数据
let leftMenuList = this.Cates.map(v => v.cat_name);
// 构造右侧商品数据
let rightContent = this.Cates[0].children;
this.setData({
leftMenuList,
rightContent
})
},
在网络请求后,调用小程序API存储数据:
/*
加载分类数据
*/
getCates(){
request({
url: "https://api-hmugo-web.itheima.net/api/public/v1/categories"
}).then(result => {
console.log(result)
this.Cates = result.data.message;
// 本地存储数据
wx.setStorageSync("cates", { time: Date.now(), data: this.Cates });
this.updateUI();
})
},
在页面onLoad
方法中,根据思路,假如本地缓存判断相关代码,详细如下:
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
// 获取本地存储数据
const localCates = wx.getStorageSync("cates");
if (!localCates) {
// 本地没有,网络请求
this.getCates();
} else {
// 本地有数据,判断是否过期 此处为60秒
if (Date.now() - localCates.time > 1000 * 10 * 6) {
// 数据过期
this.getCates();
} else {
// 本地数据有效
this.Cates = localCates.data;
this.updateUI();
}
}
},
如上,完成后可自行测试,绝对生效了~
现在分类页面还存在一个问题,当选中一个菜单,右边内容向下滚动后,再次点菜单按钮,右侧内容显示没有回顶部,效果如下:
接下来,修复一下这个问题,其实也很简单,scroll-view
提供了一个属性scrollTop
,在切换左侧菜单的时候,将其属性设置为0即可。
scrollToTop
属性在category/index.js
中的Page data
中,声明属性,如下:
// 右侧内容的滚动条
scrollToTop: 0
在点击事件中,对当前点击菜单进行判断:
// 菜单点击事件
handItemTab(e) {
console.log(e);
// 获取索引
const { index } = e.currentTarget.dataset;
// 如果重复点击标签,不做操作
if(index==this.data.currentIndex){
return;
}
// 更新右侧商品数据
let rightContent = this.Cates[index].children;
this.setData({
currentIndex: index,
rightContent,
scrollToTop: 0
})
},
scrollTop
属性在category/index.wxml
中给scroll-view
添加属性
<!-- 右侧商品内容 -->
<scroll-view class="right_content" scroll-y scroll-top="{{scrollToTop}}">
....
</scroll-view>
本节初步完成了分类页面的展示,关键点如下:
scroll-view
使用及注意事项