前端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;
  }
},

  显示效果如下所示

  

 

posted @ 2019-08-12 18:26  休耕  阅读(5540)  评论(0编辑  收藏  举报