饿了么项目---13、模块化编程,实现商品详情页面
来源:互联网 发布:wto国际贸易统计数据库 编辑:程序博客网 时间:2024/05/16 15:52
本节重点:
- 父组件到子组件的数据传递
- 子组件到父组件的数据传递
- js的模块化,按需引入
- 组件的模块化,重复使用
- 数组过滤与过滤器的使用
一、goods商品界面点击到food详情界面的实现
- 父组件good.vue界面:
- 与子组件的关联
- 点击商品时,更改传入的商品数据this.selectedfood = food
- 根据子组件的DOM节点this.$refs.thisfood,调用子组件的showthisfood方法,显示子组件
- 代码部分如下:
<template><food @cartAddEvent='_drop' ref='thisfood' :selectedfood = 'selectedfood'></food></template>
点击商品时触发事件调用该方法:
//点击展示商品详情界面showfood(food,event){ //better scroll中阻止浏览器默认的点击事件 if(!event._constructed) return false; this.selectedfood = food; this.$refs.thisfood.showthisfood()}
二、food详情界面的实现
- 界面实现结构图
- 详情界面切入、切出使用过渡
- 详情界面内容过长时,使用better scroll滑动组件
- 加入购物车cartcontrol组件的复用
- 详情界面中第一次添加商品到购物车使用 加入购物车按钮,并添加小球抛入到购物车的效果
- 当该商品已经被添加过,引入加入购物车cartcontrol组件,实现商品累加与累减功能
- 这个功能实现时,遇到一个的问题,点击加入购物车按钮,该按钮消失,加入购物车cartcontrol组件展示。此时实现小球抛入效果,无法取得该DOM节点的坐标,此DOM节点已经display:none .解决方法:给加入购物车按钮的消失一个过渡效果,巧妙的在小球抛入过渡时取到改DOM节点
- 商品评价中,筛选条件在另一个模块可以被复用,抽象为ratingSelecte组件,详细组件代码见本章尾部
<!---- ratings: 该商品的评论数据 Array ;-- suggestion:商品评价的中文条件 Object-- selectType:商品评价的中文条件选中的值,默认为全部 Number-- onlyContent:是否只看内容的值 ,默认为false ,Boolean-- 事件 onlyshow,selectCon: 点击筛选条件时派发的事件,更新父组件的数据--><ratingSelecte :ratings = 'selectedfood.ratings' :suggestion ='suggestion' :selectType = 'selectType' :onlyContent='onlyContent' @onlyshow='onlyshowcon' @selectCon = 'selectContent'></ratingSelecte>
- 根据ratingSelecte组件的筛选条件,过滤 评论内容
- 每一行评论是否显示的控制v-show=’showRating(rating)’,showRating方法根据筛选条件来进行过滤
Template模板部分:<div class='select-content'> <ul v-if='selectedfood.ratings'> <li v-show='showRating(rating)' class='ratingGroup' v-for='rating in selectedfood.ratings'> <div class='ratingH clearfix'> <div class='time'>{{rating.rateTime | dateString}}</div> <div class='user'><span class='username'>{{rating.username}}</span><img class='userImg' :src='rating.avatar'></div> </div> <div class='ratingC'><span class='iconThumb' :class='{"icon-thumb_up":rating.rateType===0,"icon-thumb_down":rating.rateType===1}'></span><span class='text'>{{rating.text}}</span></div> </li> </ul> </div>
JS代码部分
//是否显示评价信息 showRating(rating){ //只看评价时,不显示的 if(this.onlyContent && rating.text==''){ return false; } //点击三个评价筛选 if(this.selectType===All){ return true; }else{ return this.selectType ===rating.rateType; } }
三、js模块化
将需要重复使用的js 方法抽象成一个公共的js,在需要使用到的组件中,import引入方法
import {dateToString} from '../../common/js/common.js';
需要引入多个方法时,例如需要引入a,b,c方法
import {a,b,c} from '../../common/js/common.js';
common.js:
// 将时间对象转换成字符串 “yyyy-mm-dd hh:mm”export function dateToString(date) { if (date == null || date == '') { date = ''; return date; } var year = date.getFullYear(); var month =parseInt(date.getMonth())+1; var day = parseInt(date.getDate()); var hours = date.getHours(); var Minutes = date.getMinutes(); if (Minutes < 10) { Minutes = Minutes + "0"; } date =year+'-'+month+'-'+day+' '+ hours + ':' + Minutes; return date;}
涉及的完整代码
food组件
<template> <transition name='food'> <div class="food" v-show='showthis' ref='food'> <!-- 为bettter scroll 添加div层 --> <div> <!-- 商品图片 --> <div class='foodImg'> <img :src="selectedfood.image"> </div> <!-- 返回到商品foods.vue页面 --> <div class='backGoods' @click='hidethisfood'><span class='icon-arrow_lift'></span></div> <!-- 商品信息 --> <div class='foodInfo'> <div class='goodsName'>{{selectedfood.name}}</div> <div class='goodsxs'><span>月售{{selectedfood.sellCount}}份</span><span>好评率{{selectedfood.rating}}%</span></div> <div class='foodsPrice'><span>¥{{selectedfood.price}}</span><span class='old' v-show='selectedfood.oldPrice!=""'>¥{{selectedfood.oldPrice}}</span> </div> <div class='cartcontrol-wrapper'> <cartcontrol @cartAdd ='cartAddcontrol' :food ='selectedfood'></cartcontrol> </div> <transition name='firstAdd'> <div class='addtocart' v-show='selectedfood.count===0||!selectedfood.count' @click='addCount($event)'>加入购物车</div> </transition> </div> <!-- 商品介绍 --> <div class='foodDetail'> <h1 class='food-header'>商品介绍</h1> <div class='food-content'>{{selectedfood.info}}</div> </div> <div class='foodAsses'> <h1 class='Asses-header'>商品评价</h1> <ratingSelecte :ratings = 'selectedfood.ratings' :suggestion ='suggestion' :selectType = 'selectType' :onlyContent='onlyContent' @onlyshow='onlyshowcon' @selectCon = 'selectContent'></ratingSelecte> <div class='select-content'> <ul v-if='selectedfood.ratings'> <li v-show='showRating(rating)' class='ratingGroup' v-for='rating in selectedfood.ratings'> <div class='ratingH clearfix'> <div class='time'>{{rating.rateTime | dateString}}</div> <div class='user'><span class='username'>{{rating.username}}</span><img class='userImg' :src='rating.avatar'></div> </div> <div class='ratingC'><span class='iconThumb' :class='{"icon-thumb_up":rating.rateType===0,"icon-thumb_down":rating.rateType===1}'></span><span class='text'>{{rating.text}}</span></div> </li> </ul> </div> </div> </div> </div> </transition></template><script>import BScroll from 'better-scroll';import cartcontrol from '../cartcontrol/cartcontrol.vue';import ratingSelecte from '../ratingSelecte/ratingSelecte.vue';import {dateToString} from '../../common/js/common.js';//商品评价的筛选状态const SATISFY=0; //推荐const UNSATISFY=1; //吐槽const All=2; //全部 export default{ name:'food', props:{ selectedfood:{ type:Object } }, data(){ return{ showthis:false,//显示或隐藏改组件 suggestion:{ all:'全部', satisfy:'推荐', unsatisfy:'吐槽' }, selectType:All, onlyContent:false//只看内容 } }, methods:{ showthisfood(){ this.showthis = true; //初始化筛选内容 this.selectType=All, this.onlyContent=false//只看内容 this.$nextTick(()=>{ //better scroll需要更新DOM对象 if(!this.scroll){ this.scroll = new BScroll(this.$refs.food, { click:true }); }else{ this.scroll.refresh(); } }) }, hidethisfood(){ this.showthis = false; }, cartAddcontrol(el){ this.$emit('cartAddEvent',el); }, addCount(el){ //为food数量置1 this.$set(this.selectedfood,'count',1) //派发小球点击事件,做抛物动画 this.$emit('cartAddEvent',el.target); }, //切换评价筛选条件 selectContent(type){ this.selectType = type //切换筛选条件时,更新了DOM节点,要更新better scroll this.$nextTick(()=>{ this.scroll.refresh() }) }, onlyshowcon(){ this.onlyContent = !this.onlyContent this.$nextTick(()=>{ this.scroll.refresh() }) }, //是否显示评价信息 showRating(rating){ //只看评价时,不显示的 if(this.onlyContent && rating.text==''){ return false; } //点击三个评价筛选 if(this.selectType===All){ return true; }else{ return this.selectType ===rating.rateType; } } }, components:{cartcontrol,ratingSelecte} , filters:{ //将字符串时间转换成时间格式 dateString(datenumber) { let date = new Date(datenumber); return dateToString(date); } } }</script><style lang="stylus" rel="stylesheet/stylus" scope>@import '../../common/stylus/mixin.styl'.food position:fixed top:0 left:0 bottom:48px width:100% background-color:#f3f5f7 z-index:30 &.food-enter-active,&.food-leave-active transition:all 0.4s &.food-enter,&.food-leave-to transform:translate3d(100%,0,0) .foodImg position:relative width:100% height:0 padding-top:100% img position:absolute left:0 top:0 width:100% height:100% .backGoods position:absolute left:10px top:10px .icon-arrow_lift color:#fff .foodInfo position:relative padding:18px; background-color:#fff border-1px(rgba(7,17,27,0.1)) .goodsName font-size:14px font-weight:700 color:rgb(7,17,27) line-heigth:14px .goodsxs margin:8px 0 18px 0 line-height:10px font-size:10px color:rgb(147,153,159) span:first-child margin-right:12px .foodsPrice font-size:10px color:rgb(240,20,20) font-weight: normal line-height: 14px margin-top:8px .old text-decoration:line-through margin-left:8px color:rgb(147,153,159) .cartcontrol-wrapper, .addtocart position:absolute bottom:18px right:18px .addtocart width:74px height:24px color:#fff font-size:10px line-height:24px text-align:center border-radius:12px background-color:rgb(0,160,220) &.firstAdd-enter-active,&.firstAdd-leave-active transition:opacity 0.6s &.firstAdd-enter,&.firstAdd-leave-to opacity:0 .foodDetail margin:16px 0 padding:18px background-color:#fff border-1px(rgba(7,17,27,0.1)) borderTop-1px(rgba(7,17,27,0.1)) .food-header font-size:14px font-weight:500 .food-content margin-top:6px padding:0 8px font-size:12px font-weight:200 line-height:24px color:rgb(77,85,93) .foodAsses background-color:#fff border-1px(rgba(7,17,27,0.1)) borderTop-1px(rgba(7,17,27,0.1)) .Asses-header padding:18px 18px 6px 18px font-size:14px font-weight:500 .select-content padding:0 18px .ratingGroup:last-child border-none() .ratingGroup padding:16px 0 border-1px(rgba(7,17,27,0.1)) .ratingH margin-bottom:6px .time float:left line-height:12px color:rgb(147,153,159) font-size:10px .user float:right height:12px .username display:inline-block vertical-align:top line-height:12px color:rgb(147,153,159) font-size:10px margin-right:6px .userImg display:inline-block vertical-align:top width:12px height:12px border-radius:50% img width:100% height:100% .ratingC line-height: 24px; height: 24px; .iconThumb font-size:12px display:inline-block vertical-align:middle margin-right:4px .icon-thumb_down color:rgb(147,153,159) .icon-thumb_up color:rgb(0,160,222) .text font-size:12px</style>
ratingSelect组件
<template> <div class='ratingSelect'> <div class='select-header'> <div v-if='ratings' class='suggestion'> <span class='su' :class="{on:selectType == 2}" @click='_selectContent(2)'>{{suggestion.all}} {{ratings.length}}</span> <span class='su' :class="{on:selectType == 0}" @click='_selectContent(0)'>{{suggestion.satisfy}} {{satisfyNumber.length}}</span> <span class='no' :class="{on:selectType == 1}" @click='_selectContent(1)'>{{suggestion.unsatisfy}} {{unsatisfyNumber.length}}</span> </div> <div class='onlyContent' @click='_onlyshowcon'> <span class='icon-check_circle' :class='{oncheck_circle:onlyContent===true}'></span><span class='text'>只看有内容的评价</span> </div> </div> </div></template><script>const SATISFY=0; //推荐const UNSATISFY=1; //吐槽const All=2; //全部 export default{ name:'ratingSelect', props:{ ratings:{ type:Array }, suggestion:{ type:Object }, //筛选条件之一 selectType:{ type:Number, default:All }, //是否只看内容 onlyContent:{ type:Boolean, default:false } }, computed:{ satisfyNumber(){ return this.ratings.filter((rating)=>{ return rating.rateType === SATISFY }) }, unsatisfyNumber(){ return this.ratings.filter((rating)=>{ return rating.rateType === UNSATISFY }) } }, methods:{ _selectContent(type){ if (!event._constructed) { return; } // this.selectType = type this.$emit('selectCon',type) }, _onlyshowcon(){ if (!event._constructed) { return; } // this.onlyContent = !this.onlyContent this.$emit('onlyshow') } } }</script><style lang="stylus" rel="stylesheet/stylus" scope> @import '../../common/stylus/mixin.styl' .ratingSelect .select-header .suggestion padding:12px 0 18px 0 margin:0 18px border-1px(rgba(7,17,27,0.1)) font-size:0 .su,.no font-size:12px padding:8px 12px border-radius:2px .su margin-right:8px background-color:rgba(0,160,220,0.2) .no background-color:rgba(77,85,93,0.2) .on background-color:rgb(0,160,220) color:#fff .onlyContent padding:12px 18px border-1px(rgba(7,17,27,0.1)) .icon-check_circle display:inline-block vertical-align:middle font-size:24px color:rgb(147,153,159) margin-right:4px .oncheck_circle color: #00c850 .text display:inline-block color:rgb(147,153,159) font-size:12px line-height:24px</style>
阅读全文
0 0
- 饿了么项目---13、模块化编程,实现商品详情页面
- 商品详情页面描述
- 商品详情页面布局
- 仿写京东商品详情页面
- 商品详情页面展示
- 商品详情页面
- 商品详情页面demo
- 商品详情简单实现
- Jsp动态网站初步项目 --简单的商品浏览页面 (商品详情页面details.jsp)
- Vue模拟数据,实现路由进入商品详情页面
- 淘淘商城系列——实现商品详情页面展示
- 商品详情页面实现点击收藏,取消收藏
- 商城项目实战32:商品详情页实现
- 原型设计创新[商品详情页面]
- 仿淘宝商品详情页面Android
- B2Ctt商城09 商品详情页面
- Android listView中点击item或Item中控件跳转对应的详情页面的实现(商品详情查看)
- 实现淘宝商品详情页面的viewPager滑动到最后一张图片跳转的功能
- <c:forEach varStatus="status">中 varStatus的使用
- filter过滤器设置编码
- 简单入门shell脚本编程
- 剑指 Offer —16—合并两个排序的链表
- Okhttp框架缓存使用
- 饿了么项目---13、模块化编程,实现商品详情页面
- WordPress 使用 Email Subscribers & Newsletters 添加邮件订阅功能
- inline用法详解
- wpf中一个ProcessBar的实现
- 数据处理:如何处理缺失数据(missing value)? 各种处理方法有什么利弊?
- 使用Maven搭建Struts2+Spring3+Hibernate4的整合开发环境
- 解析ZCSJEnity的函数
- android获取各种系统路径的方法
- WINDOWS API ——SETWINDOWLONG—— 设置窗口样式 SetWindowLong 函数原型为:LONG SetWindowLong(HWND hwnd,int nIndex,Lon