手记

goods-seller-vuejs笔记

component/goods/goods.vue
<template>
<div>
<div class="goods">
<div class="menu-wrapper" ref="menuWrapper">
<ul>
<li v-for="(item,index) in goods" class="menu-item" :class="{'current':currentIndex===index}"
@click="selectMenu(index,$event)">
<span class="text border-1px">
<span v-show="item.type>0" class="icon" :class="classMap[item.type]"></span>{{item.name}}
</span>
</li>
</ul>
</div>
<div class="foods-wrapper" ref="foodsWrapper">
<ul>
<li v-for="item in goods" class="food-list" ref="foodList">
<h1 class="title">{{item.name}}</h1>
<ul>
<li @click="selectFood(food,$event)" v-for="food in item.foods" class="food-item border-1px">
<div class="icon">
<img width="57" height="57" :src="food.icon">
</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>好评率{{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 @add="addFood" :food="food"></cartcontrol>
</div>
</div>
</li>
</ul>
</li>
</ul>
</div>
<shopcart ref="shopcart" :selectFoods="selectFoods" :deliveryPrice="seller.deliveryPrice"
:minPrice="seller.minPrice"></shopcart>
</div>
<food @add="addFood" :food="selectedFood" ref="food"></food>
</div>
</template>

<script type="text/ecmascript-6">
import BScroll from 'better-scroll';
import shopcart from 'components/shopcart/shopcart';
import cartcontrol from 'components/cartcontrol/cartcontrol';
import food from 'components/food/food';

const ERR_OK = 0;

export default {
props: {
seller: {
type: Object
}
},
data() {
return {
goods: [],
listHeight: [],
scrollY: 0,
selectedFood: {}
};
},
computed: {
currentIndex() {
for (let i = 0; i < this.listHeight.length; i++) {
let height1 = this.listHeight[i];
let height2 = this.listHeight[i + 1];
if (!height2 || (this.scrollY >= height1 && this.scrollY < height2)) {
return i;
}
}
return 0;
},
selectFoods() {
let foods = [];
this.goods.forEach((good) => {
good.foods.forEach((food) => {
if (food.count) {
foods.push(food);
}
});
});
return foods;
}
},
created() {
this.classMap = ['decrease', 'discount', 'special', 'invoice', 'guarantee'];

  this.$http.get('/api/goods').then((response) => {
    response = response.body;
    if (response.errno === ERR_OK) {
      this.goods = response.data;
      this.$nextTick(() => {
        this._initScroll();
        this._calculateHeight();
      });
    }
  });
},
methods: {
  selectMenu(index, event) {
    if (!event._constructed) {
      return;
    }
    let foodList = this.$refs.foodList;
    let el = foodList[index];
    this.foodsScroll.scrollToElement(el, 300);
  },
  selectFood(food, event) {
    if (!event._constructed) {
      return;
    }
    this.selectedFood = food;
    this.$refs.food.show();
  },
  addFood(target) {
    this._drop(target);
  },
  _drop(target) {
    // 体验优化,异步执行下落动画
    this.$nextTick(() => {
      this.$refs.shopcart.drop(target);
    });
  },
  _initScroll() {
    this.meunScroll = new BScroll(this.$refs.menuWrapper, {
      click: true
    });

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

    this.foodsScroll.on('scroll', (pos) => {
      this.scrollY = Math.abs(Math.round(pos.y));
    });
  },
  _calculateHeight() {
    let foodList = this.$refs.foodList;
    let height = 0;
    this.listHeight.push(height);
    for (let i = 0; i < foodList.length; i++) {
      let item = foodList[i];
      height += item.clientHeight;
      this.listHeight.push(height);
    }
  }
},
components: {
  shopcart,
  cartcontrol,
  food
}

};
</script>

<style lang="stylus" rel="stylesheet/stylus">
@import "../../common/stylus/mixin.styl"

.goods
display: flex
position: absolute
top: 174px
bottom: 46px
width: 100%
overflow: hidden
.menu-wrapper
flex: 0 0 80px
width: 80px
background: #f3f5f7
.menu-item
display: table
height: 54px
width: 56px
padding: 0 12px
line-height: 14px
&.current
position: relative
z-index: 10
margin-top: -1px
background: #fff
font-weight: 700
.text
border-none()
.icon
display: inline-block
vertical-align: top
width: 12px
height: 12px
margin-right: 2px
background-size: 12px 12px
background-repeat: no-repeat
&.decrease
bg-image('decrease_3')
&.discount
bg-image('discount_3')
&.guarantee
bg-image('guarantee_3')
&.invoice
bg-image('invoice_3')
&.special
bg-image('special_3')
.text
display: table-cell
width: 56px
vertical-align: middle
border-1px(rgba(7, 17, 27, 0.1))
font-size: 12px
.foods-wrapper
flex: 1
.title
padding-left: 14px
height: 26px
line-height: 26px
border-left: 2px solid #d9dde1
font-size: 12px
color: rgb(147, 153, 159)
background: #f3f5f7
.food-item
display: flex
margin: 18px
padding-bottom: 18px
border-1px(rgba(7, 17, 27, 0.1))
&:last-child
border-none()
margin-bottom: 0
.icon
flex: 0 0 57px
margin-right: 10px
.content
flex: 1
.name
margin: 2px 0 8px 0
height: 14px
line-height: 14px
font-size: 14px
color: rgb(7, 17, 27)
.desc, .extra
line-height: 10px
font-size: 10px
color: rgb(147, 153, 159)
.desc
line-height: 12px
margin-bottom: 8px
.extra
.count
margin-right: 12px
.price
font-weight: 700
line-height: 24px
.now
margin-right: 8px
font-size: 14px
color: rgb(240, 20, 20)
.old
text-decoration: line-through
font-size: 10px
color: rgb(147, 153, 159)
.cartcontrol-wrapper
position: absolute
right: 0
bottom: 12px
</style>

seller.vue:
<template>
<div class="seller" ref="seller">
<div class="seller-content">
<div class="overview">
<h1 class="title">{{seller.name}}</h1>
<div class="desc border-1px">
<star :size="36" :score="seller.score"></star>
<span class="text">({{seller.ratingCount}})</span>
<span class="text">月售{{seller.sellCount}}单</span>
</div>
<ul class="remark">
<li class="block">
<h2>起送价</h2>
<div class="content">
<span class="stress">{{seller.minPrice}}</span>元
</div>
</li>
<li class="block">
<h2>商家配送</h2>
<div class="content">
<span class="stress">{{seller.deliveryPrice}}</span>元
</div>
</li>
<li class="block">
<h2>平均配送时间</h2>
<div class="content">
<span class="stress">{{seller.deliveryTime}}</span>分钟
</div>
</li>
</ul>
<div class="favorite" @click="toggleFavorite">
<span class="icon-favorite" :class="{'active':favorite}"></span>
<span class="text">{{favoriteText}}</span>
</div>
</div>
<split></split>
<div class="bulletin">
<h1 class="title">公告与活动</h1>
<div class="content-wrapper border-1px">
<p class="content">{{seller.bulletin}}</p>
</div>
<ul v-if="seller.supports" class="supports">
<li class="support-item border-1px" v-for="(item,index) in seller.supports">
<span class="icon" :class="classMap[seller.supports[index].type]"></span>
<span class="text">{{seller.supports[index].description}}</span>
</li>
</ul>
</div>
<split></split>
<div class="pics">
<h1 class="title">商家实景</h1>
<div class="pic-wrapper" ref="picWrapper">
<ul class="pic-list" ref="picList">
<li class="pic-item" v-for="pic in seller.pics">
<img :src="pic" width="120" height="90">
</li>
</ul>
</div>
</div>
<split></split>
<div class="info">
<h1 class="title border-1px">商家信息</h1>
<ul>
<li class="info-item" v-for="info in seller.infos">{{info}}</li>
</ul>
</div>
</div>
</div>
</template>

<script type="text/ecmascript-6">
import BScroll from 'better-scroll';
import {saveToLocal, loadFromLocal} from 'common/js/store';
import star from 'components/star/star';
import split from 'components/split/split';

export default {
props: {
seller: {
type: Object
}
},
data() {
return {
favorite: (() => {
return loadFromLocal(this.seller.id, 'favorite', false);
})()
};
},
computed: {
favoriteText() {
return this.favorite ? '已收藏' : '收藏';
}
},
created() {
this.classMap = ['decrease', 'discount', 'special', 'invoice', 'guarantee'];
},
watch: {
'seller'() {
this.$nextTick(() => {
this._initScroll();
this._initPics();
});
}
},
mounted() {
this.$nextTick(() => {
this._initScroll();
this._initPics();
});
},
methods: {
toggleFavorite(event) {
if (!event._constructed) {
return;
}
this.favorite = !this.favorite;
saveToLocal(this.seller.id, 'favorite', this.favorite);
},
_initScroll() {
if (!this.scroll) {
this.scroll = new BScroll(this.$refs.seller, {
click: true
});
} else {
this.scroll.refresh();
}
},
_initPics() {
if (this.seller.pics) {
let picWidth = 120;
let margin = 6;
let width = (picWidth + margin) * this.seller.pics.length - margin;
this.$refs.picList.style.width = width + 'px';
this.$nextTick(() => {
if (!this.picScroll) {
this.picScroll = new BScroll(this.$refs.picWrapper, {
scrollX: true,
eventPassthrough: 'vertical'
});
} else {
this.picScroll.refresh();
}
});
}
}
},
components: {
star,
split
}
};
</script>

<style lang="stylus" rel="stylesheet/stylus">
@import "../../common/stylus/mixin.styl"

.seller
position: absolute
top: 174px
bottom: 0
left: 0
width: 100%
overflow: hidden
.overview
position: relative
padding: 18px
.title
margin-bottom: 8px
line-height: 14px
color: rgb(7, 17, 27)
font-size: 14px
.desc
padding-bottom: 18px
border-1px(rgba(7, 17, 27, 0.1))
font-size: 0
.star
display: inline-block
margin-right: 8px
vertical-align: top
.text
display: inline-block
margin-right: 12px
line-height: 18px
vertical-align: top
font-size: 10px
color: rgb(77, 85, 93)
.remark
display: flex
padding-top: 18px
.block
flex: 1
text-align: center
border-right: 1px solid rgba(7, 17, 27, 0.1)
&:last-child
border: none
h2
margin-bottom: 4px
line-height: 10px
font-size: 10px
color: rgb(147, 153, 159)
.content
line-height: 24px
font-size: 10px
color: rgb(7, 17, 27)
.stress
font-size: 24px
.favorite
position: absolute
width: 50px
right: 11px
top: 18px
text-align: center
.icon-favorite
display: block
margin-bottom: 4px
line-height: 24px
font-size: 24px
color: #d4d6d9
&.active
color: rgb(240, 20, 20)
.text
line-height: 10px
font-size: 10px
color: rgb(77, 85, 93)
.bulletin
padding: 18px 18px 0 18px
.title
margin-bottom: 8px
line-height: 14px
color: rgb(7, 17, 27)
font-size: 14px
.content-wrapper
padding: 0 12px 16px 12px
border-1px(rgba(7, 17, 27, 0.1))
.content
line-height: 24px
font-size: 12px
color: rgb(240, 20, 20)
.supports
.support-item
padding: 16px 12px
border-1px(rgba(7, 17, 27, 0.1))
font-size: 0
&:last-child
border-none()
.icon
display: inline-block
width: 16px
height: 16px
vertical-align: top
margin-right: 6px
background-size: 16px 16px
background-repeat: no-repeat
&.decrease
bg-image('decrease_4')
&.discount
bg-image('discount_4')
&.guarantee
bg-image('guarantee_4')
&.invoice
bg-image('invoice_4')
&.special
bg-image('special_4')
.text
line-height: 16px
font-size: 12px
color: rgb(7, 17, 27)
.pics
padding: 18px
.title
margin-bottom: 12px
line-height: 14px
color: rgb(7, 17, 27)
font-size: 14px
.pic-wrapper
width: 100%
overflow: hidden
white-space: nowrap
.pic-list
font-size: 0
.pic-item
display: inline-block
margin-right: 6px
width: 120px
height: 90px
&:last-child
margin: 0
.info
padding: 18px 18px 0 18px
color: rgb(7, 17, 27)
.title
padding-bottom: 12px
line-height: 14px
border-1px(rgba(7, 17, 27, 0.1))
font-size: 14px
.info-item
padding: 16px 12px
line-height: 16px
border-1px(rgba(7, 17, 27, 0.1))
font-size: 12px
&:last-child
border-none()
</style>

0人推荐
随时随地看视频
慕课网APP

热门评论

什么玩意

查看全部评论