列表页面显示数据,实现按尺码进行过滤,实现价格高低排序。点击添加至购物车,实现购物车所需内容。
点击跳转至效果页面(Typescript React Shopping cart)
1.列表页Tab切换效果实现
2.列表页面点击排序效果
3.请求接口实现商品列表
4.添加购物车的数据保存到本地存储, 数据存放以及操作使用vuex。
5.商品点击加减变化效果
6.计算总数量和总价钱
7.移动端适配
列表添加至购物车(Typescript React Sho)
router-view 标签接收数据
在 main.js 页面引入 axios 插件
在 main.js 页面引入 rem 移动端适配代码
通过 rem 进行移动端适配
通过 axios 接口地址请求数据
把请求到的数据赋值给data里的选项
在 html 代码中通过 v-for 实现循环,把数据渲染至视图中
点击添加至购物车
按价格实现从高到低,从低到高
按尺码进行过滤
实现分期购买价格
通过vuex获取添加过来得数据
在 html 代码中通过 v-for 实现循环,把数据渲染至视图中
数量加减
总价和分期价格
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
Vue.prototype.$axios = axios
import '@/rem'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
const WIDTH = 375//如果是尺寸的设计稿在这里修改
const setView = () => {
//设置html标签的fontSize
document.documentElement.style.fontSize = (100 * document.documentElement.clientWidth / WIDTH) + 'px'
}
window.onresize = setView
setView()
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/shopping',
name: 'Shopping',
component:()=>import('@/views/Shopping.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<style lang="scss">
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 16px;
}
</style>
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
list: JSON.parse(localStorage.getItem('list')) || [],
},
getters: {
// 请求到多少个
totals(state) {
let num = 0;
state.list.map((item) => {
num += item.num;
});
return num;
},
// 购物车有多少个
total(state) {
let num = 0;
state.list.map((item) => {
num += item.num * item.price;
});
return num;
},
// 购物车总价
installments(state) {
let num = 0;
state.list.map((item) => {
num += (item.num * item.price) / item.installments;
});
return Math.floor(num * 100) / 100;
},
},
mutations: {
// 添加至购物车
addShopping(state, data) {
// 需要添加的内容
let arr = {id:state.list+1,title:data.title,price:data.price,style:data.style,availableSizes:data.availableSizes,num:1,installments:data.installments}
// 判断需要添加的内容在购物车中是否存在
let a = state.list.some((item) => {
return item.title == data.title;
});
// 获取添加的值在购物车中的下标
let num = 0
for(let i=0; i<state.list.length; i++){
if(state.list[i].title == data.title){
num = i
}
}
// 判断添加的内容购物车中是否存在
if (a) {
// 存在则数量加一
state.list[num].num = state.list[num].num+1
} else {
// 不存在则添加至购物车
state.list.push(arr)
}
// 存储到本地
localStorage.setItem('list',JSON.stringify(state.list))
},
// 购物车单个数量减
jian(state, data) {
// 判断数量是否大于一,大于一则点击一次减一,否则不变
data.num > 1 ? data.num = data.num - 1 : data.num
// 本地存储
localStorage.setItem('list',JSON.stringify(state.list))
},
// 购物车单个数量加
jia(state, data) {
// 点击加一
data.num = data.num + 1
// 本地存储
localStorage.setItem('list',JSON.stringify(state.list))
},
// 购物车中删除
deletes(state, data) {
// 点击删除
state.list.splice(data.id - 1, 1)
// 本地存储
localStorage.setItem('list',JSON.stringify(state.list))
},
},
actions: {
},
modules: {
}
})
<template>
<div class="box">
<div class="top">
<div class="topleft"></div>
<router-link to="/shopping" tag="div" class="topright">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADdcAAA3XAUIom3gAAAAHdElNRQfiCwwQEgYn7+gWAAABQklEQVRIx9WTsUoDQRRF72xMYSFokcRCjBFESGWRwtZe8AtEFFNrI1bB0tLGQuzs/AJB8AO2kZRCxBiRQNKIoIYoyLFwCZuss9nNgpBXzc7be3j3zow09mU48321zVF8gNtbZ5Q1UwmGYQPIxFU5vnVdUuHfARO+OD5oa9GzM6NcbICkem+CLZ0kA1zKHQ2w6tlpqRUN4AwA5knFiTAISGsuHqDfwoOkgp4kUkoP1WI+Azt02ZYk9hle3cAEBh69c7iKEOJ30IJU/71KpqbaKCH6b0LEGgTcaYXpeIj+GJf54pyI70CSTACxq1M5ehmqvDCHfwIkFrQW4S1WzXUCq+E5lNhkMqSfo0ze3t7hlWeqIfJ3GnQo2n644ZhZYMnSL9OQcKnYAHs0ueUeY+nn6eDyRskGcFjngGxIBkUqVvk41g+oBJ136GBf8AAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOC0xMS0xMlQxNjoxODowNiswMTowMEVm3zEAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTgtMTEtMTJUMTY6MTg6MDYrMDE6MDA0O2eNAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAABJRU5ErkJggg=="
alt=""
/>
<span>{{ totals }}</span>
</router-link>
</div>
<div class="sizes">
<div class="sizes-li">
<h4>Sizes:</h4>
<div class="size">
<button @click="sizes('XS')">XS</button>
<button @click="sizes('S')">S</button>
<button @click="sizes('M')">M</button>
<button @click="sizes('ML')">ML</button>
<button @click="sizes('L')">L</button>
<button @click="sizes('XL')">XL</button>
<button @click="sizes('XXL')">XXL</button>
</div>
<p>Leave a star on Github if this repository was useful :)</p>
<a href="#">Star</a>
</div>
<p>{{ listd.length }} Product(s) found</p>
<select name="" id="" v-model="val" @click="vals">
<option value="默认">默认</option>
<option value="升序">高到低</option>
<option value="降序">低到高</option>
</select>
</div>
<ul class="content">
<li v-for="item in lists" :key="item.id">
<div class="img">
<p v-show="item.isFreeShipping">免运费</p>
</div>
<div class="title">{{ item.title }}</div>
<p class="price">{{ item.currencyFormat }} {{ item.price }}</p>
<p class="installments" v-show="item.installments == 0 ? false : true">
or {{ item.installments }} x {{ item.currencyFormat }}
{{ Math.floor((item.price / item.installments) * 100) / 100 }}
</p>
<router-link to="/shopping" class="join"
><button @click="addShopping(item)">加入购物车</button></router-link
>
</li>
</ul>
</div>
</template>
<script>
import { mapState, mapGetters } from "vuex";
export default {
data() {
return {
listd: [],
lists: [],
val: "默认",
};
},
// 获取 vuex 里的内容
computed: {
...mapState(["list"]),
...mapGetters(["totals"]),
},
created() {
// 进入时调用
this.request();
},
methods: {
request() {
// 请求接口
this.$store.commit("request");
this.$axios
.get(`https://react-shopping-cart-67954.firebaseio.com/products.json`)
.then(({ data }) => {
console.log(data);
// 把请求到的值分别赋值给 listd 和 lists
this.listd = data.products;
this.lists = data.products;
// 存储到本地
localStorage.setItem("listsd", JSON.stringify(this.listd));
});
},
//添加到购物车
addShopping(item) {
this.$store.commit("addShopping", item);
},
// 点击显示尺码
sizes(val) {
// lists 赋值为空
this.lists = [];
// 给 listd 进行过滤
this.listd.filter((item, index) => {
// listd值得availableSizes进行循环
item.availableSizes.some((items) => {
// 判断availableSizes的值是否等于传递过来的参数
if (items == val) {
// 等于则追加到 lists 中
this.lists.push(item);
}
});
});
},
// 升序降序
vals() {
// 给 lists 用 sort 进行排序
this.lists.sort((p1, p2) => {
// 判断val 等于升序 则 2 - 1
if (this.val == "升序") {
return p2.price - p1.price;
// 判断val 等于降序 则 1 - 2
} else if (this.val == "降序") {
return p1.price - p2.price;
// 判断val 等于默认 则把本地存储的值赋值给lists
} else if (this.val == "默认") {
this.lists = JSON.parse(localStorage.getItem("listsd"));
}
});
},
},
};
</script>
<style lang="scss" scoped>
.box {
width: 100%;
.top {
width: 100%;
height: 0.5rem;
// background-color: red;
position: relative;
.topleft {
width: 1.2rem;
height: 1.2rem;
background-color: #000;
position: absolute;
transform: rotate(45deg);
top: -0.6rem;
left: -0.6rem;
}
.topright {
width: 0.5rem;
height: 0.5rem;
background-color: #000;
position: absolute;
right: 0;
display: flex;
justify-content: space-between;
align-items: center;
span {
display: inline-block;
position: absolute;
bottom: 0;
left: 0;
width: 0.2rem;
height: 0.2rem;
border-radius: 50%;
text-align: center;
line-height: 0.2rem;
background-color: yellow;
}
}
}
.sizes {
width: 100%;
padding: 0.15rem;
.sizes-li {
margin: 0 0.15rem;
.size {
margin: 0.2rem 0;
display: flex;
justify-content: space-between;
button {
width: 0.35rem;
height: 0.35rem;
border-radius: 50%;
background-color: aliceblue;
border: none;
}
}
p {
margin: 0.15rem 0;
font-size: 0.1rem;
}
a {
font-size: 0.15rem;
}
}
p {
margin: 0.3rem 0 0.2rem;
}
}
.content {
width: 100%;
padding: 0 0.15rem;
background-color: red;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
li {
width: 1.675rem;
height: 4.5rem;
list-style: none;
margin: 0.1rem 0;
text-align: center;
.img {
width: 100%;
height: 2.7rem;
background-color: pink;
p {
}
}
.title {
height: 0.4rem;
padding: 0 0.2rem;
margin: 0.15rem 0;
}
.price {
}
.installments {
color: gainsboro;
font-size: 0.12rem;
}
.join {
width: 100%;
height: 0.6rem;
padding: 0.15rem 0;
display: inline-block;
background-color: #000;
border: none;
margin-top: 0.1rem;
button {
border: none;
background-color: #000;
color: #fff;
}
}
}
}
}
</style>
<template>
<div class="box">
<div class="top">
<router-link to="/" tag="div" class="topleft">X</router-link>
</div>
<div class="num">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADdcAAA3XAUIom3gAAAAHdElNRQfiCwwQEgYn7+gWAAABQklEQVRIx9WTsUoDQRRF72xMYSFokcRCjBFESGWRwtZe8AtEFFNrI1bB0tLGQuzs/AJB8AO2kZRCxBiRQNKIoIYoyLFwCZuss9nNgpBXzc7be3j3zow09mU48321zVF8gNtbZ5Q1UwmGYQPIxFU5vnVdUuHfARO+OD5oa9GzM6NcbICkem+CLZ0kA1zKHQ2w6tlpqRUN4AwA5knFiTAISGsuHqDfwoOkgp4kUkoP1WI+Azt02ZYk9hle3cAEBh69c7iKEOJ30IJU/71KpqbaKCH6b0LEGgTcaYXpeIj+GJf54pyI70CSTACxq1M5ehmqvDCHfwIkFrQW4S1WzXUCq+E5lNhkMqSfo0ze3t7hlWeqIfJ3GnQo2n644ZhZYMnSL9OQcKnYAHs0ueUeY+nn6eDyRskGcFjngGxIBkUqVvk41g+oBJ136GBf8AAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOC0xMS0xMlQxNjoxODowNiswMTowMEVm3zEAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTgtMTEtMTJUMTY6MTg6MDYrMDE6MDA0O2eNAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAABJRU5ErkJggg=="
alt=""
/>
<h4>Cart</h4>
</div>
<ul class="content">
<li v-for="item in list" :key="item.id">
<div class="img"></div>
<div class="center">
<p>{{ item.title }}</p>
<p>{{ item.availableSizes[0] }} | {{ item.style }}</p>
<p>数量:{{ item.num }}</p>
</div>
<div class="right">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAOCAYAAADT0Rc6AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMzgwMTE3NDA3MjA2ODExODA4MzlFRjgwMkJGMENDMSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo0NzRFMzQ0QjI3MzgxMUU4QjRFMUVBNEJCODU5RDAzMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo0NzRFMzQ0QTI3MzgxMUU4QjRFMUVBNEJCODU5RDAzMSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RUE3RjExNzQwNzIwNjgxMUIxQTQ5QTgyNkJBMzJBOEUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDM4MDExNzQwNzIwNjgxMTgwODM5RUY4MDJCRjBDQzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5cNiR0AAAA50lEQVR42qSUaw6EMAiEYY8rB7JcVrYoNaQCNbsk88N2ypc+HICrtq69CyEvNM8mIuCk33sXTuNeaJ5zrRZ1HV361RIw2pyYd4Cp65CrWgJGmxPz6gbvZpKAMfJYw9FMEjBGntGUE3AEVC+6ppyAI6B60e8mAldAWIBD4LjTCvwAqjG5txkcAmdoBWZ/z8UL5RVQ9YF3JfB7lWtXx9v+ON4WHW8E5GTszUPiZOx+SBkQq7kFEKs5yH6LxbFn4cBBOHAUDj4GuYhBdjFIQQxyEYPsYpBGUypyd45DmppSkbtzHJ5rvwIMAKXLCXxfiHXkAAAAAElFTkSuQmCC"
@click="deletes(item)"
/>
<p>$ {{ item.price * item.num }}</p>
<div>
<button @click="jian(item)">-</button>
<button @click="jia(item)">+</button>
</div>
</div>
</li>
</ul>
<div class="bottom">
<div>
<span>小计</span>
<span>
$ {{ total }}
<p v-if="list.length < 1 ? false : true">
or up to {{ list[list.length - 1].installments }} X $
{{ installments }}
</p>
</span>
</div>
<button @click="collection">收款处</button>
</div>
</div>
</template>
<script>
import { mapGetters, mapState } from "vuex";
export default {
computed: {
// 获取 vuex 里的内容
...mapState(["list", "num"]),
...mapGetters(["total", "installments"]),
},
methods: {
// 减
jian(item) {
this.$store.commit("jian", item);
},
// 加
jia(item) {
this.$store.commit("jia", item);
},
// 收款
collection() {
alert("Checkout - Subtotal: $ " + this.total);
},
// 删除
deletes(item) {
this.$store.commit("deletes", item);
},
},
};
</script>
<style lang="scss" scoped>
.box {
width: 100%;
height: 100vh;
background-color: #000;
opacity: 0.9;
color: #fff;
.top {
.topleft {
width: 0.5rem;
height: 0.5rem;
text-align: center;
line-height: 0.5rem;
}
}
.num {
width: 100%;
// background-color: red;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
h4 {
margin-left: 0.2rem;
}
}
.content {
li {
width: 100%;
padding: 0 0.15rem;
border-top: 1px solid #000;
opacity: 1;
display: flex;
justify-content: space-between;
.img {
width: 0.5rem;
height: 0.75rem;
background-color: #fff;
}
}
}
.bottom {
width: 100%;
position: fixed;
bottom: 0;
div {
width: 100%;
display: flex;
justify-content: space-between;
}
button {
width: 100%;
height: 0.5rem;
border: none;
}
}
}
</style>
以上就是列表添加至购物车(Typescript React Shopping cart)的代码,不懂得也可以在评论区里问我,以后会持续添加一些新的功能,敬请关注。
我的其他文章:https://blog.csdn.net/weixin_62897746?type=blog