vue 之 tab + list 上拉加载功能实现
tab组件
- 点击那个tab栏目,然后高亮那个tab栏目
- 点击那个tab栏目,然后触发父组件的
tabClick
事件 为了匹配对应的tab栏目,然后发起请求,渲染对应的tab栏目的数据
<!-- tab 选项卡组件 文字不一样的话,直接传入数组即可 相对来说,比插槽好 -->
<template>
<div class="tab_control">
<div
class="tab_item"
v-for="(item,index) in titles"
:key="item"
:class="currentIndex===index?'active':''"
@click="tabClick(index)"
>
<span>{{ item }}</span>
</div>
</div>
</template>
<script>
export default {
name: "",
props: {
titles: {
type: Array,
default() {
return [];
}
}
},
data() {
return {
currentIndex: 0
};
},
methods: {
tabClick(index) {
this.currentIndex = index;
this.$emit("tabClick", index);
}
}
};
</script>
<style lang="scss" scoped>
.tab_control {
display: flex;
text-align: center;
font-size: 14px;
.tab_item {
flex: 1;
height: 40px;
line-height: 40px;
}
.active {
color: red;
span {
border-bottom: 3px solid red;
}
}
}
</style>
list组件之 GoodsList GoodsListItem
<template>
<div class="goods_list">
<GoodsListItem v-for="item in goodsList" :key="item.id" :goodsListItem="item"></GoodsListItem>
</div>
</template>
<script>
import GoodsListItem from "./GoodsListItem";
export default {
name: "",
// 引用 GoodsList组件的时候 向这边传递数据 goodsList
props: {
goodsList: {
type: Array,
default() {
return [];
}
}
},
data() {
return {};
},
methods: {},
components: {
GoodsListItem
}
};
</script>
<!-- -->
<template>
<div class="goodsList_item">
<img :src="goodsListItem.imgUrl" alt />
<span>{{ goodsListItem.price }}</span>
<span>{{ goodsListItem.info }}</span>
</div>
</template>
<script>
export default {
name: "",
props: {
goodsListItem: {
type: Object,
default() {
return {};
}
}
}
};
Home组件
- home组件 用于呈现对应的数据
- 引入tab组件
- 引入GoodsList组件
- 具体的逻辑思路
- 点击tab的时候,触发tab组件,然后在触发home组件引用tab组件的
tabClick
这里面去匹配对应的tab栏目 然后赋值给当前的类型 currentType
- 定义一个对象
goods
用于存储tab栏目中的数据 - 考虑到tab栏目的数据,需要经常切换,因此把需要向
GoodsList
组件传递数据 把这个在计算属性中处理 goods:{
pop: { page: 0, list: []},
new: { page: 0, list: []},
sell: { page: 0, list: []},
}
- 然后在methods中定义一个方法,发起请求
<template>
<div class="home">
<TabControl :titles="titles" @tabClick="tabClick"></TabControl>
<GoodsList :goodsList="showGoods"></GoodsList>
<BackTop></BackTop>
</div>
</template>
<script>
import TabControl from "@/components/TabControl.vue";
import GoodsList from "@/components/goods/GoodsList.vue";
export default {
data() {
return {
titles: ["流行", "精选", "超值"],
// 这是定义的假数据 真数据需要请求回来
goods: {
pop: {
page: 0,
list: [
{
id: 1,
imgUrl: "XXX",
price: 992,
info: "我是流行1"
},
{
id: 2,
imgUrl: "XXX",
price: 888,
info: "我是流行2"
},
]
},
new: {
page: 0,
list: [
{
id: 1,
imgUrl: "XXX",
price: 991,
info: "我是精选"
},
{
id: 2,
imgUrl: "XXX",
price: 888,
info: "我是精选2"
},
]
},
sell: {
page: 0,
list: [
{
id: 1,
imgUrl: "XXX",
price: 991,
info: "我是超值"
},
{
id: 2,
imgUrl: "XXX",
price: 888,
info: "我是超值2"
},
]
}
},
currentType: "pop"
};
},
components: {
TabControl,
GoodsList
},
created() {
// 购物开始 流行 新款 热卖
this.getHomeGoods("pop");
this.getHomeGoods("new");
this.getHomeGoods("sell");
// 购物结束
this.selectCategory();
},
// 对应tab切换是 需要显示的的数据 就是向goodList组件传递下去的数据
computed: {
showGoods() {
return this.goods[this.currentType].list;
}
},
methods: {
// 购物开始
// 发起请求 或者到对应 tab点击的数据! 点击的时候 根据不同的tab类型 发起请求
getHomeGoods(type) {
// 最初为0页 然后第一页的时候 才有数据 于是 发起请求前 需要先+1
const page = this.goods[type].page + 1;
// 发起请求
this.$api.getHomeGoods((type, page)).then(res => {
this.goods[type].list.push(...res.data.list);
this.goods[type].page += 1;
});
},
tabClick(index) {
switch (index) {
case 0:
this.currentType = "pop";
break;
case 1:
this.currentType = "new";
break;
case 2:
this.currentType = "sell";
break;
}
}
}
};
</script>
<style lang="scss">
</style>