前端Vue项目——购物车页面
一、加入购物车的两种策略
1、加入购物车接口
在 src/restful/api.js 中写入添加购物车接口:
// 加入购物车的接口 export const shopCart = (params) => { return Axios.post('user/shop_cart/create/', params).then(res=>res.data) };
2、添加Axios的请求拦截器
Axios 的拦截器:在请求或响应被 then
或 catch
处理前拦截它们,说明文档:Axios使用说明。模板如下所示:
// 添加请求拦截器 axios.interceptors.request.use(function (config) { // 在发送请求之前做些什么 return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); }); // 添加响应拦截器 axios.interceptors.response.use(function (response) { // 对响应数据做点什么 return response; }, function (error) { // 对响应错误做点什么 return Promise.reject(error); });
在项目 src/restful/api.js 中添加请求拦截器:
import Axios from 'axios' // 导入axios Axios.defaults.baseURL = 'https://www.luffycity.com/api/v1/'; // 设置公共url // 添加请求拦截器 Axios.interceptors.request.use(function (config) { // 在发送请求之前做些什么 if (localStorage.getItem('access_token')){ // 配置的默认值/defaults // Axios.defaults.headers.common['Authorization'] = localStorage.getItem('access_token'); console.log(config.headers); config.headers.Authorization = localStorage.getItem('access_token'); } return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); });
查看控制台 config.headers 中包含的信息:
3、改写CouseDetail页面中购物车事件
(1)课程信息获取
添加购物车首先要获取当前课程信息。
<script> export default { name: 'CourseDetail', data(){ return { // 声明变量存储数据 coursedetailtop: {}, // 课程顶部详情数据 content: "", // currentIndex: 0, // 为0时,页面刷新默认选择了第一项 currentIndex: null, // 默认不选择 prices: [] } }, methods: { // 加入购物车事件 addShopCart(){ if(this.currentIndex){ // 判断当前currentIndex是否有值 if(window.localStorage.getItem('access_token')){ // 判断用户是否登录 // 添加到购物车 alert('买吧'); let course = { courseId: this.$route.params.detailId, // 课程id validPeriodId: this.prices[this.currentIndex].valid_period, }; console.log(course); // this.$http.shopCart(); } else { // 跳转登录页面 // 使用编程式导航来跳转// 代码略 </script>
在控制台查看打印的course对象:
(2)添加购物车事件
methods: { // 加入购物车事件 addShopCart(){ if(this.currentIndex){ // 判断当前currentIndex是否有值 if(window.localStorage.getItem('access_token')){ // 判断用户是否登录 // 添加到购物车 alert('买吧'); let course = { courseId: this.$route.params.detailId, // 课程id validPeriodId: this.prices[this.currentIndex].valid_period, }; console.log(course); this.$http.shopCart(course) .then(res=>{ console.log("当前添加是否成功", res); }) .catch(err=>{ console.log('添加失败', err); }) } else { // 跳转登录页面 // 使用编程式导航来跳转 this.$router.push({ name: 'Login', query: { // window.location 只读属性,返回一个 Location 对象,其中包含有关文档当前位置的信息 return_url: window.location.href, // 将当前页面地址作为查询参数 } }) } } else { // element组件错误提示 this.$message({ message: '您还没有选择要加入的套餐哦!', center: true // 使用 center 属性让文字水平居中 }); } },
点击添加购物车显示效果如下:
购物车没有当前课程时,点击添加后,信息为error_no:0,显示 “添加成功”。
如果购物车已经有了当前课程,选择一个套餐后点击添加,信息为error_no:10,显示“购物车中该课程已更新成功”。
二、购物车页面实现
1、使用elementui显示加入购物车提示
elementui中Message消息提示:常用于主动操作后的反馈提示。这里引入基础用法,从顶部出现,3秒后自动消失。
methods: { // 加入购物车事件 addShopCart(){ if(this.prices[this.currentIndex]){ // 不能直接使用this.currentIndex,因为第一个值为0 if(window.localStorage.getItem('access_token')){ // 判断用户是否登录 // 添加到购物车 alert('买吧'); let course = { courseId: this.$route.params.detailId, // 课程id validPeriodId: this.prices[this.currentIndex].valid_period, }; console.log(course); this.$http.shopCart(course) .then(res=>{ console.log("当前添加是否成功", res); if(res.error_no===0){ this.$message('购物车' + res.data.status); // elementui提示框 } if(res.error_no===10){ this.$message(res.msg); } }) .catch(err=>{ console.log('添加失败', err); }) } else { // 跳转登录页面 // 使用编程式导航来跳转 this.$router.push({ name: 'Login', query: { // window.location 只读属性,返回一个 Location 对象,其中包含有关文档当前位置的信息 return_url: window.location.href, // 将当前页面地址作为查询参数 } }) } } else { // element组件错误提示 this.$message({ message: '您还没有选择要加入的套餐哦!', center: true // 使用 center 属性让文字水平居中 }); } },
选择套餐后点击“加入购物车”,显示如下信息:
2、购物车组件及路由
(1)index.js中添加购物车组件路由
// 代码略 import Cart from '@/components/Cart/Cart' Vue.use(Router); // 配置路由规则 export default new Router({ linkActiveClass: 'is-active', mode: 'history', // 改为history模式 routes: [ // 代码略 // 购物车页面 { path: '/purchase/shopping_cart', name: 'purchase.shop', component: Cart } ] })
(2)创建购物车组件
创建购物车文件夹及文件:src/components/Cart/Cart.vue
使用elementUI中Table表格模板来构筑组件页面结构。Table表格可用于展示多条结构类似的数据,可对数据进行排序、筛选、对比或其他自定义操作。
实现多选非常简单: 手动添加一个el-table-column
,设type
属性为selection
即可。每个 el-table-column 组件中有 template,可以定义当前内容的展示。
scope.row相当于获取了数组中的每一条数据。
<template> <div class="shopping-cart-wrap"> <h3 class="shopping-cart-tit">我的购物车<small>共1门课程</small></h3> <div class="row"> <el-table ref="multipleTable" :data="shopCartList" tooltip-effect="dark" style="width: 100%" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="55"> </el-table-column> <el-table-column label="日期" width="120"> <template slot-scope="scope">{{ scope.row.date }}</template> </el-table-column> <el-table-column prop="name" label="姓名" width="120"> </el-table-column> <el-table-column prop="address" label="地址" show-overflow-tooltip> </el-table-column> </el-table> </div> <div class="total"> <el-button type="primary">去结算</el-button> <h3>总计: ¥399</h3> </div> </div> </template> <script> export default { name:'Cart', data(){ return { } }, }; </script>
(3)页首按钮跳转购物车
<div class="nav-right" v-if="userInfo.access_token" @mouseenter="enterHandler" @mouseleave="leaveHandler"> <span class = 'el-dropdown-link'>学习中心</span> <span class="user">{{userInfo.username}}</span> <img :src="userInfo.avatar" alt=""> <ul class="my_account" v-show="isShow"> <li>我的账户<i>></i></li> <li>我的订单<i>></i></li> <li>我的优惠券<i>></i></li> <li>我的消息<span class="msg">({{userInfo.notice_num}})</span><i>></i></li> <li @click="shopCartInfo">购物车<span class="count">({{userInfo.shop_cart_num}})</span></li> <li>退出<i>></i></li> </ul> </div> methods: { shopCartInfo(){ // 跳转到购物车路由 this.$router.push({ name: 'purchase.shop' }) },
三、购物车页面数据展示
1、获取购物车页面接口
在 src/restful/api.js 添加如下信息:
// 购物车数据 export const shopCartList = () => { return Axios.get('user/shop_cart/list/').then(res=>res.data); };
2、car组件发送请求
修改Cart.vue组件。
handleSelectionChange(val) { this.multipleSelection = val; } 其中,val 为选中数据的集合。通过this.multipleSelection.prop字段 取得每一个选项的值,prop字段就是表格里面子项的prop值。this.multipleSelection.length为选择了多少项。
<script> export default { name:'Cart', data(){ return { multipleSelection: [], // 存放选中的当前数据 shopCartList: [], } }, methods: { getShopCartList(){ this.$http.shopCartList() .then(res=>{ console.log(res); if(res.error_no === 0){ this.shopCartList = res.data.myShopCart; } }) .catch(err=>{ console.log(err); }) }, handleSelectionChange(val){ // 处理点选 this.multipleSelection = val; } }, created() { this.getShopCartList(); } }; </script>
3、将数据绑定到template中
(1)页面构建和数据绑定
javascript:void(0) 中最关键的是 void 关键字, void 是 JavaScript 中非常重要的关键字,该操作符指定要计算一个表达式但是不返回值。
有效期栏目中,添加select组件,点选到对应的有效期。HTML <select>
元素表示一个控件,提供一个选项菜单。菜单内的选项为
, 可以由 <option>
元素分组。选项可以被用户预先选择。<optgroup>
<div class="row"> <el-table ref="multipleTable" :data="shopCartList" tooltip-effect="dark" style="width: 100%" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="55"> </el-table-column> <el-table-column label="课程" width="555"> <template slot-scope="scope"> <img :src="scope.row.courseImg" alt=""> <a href="javascript:void(0);">{{scope.row.courseName}}</a> </template> </el-table-column> <el-table-column prop="name" label="有效期" width="212"> <template slot-scope="scope"> <select> <option v-for="(item, index) in scope.row.validPeriodChoices" :value="item.validPeriodId" :key="index"> 有效期: {{item.validPeriodId}} </option> </select> </template> </el-table-column> <el-table-column prop="address" label="单价" show-overflow-tooltip> <template slot-scope="scope"> ¥{{scope.row.coursePrice}} </template> </el-table-column> </el-table> </div>
显示效果如下所示:
(2)v-model默认选定selected
在select中,当v-model的值等于option中的value,则默认选中。
<el-table-column prop="name" label="有效期" width="212"> <template slot-scope="scope"> <select v-model="scope.row.validPeriodId"> <option v-for="(item, index) in scope.row.validPeriodChoices" :value="item.validPeriodId" :key="index"> 有效期: {{item.validPeriodId}} </option> </select> </template> </el-table-column>
四、购物车页面数据响应
1、添加删除按钮
(1)表格中添加操作列
@click.native.prevent:调用组件原生的click事件,阻止默认事件发生。在封装好的组件上使用,所以要加上.native才能click。
prevent就相当于 event.preventDefault():如果此事件没有被显式处理,那么它默认的动作也不要做(因为默认是要做的)。此事件还是继续传播,除非碰到事件侦听器调用stopPropagation()
或stopImmediatePropagation()
,才停止传播。
<el-table> <!--代码略--> <el-table-column fixed="right" label="操作" width="100"> <template slot-scope="scope"> <el-button @click.native.prevent="deleteRow(scope.$index, shopCartList)" type="text" size="small"> 删除 </el-button> <el-button type="text" size="small">编辑</el-button> </template> </el-table-column> </el-table>
(2)删除课程操作
未完成
methods: { // 删除课程 deleteRow(index, rows){ console.log(index); console.log(rows); rows.splice(index, 1); },
2、监控课程总价变化
使用computed实时监控鼠标点选课程总价变化。
computed: { totalPrice(){ let total_price = 0; this.multipleSelection.forEach((item,index)=>{ // 遍历数组中对象的价格 // parseInt() 方法用于将字符串参数作为有符号的十进制整数进行解析 total_price += parseInt(item.coursePrice) // 将获取的价格相加 }); return total_price; } },
显示效果如下所示