其他分享
首页 > 其他分享> > Vue2外卖总结

Vue2外卖总结

作者:互联网

Vue2外卖总结

先看一下效果,这是跟随硅谷外卖做的一个小项目。但是很多都是没有接口导致许多不太一致。

请添加图片描述

简介:

​ 这是一个基础Vue2实现的一个外卖项目,部分图如上所示,数据没有调用一个接口,全都是模拟数据。相关视频在哔哩哔哩尚硅谷。链接https://www.bilibili.com/video/BV1hs411E7cB?spm_id_from=333.337.search-card.all.click 。组件部分:axios better-scroll core-js element-ui mockjs swipper vuex xue-router等

目录结构为:

srcApp.vuemain.jssrc.txtapiajax.jsindex.jscommonstylusmixins.stylcomponentsAlertTipAlertTip.vueCartControlCartControl.vueFoodFood.vueFoosterGuideFoosterGuide.vueHeaderTopHeaderTop.vueShopCartShopCart.vueShopHeaderShopHeader.vueShopListShopList.vueimagesshop1.jpg2.jpg3.jpg4.jpgstarsstar24half@2x.pngstar24off@2x.pngstar24on@2x.pngstar36half@2x.pngstar36off@2x.pngstar36on@2x.pngstar48half@2x.pngstar48off@2x.pngstar48on@2x.pngStarstar.vuestarsstar24half@2x.pngstar24off@2x.pngstar24on@2x.pngstar36half@2x.pngstar36on@2x.pngstar48half@2x.pngstar48off@2x.pngstar48on@2x.pngfiltersmockmock.jspagesLoginLogin.vueimagescaptcha.svgMsiteMsite.vueOrderOrder.vueimagesorderperson.pngProfileProfile.vueSearchSearch.vueShopShop.vueShopGoodsShopGoods.vueShopInfoShopInfo.vueShopRatingsShopRating.vuerouterindex.jsstaticstoreactions.jsgetters.jsindex.jsmutations.jsstate.js src │ App.vue │ main.js │ src.txt │ ├─api │ ajax.js │ index.js │ ├─common │ └─stylus │ mixins.styl │ ├─components │ ├─AlertTip │ │ AlertTip.vue │ │ │ ├─CartControl │ │ CartControl.vue │ │ │ ├─Food │ │ Food.vue │ │ │ ├─FoosterGuide │ │ FoosterGuide.vue │ │ │ ├─HeaderTop │ │ HeaderTop.vue │ │ │ ├─ShopCart │ │ ShopCart.vue │ │ │ ├─ShopHeader │ │ ShopHeader.vue │ │ │ ├─ShopList │ │ │ ShopList.vue │ │ │ │ │ └─images │ │ ├─shop │ │ │ 1.jpg │ │ │ 2.jpg │ │ │ 3.jpg │ │ │ 4.jpg │ │ │ │ │ └─stars │ │ star24_half@2x.png │ │ star24_off@2x.png │ │ star24_on@2x.png │ │ star36_half@2x.png │ │ star36_off@2x.png │ │ star36_on@2x.png │ │ star48_half@2x.png │ │ star48_off@2x.png │ │ star48_on@2x.png │ │ │ └─Star │ │ star.vue │ │ │ └─stars │ star24_half@2x.png │ star24_off@2x.png │ star24_on@2x.png │ star36_half@2x.png │ star36_on@2x.png │ star48_half@2x.png │ star48_off@2x.png │ star48_on@2x.png │ ├─filters ├─mock │ mock.js │ ├─pages │ ├─Login │ │ │ Login.vue │ │ │ │ │ └─images │ │ captcha.svg │ │ │ ├─Msite │ │ Msite.vue │ │ │ ├─Order │ │ │ Order.vue │ │ │ │ │ └─images │ │ └─order │ │ person.png │ │ │ ├─Profile │ │ Profile.vue │ │ │ ├─Search │ │ Search.vue │ │ │ └─Shop │ │ Shop.vue │ │ │ ├─ShopGoods │ │ ShopGoods.vue │ │ │ ├─ShopInfo │ │ ShopInfo.vue │ │ │ └─ShopRatings │ ShopRating.vue │ ├─router │ index.js │ ├─static └─store actions.js getters.js index.js mutations.js state.js src│App.vue│main.js│src.txt│├─api│ajax.js│index.js│├─common│└─stylus│mixins.styl│├─components│├─AlertTip││AlertTip.vue│││├─CartControl││CartControl.vue│││├─Food││Food.vue│││├─FoosterGuide││FoosterGuide.vue│││├─HeaderTop││HeaderTop.vue│││├─ShopCart││ShopCart.vue│││├─ShopHeader││ShopHeader.vue│││├─ShopList│││ShopList.vue│││││└─images││├─shop│││1.jpg│││2.jpg│││3.jpg│││4.jpg│││││└─stars││star24h​alf@2x.png││star24o​ff@2x.png││star24o​n@2x.png││star36h​alf@2x.png││star36o​ff@2x.png││star36o​n@2x.png││star48h​alf@2x.png││star48o​ff@2x.png││star48o​n@2x.png│││└─Star││star.vue│││└─stars│star24h​alf@2x.png│star24o​ff@2x.png│star24o​n@2x.png│star36h​alf@2x.png│star36o​n@2x.png│star48h​alf@2x.png│star48o​ff@2x.png│star48o​n@2x.png│├─filters├─mock│mock.js│├─pages│├─Login│││Login.vue│││││└─images││captcha.svg│││├─Msite││Msite.vue│││├─Order│││Order.vue│││││└─images││└─order││person.png│││├─Profile││Profile.vue│││├─Search││Search.vue│││└─Shop││Shop.vue│││├─ShopGoods││ShopGoods.vue│││├─ShopInfo││ShopInfo.vue│││└─ShopRatings│ShopRating.vue│├─router│index.js│├─static└─storeactions.jsgetters.jsindex.jsmutations.jsstate.js

主要模块

1.登录注册(未注册自动注册)

2.个人中心

3.外卖首页

4.商家部分(商品列表,评价,等等)

功能实现

1.手机号验证,验证码验证,验证码设定时效

2.首页上方轮播图(非自动轮播)

3.购物车部分(查看,修改,遮盖)

4.评价筛选部分(过滤)

5.评价分数星计算

1.注册登录

​ 登录部分两种不同的登录方式,短信登录与密码登录。使用正则对手机号格式验证,格式正确才能够发送验证码,否则发送验证码按钮为disable。验证码通过mock随机数生成,设置指定时间让其消失,实现验证码时效效果。当手机号或者验证码不正确弹出提示框。

2.首页

​ 上方为轮播,需要滑动显示轮播效果。categorysArr页面为挂载时,使用mock获取的数据。通过设置watch监视,来判断categorysArr当中是否已经存在数据。this.$nextTick(), 作用就是等待页面渲染完毕后再去执行当中代码。因为需要计算高度。下方商家列表是v-for循环遍历mock数据,来渲染页面。

    <nav class="msite_nav">
      <div class="swiper">
        <div class="swiper-wrapper">
          <div
            class="swiper-slide"
            v-for="(categorys, index) in categorysArr"
            :key="index"
          >
            <a
              href="javascript:"
              class="link_to_food"
              v-for="(category, index) in categorys"
              :key="index"
            >
              <div class="food_container">
                <img :src='category.img_url' alt="">
              </div>
              <span>{{ category.name }}</span>
            </a>
          </div>
        </div>
        <!-- 如果需要分页器 -->
        <!-- <div class="swiper-pagination"></div> -->
        <!-- 如果需要滚动条 -->
        <!-- <div class="swiper-scrollbar"></div> -->
      </div>
    </nav>
  watch: {
    categorys() {
      if (this.categorysArr.length !== 0) {
        this.$nextTick(() => {
          new Swiper(".swiper", {
            // loop 设置左右滑动模式 如果是true则会无限滑动
            // loop: true, // 循环模式选项
            // 如果需要分页器 pagination指的是分页器
            // pagination: {
            //   el: ".swiper-pagination",
            // },
            // scrollbar: {
            //   el: ".swiper-scrollbar",
            // },
            // 如果需要前进后退按钮
            // navigation: {
            //   nextEl: ".swiper-button-next",
            //   prevEl: ".swiper-button-prev",
            // },
          });
        });
      }
    },
  },

3.个人中心

​ 首先就是判断用户使用哪种登录方式来显示登录页面的不同内容。以及首页右上角是显示登录还是已经登录。未登录不会显示立即退出按钮。未绑定手机号显示手机号为绑定。如果绑定则不显示。

4.商家

(1)商品列表

​ 单击加号放入购物车,当购物车当中没有该商品数据则减号不显示。价格对应下方计算,三种显示模式,未选中商品,显示 ¥20起送;选中但是为满20元起送显示 还差¥XX元起送 ;>=20元,则显示为绿色结算。购物车部分对应显示商品列表,并且小圆点显示购物车当中数量。

​ 左侧导航栏点击后,会跳转到对用商品列表,跳转过程商品列表滑动显示。需要先获取对用列表的top值,然后为每一个li添加点击事件,让top值修改为对应top值的高度。

​ 对应购物车当中的数据也是存储在vuex当中,相关vuex的讲解我也有文章讲解,感兴趣的各位可以去查看我的vuex当中的解释。

methods: {
    // 相关better-scroll都能够在官网查找到相关的api

    //  初始化滑动
    initScroll() {
      this.scroll =  new BScroll(".menu-wrapper",{
        mouseWheel: true,
        click: true
      });
      this.foodScroll = new BScroll(".foods-wrapper", {
        probeType: 2, // 惯性滑动不会触发
        mouseWheel: true,
        // 可能会出现兼容性的问题,所以在此处最好还是加上
        click: true,
      });
      // 绑定滚动监听
      this.foodScroll.on("scroll", ({ x, y }) => {
        // console.log(y);
        this.scrollY = Math.abs(y); //返回绝对值
      });
      //  解决惯性滑动不刷新的bug
      this.foodScroll.on("scrollEnd", ({ x, y }) => {
        // console.log(y);
        this.scrollY = Math.abs(y); //返回绝对值
      });
      this.scroll.refresh();
      this.foodScroll.refresh();
    },
    //  初始获取top
    initTops() {
      let top = 0;
      this.tops.push(top);
      const lis = this.$refs.foodsUl.getElementsByClassName("food-list-hook");
      Array.prototype.slice.call(lis).forEach((li) => {
        top += li.clientHeight;
        this.tops.push(top);
        // console.log(this.tops);
      });
    },
    //  获取索引  左侧点击切换 scroolTo(x, y, time, easing(缓动函数,一般不建议修改))
    clickMenu(index) {
      this.scrollY = -this.tops[index];
        // scrollTo显而易见滚动到,后面300位时间 
      this.foodScroll.scrollTo(0, this.scrollY, 300);
    },
    //  点击显示Food,小图切换大图显示
    showFood(food) {
      this.food = food;
      this.$refs.food.toggleShow();
    },
  },
      // 挂载的时候调用上方方法,this.$nextTick等获取到数据后执行
   mounted() {
    this.$store.dispatch("get_restaurant", () => {
      this.$nextTick(() => {
        this.initScroll();
        this.initTops();
      });
    });
  },

这是相关html当中的内容

      <div class="foods-wrapper">
        <ul ref="foodsUl">
          <li
            class="food-list-hook"
            v-for="(good, index) in goods"
            :key="index"
          >
            <h1 class="title">{{ good.name }}</h1>
            <ul>
              <li
                class="food-item bottom-border-1px"
                v-for="(food, index) in good.foods"
                :key="index"
              >
                <div class="icon">
                  <img
                    width="57"
                    height="57"
                    :src="food.image"
                    @click="showFood(food)"
                  />
                </div>
                <div class="content">
                  <h2 class="name">{{ food.name }}</h2>
                  <p class="desc">{{ food.description }}</p>
                  <div class="extra">
                    <span class="count">月售{{ food.sellCount }}份11</span>
                    <span>好评率{{ food.rating }}%</span><br /><br />
                    <span class="now">¥{{ food.price }}</span>
                    <span class="old" v-if="food.oldPrice"
                      >¥{{ food.oldPrice }}</span
                    >
                  </div>
                  <div class="cartcontrol-wrapper"></div>
                  <CartControl :food="food" />
                </div>
              </li>
            </ul>
          </li>
        </ul>
      </div>
(2)评价

​ 需要计算星星,该部分为一个通用组件,计算方法如下代码,读者自行查看结构挺简单的。

<template>
  <!-- 接收参数 -->
  <div class="star" :class="'star-' + size">
    <span
      class="star-item"
      v-for="(sc, index) in starClasses"
      :class="sc"
      :key="index"
    ></span>
  </div>
</template>

export default {
  name: "Star",
    // 组件调用需要传过来参数,评价分数,以及星星大小
  props: {
      // 传过来的分数
    score: Number,
      // 使用星星的大小
    size: Number,
  },
  computed: {
    starClasses() {
      const score = this.score;
      const scs = [];
        // ons代表满星几颗
      const ons = Math.floor(score);
      for (let i = 0; i < ons; i++) {
        scs.push("on");
      }
        // 首先半星只会出现 0 或 1 个由于小数部分计算会出现问题,所以采用*10计算
      const halfs = (score * 10) % 10;
      if (halfs > 5) {
        scs.push("half");
      }
        // 总分为5颗星,其他的(满星,半星)添加进来后剩下的都是灰色星星
      while (scs.length < 5) {
        scs.push("off");
      }
      return scs;
    },
  },
};

​ 下方评价现实就是一个过滤器,拿到mock模拟的评价数组,根据不同的点击事件,来显示不同的内容。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J7k1RuuH-1647658347669)(C:\Users\86150\AppData\Roaming\Typora\typora-user-images\image-20220319104201722.png)]

(3)商家信息

​ 首先还是拿到由mock模拟的数据,然后渲染页面。值得一提的是,图片的左右滑动。

      <section class="section">
        <h3 class="section-title">商家实景</h3>
        <div class="pic-wrapper">
          <ul class="pic-list" ref="picsUl">
            <li class="pic-item" v-for="(pic, index) in info.pics" :key="index">
              <img width="120" height="90" :src="pic" />
            </li>
          </ul>
        </div>
      </section>
  methods: {
    initScroll() {
      new BScroll(".shop-info", {
        click: true,
      });
        // 首先拿到ref
      const ul = this.$refs.picsUl;
        // 每张图片大小 120px
      const Width = 120;
        // 间隔 6px
      const space = 6;
        // 用来动态计算数组长度,来设置宽度
      const count = this.info.pics.length;
      ul.style.width = (Width + space) * count - space + "px";
      new BScroll(".pic-wrapper", {
        click: true,
        scrollX: true,
      });
    },
  },

o", {
click: true,
});
// 首先拿到ref
const ul = this.$refs.picsUl;
// 每张图片大小 120px
const Width = 120;
// 间隔 6px
const space = 6;
// 用来动态计算数组长度,来设置宽度
const count = this.info.pics.length;
ul.style.width = (Width + space) * count - space + “px”;
new BScroll(".pic-wrapper", {
click: true,
scrollX: true,
});
},
},


标签:总结,vue,const,外卖,2x,jpg,js,Vue2,png
来源: https://blog.csdn.net/qq_53157160/article/details/123590666