商品详情页(food组件)

Posted Emily

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了商品详情页(food组件)相关的知识,希望对你有一定的参考价值。

前言

本节分为四大块:

1. 商品信息(布局样式、第三方插件库better-scroll 的应用、split 组件)

2. 商品评价(ratingselect 组件)

3. 商品评价(评价列表)

 PS:本节所有代码在文章底部。

 

 

商品信息

1. CSS 设置

  1 <style lang="stylus" rel="stylesheet/stylus">
  2   @import "../../common/stylus/mixin.styl"
  3 
  4   .food
  5     position fixed
  6     left 0
  7     top 0
  8     bottom 48px
  9     z-index 30
 10     width 100%
 11     background #fff
 12     transform translate3d(0, 0, 0)
 13     &.move-enter-active, &.move-leave-active
 14       transition all 0.2s linear
 15     &.move-enter, &.move-leave-active
 16       transform translate3d(100%, 0, 0)
 17     .image-header
 18       position relative
 19       width 100%
 20       height 0
 21       padding-top 100%
 22       img
 23         position absolute
 24         left 0
 25         top 0
 26         width 100%
 27         height 100%
 28       .back
 29         position absolute
 30         left 0
 31         top 10px
 32         .icon-arrow_lift
 33           display block
 34           /*点击区域变大*/
 35           padding 10px
 36           font-size 20px
 37           color #fff
 38     .content
 39       position relative
 40       padding 18px
 41       .title
 42         margin-bottom 8px
 43         line-height 14px
 44         font-size 14px
 45         font-weight 700
 46         color rgb(7, 17, 27)
 47       .detail
 48         margin-bottom 18px
 49         height 10px
 50         line-height 10px
 51         font-size 0
 52         .sell-count, .rating
 53           font-size 10px
 54           color rgb(147, 153, 159)
 55         .sell-count
 56           margin-right 12px
 57       .price
 58         font-weight 700
 59         line-height 24px
 60         .now
 61           margin-right 8px
 62           font-size 14px
 63           color rgb(240, 20, 20)
 64         .old
 65           text-decoration line-through
 66           font-size 10px
 67           color rgb(147, 153, 159)
 68       .cartcontrol-wrapper
 69         position absolute
 70         right 12px
 71         bottom 12px
 72       .buy
 73         position absolute
 74         right 18px
 75         bottom 18px
 76         /*因为要盖住cartcontrol组件*/
 77         z-index 10
 78         height 24px
 79         line-height 24px
 80         padding 0 12px
 81         box-sizing border-box
 82         border-radius 12px
 83         font-size 10px
 84         color #fff
 85         background-color rgb(0, 160, 220)
 86         opacity 1
 87         &.fade-enter-active, &.fade-leave-active
 88           transition all 0.2s linear
 89         &.fade-enter, &.fade-leave-active
 90           opacity 0
 91           z-index -1
 92     .info
 93       padding: 18px
 94       .title
 95         line-height: 14px
 96         margin-bottom: 6px
 97         font-size: 14px
 98         color: rgb(7, 17, 27)
 99       .text
100         line-height: 24px
101         padding: 0 8px
102         font-size: 12px
103         color: rgb(77, 85, 93)
104     .rating
105       padding-top: 18px
106       .title
107         line-height: 14px
108         margin-left: 18px
109         font-size: 14px
110         color: rgb(7, 17, 27)
111       .rating-wrapper
112         padding 0 18px
113         .rating-item
114           position relative
115           padding 16px 0
116           border-1px(rgba(7, 17, 27, 0.1))
117           .user
118             position absolute
119             top 16px
120             right 0
121             line-height 12px
122             font-size 0
123             .username
124               margin-right 6px
125               display inline-block
126               vertical-align top
127               font-size 10px
128               color rgb(147, 153, 159)
129             .avatar
130               border-radius 50%
131           .time
132             margin-bottom 6px
133             line-height 12px
134             font-size 10px
135             color rgb(147, 153, 159)
136           .text
137             line-height 16px
138             font-size 12px
139             color rgb(7, 17, 27)
140             .icon-thumb_up, .icon-thumb_down
141               margin-right 4px
142               line-height 16px
143               font-size 12px
144             .icon-thumb_up
145               color rgb(0, 160, 220)
146             .icon-thumb_down
147               color rgb(147, 153, 159)
148       .no-rating
149         padding 16px 0
150         font-size 12px
151         color rgb(147, 153, 159)
152 </style>
CSS 设置

1)相对于屏幕进行定位,使用 fixed 布局。

2)底部有购物车,所以设置 bottom 为 48px。

3)z-index 的值应该小于购物车详情层的 z-index,因为购物车详情层弹出应该要遮盖住商品详情层。

4)加上 transition 动画

5)图片高度应该和屏幕宽度一样,是动态变化的。图片加载是异步过程,如果不设置图片高度,等到图片加载完毕,页面高度会突然被撑开。如何解决?先把宽高设好,设置 height 0,padding-top 100%。这是 W3C 的一个特定写法,当 padding 的 top 或 bottom 设置为100% 时,会相对于盒子的 width 100%,这就相当于有一个宽高相等的盒子。(同理,当 padding 的 left 或 right 设置为100% 时,会相对于盒子的 height 100%)

 

2. 数据获取

 1 food.vue文件
 2     props: {
 3       food: {
 4         type: Object
 5       }
 6     },
 7 
 8 
 9 goods.vue文件
10     <food :food="selectedFood" ref="food"></food>
11 
12     import food from \'../../components/food/food\';
13     data() {
14       return {
15         selectedFood: {}
16       };
17     },
18     methods: {
19       selectFood(food, event) {
20         if (!event._constructed) {
21           // eslint-disable-next-line
22           return;
23         }
24         this.selectedFood = food;
25       },
26     }
数据获取

1)商品详情页关联的是商品本身,也就是食品分类下的每个商品。使用 props 接收 food 对象。

2)在 goods 组件中引用 food 组件,并且传入food,设定变量为 selectedFood(即选中的 food),在 data 中定义该变量,为一个空对象。

3)selectedFood 是选中的 food,那么什么时候选中?当点击 food 时。如何实现:在 li 中添加点击事件 selectFood(food,$event),传入参数 food,因为这里是 foodWrapper,所以点击的时候也要拿到 event,接着在在 methods 中实现该方法。先 return 掉浏览器默认的点击事件,将参数 food 传递给变量 selectedFood。如何检验:在浏览器调试窗口中找到 food 层,取消display属性,看看布局有没有错。

 

3. show 方法的实现:点击商品时,商品详情层展开

 1 food.vue文件
 2     <div class="food" v-show="showFlag" ref="food">
 3 
 4     data() {
 5       return {
 6         showFlag: false
 7         }
 8       };
 9     },
10     methods: {
11       show() {
12         this.showFlag = true;
13       },
14     }
15 
16 goods.vue文件
17     methods: {
18       selectFood(food, event) {
19         this.$refs.food.show();
20       }
21     }
show方法

在 food 组件中定义 show 方法,show 方法通过改变 showFlag 的值来实现商品详情层的展开功能,在此之前,需要在 data 中先定义 showFlag。然后在 goods 组件中通过 ref 获取组件,并通过 $refs 调用子组件的 show 方法。

PS:1)父组件可以调用子组件方法,子组件不能调用父组件方法。2)设计规范:下划线开头是私有方法(_drop)。

 

4. 给返回按钮添加点击事件 hide

1 <div class="back" @click="hide">
2 
3 methods: {
4       hide() {
5         this.showFlag = false;
6       }
7 }
hide方法

1)CSS设置:(display block,padding 10px)先设置display,才能设置padding,使点击区域变大。

2)hide 方法通过改变 showFlag 的值为 false 来实现返回功能。
设置其他样式

 

5.  better-scroll 的使用

 1 <div class="food" v-show="showFlag" ref="food">
 2     <div class="food-content">
 3     </div>
 4 </div>
 5 
 6 methods: {
 7       show() {
 8         this.$nextTick(() => {
 9           if (!this.scroll) {
10             this.scroll = new BScroll(this.$refs.food, {
11               click: true
12             });
13           } else {
14             this.scroll.refresh();
15           }
16         });
17       }
18 }
better-scroll 的使用

原理:当内部(content)的内容高度大于视口高度,则产生滚动效果

固定框架:外层是一个 wrapper,里面有一个 content,并且这个 content 高度是由其中的内容撑开的。

使用:better-scroll 应该绑定在最外层(.food)。依旧是通过 ref 获取组件,并通过 $refs 调用组件。better-scroll 应该在商品详情层展开时就进行初始化,所以其初始化应该在 show 方法中。

6. 购物车模块

 1 food.vue文件:
 2 <div class="cartcontrol-wrapper">
 3     <cartcontrol :food="food"></cartcontrol>
 4 </div>
 5 <transition name="fade">
 6     <div @click.stop.prevent="addFirst" class="buy" v-show="!food.count || food.count===0">加入购物车</div>
 7 </transition>
 8 
 9 import Vue from \'vue\';
10 methods: {
11       addFirst(event) {
12         console.log(\'click\');
13         if (!event._constructed) {
14           // eslint-disable-next-line
15           return;
16         }
17         this.$emit(\'add\', event.target);
18         console.log(event.target);
19         Vue.set(this.food, \'count\', 1);
20       }
21 }
22 
23 cartcontrol.vue文件:
24 <div class="cart-decrease" v-show="food.count>0" @click.stop.prevent="decreaseCart">
25 <div class="cart-add icon-add_circle" @click.stop.prevent="addCart"></div>
购物车模块

有两种样式:当加入商品时,“加入购物车” 文字消失,显示 cartcontrol 组件。所以应该加入两个层,这两个层平级,分别是 buy 层和 cartcontrol 层。

1)这两个层都是绝对定位。

2)buy 层加入 transition 动画及 v-show 指令(当 food.count 不存在或等于 0 时,该层显示)。

3)buy 层进行样式设计:z-index 10,因为要盖住 cartcontrol 组件。

4)添加点击按钮事件 addFirst。首先阻止浏览器默认点击事件,然后引入 vue,利用 Vue.set,将 this.count 置为1,最后使用 $emit 

将事件事件传出去。

PS:1)不传参数的话,则默认参数为event。2)不传参数得写为addFirst,而不能写成addFirst()。

Q1:在 buy 层点击时,发现小球位下落置不正确。

A1:因为点击后,count>0,此时 buy 层因为 v-show 指令,会被隐藏,display 瞬间变成 none。所以在 $nextTick 中做动画时就找不到小球初始位置。

R1:将 buy 层的消失做成一个动画(transition,渐隐效果),这样 buy 层就不会立刻隐藏,display 属性不会立刻被设置 none,位置就能被计算。

Q2:点击商品页(goods 组件)的小球,商品详情页会弹出。

A2:这是因为事件冒泡,所以要阻止事件冒泡。

R2:给 cartcontro l组件的加号和减号小球的点击事件添加修饰符(@click.stop.prevent)。

 

6. 新建组件(components -> split ->split.vue),在 food.vue 引入注册并使用。

 1 <template>
 2   <div class="split"></div>
 3 </template>
 4 
 5 <script type="text/ecmascript-6">
 6   export default {};
 7 </script>
 8 
 9 <style lang="stylus" rel="stylesheet/stylus">
10   .split
11     width: 100%
12     height: 16px
13     border-top: 1px solid rgba(7, 17, 27, 0.1)
14     border-bottom: 1px solid rgba(7, 17, 27, 0.1)
15     background: #f3f5f7
16 </style>
split.vue

 

7. food.info 不是每个数据都有,所以 food.info 要加 v-show 指令。

 

 

商品评价(ratingselect 组件)

1. 新建组件(components -> ratingselect->ratingselect.vue)。

 

2. ratingselect 组件需要在 props 中先接收四个参数:一个变量控制评价数组(ratings),一个变量维护描述(desc),一个变量确定是否只看内容(onlyContent),一个变量维护选择的评价类型(selectType)。

 1   const POSITIVE = 0; // 正面评价
 2   const NEGATIVE = 1; // 负面评价
 3   const ALL = 2;      // 所有评价
 4 
 5     props: {
 6       // 评价数组
 7       ratings: {
 8         type: Array,
 9         default() {
10           return [];
11         }
12       },
13       // 选择评论类型
14       selectType: {
15         type: Number,
16         default: ALL
17       },
18       // 只看有内容评论
19       onlyContent: {
20         type: Boolean,
21         default: false
22       },
23       // 评论描述
24       desc: {
25         type: Object,
26         default() {
27           return {
28             all: \'全部\',
29             positive: \'满意\',
30             negative: \'不满意\'
31           };
32         }
33       }
34     },
props接收的变量

评价类型一般分为所有评价,正面评价和负面评价,将这三个定义为常量。评价类型默认选所有评价。

 

 

3. 在 food.vue 引入注册并使用 ratingselect 组件,完成布局及CSS设置。

 1 <div class="rating">
 2     <h1 class="title">商品评价</h1>
 3     <ratingselect :selectType="selectType" :onlyContent="onlyContent" :desc="desc" :ratings="food.ratings" @select="selectRating" @toggle="toggleContent"></ratingselect>
 4 </div>
 5 
 6 .rating
 7       padding-top: 18px
 8       .title
 9         line-height: 14px
10         margin-left: 18px
11         font-size: 14px
12         color: rgb(7, 17, 27)
13      
food.vue
 1 <template>
 2   <div class="ratingselect">
 3     <div class="rating-type border-1px">
 4       <span @click="select(2,$event)" class="block positive" :class="{\'active\':selectType===2}">{{desc.all}}<span
 5         class="count">{{ratings.length}}</span></span>
 6       <span @click="select(0,$event)" class="block positive" :class="{\'active\':selectType===0}">{{desc.positive}}<span
 7         class="count">{{positives.length}}</span></span>
 8       <span @click="select(1,$event)" class="block negative" :class="{\'active\':selectType===1}">{{desc.negative}}<span
 9         class="count">{{negatives.length}}</span></span>
10     </div>
11     <div @click="toggleContent" class="switch" :class="{\'on\':onlyContent}">
12       <span class="icon-check_circle"></span>
13       <span class="text">只看有内容的评价</span>
14     </div>
15   </div>
16 </template>
17 
18 <style lang="stylus" rel="stylesheet/stylus">
19   @import "../../common/stylus/mixin.styl"
20 
21   .ratingselect
22     .rating-type
23       padding: 18px 0
24       margin: 0 18px
25       border-1px(rgba(7, 17, 27, 0.1))
26       /* 消除空白字符影响 */
27       font-size: 0
28       .block
29         display: inline-block
30         padding: 8px 12px
31         margin-right: 8px
32 Flutter 仿京东商品详情页嵌套滚动组件

mpvue采坑记(同一个页面或者组件反复进入动态数据被覆盖)

电商小程序实战教程-商品详情页

电商小程序实战教程-商品详情页开发

电商小程序实战教程-商品详情页开发

(生鲜项目)19. ViewSet实现商品详情页接口