vue饿了么项目-goods商品列表页开发

乘客 乘客     2022-09-01     487

关键词:

1.flex 属性是 flex-grow、flex-shrink 和 flex-basis 属性的简写属性。

flex-grow 一个数字,规定项目将相对于其他灵活的项目进行扩展的量。
flex-shrink 一个数字,规定项目将相对于其他灵活的项目进行收缩的量。
flex-basis 项目的长度。合法值:"auto"、"inherit" 或一个后跟 "%"、"px"、"em" 或任何其他长度单位的数字。

2.采用绝对定位,相对于父元素

.good
  display flex
  position absolute
  width 100%
  top 174px
  bottom 46px
  overflow hidden

3.使用vue-resourse获取json并应用到模板

现在越来越多的数据传输方式都是json数据格式,包括用jquery开发时,也有很好用的$.ajax来进行数据请求与处理,那么vue-resource提供了一种类似的,并且api更加简洁易用,压缩后文件更小。配合ES 6的Lambda写法,更加优雅

官网:https://github.com/pagekit/vue-resource/blob/master/docs/http.md

props: {
      seller: {
        type: Object
      }
    },
    data () {
      return {
        goods: [],  //一开始goods为空
        listHeight: [],
        scrolly: 0,
        selectedFood: {}
      };
    },
    created() {   //当这个组件被调用的时候,通过后端获得数据赋值给goods
      this.$http.get(‘/api/goods‘).then((response) => {  //   ‘/api/goods‘请求的是data.json下的goods数组
        response = response.body;
        if (response.errno === ERR_OK) {
         this.goods = response.data;
        this.$nextTick(() => {  //可以用 $nextTick 來确保Dom变化后再执行一些事情
         this._initScroll();
         this._calculateHeight();
      });
       }
      });this.classMap = [‘decrease‘, ‘discount‘, ‘special‘, ‘invoice‘, ‘guarantee‘];
    },

注:vue更新到2.0之后,作者就宣告不再对vue-resource更新,而是推荐的axios,它的基本用法可以参考:http://www.kancloud.cn/yunye/axios/234845

4.遍历取数据

        <span class="text">
            <span v-show="item.type>0" class=" icon" :class="classMap[item.type]"></span>{{item.name}}
          </span>   

classMap[item.type]是一个数组,通过item.type去取对应的class,item.type是data.json中mock的数据

5.display table

此元素会作为块级表格来显示(类似 <table>),表格前后带有换行符。

在table中可用vertical-align middle实现垂直居中

6.添加better-scroll依赖

链接:https://github.com/ustbhuangyi/better-scroll

<div class="menu-wrapper" ref="menuWrapper">
      <ul>
        <li v-for="(item, index) in goods" class="menu-item border-1px" :class="{‘current‘:currentIndex === index}"
            @click="selectMenu(index, $event)">
          <span class="text">
            <span v-show="item.type>0" class=" icon" :class="classMap[item.type]"></span>{{item.name}}
          </span>
        </li>
      </ul>
    </div>
    <div class="foods-wrapper" ref="foodWrapper">
      <ul>
        <li v-for="item in goods" class="food-list food-list-hook">
          <h1 class="title">{{item.name}}</h1>
          <ul>
            <li v-for="food in item.foods" class="food-item" @click="selectFood(food, $event)">
              <div class="icon">
                <img :src="food.icon" alt="" width="57">
              </div>
              <div class="content">
                <h2 class="name">{{food.name}}</h2>
                <p class="desc">{{food.description}}</p>
                <div class="extra">
                  <span class="count">月售{{food.sellCount}}</span><span class="count">好评{{food.rating}}</span>
                </div>
                <div class="price">
                  <span class="now">¥{{food.price}}</span><span class="old"
                                                                v-show="food.oldPrice">¥{{food.oldPrice}}</span>
                </div>
                <div class="cartControl-wrapper">
                  <cartControl :food="food" @increment="incrementTotal"></cartControl>
                </div>
              </div>
            </li>
          </ul>
        </li>
      </ul>
    </div>

6.1 $refs 的使用是vue 2 操作dom的一种方式

ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。

如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素; 如果用在子组件上,引用就指向组件实例:

      _initScroll(){
      //初始化scroll区域
        this.menuScroll = new BScroll(this.$refs.menuWrapper, {
          click: true //结合BScroll的接口使用,是否将click事件传递,默认被拦截了
        });
        this.foodsScroll = new BScroll(this.$refs.foodsWrapper, {
          probeType: 3 //结合BScroll的接口使用,3实时派发scroll事件,探针的作用
        });
        //结合BScroll的接口使用,监听scroll事件(实时派发的),并获取鼠标坐标,当滚动时能实时暴露出scroll
        this.foodsScroll.on(‘scroll‘, (pos) => { //事件的回调函数
          this.scrollY = Math.abs(Math.round(pos.y));//滚动坐标会出现负的,并且是小数,所以需要处理一下,实时取得scrollY
  }) }

vue中更改数据,DOM会跟着做映射,但vue更新DOM是异步的,用 $nextTick ()来确保Dom变化后能调用到_initScroll()方法。调用_initScroll()方法能计算内层ul的高度,当内层ul的高度大于外层wrapper的高度时,可以实现滚动。

6.2 左右两边联动

  • 在vue实例生命周期的开始created分别加载 _initScroll 和 _calculateHeight

  • 通过 _calculateHeight 计算foods内部每一个块的高度,组成一个数组listHeight

  • 在_initScroll里面,设置了bscroll插件的一个监听事件scroll,将food区域当前的滚动到的位置的y坐标设置到一个vue实例属性scrollY this.scrollY = Math.abs(Math.round(pos.y));

  • 通过计算属性currentIndex,获取到food滚动区域对应的menu区域的子块的索引,然后通过设置一个class来做样式切换变化 :class="{‘current‘:currentIndex === index} ,实现联动

  • 另外当点击menu 区域的时候,会触发selectMenu事件,也会根据点击到的menu子块的索引然后去触发food区域滚动到对应的高度区块区间 this.foodsScroll.scrollToElement(el, 300);scrollToElement():是better-scroll中的方法,滚动到某个元素,el(必填)表示 dom 元素,time 表示动画时间,offsetX 和 offsetY 表示坐标偏移量,easing 表示缓动函数

  • 这样完成整个对应

_calculateHeight()方法计算各个右侧区间的高度

 _calculateHeight(){
        let foodList = this.$refs.foodsWrapper.getElementsByClassName(‘food-list-hook‘); //获取每一个food的dom对象
        let height = 0;
        this.listHeight.push(height); //初始化第一个高度为0
        for (let i = 0; i < foodList.length; i++) {
          let item = foodList[i]; //每一个item都是刚才获取的food的每一个dom
          height += item.clientHeight; //主要是为了获取每一个foods内部块的高度
          this.listHeight.push(height);
        }
      }
    }

实时取得scrollY的值后,需要与左边进行映射,利用计算属性:

computed: {
      currentIndex(){ //计算到达哪个区域的区间的时候的对应的索引值
        for (let i = 0; i < this.listHeight.length; i++) {
          let height1 = this.listHeight[i]; //当前menu子块的高度
          let height2 = this.listHeight[i + 1]; //下一个menu子块的高度
          //滚动到底部的时候,height2为undefined,需要考虑这种情况
          //需要确定是在两个menu子块的高度区间
          if (!height2 || (this.scrollY >= height1 && this.scrollY < height2)) {
            return i; //返回这个menu子块的索引
          }
        }
        return 0;
      },
      selectFoods() { //自动将所有的goods.food添加一个count属性,方便做数量运算
        let foods = [];
        this.goods.forEach((good) => {
          good.foods.forEach((food) => {
            if (food.count) {
              foods.push(food);
            }
          });
        });
        return foods;
      }
    }

:class="{‘current‘:currentIndex === index}"当currentIndex === index时才设置current这个class

点击左侧 ,右侧响应:

关于在selectMenu中点击,在pc界面会出现两次事件,在移动端就只出现一次事件的问题:

原因:bsScrooler会监听事件(例如touchmove,click之类),并且阻止默认事件(prevent stop),并且他只会监听移动端的,pc端的没有监听

在pc页面上 bsScroller也派发了一次click事件,原生也派发了一次click事件

//bsScroll的事件,有_constructed: true
MouseEvent {isTrusted: false, _constructed: true, screenX: 0, screenY: 0, clientX: 0…}
//pc的事件
MouseEvent {isTrusted: true, screenX: -1867, screenY: 520, clientX: 53, clientY: 400…}

解决:针对bsScroole的事件,有_constructed: true,所以做处理,return掉非bsScroll的事件

selectMenu(index, event){
        if (!event._constructed) { //去掉自带的click事件点击,即pc端直接返回
          return;
        }
        let foodsList = this.$refs.foodsWrapper.getElementsByClassName(‘food-list-hook‘);
        let el = foodsList[index];
        //类似jump to的功能,通过这个方法,跳转到指定的dom
        this.foodsScroll.scrollToElement(el, 300);
      },

7.shopcart组件

也是采用flex布局,右侧部分固定宽度(flex 0 0 105px),左边自适应宽度(flex 1)

采用固定定位,定位在底部(position fixed)

横向排列display:inline-block

包含购物车图标的div超出了父元素的高度,我们使用position:relative,并设置top为负来实现

box-sizing: border-box;  则div 设置的宽高将包含 边框及 padding

border-radius 50%,形成一个圆

选择了多少商品:定义成数组,底栏其余部分的变化都基于这个对象的变化而变化

selectFoods: {
        type: Array,
        default() {
          return [{price: 20, count: 2}];
        }
      }

计算部分(都基于selectFoods进行相应计算)computed中的函数可以直接在Tempplate中以指针的形式引用

computed: {
      totalPrice() {//计算总价,超过起送额度后提示可付款
        let total = 0;
        this.selectFoods.forEach((food) => {
          total += food.price * food.count;
        });
        return total;
      },
      totalCount() {//计算选中的food数量,在购物车图标处显示,采用绝对定位,top:0;right:0;显示在购物车图标右上角
        let count = 0;
        this.selectFoods.forEach((food) => {
          count += food.count;
        });
        return count;
      }

控制底部右边内容随food的变化而变化,payDesc()控制显示内容,payClass()添加类调整显示样式

 在template中  
         <div class="pay" :class="payClass">
            {{payDesc}}
          </div>    
在computed中:
payDesc() {
        if (this.totalPrice === 0) {
          return `¥${this.minPrice}元起送`; //这里使用的是es6中的反引号
        } else if (this.totalPrice < this.minPrice) {
          let diff = this.minPrice - this.totalPrice;
          return `还差¥${diff}元起送`;
        } else {
          return ‘去结算‘;                 //单引号,单引号和反引号不同
        }
      },
      payClass() {
        if (this.totalPrice < this.minPrice) {
          return ‘not-enough‘;
        } else {
          return ‘enough‘;
        }
      }

总结:通过以上学习我们能发现,selectFoods()的变化起着关键作用,它的变化会引起DOM的变化,并最终体现到界面上,而我们不用关注DOM内部的具体实现,这就是vue的一大好处。如果采用jQuery完成这些功能会略显繁杂。

8 cartcontrol组件,它是shopcart的子组件

可以给按钮增加padding,方便用户点击

this.foodScroll = new BScroll(this.$refs.foodWrapper, {
          probeType: 3,
          click: true
        });

click: true 是否派发click事件

通过import Vue from ‘vue‘;使用set接口,通过vue.set()添加属性,当它变化时就能被检测到

methods: {
      addCart(event) {
        if (!event._constructed) {
          // 去掉自带click事件的点击
          return;
        }
        if (!this.food.count) {
          Vue.set(this.food, ‘count‘, 1);
        } else {
          this.food.count++;
        }
//        event.srcElement.outerHTML
        this.$emit(‘increment‘, event.target); // 子组件通过 $emit触发父组件的方法 increment   还
      },
      decreaseCart(event) {
        if (!event._constructed) {
          // 去掉自带click事件的点击
          return;
        }
        this.food.count--;
      }
    }
  };

9 为减号按钮添加平移、滚动的动画

  <transition name="fade">   //减号和数字平移动画
        <div class="cart-decrease" v-show="food.count>0" @click.stop.prevent="decreaseCart($event)">
          <transition name="inner">    //数字滚动动画
          <span class="inner iconfont icon-jian"></span>
          </transition>
        </div>
    </transition>
&.fade-enter-active, &.fade-leave-active {
      transition: all 0.4s linear    <--过渡效果的 CSS 属性的名称、过渡效果需要多少时间、速度效果的速度曲线-->
    }
    &.fade-enter, &.fade-leave-active {
      opacity: 0
      transform translate3d(24px, 0, 0) //这样可以开启硬件加速,动画更流畅,3D旋转,X轴位移24px
    }
    .inner
      display inline-block <--设置成inline-block才有高度,才能有动画-->
      line-height 24px
      font-size 24px
      vertical-align top
      color rgb(0, 160, 220, 0.2)
      &.inner-enter-active, &.inner-leave-active {
        transition: all 0.4s linear
        transform: rotate(0)
      }
      &.inner-enter, &.inner-leave-active {
        opacity: 0
        transform  rotate(180deg)
      }

10 购物小球(抛物线小球)

vuejs仿美团,饿了么项目之——商品数量加减篇

参考技术A首先,新增个商品数量的加减功能组件,就叫cartcontrol.vue吧。新增个底部购物车组件,叫shopcart.vue吧。在good.vue中引入并注册组件。cartcontrol.vue中,通过props来接收list对象因为我在json中没有设置数量这个key,所以需要... 查看详情

仿饿了么购物车下单效果

仿饿了么购物车下单效果前一段由于新项目需要,开发一个类似饿了么购物车下单效果,电商类、外卖类、点餐类项目都可以用的上,废话不多说请看效果。效果图如下:主要的功能:就是左侧展示分类,右侧展示分类下商品的,... 查看详情

5.goods商品列表页开发

goods组件显示的区域是固定的,也没有滚动条,所以是采用绝对布局的,左右分为menu栏和foods栏,左边固定布局,右边自适应布局,采用flex布局。写CSS样式的时候,尽量用class,少用tag,因为class的查找效率优于tag,尤其是嵌套... 查看详情

vue饿了么项目-header组件开发

1.数据传递的理解在App.vue中用到了header组件,首先注册组件components:{‘v-header‘:header}然后才能引用<v-header:seller="seller"></v-header>:seller="seller"的意思是将seller对象传递给v-header中的seller,而v-header中从哪里获得seller呢?通... 查看详情

基于vue来开发一个仿饿了么的外卖商城(代码片段)

一、准备工作1.大前提:已安装好node、npm、vue、vue-cli、stylus(此项目使用stylus来编译)2.开发软件:GoogleChrome(建议安装插件vue-devtools,方便调试),webstorm/sublimeText/VSCode(推荐使用webstorm,sublime和VSCode需要安装相应的插件)3.... 查看详情

vue饿了么项目实战笔记

1.页面骨架开发1.1组件拆分手机浏览器是把页面放在一个虚拟的“窗口”(viewport)中,通常这个虚拟的“窗口”(viewport)比屏幕宽,这样就不用把每个网页挤到很小的窗口中(这样会破坏没有针对手机浏览器优化的网页的布局... 查看详情

饿了么基于vue2.0的通用组件开发之路(分享会记录)

 Element:一套通用组件库的开发之路Element是由饿了么UED设计、饿了么大前端开发的一套基于Vue2.0的桌面端组件库。今天我们要分享的就是开发Element的一些心得。官网:http://element.eleme.io/#/github:https://github.com/ElemeFE/element ... 查看详情

vue饿了么项目的相关笔记链接

http://www.mtons.com/content/1819.htmhttp://www.tuicool.com/articles/F7BnaiYhttps://segmentfault.com/a/1190000007784366http://www.tuicool.com/articles/7zUruij 查看详情

仿饿了么项目-vue-cli开启项目

环境搭建安装nodeJs在用vue-cli开启项目之前,首先我们需要安装Node环境,安装Node很简单,只需要去官网下载http://nodejs.cn/download/,下载完成后点击安装,安装过程很简单,一直next即可,安装完成会自动添加node及npm环境变量。检... 查看详情

element+springboot实现简单的商品管理

  element是饿了么团队开发的PC端用的基于vue的框架,之前在写app端的时候用的是MintUI(饿了么团队)、vux(这个比较好用)。  element官网: https://element.eleme.cn/#/zh-CN  在这里直接下载git上别人写好的: vue-admin-template1.下... 查看详情

vue2高仿饿了么app

Github地址: https://github.com/ccyinghua/appEleme-project 一、构建项目所用:vueinitwebpackappEleme-projectnpmrundevcnpminstallnode-sass--save-devcnpminstallsass-loader--save-dev//sass-loader依赖于node-sas 查看详情

基于vue来开发一个仿饿了么的外卖商城(代码片段)

一、抽出头部作为一个组件,在底部导航的时候可以相应的显示不同的标题技术点:使用slot进行组件间的通信;父组件给子组件传值(子组件里面通过props接收父组件传过来的数据)查看链接:https://blog.csdn.net/sinat_17775997/article/... 查看详情

如何将后台的树形数据、倒序的展示到前台vue+饿了么ui组件中的面包屑里面呢

这个图片是树形数据、想倒序的展示到面包屑里面、求大神参考技术A先处理数据顺序在渲染组件即可1、先使用js对数据进行排序,按照倒序的排列好之后在把数据给到elementUI的组件中渲染即可2、js中最基本的数组排序方法是sort(... 查看详情

vue2+cli3实战项目-饿了么

参考技术A项目地址:Vue2+Cli3实战项目-还原饿了么订餐app项目截图:我们使用npm安装一些包的时候可能会比较慢,这时候我们可以使用cnpm,cnpm是中国NPM镜像。cnpm是一个完整npmjs.org镜像,你可以用此代替官方版本(只读),同步频... 查看详情

eleme饿了么vue项目随笔,随时更新,想到哪里写到哪里比较凌乱一直更新

组件设计原则:就近维护  mock数据模拟:/#/xx/api  vue1.0json获取不到(请求出现sockjs-node/info文件,所以不能加地址栏不加#来获取模拟请求数据)   vue2.0前端请求直接  /api 来获取数据 组件... 查看详情

ecshop模板开发:商品详情页超值大礼包优惠活动

1、html代码if$package_goods_list<h2>超值礼包</h2>foreachfrom=$package_goods_listitem=goods_list<h4>$goods_list.act_name</h4>foreachfrom=$goods_list.goods_listitem=package<p>$pac 查看详情

vue饿了么的技术点

一:项目目录设计。1:制作矢量图片的图标字体。打开icomoon.io网站,点击importicons,上传自己的svg图片,制作自己的图片,上传之后点击generatefont图标,下载然后把其中的font文件夹复制,style.css复制到style文件夹,修改为icom.styl... 查看详情

基于vue2+nuxt构建的高仿饿了么(2018版)(代码片段)

前言高仿饿了么,以nuxt作为vue的服务端渲染,适合刚接触或者准备上vuessr的同学参考和学习项目地址如遇网络不佳,请移步国内镜像加速节点效果演示查看demo请戳这里(请用chrome手机模式预览)移动端扫描下方二维码API接口文... 查看详情