vue?實現(xiàn)列表跳轉(zhuǎn)至詳情且能添加至購物車功能
效果概述:
列表頁面顯示數(shù)據(jù),點擊跳轉(zhuǎn)到對應的詳情頁,詳情頁可以添加并跳轉(zhuǎn)到購物車,購物車具有常見功能。
具體效果:
1、所有頁面根據(jù)效果圖100%還原。
2、列表頁面通過axios請求拿到數(shù)據(jù)并顯示。
3、跳轉(zhuǎn)到詳情頁時,顯示對應列表的數(shù)據(jù)。
4、詳情頁內(nèi)容可以添加到購物車中并顯示。
5、購物車商品的所有小計可根據(jù)數(shù)量的變化而動態(tài)顯示。
6、購物車商品的總計可根據(jù)數(shù)量的變化動態(tài)顯示。
7、購物車的全選按鈕可以選中所有商品,所有商品均被選中時,全選按鈕也會自動顯示被選中。
實現(xiàn)后效果圖:
vue實現(xiàn)列表的渲染并跳轉(zhuǎn)至詳情,并可以加入購物車
大致代碼思路
- 根頁面:
使用 router-link 標簽寫出頁面跳轉(zhuǎn)塊
并在 vuex 里引入購物車里的內(nèi)容,把他的長度顯示在購物車字體的左上角
- 列表頁:
在 main.js 頁面引入 axios 插件
在 main.js 頁面引入 rem 移動端適配代碼
通過 rem 進行移動端適配
通過 axios 接口地址請求數(shù)據(jù)
把請求到的數(shù)據(jù)賦值給data里的選項
在 html 代碼中通過 v-for 實現(xiàn)循環(huán),把數(shù)據(jù)渲染至視圖中
使用 router-link 標簽實現(xiàn)跳轉(zhuǎn)功能,并把列表的 id 通過 query 傳遞至跳轉(zhuǎn)后的頁面
- 詳情頁:
使用 this.$route.query.id 獲取上個頁面通過 query 傳遞的 id 值
使用 axios 接口地址和接收到的 id 值請求詳細數(shù)據(jù)
把請求到的數(shù)據(jù)賦值給data里的選項
在 html 代碼中通過 v-for 實現(xiàn)循環(huán),把數(shù)據(jù)渲染至視圖中
通過編程式導航,實現(xiàn)頁面跳轉(zhuǎn)效果,并在組件中整理需要添加至購物車里的內(nèi)容
并通過動畫效果實現(xiàn)添加時執(zhí)行的動畫效果
把需要添加至購物車的內(nèi)容,通過 vuex 的同步請求,把內(nèi)容添加至 vuex 里面
添加后把內(nèi)容保存至本地
- 購物車頁:
通過 vuex 的輔助函數(shù)獲取到上個頁面中添加的內(nèi)容
通過 v-for 循環(huán),渲染到視圖中
通過全選按鈕實現(xiàn)全選/全不選功能
點擊全選則全選的值進行反轉(zhuǎn)
通過 some 循環(huán),把全選的值賦值給所有單選框
單選全部選中則全選也選中
使用 filter 過濾出所有單選框為 true 的列表
把他的長度和所有列表的長度進行比較
如果等于則全選框為 true,否則全選框的值為 false
點擊加則數(shù)量加一,點擊減則數(shù)量減一
單價等于 單個的價格乘以數(shù)量
總價等于 單價乘以數(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//如果是尺寸的設計稿在這里修改 const setView = () => { //設置html標簽的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': '' } } } } })
實現(xiàn)路由跳轉(zhuǎn)頁代碼
import Vue from 'vue' import VueRouter from 'vue-router' import Home from '@/views/Home.vue' Vue.use(VueRouter) // 配置路由跳轉(zhuǎn)項 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> <!-- 聲明式導航,通過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> <!-- 價格 --> <b>¥{{ item.price }}</b> </p> </span> </router-link> </ul> </div> </template> <script> export default { data() { return { list: [], }; }, created() { // 進入頁面時執(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; //設置伸縮盒子對象的子元素的排列方式 -webkit-line-clamp: 2; //設置 塊元素包含的文本行數(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> <!-- 價格 --> <b>¥{{ list.price }}</b> </p> </span> <span> <!-- 點擊跳轉(zhuǎn)至購物車頁面,并添加當前頁面內(nèi)容至購物車。同時執(zhí)行兩個點擊事件--> <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() { // 進入時執(zhí)行請求 this.request(); }, methods: { // 請求 request() { // 使用axios請求所需下標的參數(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, // 單價 Price: this.list.price, // 數(shù)量 num: 1, }; // 觸發(fā)vuex里的功能,把自定義的內(nèi)容傳遞值vuex this.$store.commit("ShoppingClick", arr); // 編程式導航,跳轉(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> <!-- 單個價格 --> <p class="price">¥{{ item.Price * item.num }}</p> <span class="number"> <!-- 點擊實現(xiàn)單個加一 --> <button @click="addClick(item)">+</button> <!-- 單個數(shù)量 --> <input type="text" v-model="item.num" /> <!-- 點擊實現(xiàn)單個減一 --> <button @click="subtract(item)">-</button> </span> </div> </li> </ul> <div class="bottom"> <span> <input type="checkbox" v-model="alls" @change="AllClick" /> 全選 </span> <!-- 總價 --> <span>總計:¥{{ total }}</span> </div> </div> </template> <script> // 引入 vuex 的輔助函數(shù) import { mapState } from "vuex"; export default { data() { return {}; }, computed: { // 獲取vuex里面的值 ...mapState(["lists", "alls", "number"]), // 總計 total() { // 聲明一個變量 num ,默認為0 let num = 0; // 給 lists 數(shù)組進行 map 循環(huán) this.lists.map((item) => { // 判斷是否選中 if (item.checked) { // num += 數(shù)量 乘以 單價 // +=代表: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 進行 some 循環(huán) let a = state.lists.some((item)=>{ // lists 里存在的和添加的name名相同則返回true,否則返回false return item.name == data.name }) // 判斷出加入購物車時已經(jīng)存在的下標 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 // 并且進行選中 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進行過濾 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)) }, // 單個價格加 addClick(state,item){ // 傳遞過來的當前列表里的num加1 item.num = item.num+1 // console.log(state.number); // 保存至本地 localStorage.setItem('list',JSON.stringify(state.lists)) }, // 單個價格減 subtract(state,item){ // 判斷數(shù)量是否大于1 if(item.num>1){ // 大于1則執(zhí)行,傳遞過來的當前列表里的num減1 item.num = item.num-1 // 保存至本地 localStorage.setItem('list',JSON.stringify(state.lists)) } } }, actions: { }, modules: { } })
以上就是列表跳轉(zhuǎn)至詳情并加入購物車的代碼,不懂得也可以在評論區(qū)里問我,以后會持續(xù)添加一些新的功能,敬請關注。
到此這篇關于vue 實現(xiàn)列表跳轉(zhuǎn)至詳情且能添加至購物車的文章就介紹到這了,更多相關vue添加購物車內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Vue CLI4.0 webpack配置屬性之productionSourceMap用法
這篇文章主要介紹了Vue CLI4.0 webpack配置屬性之productionSourceMap用法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06vue的template模板是如何轉(zhuǎn)為render函數(shù)的過程
Vue從template到render函數(shù)的轉(zhuǎn)換經(jīng)歷模板解析、AST構(gòu)建、優(yōu)化、生成渲染函數(shù)等步驟,首先進行詞法分析將模板拆解為tokens,再進行語法分析構(gòu)建AST,然后對AST進行靜態(tài)標記和提升優(yōu)化,最后轉(zhuǎn)換成JavaScript渲染函數(shù),生成虛擬DOM,完成組件的渲染和更新,實現(xiàn)了模板的高效轉(zhuǎn)化2024-10-10