vue?實(shí)現(xiàn)列表跳轉(zhuǎn)至詳情且能添加至購(gòu)物車功能
效果概述:
列表頁(yè)面顯示數(shù)據(jù),點(diǎn)擊跳轉(zhuǎn)到對(duì)應(yīng)的詳情頁(yè),詳情頁(yè)可以添加并跳轉(zhuǎn)到購(gòu)物車,購(gòu)物車具有常見(jiàn)功能。
具體效果:
1、所有頁(yè)面根據(jù)效果圖100%還原。
2、列表頁(yè)面通過(guò)axios請(qǐng)求拿到數(shù)據(jù)并顯示。
3、跳轉(zhuǎn)到詳情頁(yè)時(shí),顯示對(duì)應(yīng)列表的數(shù)據(jù)。
4、詳情頁(yè)內(nèi)容可以添加到購(gòu)物車中并顯示。
5、購(gòu)物車商品的所有小計(jì)可根據(jù)數(shù)量的變化而動(dòng)態(tài)顯示。
6、購(gòu)物車商品的總計(jì)可根據(jù)數(shù)量的變化動(dòng)態(tài)顯示。
7、購(gòu)物車的全選按鈕可以選中所有商品,所有商品均被選中時(shí),全選按鈕也會(huì)自動(dòng)顯示被選中。
實(shí)現(xiàn)后效果圖:
vue實(shí)現(xiàn)列表的渲染并跳轉(zhuǎn)至詳情,并可以加入購(gòu)物車
大致代碼思路
- 根頁(yè)面:
使用 router-link 標(biāo)簽寫(xiě)出頁(yè)面跳轉(zhuǎn)塊
并在 vuex 里引入購(gòu)物車?yán)锏膬?nèi)容,把他的長(zhǎng)度顯示在購(gòu)物車字體的左上角
- 列表頁(yè):
在 main.js 頁(yè)面引入 axios 插件
在 main.js 頁(yè)面引入 rem 移動(dòng)端適配代碼
通過(guò) rem 進(jìn)行移動(dòng)端適配
通過(guò) axios 接口地址請(qǐng)求數(shù)據(jù)
把請(qǐng)求到的數(shù)據(jù)賦值給data里的選項(xiàng)
在 html 代碼中通過(guò) v-for 實(shí)現(xiàn)循環(huán),把數(shù)據(jù)渲染至視圖中
使用 router-link 標(biāo)簽實(shí)現(xiàn)跳轉(zhuǎn)功能,并把列表的 id 通過(guò) query 傳遞至跳轉(zhuǎn)后的頁(yè)面
- 詳情頁(yè):
使用 this.$route.query.id 獲取上個(gè)頁(yè)面通過(guò) query 傳遞的 id 值
使用 axios 接口地址和接收到的 id 值請(qǐng)求詳細(xì)數(shù)據(jù)
把請(qǐng)求到的數(shù)據(jù)賦值給data里的選項(xiàng)
在 html 代碼中通過(guò) v-for 實(shí)現(xiàn)循環(huán),把數(shù)據(jù)渲染至視圖中
通過(guò)編程式導(dǎo)航,實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)效果,并在組件中整理需要添加至購(gòu)物車?yán)锏膬?nèi)容
并通過(guò)動(dòng)畫(huà)效果實(shí)現(xiàn)添加時(shí)執(zhí)行的動(dòng)畫(huà)效果
把需要添加至購(gòu)物車的內(nèi)容,通過(guò) vuex 的同步請(qǐng)求,把內(nèi)容添加至 vuex 里面
添加后把內(nèi)容保存至本地
- 購(gòu)物車頁(yè):
通過(guò) vuex 的輔助函數(shù)獲取到上個(gè)頁(yè)面中添加的內(nèi)容
通過(guò) v-for 循環(huán),渲染到視圖中
通過(guò)全選按鈕實(shí)現(xiàn)全選/全不選功能
點(diǎn)擊全選則全選的值進(jìn)行反轉(zhuǎn)
通過(guò) some 循環(huán),把全選的值賦值給所有單選框
單選全部選中則全選也選中
使用 filter 過(guò)濾出所有單選框?yàn)?true 的列表
把他的長(zhǎng)度和所有列表的長(zhǎng)度進(jìn)行比較
如果等于則全選框?yàn)?true,否則全選框的值為 false
點(diǎn)擊加則數(shù)量加一,點(diǎn)擊減則數(shù)量減一
單價(jià)等于 單個(gè)的價(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')
移動(dòng)端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()
解決跨域問(wèn)題,在vue.config.js里添加代碼
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, // 解決跨域問(wèn)題 devServer:{ proxy:{ '/api':{ target: 'http://192.168.1.13:8765/', pathRewrite:{ '^/api': '' } } } } })
實(shí)現(xiàn)路由跳轉(zhuǎn)頁(yè)代碼
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"> <!-- 切換頁(yè) --> <router-link to="/">首頁(yè)</router-link> <router-link to="/shopping" >購(gòu)物車<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>
效果列表頁(yè)代碼
<template> <div class="home-box"> <ul> <!-- 聲明式導(dǎo)航,通過(guò)query把id值傳遞至詳情頁(yè)中 --> <!-- 給 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)入頁(yè)面時(shí)執(zhí)行該方法 this.request(); }, methods: { // 請(qǐng)求 request() { // 請(qǐng)求到所以數(shù)據(jù) this.$axios.get(`/api/meishi?star=1&num=15`).then((res) => { // 把請(qǐng)求到的數(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; //對(duì)象作為彈性伸縮盒子模型顯示 overflow: hidden; //溢出隱藏 -webkit-box-orient: vertical; //設(shè)置伸縮盒子對(duì)象的子元素的排列方式 -webkit-line-clamp: 2; //設(shè)置 塊元素包含的文本行數(shù) } } } } } </style>
詳情頁(yè)代碼
<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)至購(gòu)物車頁(yè)面,并添加當(dāng)前頁(yè)面內(nèi)容至購(gòu)物車。同時(shí)執(zhí)行兩個(gè)點(diǎn)擊事件--> <button @click="ShoppingClick(), isends()">加入購(gòu)物車</button> <!-- 添加時(shí)的樣式 --> <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)入時(shí)執(zhí)行請(qǐng)求 this.request(); }, methods: { // 請(qǐng)求 request() { // 使用axios請(qǐng)求所需下標(biāo)的參數(shù) this.$axios.get(`/api/meishi?id=${this.$route.query.id}`).then((res) => { // 把請(qǐng)求到的值賦值給data里的list參數(shù) this.list = res.data; }); }, // 加入購(gòu)物車 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)至購(gòu)物車頁(yè)面,等樣式執(zhí)行完畢后跳轉(zhuǎn) setTimeout(() => { this.$router.push({ name: "Shopping", }); }, 500); }, isends() { // 添加至購(gòu)物車時(shí)的樣式 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; } // 添加開(kāi)始時(shí)的動(dòng)畫(huà)效果 .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é)束后的動(dòng)畫(huà)效果 .js_animation_box.end { opacity: 1; position: fixed; bottom: 0.2rem; left: 60%; } } } </style>
購(gòu)物車頁(yè)面代碼
<template> <div class="Shopping-box"> <div class="top">購(gòu)物車</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> <!-- 單個(gè)價(jià)格 --> <p class="price">¥{{ item.Price * item.num }}</p> <span class="number"> <!-- 點(diǎn)擊實(shí)現(xiàn)單個(gè)加一 --> <button @click="addClick(item)">+</button> <!-- 單個(gè)數(shù)量 --> <input type="text" v-model="item.num" /> <!-- 點(diǎn)擊實(shí)現(xiàn)單個(gè)減一 --> <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() { // 聲明一個(gè)變量 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"); }, // 單個(gè)數(shù)量加 addClick(item) { // 觸發(fā)vuex里的同步提交 this.$store.commit("addClick", item); }, // 單個(gè)數(shù)量減 subtract(item) { // 觸發(fā)vuex里的同步提交,把 item 代表的值傳遞過(guò)去 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頁(yè)面代碼
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ // 頁(yè)面刷新時(shí)調(diào)用 state: { // 如果有本地存儲(chǔ)則顯示否則顯示空數(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值得長(zhǎng)度是否等于所以的長(zhǎng)度,如果等于則全選框選中,否則不選中 arr.length == state.lists.length ? (state.alls = true) : (state.alls = false); }, // 加入購(gòu)物車 ShoppingClick(state,data){ // 給 lists 進(jìn)行 some 循環(huán) let a = state.lists.some((item)=>{ // lists 里存在的和添加的name名相同則返回true,否則返回false return item.name == data.name }) // 判斷出加入購(gòu)物車時(shí)已經(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)容購(gòu)物車內(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)行過(guò)濾 let arr = state.lists.filter((item) => { // 返回checked為true的值 return item.checked; }); // 判斷l(xiāng)ists里checked為true值得長(zhǎng)度是否等于所以的長(zhǎng)度,如果等于則全選框選中,否則不選中 arr.length == state.lists.length ? (state.alls = true) : (state.alls = false); // 保存至本地 localStorage.setItem('list',JSON.stringify(state.lists)) }, // 單個(gè)價(jià)格加 addClick(state,item){ // 傳遞過(guò)來(lái)的當(dāng)前列表里的num加1 item.num = item.num+1 // console.log(state.number); // 保存至本地 localStorage.setItem('list',JSON.stringify(state.lists)) }, // 單個(gè)價(jià)格減 subtract(state,item){ // 判斷數(shù)量是否大于1 if(item.num>1){ // 大于1則執(zhí)行,傳遞過(guò)來(lái)的當(dāng)前列表里的num減1 item.num = item.num-1 // 保存至本地 localStorage.setItem('list',JSON.stringify(state.lists)) } } }, actions: { }, modules: { } })
以上就是列表跳轉(zhuǎn)至詳情并加入購(gòu)物車的代碼,不懂得也可以在評(píng)論區(qū)里問(wèn)我,以后會(huì)持續(xù)添加一些新的功能,敬請(qǐng)關(guān)注。
到此這篇關(guān)于vue 實(shí)現(xiàn)列表跳轉(zhuǎn)至詳情且能添加至購(gòu)物車的文章就介紹到這了,更多相關(guān)vue添加購(gòu)物車內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Vue+Node實(shí)現(xiàn)商品列表的分頁(yè)、排序、篩選,添加購(gòu)物車功能詳解
- vue從后臺(tái)渲染文章列表以及根據(jù)id跳轉(zhuǎn)文章詳情詳解
- vue 列表頁(yè)跳轉(zhuǎn)詳情頁(yè)獲取id以及詳情頁(yè)通過(guò)id獲取數(shù)據(jù)
- vue 詳情跳轉(zhuǎn)至列表頁(yè)實(shí)現(xiàn)列表頁(yè)緩存
- 基于vue循環(huán)列表時(shí)點(diǎn)擊跳轉(zhuǎn)頁(yè)面的方法
- vue如何通過(guò)id從列表頁(yè)跳轉(zhuǎn)到對(duì)應(yīng)的詳情頁(yè)
相關(guān)文章
vue-editor-bridge報(bào)錯(cuò)的解決方案
這篇文章主要介紹了vue-editor-bridge報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04vue+element tabs選項(xiàng)卡分頁(yè)效果
這篇文章主要為大家詳細(xì)介紹了vue+element tabs選項(xiàng)卡分頁(yè)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09Vue 樣式切換及三元判斷樣式關(guān)聯(lián)操作
這篇文章主要介紹了Vue 樣式切換及三元判斷樣式關(guān)聯(lián)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08vue多語(yǔ)言轉(zhuǎn)換的幾種方法總結(jié)
這篇文章主要介紹了vue多語(yǔ)言轉(zhuǎn)換的幾種方法總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02Vue CLI4.0 webpack配置屬性之productionSourceMap用法
這篇文章主要介紹了Vue CLI4.0 webpack配置屬性之productionSourceMap用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06vue的template模板是如何轉(zhuǎn)為render函數(shù)的過(guò)程
Vue從template到render函數(shù)的轉(zhuǎn)換經(jīng)歷模板解析、AST構(gòu)建、優(yōu)化、生成渲染函數(shù)等步驟,首先進(jìn)行詞法分析將模板拆解為tokens,再進(jìn)行語(yǔ)法分析構(gòu)建AST,然后對(duì)AST進(jìn)行靜態(tài)標(biāo)記和提升優(yōu)化,最后轉(zhuǎn)換成JavaScript渲染函數(shù),生成虛擬DOM,完成組件的渲染和更新,實(shí)現(xiàn)了模板的高效轉(zhuǎn)化2024-10-10