vue2.0饿了么学习笔记(15)ratingselect组件的实现

ratingselect组件的实现


1)创建ratingselect文件和ratingselect.vue
2)设置ratingselect组件中需要的props接收的数据,数据应从food.vue组件传入<ratingselect></ratingselect>,并由ratingselect.vue的props接收


 const POSITIVE = 0;
    const NEGATIVE = 1;
    const ALL = 2;
      export default {
        //需要一些评价数据才能完成评价组件
        props: {
           ratings: {
               type: Array,
               default() {
                   return [];
               }
           },
            selectType: { //全部,满意,不满意
                type: Number,
                default: ALL //默认情况时ALL,值等于2
            },
            onlyContent: { //只看有内容的评价还是所有的评价
                type: Boolean,
                default: false //设置为可以看到所有的评价
            },
            desc: { //描述
                type: Object,
                default() { //默认desc是这三种,在商品详情页的时候传入推荐或者吐槽
                    return {
                        all: '全部',
                        positive: '满意',
                        negative: '不满意'
                    };
                }
            }
        },
3)food.vue中,在foods组件中引入并注册ratingselect.vue组件,并data属性和(:)属性将2)中需要的数据从foods组件中传到ratingselect.vue组件的props中
data () {
        return {
            showFlag: false,
            selectType: ALL,
            onlyContent: false, //先设置组件一开始显示有内容的评价
            desc: { //desc做了改变
                all: '全部',
                positive: '推荐',
                negative: '吐槽' 
            }
        };
    },
<!--  ratings对应被点击的food的ratings-->
 <ratingselect  @increment="incrementTotal" :select-type="selectType" :only-content="onlyContent" :desc="desc" :ratings="food.ratings"></ratingselect>

此时,desc已经从默认的满意和不满意变成了推荐和吐槽,接下来在foods.vue中为title和ratingselect部分编写样式和ratingselect自身样式的编写(ratingType和switch的普通样式和点击时的样式变化,若要改变初始状态就在food.vue中的show()函数中改变,show()函数是用来被goods.vue调用并展开详情界面的

<template>
  <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>
</template>
.ratingselect
    .rating-type
        padding 18px 0
        margin 0 18px //保证横线的长度
        border-1px(rgba(7,17,27,0.1))
        font-size 0
        .block //没有写文字的时候是没有被撑开的
            display inline-block
            padding 8px 12px
            margin-right 8px
            border-radius 1px
            line-height 16px
            font-size 12px
            color rgb(77,85,93)
            &.active  // block的active要设置一下
                 color #ffffff
            .count
                margin-left 2px
                font-size 8px
            &.positive
                background rgba(0,160,220,.2)
                &.active
                    background rgb(0,160,220)
            &.negative
                background  rgba(77,85,93,0.2)
                &.active
                    background  rgb(77,85,93)
    .switch
        padding 12px 18px
        line-height 24px
        border-bottom 1px solid rgba(7,17,27,0.1)
        color rgb(147,153,159)
        font-size 0
        &.on
            .icon-check_circle
                color #00c850
        .icon-check_circle
            display inline-block
            vertical-align top 
            margin-right 4px
            font-size 24px
        .text
            display inline-block
            vertical-align top
            font-size 12px
        
        
</style>
4)为ratingType(是否满意)和switch(是否查看全部评估)编写点击事件,ratingselect.vue在select()中改变了selectType的值,要将改变的值通知到父组件food.vue的show()方法,可以通过派发事件完成

在ratingselect中重新定义变量接收父组件food传过来的值

food.vue 将selectType和onlyContent传入子组件

<ratingselect  @increment="incrementTotal" :select-type="selectType" :only-content="onlyContent" :desc="desc" :ratings="food.ratings"></ratingselect>
子组件在data中定义新的变量接收接收:
data() {
            return {
                    sType: this.selectType,
                    oContent: this.onlyContent,
                }
            },
 methods: {
            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);
            }
        },  

回到父组件food.vue中编写监听函数,并关联组件

     incrementTotal(type, data) {
            this[type] = data;
            this.$nextTick(() => {
                this.scroll.refresh();
        });
      },
<ratingselect  @increment="incrementTotal" :select-type="selectType" :only-content="onlyContent" :desc="desc" :ratings="food.ratings"></ratingselect>

5)统计不同评价的数量(过滤评价类型),添加positives和negitives数组,长度即为评价数量

<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>
     computed: {
            positives() { //对应所有正向评价的数组
                return this.ratings.filter((rating) => {
                    return rating.rateType === POSITIVE;
                });
            },
            negatives() {
                return this.ratings.filter((rating) => {
                    return rating.rateType === NEGATIVE;
                });
            }
        },
6)为其中时间的显示添加过滤器
 
<div class="time">{{rating.rateTime | formatDate}}</div>
 import {formatDate} from 'common/js/date.js';
export function formatDate(date, fmt) {
   if (/(y+)/.test(fmt)) {
    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
   }
  let o = {
    'M+': date.getMonth() + 1,
    'd+': date.getDate(),
    'h+': date.getHours(),
    'm+': date.getMinutes(),
    's+': date.getSeconds()
  };
  for (let k in o) {
    if (new RegExp(`(${k})`).test(fmt)) {
      let str = o[k] + '';
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));
    }
  }
  return fmt;
}

function padLeftZero(str) {
  return ('00' + str).substr(str.length);
}

8)点击是否满意和只看有评价内容时,评价列表的显示,不是ratingselect组件的内容,写在food.vue中
             <div class="rating-wrapper"> <!-- 评价列表-->
                    <ul v-show="food.ratings && food.ratings.length">
                        <li v-show="needShow(rating.rateType, rating.text)" v-for="rating in food.ratings" :key="rating.id" class="rating-item border-1px">
                            <div class="user">
                                <span class="name">{{rating.username}}</span>
                                <img class="avatar" height="12" width="12"  :src="rating.avatar" alt="">
                            </div>
                            <div class="time">{{rating.rateTime | formatDate}}</div>
                            <p class="text">
                                <span :class="{'icon-thumb_up':rating.rateType === 0, 'icon-thumb_down':rating.rateType === 1}"></span>{{rating.text}}
                            </p>
                        </li>
                    </ul>
                    <div class="no-ratings" v-show="!food.ratings || !food.ratings.length">暂无评价</div>
                </div>

利用needshow进行切换

     needShow(type, text) {
             // console.log('this.selectType: ' + this.selectType + '  type: ' + type + ' out  ' + text);
            if (this.onlyContent && !text) {
                return false;
            }
            if (this.selectType === ALL) {
                return true;
            } else {
                //console.log('this.selectType: ' + this.selectType + 'type: ' + type + ' in ' + text);
                return type === this.selectType;
            }
        },

猜你喜欢

转载自blog.csdn.net/qq_22317389/article/details/80459310