效果展示
本篇要做的是个购物车的案例,接下来我们要对购物车中的商品进行综合排序、销量优先、价格从高到低的排序。还有Tab切换,对母婴、鞋包等标签做出相对应的商品展示。这些数据我们可以从后端获取进行使用。
下面是效果图
下面代码是储存在local Storage后端的数据,储存名字为goods
[
// {
// "id": 1001,
// "name": "Beats EP头戴式耳机",
// "price": 558,
// "type": 4,
// "stock": 128,
// "sales": 1872,
// "img": "http://img11.360buyimg.com/n1/s528x528_jfs/t3109/194/2435573156/46587/e0e867ac/57e10978N87220944.jpg!q70.jpg"
// },
// {
// "id": 1002,
// "name": "雀巢(Nestle)高钙成人奶粉",
// "price": 60,
// "type": 3,
// "stock": 5,
// "sales": 2374,
// "img": "http://m.360buyimg.com/babel/jfs/t5197/28/400249159/97561/304ce550/58ff0dbeN88884779.jpg!q50.jpg.webp"
// },
// {
// "id": 1003,
// "name": "煎炒烹炸一锅多用",
// "price": 216,
// "type": 5,
// "stock": 2,
// "sales": 351,
// "ishot": true,
// "img": "http://gw.alicdn.com/tps/TB19OfQRXXXXXbmXXXXL6TaGpXX_760x760q90s150.jpg_.webp"
// },
// {
// "id": 1004,
// "name": "ANNE KLEIN 潮流经典美式轻奢",
// "price": 585,
// "type": 2,
// "stock": 465,
// "sales": 8191,
// "img": "http://gw.alicdn.com/tps/TB1l5psQVXXXXcXaXXXL6TaGpXX_760x760q90s150.jpg_.webp"
// },
// {
// "id": 1005,
// "name": "乐高EV3机器人积木玩具",
// "price": 3099,
// "type": 1,
// "stock": 154,
// "sales": 165,
// "img": "https://m.360buyimg.com/mobilecms/s357x357_jfs/t6490/168/1052550216/653858/9eef28d1/594922a8Nc3afa743.jpg!q50.jpg"
// },
// {
// "id": 1006,
// "name": "全球购 路易威登(Louis Vuitton)新款女士LV印花手袋 M41112",
// "price": 10967,
// "type": 2,
// "stock": 12,
// "sales": 6,
// "img": "https://m.360buyimg.com/n1/s220x220_jfs/t1429/17/1007119837/464370/310392f4/55b5e5bfN75daf703.png!q70.jpg"
// },
// {
// "id": 1007,
// "name": "Kindle Paperwhite3 黑色经典版电纸书",
// "price": 805,
// "type": 4,
// "stock": 3,
// "sales": 395,
// "img": "http://img12.360buyimg.com/n1/s528x528_jfs/t4954/76/635213328/51972/ec4a3c3c/58e5f717N4031d162.jpg!q70.jpg"
// },
// {
// "id": 1008,
// "name": "DELSEY 男士双肩背包",
// "price": 269,
// "type": 2,
// "stock": 18,
// "sales": 69,
// "ishot": true,
// "img": "http://gw.alicdn.com/tps/LB1HL0mQVXXXXbzXVXXXXXXXXXX.png"
// },
// {
// "id": 1009,
// "name": "荷兰 天赋力 Herobaby 婴儿配方奶粉 4段 1岁以上700g",
// "price": 89,
// "type": 1,
// "stock": 36,
// "sales": 1895,
// "img": "http://m.360buyimg.com/babel/s330x330_jfs/t4597/175/4364374663/125149/4fbbaf21/590d4f5aN0467dc26.jpg!q50.jpg.webp"
// },
// {
// "id": 1010,
// "name": "【全球购】越南acecook河粉牛肉河粉特产 速食即食方便面粉丝 牛肉河粉米粉65克*5袋",
// "price": 19.9,
// "type": 3,
// "stock": 353,
// "sales": 3041,
// "ishot": true,
// "img": "https://m.360buyimg.com/mobilecms/s357x357_jfs/t3169/228/5426689121/95568/d463e211/586dbf56N37fcd503.jpg!q50.jpg"
// },
// {
// "id": 1011,
// "name": "正品FENDI/芬迪女包钱包女长款 百搭真皮钱夹 女士小怪兽手拿包",
// "price": 3580,
// "type": 2,
// "stock": 5,
// "sales": 18,
// "img": "http://img.alicdn.com/imgextra/i3/TB16avCQXXXXXcsXpXXXXXXXXXX_!!0-item_pic.jpg_400x400q60s30.jpg_.webp"
// }]
index.js
首先声明一个goodsData数组,在mutations中请求商品列表,在actions中获取后端名为goods的数据放在goodsData数组中并进行提交。提交完之后当然要在我们的组件中进行使用渲染啦。
往下看
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
goodsData:[],
},
mutations: {
//1. 请求商品列表
SET_DATA(state,data){
const {goodsData}=data;
state.goodsData=goodsData;
},
},
actions: {
setData({commit}){
const goodsData=JSON.parse(localStorage.getItem('goods'))||[];
commit('SET_DATA',{
goodsData
})
},
},
modules: {
}
})
Home.vue组件
现在,我们vuex中的goodsData有数据了,就可以使用…扩展符获取vuex中的goodsData,并在HTML中v-for渲染显示,记得要想渲染的商品不被刷新掉,就要在生命周期创建后的created中调用vuex中的actions的setData函数
Tab切换
声明一个carType数组用来循环Tab标签并在data中调用。在li标签v-for循环carType,这样Tab按钮就有了。在上面效果图中可以看出Tab切换是点击哪个哪个就有背景颜色,所以绑定名为tab-active的class根据click点击的type进行切换显示商品。因此在computed计算属性中来一个showGoodsData函数,对Tab标签的type进行判断,来过滤筛选,
商品排序
同样有点击颜色,跟上面的Tab切换一样,只不过排序是根据status的类型进行操作。所以在li中的三个排序分别写入不一样status类型。排序可以在computed计算属性中计算。首先来一个showGoodsData函数,使用switch 来对status的类型进行sort排序,
由于排序中的价格排序有两种,所以要单独写一个方法。首先let声明一个boo默认为true,再在methods中来一个changePrice函数,判断boo的值来对status的类型进行显示或隐藏操作
import { mapState } from "vuex";
const cartType = [
{
name: "推荐",
type: 0,
},
{
name: "母婴",
type: 1,
},
{
name: "鞋包饰品",
type: 2,
},
{
name: "食品",
type: 3,
},
{
name: "数码家电",
type: 4,
},
{
name: "居家百货",
type: 5,
},
];
let boo = true;
export default {
data() {
return {
cartType,
type: 0,
status: "all",
};
},
computed: {
...mapState(["goodsData"]),
showGoodsData() {
let data = "";
//Tab切换
if (this.type == 0) {
data = this.goodsData.map((item) => item);
} else {
data = this.goodsData.filter((item) => item.type == this.type);
}
//商品排序
switch (this.status) {
case "all":
return data;
case "sales":
console.log(123);
return data.sort((a, b) => {
return b.sales - a.sales;
});
case "priceMax":
return data.sort((a, b) => b.price - a.price);
case "priceMin":
return data.sort((a, b) => a.price - b.price);
}
return data;
},
},
created() {
this.$store.dispatch("setData");
},
methods: {
changePrice() {
if (boo) {
this.status = "priceMax";
boo = false;
} else {
this.status = "priceMin";
boo = true;
}
},
},
};
HTML
<template>
<div class="home">
<header>
<span>商品列表</span>
<router-link to="/About" class="gwc">购物车</router-link>
</header>
<div class="flex">
<ul class="list">
<li
class="cate"
:class="{ 'tab-active': type == item.type }"
v-for="item in cartType"
:key="item.id"
@click="type = item.type"
>
{{ item.name }}
</li>
</ul>
</div>
<ul class="Composite">
<li
class="filter-opt price-up"
:class="{ 'filter-active': status == 'all' }"
@click="status = 'all'"
>
综合排序
</li>
<li
class="filter-opt price-up"
:class="{ 'filter-active': status == 'sales' }"
@click="status = 'sales'"
>
销量优先
</li>
<li
class="filter-opt filter-price price-up"
:class="{
'filter-active': status == 'priceMax' || status == 'priceMin',
}"
@click="changePrice"
>
价格
</li>
</ul>
<div class="scorll">
<div class="tj" v-for="item in showGoodsData" :key="item.id">
<img :src="item.img" alt="" />
<ul class="xx">
<li>
{{ item.name }}
</li>
<li><span>¥</span>{{ item.price }}</li>
<li>{{ item.sales }}付款</li>
</ul>
<button class="btn" @click="setCartHandle(item, 'PLUS')">+</button>
</div>
</div>
</div>
</template>
Style样式
<style lang="scss" scoped>
.home {
header {
height: 0.3rem;
display: flex;
align-items: center;
justify-content: space-around;
.gwc {
position: absolute;
float: right;
top: 0;
right: 20px;
line-height: 0.3rem;
}
}
.flex {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
background: pink;
// 清除滚动条
.list::-webkit-scrollbar {
display: none;
}
.list {
// 文本强制不换行
// white-space: nowrap;
display: flex;
overflow-x: scroll;
li {
width: 0.8rem;
height: 53px;
flex-shrink: 0;
// display: inline-block;
line-height: 50px;
text-align: center;
padding: 0 7px;
font-size: 13px;
}
.tab-active {
background-color: white;
}
}
}
.Composite {
display: flex;
align-items: center;
justify-content: space-around;
height: 0.3rem;
color: black;
border-bottom: solid 1px pink;
}
.scorll {
overflow-y: scroll;
.tj {
padding: 10px 0;
display: flex;
background: white;
justify-content: space-around;
align-items: flex-end;
margin-bottom: 20px;
align-items: center;
box-shadow: 0 2px 10px pink;
img {
width: 80px;
height: 80px;
float: left;
}
.xx {
width: 2rem;
text-align: left;
li:nth-child(1) {
// 老弹性盒
display: -webkit-box;
-webkit-box-orient: vertical;
// 多行显示 最大两行
-webkit-line-clamp: 2;
// 超出文本隐藏
overflow: hidden;
}
li:nth-child(2) {
color: pink;
font-weight: 600;
}
li {
margin-top: 5px;
}
}
.btn {
background: pink;
text-align: center;
font-size: 25px;
font-weight: 700;
color: white;
width: 0.2rem;
border: none;
}
}
}
.filter-active {
color: pink;
}
}
</style>