vant框架的使用

  • 适用于移动端!
  • 官网:https://vant-contrib.gitee.io/vant/#/zh-CN/quickstart
  • 安装:npm i vant -S
  • 使用:
    • 方式1:导入所有组件
      import Vue from 'vue';
      import Vant from 'vant';
      import 'vant/lib/index.css';
    
      Vue.use(Vant);
    
    • 方式2:自动按需引入组件 (推荐)
      babel-plugin-import 是一款 babel 插件,它会在编译过程中将 import 的写法自动转换为按需引入的方式
      + 安装插件 `npm i babel-plugin-import -D`
    
      // 在.babelrc 中添加配置 => 根目录下创建这个文件夹!
    
      // 方式1:  注意:webpack 1 无需设置 libraryDirectory
      {
        "plugins": [
          ["import", {
            "libraryName": "vant",
            "libraryDirectory": "es",
            "style": true
          }]
        ]
      }
    
      //方式2: 对于使用 babel7 的用户,可以在 babel.config.js 中配置 =>** 推荐使用这种!**
      module.exports = {
        plugins: [
          ['import', {
            libraryName: 'vant',
            libraryDirectory: 'es',
            style: true
          }, 'vant']
        ]
      };
    
      // 接着你可以在代码中直接引入 Vant 组件
      // 插件会自动将代码转化为方式二中的按需引入形式
      import { Button } from 'vant';
      //如果你在使用 TypeScript,可以使用 ts-import-plugin 实现按需引入
    

使用一个Tabbar 标签栏

  • 官网:https://vant-contrib.gitee.io/vant/#/zh-CN/tabbar
  • 作用:就是在引入一个tabbar 标签栏 由于这个组件是在多个页面使用到的,因此在App.vue组件中引入和使用

App.vue

<template>
  <div id="app">
    <main-tabbar></main-tabbar>
    <router-view />
  </div>
</template>
<script>
import MainTabbar from "./components/MainTabbar";
export default {
  name: "App",
  components: {
    MainTabbar,
  },
};
</script>

封装为一个MainTabbar.vue组件

  • import { Tabbar, TabbarItem } from "vant"; 导入组件!
  • v-model="active" 高亮显示,默认为0
  • v-for="item in tabList" 遍历的数据
  • route => 以路由的形式跳转
  • :to="item.path" => 点击后,跳转到对应的path
<!--  -->
<template>
  <van-tabbar v-model="active" route>
    <van-tabbar-item
      v-for="item in tabList"
      :key="item.text"
      :icon="item.icon"
      :to="item.path"
    >{{item.text}}</van-tabbar-item>
  </van-tabbar>
</template>

<script>
import Vue from "vue";
import { Tabbar, TabbarItem } from "vant";
Vue.use(Tabbar);
Vue.use(TabbarItem);
export default {
  name: "MainTabber",
  data() {
    return {
      active: 0,
      tabList: [
        {
          path: "/home",
          text: "首页",
          icon: "wap-home-o",
        },
        {
          path: "/category",
          text: "分类",
          icon: "apps-o",
        },
        {
          path: "/cart",
          text: "购物车",
          icon: "shopping-cart-o",
        },
        {
          path: "/profile",
          text: "我的",
          icon: "user-o",
        },
      ],
    };
  },
  methods: {},
  components: {},
};
</script>
<style  lang="scss" scoped>
</style>

使用一个Swipe 轮播图

  • 官网:https://vant-contrib.gitee.io/vant/#/zh-CN/swipe
  • 引入:需要在哪个组件使用,就引入即可!
    import Vue from 'vue';
    import { Swipe, SwipeItem, Lazyload, Image } from "vant";
    
    Vue.use(Swipe);
    Vue.use(SwipeItem);
    Vue.use(Lazyload);//懒加载
    Vue.use(Image); //显示img的!
    

Home.vue组件使用轮播图

  <div class="home">
    <van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
      <van-swipe-item v-for="item in rotationList" :key="item._id">
        <img v-lazy="item.imgurl" />
      </van-swipe-item>
    </van-swipe>
  </div>
import Vue from "vue";
import { Swipe, SwipeItem, Lazyload, Image } from "vant";

Vue.use(Swipe);
Vue.use(SwipeItem);
Vue.use(Lazyload);
Vue.use(Image);
export default {
  name: "Home",
  data() {
    return {
      //轮播图的数据
      rotationList: [],
    };
  },
  async created() {
    const { data: rotationList } = await this.$request.get("/goods", {
      params: {
        size: 5,
      },
    });
    console.log("我是data", rotationList);
    this.rotationList = rotationList;
  },
  components: {},
};
.my-swipe .van-swipe-item {
  color: #fff;
  font-size: 20px;
  height: 150px;
  text-align: center;
  /* background-color: #39a9ed; */
}
.my-swipe .van-swipe-item img {
  width: 100px;
  height: 100%;
}

使用一个 Gird 宫格 实现商品列表展示

  • 官网:https://vant-contrib.gitee.io/vant/#/zh-CN/grid

  • 宫格可以在水平方向上把页面分隔成等宽度的区块,用于展示内容或进行页面导航

  • 引入:所需的.vue组件内引入

    import Vue from 'vue';
    import { Grid, GridItem } from 'vant';
    
    Vue.use(Grid);
    Vue.use(GridItem);
    
  • 需求:显示商品列表,并且点击的时候,跳转到对应的详情页之中!

Home.vue组件

  • :column-num="2" => 显示的列数
  • goodsList => 商品的数据
  • @click="gotoDetails(value._id)" => 点击事件,点击格子的时候触发
    <!-- 商品列表 -->
    <van-grid class="my-goods" :column-num="2">
      <van-grid-item v-for="value in goodsList" :key="value._id" @click="gotoDetails(value._id)">
        <van-image class="goodsImg" :src="value.imgurl" />
        <h4>{{ value.name}}</h4>
      </van-grid-item>
    </van-grid>
import Vue from "vue";
import {  Lazyload, Image, Grid, GridItem } from "vant";

Vue.use(Lazyload);
Vue.use(Image);
Vue.use(Grid);
Vue.use(GridItem);

export default {
  name: "Home",
  data() {
    return {
      //商品列表的数据
      goodsList: [],
    };
  },
  async created() {
    //商品列表的请求
    const { data: goodsList } = await this.$request.get("/goods");
    // console.log("我是商品列表", goodsList);
    this.goodsList = goodsList;
  },
  methods: {
    //点击 具体的商品 去往详情页!
    gotoDetails(id) {
      console.log(id);
      this.$router.push({
        name: "GotoDetails",
        params: {
          id,
        },
      });
    },
  },
};

goodsDetails.vue详情页组件

  • 接受到home.vue组件传递过来的id,然后发起请求,展示详情页!
<template>
  <div>我是商品详情页</div>
</template>

<script>
export default {
  name: "GotoDetails",
  data() {
    return {};
  },
  created() {
    this.getDetail();
  },
  methods: {
    async getDetail() {
      const id = this.$route.params.id;
      //拿着id 发起请求 拿到详情页的数据
      const {
        data: {
          data: { result: goods },
        },
      } = await this.$request.get("/goods/" + id);

      console.log("我是详情页", goods);
      this.goods = goods;
    },
  },
  components: {},
};
</script>
<style  lang="scss" scoped>
</style>

商品列表之中 点击图片显示商品的预览 大图片

  • 官网:https://vant-contrib.gitee.io/vant/#/zh-CN/image-preview
    Details.vue组件
  <div class="details">
    <div class="smallImg-box">
      <van-image class="smallImg" @click="showBig" :src="goodsDetails.imgurl"></van-image>
    </div>
  </div>
  • this.goodsDetails 为商品的数据!
    // 显示大图片
    showBig() {
      //图片传入到数组之中
      ImagePreview([this.goodsDetails.imgurl]);
    },

详情页Details.vue之中

  • 先根据id,获取对应的商品,显示在页面之中 => getDetail()

  • 获取推荐图书的数据,显示页面之中 => getRecomment

  • 点推荐图书,更换最新的图书

    • 需要在created钩子函数之中,获取id,并且调用对应的方法,至于为什么在这边获取id,这是只要一创建组件,那么就获取id!
    created() {
      const id = this.$route.params.id;
      this.getDetail(id);
      this.getRecomment();
    },
    
  • 点击跳转到详情页的时候,需要把下面的tabbar隐藏,显示加入购物车!

    • 在Vuex之中定义一个状态 => isShowMemu 这个变量! => 还未完成!
  • html

  <div class="details">
    <div class="smallImg-box">
      <van-image class="smallImg" @click="showBig" :src="goodsDetails.imgurl"></van-image>
      <div class="recommend-box">
        <h1>{{ goodsDetails.name}}</h1>
        <h4>{{ goodsDetails.auth}}</h4>
        <h5>连载中</h5>
      </div>
    </div>
    <div class="validity-con">
      <h3>内容简介</h3>
      <p>{{ goodsDetails.intro }}</p>
    </div>
    <div class="recomment-box">
      <h3>图书推荐</h3>
      <van-grid class="my-goods" :column-num="3">
        <van-grid-item
          v-for="value in goodsRecomemnt"
          :key="value._id"
          @click="gotoDetails(value._id)"
        >
          <van-image class="goodsImg" :src="value.imgurl" />
          <h4>{{ value.name}}</h4>
        </van-grid-item>
      </van-grid>
    </div>
  </div>
  • js
export default {
  name: "GotoDetails",
  data() {
    return {
      goodsDetails: [],
      goodsRecomemnt: [],
    };
  },
  created() {
    const id = this.$route.params.id;
    this.getDetail(id);
    this.getRecomment();
  },
  methods: {
    // 获取详情页的数据
    async getDetail(id) {
      //拿着id 发起请求 拿到详情页的数据
      const {
        data: {
          data: { result: goods },
        },
      } = await this.$request.get("/goods/" + id);

      // console.log("我是详情页111", goods[0]);
      this.goodsDetails = goods[0];
    },
    // 显示大图片
    showBig() {
      //图片传入到数组之中
      ImagePreview([this.goodsDetails.imgurl]);
    },
    // 获取推荐页的数据
    async getRecomment() {
      const { data } = await this.$request.get("/goods");
      // console.log("我是推荐的", data);
      this.goodsRecomemnt = data;
    },
    //跳转到 详情页
    gotoDetails(id) {
      console.log("我是跳转的id", id);
      this.$router.push({
        name: "Details",
        params: {
          id,
        }
      });
    },
  },
  beforeRouteUpdate(to, from, next) {
    // console.log(to.params.id, from.params.id);
    if (to.params.id !== from.params.id) {
      console.log("我是去的id", to.params.id);
      this.getDetail(to.params.id);
      this.getRecomment();
    }
    next();
  },s
};

详情页Details.vue之购物车

  • 官网:https://vant-contrib.gitee.io/vant/#/zh-CN/card
  • 需求:
    • 先获取到购物车的数据 渲染页面!
    • 点击左侧的img的时候,跳转到详情页 对应的详情页!

先获取到购物车的数据 渲染页面!

store/index.js
  state: {
    //是否显示那个tabbar
    isShowMemu: true,
    //购物车的数据
    cartList: [{
      "_id": "5f4f5e38aaf12252fb74c93b",
      "name": "鼎定乾坤",
      "date": "2020 08-19 11:28",
      "intro": "玄黄缔造者……极致超脱之路,哪怕天难葬其身,地难灭其魂。亦难以跳出那个圈。星空崩塌,万族凋零。如何以一己之力逆转乾坤,颠倒阴阳。且看那一袭青衫,一柄长剑,一方圆鼎:脚踏修真,拳碎仙域,剑斩神界,鼎定至尊,极致超脱。书群,1141419286扣扣",
      "auth": "浅山深水",
      "imgurl": "imgbook1/f3aa24ea917f79a95b81ea86c91b4043.jpeg",
      "price": 123.2,
      "qty": 1
    }, {
      "_id": "5f4f5e38aaf12252fb74c93b",
      "name": "鼎定乾坤",
      "date": "2020 08-19 11:28",
      "intro": "玄黄缔造者……极致超脱之路,哪怕天难葬其身,地难灭其魂。亦难以跳出那个圈。星空崩塌,万族凋零。如何以一己之力逆转乾坤,颠倒阴阳。且看那一袭青衫,一柄长剑,一方圆鼎:脚踏修真,拳碎仙域,剑斩神界,鼎定至尊,极致超脱。书群,1141419286扣扣",
      "auth": "浅山深水",
      "imgurl": "imgbook1/f3aa24ea917f79a95b81ea86c91b4043.jpeg",
      "price": 123.2,
      "qty": 1
    }]
  },
渲染页面 Cart.vue
    <!-- 购物车item -->
    <van-card
      v-for="item in cartList"
      :key="item._id"
      :num="item.qty"
      :desc="item.auth"
      :title="item.name"
      :thumb="item.imgurl"
    >
      <template #tag>
        <van-checkbox v-model="checked"></van-checkbox>
      </template>
      <template #price>
        <span class="price">¥{{ item.price }}</span>
        <van-stepper v-model="value" theme="round" button-size="22" disable-input />
      </template>
      <template #footer>
        <van-button icon="cross" size="mini" plain type="danger"></van-button>
      </template>
    </van-card>
  created() {
    this.getCartList();
  },
  methods: {
    //获取购物车的数据
    getCartList() {
      // console.log("我是购物车item", this.$store.state.cartList);
      this.cartList = this.$store.state.cartList;
    },
  }

点击左侧的img的时候,跳转到详情页 对应的详情页!

  • click-thumb 点击自定义图片时触发
CArt.vue组件
  • 给van-card 绑定事件
    <van-card
      ...
      @click-thumb="gotoDetails(item._id)"
    >
  • 在methods之中点击 跳转!
    //点击左侧的小图标 跳转到详情页
    gotoDetails(id) {
      this.$router.push({
        name: "Details",
        params: {
          id,
        },
      });
    },

点击左侧的复选框的时候,勾选上复选框,然后影响全选按钮

  • 所有的复选框勾选上了后,才触发全选按钮!
store/index.js文件中的state数据
    cartList: [{
      "_id": "5f4f5e38aaf12252fb74c93b",
      "name": "鼎定乾坤",
      "date": "2020 08-19 11:28",
      "intro": "玄黄缔造者……极致超脱之路,哪怕天难葬其身,地难灭其魂。亦难以跳出那个圈。星空崩塌,万族凋零。如何以一己之力逆转乾坤,颠倒阴阳。且看那一袭青衫,一柄长剑,一方圆鼎:脚踏修真,拳碎仙域,剑斩神界,鼎定至尊,极致超脱。书群,1141419286扣扣",
      "auth": "浅山深水",
      "imgurl": "imgbook1/f3aa24ea917f79a95b81ea86c91b4043.jpeg",
      "price": 123.2,
      "qty": 1,
      "check": false
    }, {
      "_id": "5f4f5e38aaf12252fb74c93e",
      "name": "雷神传之雷神再世",
      "date": "2020 08-18 22:47",
      "intro": "以武侠小说的名义 ,说一段刻骨铭心的爱情故事 !",
      "auth": "猛士七",
      "imgurl": "imgbook1/ba83c1528c275b6c154ffd482d4541c3.jpeg",
      "price": 12,
      "qty": 1,
      "check": false
    }]
Cart.vue中的复选框
   <!-- 购物车item -->
    <van-card
      class="card-item"
      v-for="item in cartList"
      :key="item._id"
      :num="item.qty"
      :desc="item.auth"
      :title="item.name"
      :thumb="item.imgurl"
      @click-thumb.stop.native="gotoDetails(item._id)"
    >
      <template #tag class="checkBox">
        <van-checkbox v-model="item.check"></van-checkbox>
      </template>
      <template #price>
        <span class="price">¥{{ item.price }}</span>
        <van-stepper v-model="value" theme="round" button-size="22" disable-input />
      </template>
      <template #footer>
        <van-button icon="cross" size="mini" plain type="danger"></van-button>
      </template>
    </van-card>

    <!-- 提交订单 -->
    <van-submit-bar :price="3050" button-text="提交订单" @submit="onSubmit">
      <van-checkbox v-model="checkAll">全选</van-checkbox>
      <template #tip>
        你的收货地址不支持同城送,
        <span>修改地址</span>
      </template>
    </van-submit-bar>
  computed: {
    //全选按钮和 复选按钮
    checkAll: {
      get() {
        //遍历cartList每一项 所有都为选上的时候 为真!也就是把全选勾上 
        return this.cartList.every((item) => item.check);
      },
      set(val) {
        //这是全选  设置小复选框的状态! 遍历所有小复选框 把当前的全选的val 给小复选框设置 !
        this.cartList = this.cartList.map((item) => {
          item.check = val;
          return item;
        });
      },
    },
  },

计算总价

store/index.js
  state: {
    //是否显示那个tabbar
    isShowMemu: true,
    totalPrice: "",
    //购物车的数据
    cartList: [{
      "_id": "5f4f5e38aaf12252fb74c93b",
      "name": "鼎定乾坤",
      "date": "2020 08-19 11:28",
      "intro": "玄黄缔造者……极致超脱之路,哪怕天难葬其身,地难灭其魂。亦难以跳出那个圈。星空崩塌,万族凋零。如何以一己之力逆转乾坤,颠倒阴阳。且看那一袭青衫,一柄长剑,一方圆鼎:脚踏修真,拳碎仙域,剑斩神界,鼎定至尊,极致超脱。书群,1141419286扣扣",
      "auth": "浅山深水",
      "imgurl": "imgbook1/f3aa24ea917f79a95b81ea86c91b4043.jpeg",
      "price": 123.2,
      "qty": 1,
      "check": false
    }, {
      "_id": "5f4f5e38aaf12252fb74c93e",
      "name": "雷神传之雷神再世",
      "date": "2020 08-18 22:47",
      "intro": "以武侠小说的名义 ,说一段刻骨铭心的爱情故事 !",
      "auth": "猛士七",
      "imgurl": "imgbook1/ba83c1528c275b6c154ffd482d4541c3.jpeg",
      "price": 12,
      "qty": 1,
      "check": false
    }]
  },
  getters: {
    //计算总价
    totalPrice(state) {
      return state.cartList.reduce((pre, cue) => pre + cue.price * cue.qty, 0) * 100
    }
  },
Cart.vue组件
    <!-- 提交订单 -->
    <van-submit-bar :price="totalPrice" button-text="提交订单" @submit="onSubmit">
    //计算总价
    totalPrice() {
      return this.$store.getters.totalPrice;
    },

点击修改 数量的时候,修改总价!

  • change 当绑定值变化时触发的事件
Cart.vue中的mutations属性中修改
    //修改购物车数量
    changeQty(state, payload) {
      // console.log("mu修改", payload);
      state.cartList = state.cartList.map(item => {
        if (item._id === payload.id) {
          item.qty = payload.qty
        }
        return item
      })
    },
Cart.vue组件
  • @change="changeQty(item._id,$event)" 修改里面的数据的时候 触发 传递id 和 保留之前的qty数值!
      <template #price>
        <span class="price">¥{{ item.price }}</span>
        <van-stepper
          @change="changeQty(item._id,$event)"
          v-model="item.qty"
          theme="round"
          button-size="22"
          disable-input
        />
      </template>
methods:{
      //修改数量
    changeQty(id, qty) {
      // 获取当前的值!
      // console.log("我是修改的111", id, qty);
      this.$store.commit("changeQty", { id, qty });
    },
}

点击加入购物车

  • 假如购物车之中存在这个商品,那么就触发修改qty数量的方法
  • 假如购物车里面不存在这个商品,那么就触发添加购物车商品!
store/index.js
 state: {
    //购物车的数据
    cartList: [{
      "_id": "5f4f5e38aaf12252fb74c93b",
      "name": "鼎定乾坤",
      "date": "2020 08-19 11:28",
      "intro": "玄黄缔造者……极致超脱之路,哪怕天难葬其身,地难灭其魂。亦难以跳出那个圈。星空崩塌,万族凋零。如何以一己之力逆转乾坤,颠倒阴阳。且看那一袭青衫,一柄长剑,一方圆鼎:脚踏修真,拳碎仙域,剑斩神界,鼎定至尊,极致超脱。书群,1141419286扣扣",
      "auth": "浅山深水",
      "imgurl": "imgbook1/f3aa24ea917f79a95b81ea86c91b4043.jpeg",
      "price": 123.2,
      "qty": 1,
      "check": false
    }, {
      "_id": "5f4f5e38aaf12252fb74c93e",
      "name": "雷神传之雷神再世",
      "date": "2020 08-18 22:47",
      "intro": "以武侠小说的名义 ,说一段刻骨铭心的爱情故事 !",
      "auth": "猛士七",
      "imgurl": "imgbook1/ba83c1528c275b6c154ffd482d4541c3.jpeg",
      "price": 12,
      "qty": 1,
      "check": false
    }]
  },
  getters: {
    //计算总价
    totalPrice(state) {
      return state.cartList.reduce((pre, cue) => pre + cue.price * cue.qty, 0) * 100
    }
  },
  mutations: {
    //修改购物车数量
    changeQty(state, payload) {
      // console.log("mu修改", payload);
      state.cartList = state.cartList.map(item => {
        if (item._id === payload.id) {
          item.qty = payload.qty
        }
        return item
      })
    },
    // 添加购物车
    addToCart(state, payload) {
      // console.log("我是添加购物车", payload);
      state.cartList.unshift(payload)
    }
  },
Details.vue
  <van-goods-action-button @click="addToCart" type="warning" text="加入购物车" />
  • 判断购物车里面是否有这个商品 有的话 数量+1 没有的话 就qty为1
  methods:{
    //加入购物车
    addToCart() {
      const { _id: id } = this.goodsDetails;
      //根据id 去查询购物车 里面是否含有该id的商品!
      const current = this.$store.state.cartList.filter(
        (item) => item._id === id
      )[0];
      // console.log("我是当前的", current); // 如果有的话 那么qty++ 没有的话添加商品!
      if (current) {
        this.$store.commit("changeQty", { id, qty: current.qty + 1 });
      } else {
        const goods = {
          ...this.goodsDetails,
          qty: 1,
        };
        // 调用mutation 中的addToCart方法
        this.$store.commit("addToCart", goods);
      }
    },
  }

点击购物车之中的删除按钮

store/index.js
  state: {
    //是否显示那个tabbar
    isShowMemu: true,
    totalPrice: "",
    //购物车的数据
    cartList: [{
      "_id": "5f4f5e38aaf12252fb74c93b",
      "name": "鼎定乾坤",
      "date": "2020 08-19 11:28",
      "intro": "玄黄缔造者……极致超脱之路,哪怕天难葬其身,地难灭其魂。亦难以跳出那个圈。星空崩塌,万族凋零。如何以一己之力逆转乾坤,颠倒阴阳。且看那一袭青衫,一柄长剑,一方圆鼎:脚踏修真,拳碎仙域,剑斩神界,鼎定至尊,极致超脱。书群,1141419286扣扣",
      "auth": "浅山深水",
      "imgurl": "imgbook1/f3aa24ea917f79a95b81ea86c91b4043.jpeg",
      "price": 123.2,
      "qty": 1,
      "check": false
    }, {
      "_id": "5f4f5e38aaf12252fb74c93e",
      "name": "雷神传之雷神再世",
      "date": "2020 08-18 22:47",
      "intro": "以武侠小说的名义 ,说一段刻骨铭心的爱情故事 !",
      "auth": "猛士七",
      "imgurl": "imgbook1/ba83c1528c275b6c154ffd482d4541c3.jpeg",
      "price": 12,
      "qty": 1,
      "check": false
    }]
  },
    //删除购物车 item payload 为前面传递过来的id
    delGoods(state, payload) {
      state.cartList = state.cartList.filter(item => item._id !== payload)
    }
  },
Cart.vue组件
  <van-button icon="cross" size="mini" plain type="danger" @click="delGoods(item._id)"></van-button>
  methods: {
    //获取购物车的数据
    getCartList() {
      this.cartList = this.$store.state.cartList;
    },
    //删除商品
    delGoods(id) {
      this.$store.commit("delGoods", id);
      this.getCartList();
    },
  }

点击购物车之中的清空购物车按钮

store/index.js
    //清空购物车
    clearCart(state) {
      console.log("我是清空触发");
      state.cartList = []
    }
Cart.vue组件
    <!-- 清空购物车 -->
    <div style="padding:10px">
      <p v-show="!isShowClearCart">购物车空空如也!</p>
      <van-button plain type="danger" v-show="isShowClearCart" size="small" @click="clearCart">清空购物车</van-button>
    </div>
  • 注意点:需要在data之中定义 isShowClearCart变量 默认为true 显示清空购物车按钮!
    //清空购物车
    clearCart() {
      this.$store.commit("clearCart");
      this.getCartList();
      if (this.cartList.length === 0) {
        this.isShowClearCart = false;
      } else {
        this.isShowClearCart = true;
      }
    },

在多个页面显示购物车的 数量

MainTabbar.vue

显示购物车的数量 :badge="item.text === '购物车' ? cartLength :''"

    <van-tabbar-item
      v-for="item in tabList"
      :key="item.text"
      :icon="item.icon"
      :to="item.path"
      :badge="item.text === '购物车' ? cartLength :''"
    >{{item.text}}</van-tabbar-item>
  computed: {
    cartLength() {
      return this.$store.state.cartList.length;
    },
  },

在详情页之中 添加navTab

  • 点击返回首页!
需要的组件.vue
    <!-- 导航栏目 -->
    <van-nav-bar left-text="返回" @click-left="backHome" left-arrow></van-nav-bar>
  methods: {
    //点击返回首页
    backHome() {
      this.$router.push({
        name: "Home",
      });
    },
  }

actions异步

  • 点击+ 的时候 查询库存 假如超过库存 那么就不再添加 否则可以添加!
store/index.js
 cartList: [{}],//数据
 mutations: {
    //修改购物车数量
    changeQty(state, payload) {
      console.log("mu修改数量", payload);
      state.cartList = state.cartList.map(item => {
        if (item._id === payload.id) {
          item.qty = payload.qty
        }
        return item
      })
    },
  },
  actions: {
    //请求 查询库存多少! /:id/kucun
    async changeQtyAsunc(context, payload) {
      const {
        data
      } = await $request.get(`/goods/${payload.id}/kucun`)
      if (payload.qty > data.kucun) {
        Notify({
          type: 'danger',
          message: '超过库存,仅能下单这些!'
        });
        payload.qty = data.kucun

      }
      // console.log("我是修改后的", payload);
      context.commit("changeQty", payload)
    }

  },
Cart.vue
      <template #price>
        <span class="price">¥{{ item.price }}</span>
        <van-stepper
          @change="changeQty(item._id,$event)"
          v-model="item.qty"
          theme="round"
          button-size="22"
          disable-input
        />
      </template>
mmethods:{
    //修改数量
    changeQty(id, qty) {
      // 获取当前的值!
      // console.log("我是修改的111", id, qty);
      // this.$store.commit("changeQty", { id, qty });
      this.$store.dispatch("changeQtyAsunc", { id, qty });
    },
}

Details.vue 查询库存

  • 点击购物车之中的 添加商品 查询库存
    <!-- 购物车 -->
    <van-goods-action>
      <van-goods-action-icon icon="chat-o" text="客服" color="#07c160" />
      <van-goods-action-icon :badge="cartLength" @click="gotoCart" icon="cart-o" text="购物车" />
      <van-goods-action-icon icon="star" text="已收藏" color="#ff5000" />
      <van-goods-action-button @click="addToCart" type="warning" text="加入购物车" />
      <van-goods-action-button @click="buyNow" type="danger" text="立即购买" />
    </van-goods-action>
methods:{
      //加入购物车
    addToCart() {
      //判断购物车里面是否有这个商品 有的话 数量+1 没有的话 就qty为1
      const { _id: id } = this.goodsDetails;
      //根据id 去查询购物车 里面是否含有该id的商品!
      const current = this.$store.state.cartList.filter(
        (item) => item._id === id
      )[0];
      // console.log("我是当前的", current); // 如果有的话 那么qty++ 没有的话添加商品!
      if (current) {
        this.$store.dispatch("changeQtyAsunc", { id, qty: current.qty + 1 });
      } else {
        const goods = {
          ...this.goodsDetails,
          qty: 1,
        };
        // 调用mutation 中的addToCart方法
        this.$store.commit("addToCart", goods);
      }
    },
    //立即购买
    buyNow() {
      this.addToCart();
      //跳转到购物车
      this.$router.push({
        name: "Cart",
      });
    },
}

在Home.vue组件中 一进入就获取购物车的数据

  • 在home.vue组件中先发起请求 created之中 this.$store.dispatch("getCart")
  • 在store/index.js之中,actions之中 发起请求
        state:{
          goodslist:[]
        }
        mutations:{
          initCart(state,data){
              state.goodslist = data;
          },
        },
        actions:{
          async getCart(){
              const {data} = await request.get(`/cart`);
              context.commit('initCart',data.data)
          }
      }
    
Logo

前往低代码交流专区

更多推荐