Vue ( 五 ) food 组件开发


声明:本文转载自https://my.oschina.net/u/3662721/blog/1621686,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

一、父组件调用子组件的方法

思路:用户点击商品时商品详情页出现,所以需要 父组件中点击商品时调用子组件一个方法来控制 商品详情页的 显示 隐藏。

food组件
<template> 	<div class="food" v-show="foodtoShow">		 	</div> </template>  <script> 	export default{ 		props: { 	      selcurfood: { //  用户选择的商品 	        type: Object 	      } 	   }, 	   data(){ 	   	return { 	   		foodtoShow :false //  定义商品详情页的初始状态   开始 隐藏 	   	 } 	   }, 	   methods:{ 	   	  foodinforshow(){   //  待父组件 触发了点击事件,调用 foodinforshow 方法,显示商品详情页 	   	  	this.foodtoShow = true 	   	  } 	   } 		 	} </script> 
父组件goods组件
此处省略 引入、注册...
1.绑定事件
<li @click='selectFood(food,$event)' v-for="food in item.foods" class="food-item">... 
2.应用组件
<food :selcurfood='selectedfoods' ref="food"></food> 
selectedfoods 代表用户当前点击的商品
3.建立一个接受用户选择商品的对象
data (){  	return {  		goods: [],//  goods json  数组         listHeight: [],// 存放 foods 内部的每一块的高度         scrollY:0,         selectedfoods:{} // 接收用户点击的商品  	}  }, 
4.点击事件
selectFood(food,event){     	if (!event._constructed) {// 阻止浏览器的原生 click 事件 	        return; 	      }     	this.selectedfoods=food// 传入用户选择的商品,存在selectedfoods 对象里     	this.$refs.food.foodinforshow() //利用 ref 属性 来调用 子组件的方法     } 
到这里 就和商品详情页相关联了!继续...

二、实现详情页内容的滚动

1.实现滚动需要better-scroll,所以需要dom绑定,异步加载bscroll
<template>   <transition name="move">   <!-- v-show 控制显示详情页 ref 实现dom 绑定-->   <div class="food" v-show="foodtoShow" ref='foodDetail'>   </div>   </transition> </template> 
  import BScroll from 'better-scroll';   export default {     props: { 	      selcurfood: { //  用户选择的商品 	        type: Object 	      } 	   },     data(){       return {         foodtoShow :false, //  定义商品详情页的初始状态   开始 隐藏       }     },     methods: {       show(){         this.showFlag = true;          this.$nextTick( () => { //  接口   保证dom 渲染完毕    异步添加滚动绑定    	  		if(!this.scroll){    	  			this.scroll=new BScroll(this.$refs.foodDetail,{    	  				click:true    	  			})    	  		}else{    	  			this.scroll.refresh()    	  		}    	  	})       },       foodtoHide(){ // 点击返回 图标   商品详情消失    	  	this.foodtoShow = false    	  },   } 
注意:better-scroll 作用在 ref 下的 所有内容。所以要有foodcontent 来 包裹内容,否则better-scroll 不起作用,附上部分代码。
<div class="food" v-show="foodtoShow" ref='foodDetail'> 	<div class="foodcontent"> 		<div class="image-header"> 		    <img :src="selcurfood.image" alt="" /> 			<div class="back" @click="foodtoHide"> 				<i class="icon-arrow_lift"></i> 			</div> 	    </div>	 		<div class="content"> 			<h1 class="title">{{selcurfood.name}}</h1> 			<div class="detail"> 			  <span class="sell-count">月售{{selcurfood.sellCount}}</span>	 			  <span class="rating">好评率{{selcurfood.rating}}</span> 			</div> 			<div class="price"> 			    <span class="newPrice">¥{{selcurfood.price}}</span> 			    <span  class="oldPrice"v-show='selcurfood.oldPrice'>¥{{selcurfood.oldPrice}}</span> 			</div> 			<!--引入cartcontrol组件,并且用一个div包裹他--> 			<div class="cartcontrol-wrapper">         	   <cart-control :foodsele='selcurfood' @add="addFood"></cart-control>             </div>             <transition name='fade'>             	<!--使用.stop.prevent阻止冒泡和默认事件,避免穿透-->             	<div class="buy" v-show="!selcurfood.count || selcurfood.count===0" @click.stop.prevent="ballshow">             	加入购物车                </div>             </transition> 		</div>	 		<split-line v-show="selcurfood.info"></split-line> 	  	<div class="info" v-show="selcurfood.info"> 			<h1 class="title">商品信息</h1> 			<p class="text">{{selcurfood.info}}</p> 		</div> 		<split-line ></split-line> 		<div class="rating"> 			<h1 class="title">商品评价</h1> 			<ratingselect  				:selectType="selectType" 				:onlyContent="onlyContent" :desc="desc"                 :ratings="selcurfood.ratings" > 				 			</ratingselect> 		</div> 	</div> </div> 

三、购物车按钮问题

问题:点击加入购物车,出现小球,做抛物线动画的位置从屏幕上方运动,而不是从点击购物车处开始做运动
分析:当点击加入购物车的按钮时候(ballshow),food.count被添加了数据Vue.set(this.selcurfood, 'count', 1),所以加入购物车按钮会被隐藏(v-show的display:none),但同时会执行this.$emit('add', event.target);,只不过这个是异步执行的,并且这个被异步执行的方法add是抛物线小球动画计算初始目标高度的地方,所以当传入的购物车按钮被设置为display:none的时候,动画的目标初始高度无法计算,就会去使用父层div的高度,从而影响了抛物线小球动画效果.
解决办法: 给点击购物车这个按钮消失时加一个动画,从而vue有足够的时间将数据传递到异步执行的方法,这样就不会影响抛物线小球的动画初始目标计算了。
<transition name='fade'> 	<!--使用.stop.prevent阻止冒泡和默认事件,避免穿透--> 	<div class="buy" v-show="!selcurfood.count || selcurfood.count===0" @click.stop.prevent="ballshow"> 	加入购物车    </div> </transition> 
点击出现小球
<!--引入cartcontrol组件,并且用一个div包裹他--> <div class="cartcontrol-wrapper">    <cart-control :foodsele='selcurfood' @add="addFood"></cart-control> </div> 
ballshow(event){ //  点击加入购物车按钮,传入事件,小球出现          	 if (!event._constructed) {// pc 点击    因为购物车按钮在bscroll里面,所以需要处理掉bscroll的事件类型           return;         }      	  // 抛物线小球动画         this.$emit('add', event.target); //触发当前实例food上的事件add(在goods组件上绑定在food组件的add方法)         Vue.set(this.selcurfood, 'count', 1);      },      addFood(target) { //跟add关联的addFood方法         this.$emit('add', event.target); // 触发当前实例food上的事件add(在goods组件上绑定在food组件的add方法)     } 
引用解释:两次触发当前实例的事件add是因为两个操作都是同一个动作,这个动作是绑定在food组件上的add方法,而food组件会在goods组件中被导<food :selcurfood='selectedfoods' @add="addFood" ref="food"></food>,而在goods组件里面,addFood方法就会指向当前goods组件的方法_drop,继而使用shopcart的小球抛物线动画this.$refs.shopcart.drop(target);,这样就是实现了使用跨组件调用方法的效果.

四、商品评价

(1) 评价类型选择

<ratingselect       :selectType="usrseleType"     :onlyContent="isonlyContent"      :curdesc="foodDesc"     :ratings="selcurfood.ratings"     @usrselect='usrseleRating'     @toggleSwitch='toggleContent' >						 </ratingselect>  
data(){    return {    	foodtoShow :false,   //  定义商品详情页的初始状态   开始 隐藏    	usrseleType: ALL,    //  默认类型     isonlyContent: true, //  是否只看有内容的评价 默认 不看     foodDesc: {          //  类型  对象       all: '全部',       positive: '推荐',       negative: '吐槽'     }   } } 
 usrseleRating (type){ // 子组件 传过来的事件       this.usrseleType = type       this.$nextTick(() => { // 每更改一次类型,dom 异步刷新一次       this.scroll.refresh();      });     },   toggleContent(){ //  切换显示是否有内容的评价       this.isonlyContent=!this.isonlyContent       this.$nextTick(() => { //切换的时候需要重新刷新bscroll       this.scroll.refresh();         });     },   needShow(type,txt) {      if (this.isonlyContent && !txt) { // //只显示有内容的 并且 没有内容就返回false       return false;     }     if (this.usrseleType === ALL) { //显示全部类型的评价       return true;     } else { // 显示对应的类型的评价       return type === this.usrseleType;     }   } 
usrseleRating和toggleContent使用异步$nextTick是因为vue是异步更新dom的,当改变了vue属性时候,当前的dom不是立即更新的(会导致页面的高度变化了,但是bscroll来不及更新,影响滚动体验),而是会放进去异步更新队列里面等候更新,即使这个队列的等待时间不长,但是也来不及马上更新dom,所以使用$nextTick强制刷新这个队列
在food.vue组件使用usrseleRating和toggleContent来更新food.vue组件的属性,而不能在子组件ratingSelect里面更新,因为vue限制了子组件不能更改父组件的属性,所以通过使用类似this.$emit('select', type);来调用父组件的方法来更改

(2) 评价时间转换

使用了vue 的过滤器
<div class="time">{{rating.time | formatDate}}</div> 
filters: {   formatDate(time) {      let date = new Date(time);      //调用curTime模块的formatDate函数来解析时间     return formatDate(date, 'yyyy-MM-dd hh:mm');   } } 
//在es6下,export 函数function的导入需要这样写 import { formatDate } from '../../common/js/date'; //导入自定义的date模块 
formatDate.js是一个自定义的js组件,不是vue组件,目录位于:src/common/js,这种写法是为了练习js的模块化编程
将单独的一个函数写成一个模块
通过export导出函数
通过import导入函数
export function formatDate(date, fmt) { //在es6下导出一个函数 //对一个或多个y进行匹配,匹配到就进行年的替换(年有四位,所以需要特殊处理)   if (/(y+)/.test(fmt)) {     fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));   }   let o = {     'M+': date.getMonth() + 1, //js的月是从0开始算,所以要加1     'd+': date.getDate(),     'h+': date.getHours(),     'm+': date.getMinutes(),     's+': date.getSeconds()   };   //对月,日,时,分,秒进行匹配替换(这些都是两位,可以一起处理)   for (let k in o) {     if (new RegExp(`(${k})`).test(fmt)) { //匹配到key例如MM       let str = o[k] + ''; //然后o['MM'] 就是date.getMonth() + 1              //如果匹配到的时间是1位数,例如是M,那么就直接使用date.getMonth() + 1的值,       //如果是两位数,那么就在前面补0,使用padLeftZero函数       fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));      }   }   return fmt; };  //先加两个0,然后再根据长度截取(因为最长也就2个0的长度) function padLeftZero(str) {   return ('00' + str).substr(str.length); } 

food组件到此差不多了。

本文发表于2018年02月13日 08:31
(c)注:本文转载自https://my.oschina.net/u/3662721/blog/1621686,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2024 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1