6.food商品详情页

ood采用fixed布局,z-index小于shopcart和list-mask的z-index,也就是说在商品详情页还是可以显示购物车清单页。

.food
  position: fixed
  left: 0
  top: 0
  bottom: 48px
  z-index: 30
  width: 100%
  background: #fff
  &.move-enter-active, &.move-leave-active
    transition: all 0.2s
  &.move-enter, &.move-leave-to
   transform: translate3d(100%, 0, 0)

vue组件中data中的数据的名称和methods中的方法的名字不能相同。如果重名的话,有一个会被覆盖。父组件可以调用子组件的方法,但是子组件不能调用父组件的方法。在food组件定义一个show方法,在父组件goods中调用。

food中的图片宽高是相等的,我们利用padding-top:100%来实现,padding-top是相对于width来设置的

<div class="image-header">
  <img :src="food.image">
</div>

.image-header
  position: relative
  width: 100%
  height: 0
  padding-top: 100%
  img
    position: absolute
    top: 0
    left: 0
    width: 100%
    height: 100%

ratingselect组件

ratingselect组件从父组件接收一些数据,ratings,selectType,onlyContent和desc(props中的数组和对象默认值都是一个函数)

type: Object,
  default() {
    return {
      all: '全部',
      positive: '满意',
      negative: '不满意'
    };
  }

对于不同food的ratingselect组件,我们希望他们有相同的初始状态,因此虽然在data()中虽然已经设置了参数的默认值,在show()函数中还会对selectType和onlyContent初始化

show() {
  this.showFlag = true;
  this.selectType = 0;
  this.onlyContent = true;
  this.$nextTick(() => {
    if (!this.scroll) {
      this.scroll = new BScroll(this.$refs.food, {
        click: true
      });
    } else {
      this.scroll.refresh();
    }
  });
}

为当前激活的按钮增加一个active的class,通过selectType的值确定当前激活的按钮 <span @click="select(2, $event)" class="block positive" :class="{'active':selectType===2}">{{desc.all}}<span class="count">{{ratings.length}}</span></span>

点击block按钮时,添加select事件改变给父组件food发送一个事件。

select(type, event) {
  if (!event._constructed) {
    return;
  }
  this.$emit('select', type);
}

在父组件中接收这个事件,并且改变selectType的值(prop是单向数据流的,原则上子组件修改props是不被允许,所以我们通过发送事件给父组件,在父组件中改变数值)

<ratingselect @select="selectRating" @toggle="toggleContent" :selectType="selectType" :onlyContent="onlyContent" :desc="desc" :ratings="food.ratings"></ratingselect>

selectRating(type) {
  this.selectType = type;
  this.$nextTick(() => {
    this.scroll.refresh();
  });
}

点击toggleContent也是给父组件派发以一个事件,在父组件中修改onlyContent的值

positive和negative的评价的长度通过计算属性positives()和negatives()得到

computed: {
  positives() {
    return this.ratings.filter((rating) => {
      return rating.rateType === POSITIVE;
    });
  },
  negatives() {
    return this.ratings.filter((rating) => {
      return rating.rateType === NEGATIVE;
    });
  }
}

接着在food组件写评价内容,根据评论的类型显示点赞和踩的标志,通过给<span>:class一个对象来实现<span :class="{'icon-thumb_up':rating.rateType===0, 'icon-thumb_down':rating.rateType===1}"></span>

评论的显示控制用v-show="needShow(rating.rateType,rating.text)"来实现,v-show可以绑定对象,属性,字段也可以绑定函数的返回值。

v-show="needShow(rating.rateType,rating.text)" class="rating-item border-1px" v-for="rating in food.ratings">

needShow (type, text) {
  if (this.onlyContent && !text) {
    return false;
  }
  if (this.selectType === ALL) {
    return true;
  } else {
    return type === this.selectType;
  }
}

要对时间的格式进行处理,在rating.rateTime后面加一个filter,在该组件中定义filters。用一个js模块实现formatDate,在src/js文件夹下创建date.js

<div class="time">{{rating.rateTime | formatDate}}</div>

filters: {
  formatDate(time) {
    let date = new Date(time);
    return formatDate(date, 'yyyy-MM-dd hh:mm');
  }
}

时间的格式化主要通过正则表达式来实现

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);
}

 

posted on 2017-08-03 20:54  U201113877  阅读(140)  评论(0编辑  收藏  举报