文档章节

Vue ( 五 ) food 组件开发

前端喵
 前端喵
发布于 02/12 19:43
字数 2040
阅读 585
收藏 12

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

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

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组件到此差不多了。

© 著作权归作者所有

共有 人打赏支持
前端喵
粉丝 18
博文 14
码字总数 16848
作品 0
海淀
程序员
Vue进阶(六):组件之间的数据传递

Vue进阶(六):组件之间的数据传递 Vue 的组件作用域都是孤立的,不允许在子组件的模板内直接引用父组件的数据。必须使用特定的方法才能实现组件之间的数据传递。 首先用脚手架工具 vue-cl...

sunhuaqiang1
05/05
0
0
Vue.js构建项目笔记1:vue-cli

一.一些简单的话 如果你学习或者使用过angularjs(1.x),你就会非常了解指令的使用,如:ng-click ng-if ng-show ng-src。当然还有控制器和各种服务。 如果你学习或者使用过react,你就会非...

透笔度
2017/10/18
0
0
为什么选择MpVue进行小程序的开发

前言 mpvue是一款使用Vue.js开发微信小程序的前端框架。使用此框架,开发者将得到完整的 Vue.js 开发体验,同时为H5和小程序提供了代码复用的能力。如果想将 H5 项目改造为小程序,或开发小程...

狗尾草的博客
08/01
0
0
Vue-Router源码学习之install方法

Vue是怎么注册插件的呢? 使用过Vue的coder都知道,如果想注册一个vue的插件,在vue对象上能够使用的话(并不是绑在Vue.prototype上的那种暴力方式),必须使用Vue.use(你的插件)的方式来注册...

酸楚与甘甜
09/07
0
0
Vue常用经典开源项目汇总参考-海量

Vue常用经典开源项目汇总参考-海量   Vue是什么?   Vue.js(读音 /vju/, 类似于 view) 是一套构建用户界面的 渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计。...

80368704
06/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

八种排序算法的时间复杂度复杂度

1、稳定性 归并排序、冒泡排序、插入排序。基数排序是稳定的 选择排序、快速排序、希尔排序、堆排序是不稳定的 2、时间复杂度 最基础的四个算法:冒泡、选择、插入、快排中,快排的时间复杂度...

陈刚生
21分钟前
1
0
大数据学习系列 Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 图文详解

目录 引言 目录 一、环境选择 1,集群机器安装图 2,配置说明 3,下载地址 二、集群的相关配置 1,主机名更改以及主机和IP做相关映射 2,ssh免登录 3,防火墙关闭 4,时间配置 5,快捷键设置...

董黎明
35分钟前
1
1
六元一个的私有博客系统,了解一下?

神说要有光,于是便有了光 写代码的,偶尔都想装点逼,想要自己写点博客。刚开始还能在各大社区写,比如说CSDN,开源中国,博客园什么的。但是越写就会越觉得,那些博客平台都不是自己想要的...

耒耒耒耒耒
40分钟前
1
0
maven环境隔离

一.maven项目环境根据实际情况进行隔离: 开发环境 dev 测试环境 beta 线上环境 prod 二.pom 配置: build节点 <build> <resources> <resource> <directory>src/......

imbiao
40分钟前
1
0
webrtc收包流程源码分析

版本: webrtc M59 收包流程: AsyncUDPSocket::OnReadEvent AllocationSequence::OnReadPacket HandleIncomingPacket UDPPort::OnReadPacket Connection::OnReadPacket P2PTransportChannel......

bill_shen
42分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部