vue?實(shí)現(xiàn)列表跳轉(zhuǎn)至詳情且能添加至購物車功能
效果概述:
列表頁面顯示數(shù)據(jù),點(diǎn)擊跳轉(zhuǎn)到對應(yīng)的詳情頁,詳情頁可以添加并跳轉(zhuǎn)到購物車,購物車具有常見功能。
具體效果:
1、所有頁面根據(jù)效果圖100%還原。
2、列表頁面通過axios請求拿到數(shù)據(jù)并顯示。
3、跳轉(zhuǎn)到詳情頁時,顯示對應(yīng)列表的數(shù)據(jù)。
4、詳情頁內(nèi)容可以添加到購物車中并顯示。
5、購物車商品的所有小計(jì)可根據(jù)數(shù)量的變化而動態(tài)顯示。
6、購物車商品的總計(jì)可根據(jù)數(shù)量的變化動態(tài)顯示。
7、購物車的全選按鈕可以選中所有商品,所有商品均被選中時,全選按鈕也會自動顯示被選中。
實(shí)現(xiàn)后效果圖:

vue實(shí)現(xiàn)列表的渲染并跳轉(zhuǎn)至詳情,并可以加入購物車
大致代碼思路
- 根頁面:
使用 router-link 標(biāo)簽寫出頁面跳轉(zhuǎn)塊
并在 vuex 里引入購物車?yán)锏膬?nèi)容,把他的長度顯示在購物車字體的左上角
- 列表頁:
在 main.js 頁面引入 axios 插件
在 main.js 頁面引入 rem 移動端適配代碼
通過 rem 進(jìn)行移動端適配
通過 axios 接口地址請求數(shù)據(jù)
把請求到的數(shù)據(jù)賦值給data里的選項(xiàng)
在 html 代碼中通過 v-for 實(shí)現(xiàn)循環(huán),把數(shù)據(jù)渲染至視圖中
使用 router-link 標(biāo)簽實(shí)現(xiàn)跳轉(zhuǎn)功能,并把列表的 id 通過 query 傳遞至跳轉(zhuǎn)后的頁面
- 詳情頁:
使用 this.$route.query.id 獲取上個頁面通過 query 傳遞的 id 值
使用 axios 接口地址和接收到的 id 值請求詳細(xì)數(shù)據(jù)
把請求到的數(shù)據(jù)賦值給data里的選項(xiàng)
在 html 代碼中通過 v-for 實(shí)現(xiàn)循環(huán),把數(shù)據(jù)渲染至視圖中
通過編程式導(dǎo)航,實(shí)現(xiàn)頁面跳轉(zhuǎn)效果,并在組件中整理需要添加至購物車?yán)锏膬?nèi)容
并通過動畫效果實(shí)現(xiàn)添加時執(zhí)行的動畫效果
把需要添加至購物車的內(nèi)容,通過 vuex 的同步請求,把內(nèi)容添加至 vuex 里面
添加后把內(nèi)容保存至本地
- 購物車頁:
通過 vuex 的輔助函數(shù)獲取到上個頁面中添加的內(nèi)容
通過 v-for 循環(huán),渲染到視圖中
通過全選按鈕實(shí)現(xiàn)全選/全不選功能
點(diǎn)擊全選則全選的值進(jìn)行反轉(zhuǎn)
通過 some 循環(huán),把全選的值賦值給所有單選框
單選全部選中則全選也選中
使用 filter 過濾出所有單選框?yàn)?true 的列表
把他的長度和所有列表的長度進(jìn)行比較
如果等于則全選框?yàn)?true,否則全選框的值為 false
點(diǎn)擊加則數(shù)量加一,點(diǎn)擊減則數(shù)量減一
單價(jià)等于 單個的價(jià)格乘以數(shù)量
總價(jià)等于 單價(jià)乘以數(shù)量后所有的加在一起
main.js 代碼
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
// 引入rem
import "./rem"
// 引入axios
import axios from 'axios'
// 將axios添加到vue的原型上
Vue.prototype.$axios = axios
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
移動端rem適配代碼
const WIDTH = 375//如果是尺寸的設(shè)計(jì)稿在這里修改
const setView = () => {
//設(shè)置html標(biāo)簽的fontSize
document.documentElement.style.fontSize = (100 * document.documentElement.clientWidth / WIDTH) + 'px'
}
window.onresize = setView
setView()
解決跨域問題,在vue.config.js里添加代碼
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
// 解決跨域問題
devServer:{
proxy:{
'/api':{
target: 'http://192.168.1.13:8765/',
pathRewrite:{
'^/api': ''
}
}
}
}
})
實(shí)現(xiàn)路由跳轉(zhuǎn)頁代碼
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home.vue'
Vue.use(VueRouter)
// 配置路由跳轉(zhuǎn)項(xiàng)
const routes = [
{
path:'/',
name:'Home',
component: Home
},
{
path:'/detail',
name:'Detail',
component: ()=> import('@/views/Detail.vue')
},
{
path:'/shopping',
name:'Shopping',
component: ()=> import('@/views/Shopping.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
})
export default router
app根組件代碼
<template>
<div id="app">
<div class="lists">
<!-- 切換頁 -->
<router-link to="/">首頁</router-link>
<router-link to="/shopping"
>購物車<span v-show="total">{{ total }}</span></router-link
>
</div>
<!-- 路由的出口,所有的數(shù)據(jù)都在這里顯示 -->
<router-view></router-view>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {};
},
computed: {
...mapState(["lists"]),
total() {
let num = 0;
this.lists.map((item) => {
num += item.num;
});
return num;
},
},
};
</script>
<style lang="scss">
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 16px;
}
#app {
.lists {
display: flex;
justify-content: space-around;
align-items: center;
width: 100%;
height: 0.5rem;
border-top: 1px solid gainsboro;
background-color: #fff;
position: fixed;
bottom: 0;
left: 0;
a {
display: inline-block;
width: 50%;
height: 0.5rem;
color: #000;
text-align: center;
line-height: 0.5rem;
text-decoration: none;
position: relative;
span {
display: inline-block;
width: 0.2rem;
height: 0.2rem;
background-color: red;
border-radius: 50%;
color: #000;
text-align: center;
line-height: 0.2rem;
position: absolute;
top: 0.09rem;
left: 30%;
opacity: 0.8;
}
&.router-link-exact-active {
color: red;
}
}
}
}
</style>
效果列表頁代碼
<template>
<div class="home-box">
<ul>
<!-- 聲明式導(dǎo)航,通過query把id值傳遞至詳情頁中 -->
<!-- 給 list 屬性執(zhí)行for循環(huán) -->
<router-link
:to="{ name: 'Detail', query: { id: item.id } }"
class="home-row"
v-for="item in list"
:key="item.id"
>
<span class="left">
<!-- 圖片 -->
<img :src="item.imgsrc" />
</span>
<span class="right">
<!-- 名稱 -->
<h3>{{ item.name }}</h3>
<p>
<!-- 價(jià)格 -->
<b>¥{{ item.price }}</b>
</p>
</span>
</router-link>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
};
},
created() {
// 進(jìn)入頁面時執(zhí)行該方法
this.request();
},
methods: {
// 請求
request() {
// 請求到所以數(shù)據(jù)
this.$axios.get(`/api/meishi?star=1&num=15`).then((res) => {
// 把請求到的數(shù)據(jù)賦值給list
this.list = res.data;
});
},
},
};
</script>
<style lang="scss" scoped>
.home-box {
width: 100%;
background-color: #f6f6f6;
display: flex;
justify-content: center;
ul {
margin: 0 0.2rem;
.home-row {
width: 3.55rem;
height: 1rem;
color: #000;
margin-top: 0.1rem;
text-decoration: none;
padding: 0.1rem;
display: inline-block;
background-color: #fff;
display: flex;
justify-content: center;
.left {
img {
width: 0.8rem;
}
}
.right {
padding-left: 0.2rem;
h3 {
width: 2.35rem;
font-size: 0.18rem;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
p {
padding-top: 0.2rem;
font-size: 0.14rem;
text-align: center;
display: -webkit-box; //對象作為彈性伸縮盒子模型顯示
overflow: hidden; //溢出隱藏
-webkit-box-orient: vertical; //設(shè)置伸縮盒子對象的子元素的排列方式
-webkit-line-clamp: 2; //設(shè)置 塊元素包含的文本行數(shù)
}
}
}
}
}
</style>
詳情頁代碼
<template>
<div class="detail-box">
<span>
<!-- 圖片 -->
<img :src="list.imgsrc" />
</span>
<span>
<!-- 名稱 -->
<h3>{{ list.name }}</h3>
</span>
<span>
<!-- 介紹 -->
<p>{{ list.contents.content.toString() }}</p>
</span>
<span>
<p>
<!-- 價(jià)格 -->
<b>¥{{ list.price }}</b>
</p>
</span>
<span>
<!-- 點(diǎn)擊跳轉(zhuǎn)至購物車頁面,并添加當(dāng)前頁面內(nèi)容至購物車。同時執(zhí)行兩個點(diǎn)擊事件-->
<button @click="ShoppingClick(), isends()">加入購物車</button>
<!-- 添加時的樣式 -->
<span :class="['js_animation_box', isEnd ? 'end' : '']">
<img :src="list.imgsrc" />
</span>
</span>
</div>
</template>
<script>
// 引入vuex里的輔助函數(shù)
import { mapState } from "vuex";
export default {
data() {
return {
list: [],
isEnd: false,
};
},
computed: {
// 獲取vuex里面的值
...mapState(["lists"]),
},
created() {
// 進(jìn)入時執(zhí)行請求
this.request();
},
methods: {
// 請求
request() {
// 使用axios請求所需下標(biāo)的參數(shù)
this.$axios.get(`/api/meishi?id=${this.$route.query.id}`).then((res) => {
// 把請求到的值賦值給data里的list參數(shù)
this.list = res.data;
});
},
// 加入購物車
ShoppingClick() {
// 自定義添加的內(nèi)容
let arr = {
// 單選框
checked: true,
// id值
id: this.lists.length + 1,
// 圖片鏈接
img: this.list.imgsrc,
// name名稱
name: this.list.name,
// 單價(jià)
Price: this.list.price,
// 數(shù)量
num: 1,
};
// 觸發(fā)vuex里的功能,把自定義的內(nèi)容傳遞值vuex
this.$store.commit("ShoppingClick", arr);
// 編程式導(dǎo)航,跳轉(zhuǎn)至購物車頁面,等樣式執(zhí)行完畢后跳轉(zhuǎn)
setTimeout(() => {
this.$router.push({
name: "Shopping",
});
}, 500);
},
isends() {
// 添加至購物車時的樣式
this.isEnd = true;
setTimeout(() => {
this.isEnd = false;
}, 500);
},
},
};
</script>
<style lang="scss" scoped>
.detail-box {
width: 100%;
height: 100vh;
background-color: #f6f6f6;
span {
display: inline-block;
margin: 0 0.05rem;
display: flex;
justify-content: center;
img {
width: 3.65rem;
height: 3.65rem;
}
h3 {
font-size: 0.2rem;
margin-top: 0.15rem;
}
p {
margin-top: 0.15rem;
}
// 添加開始時的動畫效果
.js_animation_box {
display: inline-block;
width: 0.2rem;
height: 0.2rem;
opacity: 0;
transition: 0.5s all;
position: fixed;
bottom: 80%;
left: 48%;
img {
width: 0.2rem;
height: 0.2rem;
}
}
// 添加結(jié)束后的動畫效果
.js_animation_box.end {
opacity: 1;
position: fixed;
bottom: 0.2rem;
left: 60%;
}
}
}
</style>
購物車頁面代碼
<template>
<div class="Shopping-box">
<div class="top">購物車</div>
<ul class="content">
<!-- 循環(huán) -->
<li class="Shopping-row" v-for="item in lists" :key="item.id">
<!-- 單選框 -->
<input type="checkbox" v-model="item.checked" @change="checkClick" />
<!-- 圖片 -->
<img :src="item.img" alt="" />
<div class="row-right">
<span class="name">{{ item.name }}</span>
<!-- 單個價(jià)格 -->
<p class="price">¥{{ item.Price * item.num }}</p>
<span class="number">
<!-- 點(diǎn)擊實(shí)現(xiàn)單個加一 -->
<button @click="addClick(item)">+</button>
<!-- 單個數(shù)量 -->
<input type="text" v-model="item.num" />
<!-- 點(diǎn)擊實(shí)現(xiàn)單個減一 -->
<button @click="subtract(item)">-</button>
</span>
</div>
</li>
</ul>
<div class="bottom">
<span>
<input type="checkbox" v-model="alls" @change="AllClick" />
全選
</span>
<!-- 總價(jià) -->
<span>總計(jì):¥{{ total }}</span>
</div>
</div>
</template>
<script>
// 引入 vuex 的輔助函數(shù)
import { mapState } from "vuex";
export default {
data() {
return {};
},
computed: {
// 獲取vuex里面的值
...mapState(["lists", "alls", "number"]),
// 總計(jì)
total() {
// 聲明一個變量 num ,默認(rèn)為0
let num = 0;
// 給 lists 數(shù)組進(jìn)行 map 循環(huán)
this.lists.map((item) => {
// 判斷是否選中
if (item.checked) {
// num += 數(shù)量 乘以 單價(jià)
// +=代表:a+=2 a=a+2
num += item.num * item.Price;
}
});
// 把 num 值 return 給 total
return num;
},
},
created() {
this.$store.commit("createds");
},
methods: {
// 全選
AllClick() {
// 觸發(fā)vuex里的同步提交
this.$store.commit("AllClick");
},
// 單選
checkClick() {
// 觸發(fā)vuex里的同步提交
this.$store.commit("checkClick");
},
// 單個數(shù)量加
addClick(item) {
// 觸發(fā)vuex里的同步提交
this.$store.commit("addClick", item);
},
// 單個數(shù)量減
subtract(item) {
// 觸發(fā)vuex里的同步提交,把 item 代表的值傳遞過去
this.$store.commit("subtract", item);
},
},
};
</script>
<style lang="scss" scoped>
.Shopping-box {
width: 100%;
// height: 100vh;
min-height: 100vh;
background-color: #f6f6f6;
.top {
width: 100%;
height: 0.5rem;
text-align: center;
line-height: 0.5rem;
font-size: 0.2rem;
background-color: #fff;
position: fixed;
top: 0;
left: 0;
}
.content {
width: 3.55rem;
margin: 0 0.1rem;
overflow: hidden;
.Shopping-row:first-child {
margin-top: 0.6rem;
}
.Shopping-row:last-child {
margin-bottom: 0.6rem;
}
.Shopping-row {
height: 1rem;
margin-top: 0.12rem;
padding: 0.1rem;
background-color: #fff;
display: flex;
justify-content: center;
img {
width: 0.8rem;
height: 0.8rem;
margin: 0 0.1rem;
}
.row-right {
.name {
display: inline-block;
width: 2.3rem;
font-weight: 800;
font-size: 0.18rem;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.price {
color: red;
font-size: 0.16rem;
}
.number {
height: 0.2rem;
display: inline-block;
border: 1px solid #f6f6f6;
border-radius: 50%;
line-height: 0.3rem;
button {
width: 0.2rem;
border-radius: 50%;
border: none;
text-align: center;
}
input {
text-align: center;
width: 0.3rem;
border: none;
}
}
}
}
}
.bottom {
width: 3.75rem;
height: 0.5rem;
padding: 0 0.1rem;
display: flex;
line-height: 0.5rem;
font-size: 0.16rem;
background-color: #fff;
justify-content: space-between;
position: fixed;
bottom: 0;
left: 0;
}
}
</style>
vuex頁面代碼
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// 頁面刷新時調(diào)用
state: {
// 如果有本地存儲則顯示否則顯示空數(shù)組
lists:JSON.parse(localStorage.getItem('list')) || [],
// 全選框
alls:false,
},
getters: {
},
mutations: {
createds(state){
let arr = state.lists.filter((item) => {
// 返回checked為true的值
return item.checked;
});
// 判斷l(xiāng)ists里checked為true值得長度是否等于所以的長度,如果等于則全選框選中,否則不選中
arr.length == state.lists.length ? (state.alls = true) : (state.alls = false);
},
// 加入購物車
ShoppingClick(state,data){
// 給 lists 進(jìn)行 some 循環(huán)
let a = state.lists.some((item)=>{
// lists 里存在的和添加的name名相同則返回true,否則返回false
return item.name == data.name
})
// 判斷出加入購物車時已經(jīng)存在的下標(biāo)
let num = 0
for(let i=0; i<state.lists.length; i++){
if(state.lists[i].name == data.name){
num = i
}
}
// 判斷 添加的內(nèi)容購物車內(nèi)是否已經(jīng)存在
if(a){
// 已經(jīng)存在則數(shù)量加一
state.lists[num].num = state.lists[num].num+1
// 并且進(jìn)行選中
state.lists[num].checked = true
// 保存至本地
localStorage.setItem('list',JSON.stringify(state.lists))
}else{
// 如果不存在則添加
state.lists.push(data)
// 保存至本地
localStorage.setItem('list',JSON.stringify(state.lists))
}
this.commit('createds')
},
// 全選
AllClick(state){
// 把全選的值改為相反
state.alls = !state.alls
// 循環(huán)lists
state.lists.some((item)=>{
// lists里input框的值,等于全選的值
item.checked = state.alls
})
// 保存至本地
localStorage.setItem('list',JSON.stringify(state.lists))
},
// 單選
checkClick(state){
// 給lists進(jìn)行過濾
let arr = state.lists.filter((item) => {
// 返回checked為true的值
return item.checked;
});
// 判斷l(xiāng)ists里checked為true值得長度是否等于所以的長度,如果等于則全選框選中,否則不選中
arr.length == state.lists.length ? (state.alls = true) : (state.alls = false);
// 保存至本地
localStorage.setItem('list',JSON.stringify(state.lists))
},
// 單個價(jià)格加
addClick(state,item){
// 傳遞過來的當(dāng)前列表里的num加1
item.num = item.num+1
// console.log(state.number);
// 保存至本地
localStorage.setItem('list',JSON.stringify(state.lists))
},
// 單個價(jià)格減
subtract(state,item){
// 判斷數(shù)量是否大于1
if(item.num>1){
// 大于1則執(zhí)行,傳遞過來的當(dāng)前列表里的num減1
item.num = item.num-1
// 保存至本地
localStorage.setItem('list',JSON.stringify(state.lists))
}
}
},
actions: {
},
modules: {
}
})
以上就是列表跳轉(zhuǎn)至詳情并加入購物車的代碼,不懂得也可以在評論區(qū)里問我,以后會持續(xù)添加一些新的功能,敬請關(guān)注。
到此這篇關(guān)于vue 實(shí)現(xiàn)列表跳轉(zhuǎn)至詳情且能添加至購物車的文章就介紹到這了,更多相關(guān)vue添加購物車內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue+element tabs選項(xiàng)卡分頁效果
這篇文章主要為大家詳細(xì)介紹了vue+element tabs選項(xiàng)卡分頁效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09
Vue 樣式切換及三元判斷樣式關(guān)聯(lián)操作
這篇文章主要介紹了Vue 樣式切換及三元判斷樣式關(guān)聯(lián)操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
Vue CLI4.0 webpack配置屬性之productionSourceMap用法
這篇文章主要介紹了Vue CLI4.0 webpack配置屬性之productionSourceMap用法,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06
vue的template模板是如何轉(zhuǎn)為render函數(shù)的過程
Vue從template到render函數(shù)的轉(zhuǎn)換經(jīng)歷模板解析、AST構(gòu)建、優(yōu)化、生成渲染函數(shù)等步驟,首先進(jìn)行詞法分析將模板拆解為tokens,再進(jìn)行語法分析構(gòu)建AST,然后對AST進(jìn)行靜態(tài)標(biāo)記和提升優(yōu)化,最后轉(zhuǎn)換成JavaScript渲染函數(shù),生成虛擬DOM,完成組件的渲染和更新,實(shí)現(xiàn)了模板的高效轉(zhuǎn)化2024-10-10

