设计商品的数据结构

在这里,首页数据是根据TabControl切换而得到的,而每次上拉加载都刷新一定数量的数据,所以根据三个切换按钮在里面又定义了三个对象,而每次上拉加载都定义为加一页(默认第一页),所以定义page用来存储当前页数信息,用list来存储到当前页加载到的商品数量

1
2
3
4
5
goods: {
'pop': {page:0, list:[]},
'new': {page:0, list:[]},
'sell': {page:0, list:[]},
}

首页数据的请求和封装

ntework里的home.js同第一个网络请求的函数一样,再次定义另外一个,获得商品数据

1
2
3
4
5
6
7
8
9
10
export function getHomeGoods(type,page) {
return request({
//接口已修改
url: '/api/h8/home/data',
params: {
type,
page
}
})
}

在home.vue调用该函数,并将其封装成方法,因为我们在网络请求后会做进一步的处理,所以我们用同名的函数将其封装起来,并在create()中调用这些网络请求以及具体的实现方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
created() {
this.getHomeMultidata()
this.getHomeGoods('pop')
this.getHomeGoods('new')
this.getHomeGoods('sell')
},
methods: {
//网络分析相关方法
getHomeMultidata() {
getHomeMultidata().then(res => {
this.banners = res.data.banner.list
this.recommends = res.data.recommend.list
})
},
getHomeGoods(type) {
const page = this.goods[type].page + 1
getHomeGoods(type, page).then(res => {
this.goods[type].list.push(...res.data.list)
this.goods[type].page ++
})
}
}

商品展示

因为涉及到该项目的业务功能(好几个页面会用到该组件),所以在components中的content中新建goods文件夹,新建两个vue文件GoodsList以及GoodsListItem,一个用来描述单个商品的详细样式,另外一个用来展示整体商品的样式

GoodsList.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<template>
<div class="goods-list">
<goods-list-item v-for="item in goods" :goods-item="item"></goods-list-item>
</div>
</template>

<script>
import GoodsListItem from './GoodsListItem.vue'
export default {
name: 'GoodsList',
props: {
goods: {
type: Array,
default() {
return []
}
}
},
components: {
GoodsListItem
}
}
</script>

<style scoped>
.goods-list {
display: flex;
padding: 2px;

/* 包裹 */
flex-wrap: wrap;
justify-content: space-around;
}
</style>

GoodsListItem.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<template>
<div class="goods-list-item">
<img :src="goodsItem.show.img" alt="">
<div class="goods-info">
<p>{{goodsItem.title}}</p>
<span class="price">{{goodsItem.price}}</span>
<span class="collect">{{goodsItem.cfav}}</span>
</div>
</div>
</template>

<script>
export default {
name: 'GoodsListItem',
props: {
goodsItem: {
type: Object,
default() {
return {}
}
}
},
components: {

}
}
</script>

<style scoped>
.goods-list-item {
position: relative;
padding-bottom: 40px;
width: 48%;
}

.goods-list-item img {
width: 100%;
border-radius: 5px;
}

.goods-info {
position: absolute;
left: 0;
right: 0;
bottom: 5px;
overflow: hidden;
text-align: center;
font-size: 12px;
}

.goods-info p {
overflow: hidden;
/* 显示省略符号来代表被修剪的文本 */
text-overflow: ellipsis;
/* 文本不换行 */
white-space: nowrap;
margin-bottom: 3px;
}

.goods-info .price {
color: var(--color-high-text);
margin-right: 20px;
}

.goods-info .collect {
position: relative;
}

.goods-info .collect::before {
content: '';
position: absolute;
left: -15px;
top: -1px;
width: 14px;
height: 14px;
background: url("~assets/img/common/collect.svg") 0 0/14px 14px;
}
</style>

这里主要有几个css的新知识点(或者遗忘点)

1
2
3
4
5
6
7
8
9
/*  显示省略符号来代表被修剪的文本 */
text-overflow: ellipsis;
/* 文本不换行 */
white-space: nowrap;

/* 包裹 在子组件定义宽度后,可以根据宽度自动排列布局*/
flex-wrap: wrap;
/* 可以使子组件的间距均匀 */
justify-content: space-around;

tabcontrol切换商品类型

回到tabcontrol,我们需要通过点击事件来切换不同的商品展示,所以这里就要动态绑定点击事件,同时,为了触发父组件的goods信息改变,我们需要将该事件点击所对应的tab的索引传给父组件

动态绑定事件

1
2
3
4
<div v-for="(item,index) in titles" 
class="tab-control-item"
:class = "{active: index === currentIndex}"
@click="itemchange(index)">

传出事件以及当前点击的索引

1
2
3
4
5
6
methods: {
itemchange(index) {
this.currentIndex = index
this.$emit('tabClick', index)
}
}

父组件接收点击事件

1
<tab-control :titles="['流行', '新款', '精选']" class="tab" @tabClick="tabClick"></tab-control>

用一个变量获得当前请求的数据索引(默认首页)

1
2
3
data () {
currentType: 'pop'
}

处理该事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
methods: {
//首页数据处理
tabClick(index) {
switch (index) {
case 0:
this.currentType = 'pop'
break
case 1:
this.currentType = 'new'
break
case 2:
this.currentType = 'sell'
break
}
}
}

再在computed中,动态改变当前请求的数据索引

1
2
3
4
5
computed: {
showGoods() {
return this.goods[this.currentType].list
}
}

在标签,动态绑定数据

1
<goods-list :goods="showGoods"></goods-list>

这样就OK啦