vue2.0 饿了么学习笔记(16)rating组件的开发

 

首先编写ratings,要用到betterScroll

<template>
  <div class="ratings" ref="ratings"> <!-- ratings-content大于ratings的时候出现滚动 -->
    <div class="ratings-content">

并添加样式:

和good组件一样,我们要固定视口的高度,所以将其定位绝对定位,top为header组件的高度

.ratings
      position absolute 
      top 174px
      bottom 0
      left 0
      width 100%
      overflow hidden

接下来编写overview部分,左边是综合评分,右边是star组件+商品评分+送达时间,下边是左侧部分的样式

    <div class="ratings-content">
      <div class="overview">
        <div class="overview-left">
          <h1 class="score">{{seller.score}}</h1>
          <div class="title">综合评分</div>
          <div class="rank">高于周边商家{{seller.rankRate}}%</div>
        </div>
        <div class="overview-right">
        .....
        </div>
      </div>
      <split></split>

其中,seller的数据由App.vue中的routerview进行传递,在rating组件中使用props进行接收,这样在模板中就可以直接引用seller的数据了

 props: {
    seller: {
      type: Object
    }
  }

添加CSS样式:左侧部分

.overview
        display flex
        padding 18px 0 18px 18px
        .overview-left
          padding-bottom 6px 0
          flex 0 0 137px
          width 137px // 防止出现兼容性问题
          border-right 1px solid rgba(7,17,27,0.1)
          text-align center
          @media only screen and (max-width 320px)
            flex 0 0 110px
            width 110px
          .score
            margin-bottom 6px
            line-height 28px
            font-size 24px
            color rgb(255, 153, 0)
          .title
            margin-bottom 8px
            line-height 12px
            font-size 12px
            color rgb(7, 17, 27)
          .rank
            line-height 10px
            font-size 10px
            color rgb(147, 153, 159)
        .overview-right
          flex 1
          padding 6px 0 6px 24px

接下来填充坐左侧部分的样式,先写布局,不要忘记引入并注册star组件,尺寸是36的

<div class="overview">
        <div class="overview-left">
          ...
        </div>
        <div class="overview-right">
          <div class="score-wrapper">
            <span class="title">服务态度</span>
            <star :size="36" :score="seller.serviceScore"></star>
            <span class="score">{{seller.serviceScore}}</span>
          </div>
          <div class="score-wrapper">
            <span class="title">商品评分</span>
            <star :size="36" :score="seller.foodScore"></star>
            <span class="score">{{seller.foodScore}}</span>
          </div>
          <div class="delivery-wrapper">
            <span class="title">送达时间</span>
            <span class="delivery">{{seller.deliveryTime}}分钟</span>
          </div>
        </div>
      </div>

之后,为右侧部分添加布局

        .overview-right
          flex 1
          padding 6px 0 6px 24px
          @media only screen and (max-width 320px)
            padding-left 6px
          .score-wrapper
            line-height 18px
            margin-top 8px
            font-size 0
            .title 
              display inline-block
              vertical-align top
              line-height 18px
              font-size 12px
              color rgb(7, 17, 27)
            .star
              display inline-block
              vertical-align top
              margin 0 12px
            .score
              display inline-block
              vertical-align top
              line-height 18px
              font-size 12px
              color rgb(255, 153, 0)
          .delivery-wrapper
            font-size 0 
            .title  //span文字和文字之间默认是垂直居中的,可以不用加display vertical-align  
              display inline-block
              vertical-align top
              line-height 18px
              font-size 12px
              color rgb(7, 17, 27)
            .delivery
              display inline-block
              margin-left 12px
              vertical-align top
              line-height 18px
              font-size 12px
              color rgb(147, 153, 159)

还有一个问题,当屏幕宽度变短时,右侧部分过长会出现折行,这不是想要的,添加一个mediea Query即媒体查询进行解决

    .overview-left
          padding-bottom 6px 0
          flex 0 0 137px
          width 137px // 防止出现兼容性问题
          border-right 1px solid rgba(7,17,27,0.1)
          text-align center
          @media only screen and (max-width 320px)
            flex 0 0 110px
            width 110px
    .overview-right
          flex 1
          padding 6px 0 6px 24px
          @media only screen and (max-width 320px)
            padding-left 6px

 4)引入并注册split.vue和ratingselect.vue组件中调用

 <split></split>
<ratingselect @increment="incrementTotal" :select-type="selectType" :only-content="onlyContent" :ratings="ratings"></ratingselect>

现在data中添加ratingselect组件中需要维护的值,上边模板中的ratings是所有商品的ratings,不是一种商品的food.ratings

5)food.vue和rating.vue都将评价类型或者是选择类型传递给ratingselect.vue组件,但是传递的数值是不一样的,在这里,:ratings="ratings",指的是随商家的评价,在foods.vue中是:ratings="food.ratings",是对商家店里某一种食物的评价

  data () {
    return {
      ratings: [],
      showFlag: false,
      selectType: ALL,
      onlyContent: true
    };
  }

6)同goods.vue,在created()函数中拿到rating的API数据,将得到的ratings传到raqtings的组件中

 created() {
      //请求的ajex地址,成功的回调,拿到一个response
      this.$http.get('/api/ratings').then((response) => {
        //response是一个属性,将其转化为json对象
        response = response.body;
        //console.log(response);
        if (response.errno === ERR_OK) {
          // 数据在data字段中,将goods对象传给header组件,通过:goods
          this.ratings = response.data;
  //        console.log(this.goods);
          this.$nextTick(() => {
            this.scroll = new BScroll(this.$refs.ratings, {
              click: true //允许点击
            });
          });
        }
      });
  },

7)拿到数据之后在raring组件中编写样式,填充html中的DOM数据

      <div class="rating-wrapper">
        <ul>
          <li v-for="rating in ratings" :key="rating.id" class="rating-item" v-show="needShow(rating.rateType, rating.text)">
            <div class="avatar">
              <img :src="rating.avatar" width="28px" height="28px">
            </div>
            <div class="content">
              <h1 class="name">{{rating.username}}</h1>
              <div class="star-wrapper">
                <star :size="24" :score="rating.score"></star>
                <span class="delivery" v-show="rating.deliveryTime">
                  {{rating.deliveryTime}}
                </span>
              </div>
              <p class="text">{{rating.text}}</p>
              <div class="recommend" v-show="rating.recommend && rating.recommend.length"> <!-- 赞或踩和相关推荐 -->
                <i class="icon-thumb_up"></i>
                <span class="item" v-for="item in rating.recommend" :key="item.id">{{item}}</span>
              </div>
              <div class="time">
                 {{rating.rateTime | formatDate}}
              </div>
            </div>
          </li>
        </ul>
      </div>

完成样式:

      .rating-wrapper
        padding 0 18px
        .rating-item
          display flex
          padding 18px 0
          border-1px(rgba(1, 17, 27, 0.1))
          .avatar
            flex 0 0 28px
            width 28px
            margin-right 12px
            img
              border-radius 50%
          .content
            position relative
            flex 1
            .name
              margin-bottom 4px
              line-height 12px
              font-weight 700
              font-size 10px
              color rgb(7, 17, 27)
            .star-wrapper
              margin-bottom 6px
              font-size 0
              .star
                display inline-block
                margin-right 16px
                vertical-align top
              .delivery
                display inline-block
                vertical-align top
                font-size 10px
                line-height 12px
                color rgb(147, 153, 159)
            .text
              line-height 18px
              color rgb(7, 17, 27)
              font-size 12px
              margin-bottom 8px
            .recommend
              line-height 16px
              font-size 0
              .icon-thumb_up, .item
                display inline-block
                margin 0 8px 4px 0
                font-size 9px
              .icon-thumb_up
                color rgb(0, 160, 220)
              .item
                padding 0 6px
                border 1px solid rgba(7, 17, 27, 0.1)
                border-radius 1px
                color rgb(147, 153, 159)
                background #fffff
            .time
              position absolute
              top 0
              right 0
              line-height 12px
              font-size 10px
              color rgb(147, 153, 159)

8)绑定BScroll进行滚动

8.1 拿到DOM数据,ref="ratings",将BS初始化写在created函数拿到api数据之后

8.2.默认进图商品界面还会导致rating界面来不及渲染,因为nextTicks是异步执行的,所以将默认进入商品界面去除
在main.js中//router.push('/goods'); // 默认进入商家页面

8.3 .点击切换评价列表,和商品详情页类似,引入子组件

<ratingselect @increment="incrementTotal" :select-type="selectType" :only-content="onlyContent" :ratings="ratings"></ratingselect>

子组件已经定义好了data数据和派发函数,在food详情页展示的时候已经写过了

 data() {
            return {
                    sType: this.selectType,
                    oContent: this.onlyContent,
                }
            },
 <div class="ratingselect">
        <div class="rating-type" border-1px>
            <span class="block positive" @click="select(2,$event)" :class="{'active':sType === 2}">{{desc.all}}<span class="count">{{ratings.length}}</span> </span>
            <span class="block positive" @click="select(0,$event)" :class="{'active':sType === 0}">{{desc.positive}}<span class="count">{{positives.length}}</span></span>
            <span class="block negative" @click="select(1,$event)" :class="{'active':sType === 1}">{{desc.negative}}<span class="count">{{negatives.length}}</span></span>
        </div>
        <div @click="toggleContent($event)"  class="switch" :class="{'on':oContent}">
            <span class="icon-check_circle"></span>
            <span class="text">只看有内容的评价</span>
        </div>
  </div>
 select (type, event) { //点击的时候外层是有一个BScroll的,所以要传递event阻止默认点击
                if (!event._constructed) { //浏览器直接return掉,去掉自带click事件的点击
                    return;
                }
                //将this.selectType设置成传入的参数,而不是food传过来的初始化的值,之后样式就可以随着点击改变了
                this.sType = type;
                //派发事件通知父组件food.vue selectType的改变,将type值传出去
                 console.log('ratingselect.vue ' + type);
                //this.$emit('se-type', type); 
                this.$emit('increment', 'selectType', this.sType);
            },
            toggleContent (event) {
                if (!event._constructed) { //浏览器直接return掉,去掉自带click事件的点击
                        return;
                }
                this.oContent = !this.oContent;
                console.log('ratingselect.vue ' + this.oContent);
               // this.$emit('toggle-content', this.oContent);
                this.$emit('increment', 'onlyContent', this.oContent);
            }
        },  

在父组件rating.vue中

    incrementTotal(type, data) {
        this[type] = data;
        this.$nextTick(() => {
          this.scroll.refresh();
      });
    },

9. 点击满意不满意和只看内容的评价,评价列表进行刷新,在li列表展示里添加needshow();,needshow中改变的是selectType的值

    <div class="rating-wrapper">
        <ul>
          <li v-for="rating in ratings" :key="rating.id" class="rating-item" v-show="needShow(rating.rateType, rating.text)">
           
 incrementTotal(type, data) {
        this[type] = data;
        this.$nextTick(() => {
          this.scroll.refresh();
      });
    },
    needShow(type, text) {
      if (this.onlyContent && !text) {
        return false;
      }
      if (this.selectType === ALL) {
        return true;
      } else {
        return type === this.selectType;
      }
    }
  }

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值