Vue (V) Development of food components

Keywords: Vue JSON Programming

1. Method of parent component calling child component

Idea: When a user clicks on a product, the product details page appears, so it needs to call a sub-component when the parent component clicks on the product to control the display hiding of the product details page.

food component
<template>
	<div class="food" v-show="foodtoShow">		
	</div>
</template>

<script>
	export default{
		props: {
	      selcurfood: { //  User-Selected Goods
	        type: Object
	      }
	   },
	   data(){
	   	return {
	   		foodtoShow :false //  Define the initial state of the merchandise details page to start hiding
	   	 }
	   },
	   methods:{
	   	  foodinforshow(){   //  When the parent component triggers a click event, it calls the foodinforshow method to display the product details page.
	   	  	this.foodtoShow = true
	   	  }
	   }
		
	}
</script>
Parent component goods component
The introduction and registration are omitted here.
1. Binding events
<li @click='selectFood(food,$event)' v-for="food in item.foods" class="food-item">...
2. Application Components
<food :selcurfood='selectedfoods' ref="food"></food>
selectedfoods represent the item the user is currently clicking on
3. Establish an object that accepts the user's choice of goods
data (){
 	return {
 		goods: [],//  goods json array
        listHeight: [],// The height of each block stored inside the foods
        scrollY:0,
        selectedfoods:{} // Goods that receive clicks from users
 	}
 },
4. Click Events
selectFood(food,event){
    	if (!event._constructed) {// Blocking native click events in browsers
	        return;
	      }
    	this.selectedfoods=food// Commodities that are imported into the user's selection exist in the selectedfoods object
    	this.$refs.food.foodinforshow() //Invoking methods of subcomponents with ref attributes
    }
Here it is related to the commodity details page! Continue...

2. Realize scrolling of details page content

1. To achieve scrolling, you need better-scroll, so you need dom bindings to load bscroll asynchronously.
<template>
  <transition name="move">
  <!-- v-show Control Display Details Page ref Realization dom binding-->
  <div class="food" v-show="foodtoShow" ref='foodDetail'>
  </div>
  </transition>
</template>
  import BScroll from 'better-scroll';
  export default {
    props: {
	      selcurfood: { //  User-Selected Goods
	        type: Object
	      }
	   },
    data(){
      return {
        foodtoShow :false, //  Define the initial state of the merchandise details page to start hiding
      }
    },
    methods: {
      show(){
        this.showFlag = true; 
        this.$nextTick( () => { //  Interface guarantees asynchronous addition of scroll binding after dom rendering
   	  		if(!this.scroll){
   	  			this.scroll=new BScroll(this.$refs.foodDetail,{
   	  				click:true
   	  			})
   	  		}else{
   	  			this.scroll.refresh()
   	  		}
   	  	})
      },
      foodtoHide(){ // Click on the return icon to disappear the details of the merchandise
   	  	this.foodtoShow = false
   	  },
  }
Note: All the content of better-scroll under ref. So you need to have a foodcontent to wrap the content, otherwise better-scroll won't work, attach some code.
<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">Monthly sale{{selcurfood.sellCount}}</span>	
			  <span class="rating">Favorable rate{{selcurfood.rating}}</span>
			</div>
			<div class="price">
			    <span class="newPrice">¥{{selcurfood.price}}</span>
			    <span  class="oldPrice"v-show='selcurfood.oldPrice'>¥{{selcurfood.oldPrice}}</span>
			</div>
			<!--Introduce cartcontrol assembly,And use one div Wrap him up.-->
			<div class="cartcontrol-wrapper">
        	   <cart-control :foodsele='selcurfood' @add="addFood"></cart-control>
            </div>
            <transition name='fade'>
            	<!--Use.stop.prevent Prevent bubbles and default events,Avoid penetration-->
            	<div class="buy" v-show="!selcurfood.count || selcurfood.count===0" @click.stop.prevent="ballshow">
            	Add to cart
               </div>
            </transition>
		</div>	
		<split-line v-show="selcurfood.info"></split-line>
	  	<div class="info" v-show="selcurfood.info">
			<h1 class="title">Commodity information</h1>
			<p class="text">{{selcurfood.info}}</p>
		</div>
		<split-line ></split-line>
		<div class="rating">
			<h1 class="title">Commodity evaluation</h1>
			<ratingselect 
				:selectType="selectType"
				:onlyContent="onlyContent" :desc="desc"
                :ratings="selcurfood.ratings" >
				
			</ratingselect>
		</div>
	</div>
</div>

3. Shopping cart buttons

Question: Click to join the shopping cart, the ball appears, the position of parabolic animation moves from the top of the screen, not from the point of clicking on the shopping cart.
Analysis: When you click on the "ballshow" button, food.count is added to the data Vue. set (this. selcurfood,'count', 1), so the "display:none" button will be hidden (v-show), but at the same time it will execute this.$emit('add', event.target);, but this is executed asynchronously, and the asynchronously executed method adds is a parabolic ball animation calculation. Where the initial target height is, when the incoming shopping cart button is set to display:none, the initial target height of the animation can not be calculated, and the height of the parent div will be used, thus affecting the animation effect of the parabolic sphere.
Solution: Add an animation when clicking the shopping cart button disappears, so that vue has enough time to transfer data to the asynchronous execution method, so that it will not affect the initial target calculation of the animation of the parabolic ball.
<transition name='fade'>
	<! - Use. stop.prevent to prevent bubbles and defau lt events, and avoid penetration - >.
	<div class="buy" v-show="!selcurfood.count || selcurfood.count===0" @click.stop.prevent="ballshow">
	Add to cart
   </div>
</transition>
Click on the ball to appear
<! - Introduce the cartcontrol component and wrap it with a div - > and
<div class="cartcontrol-wrapper">
   <cart-control :foodsele='selcurfood' @add="addFood"></cart-control>
</div>
ballshow(event){ //  Click the Add Shopping Cart button, pass in the event, the ball appears    
     	 if (!event._constructed) {// pc clicks because the shopping cart button is in bscroll, so you need to deal with the event type of bscroll
          return;
        }
     	  // Parabolic Ball Animation
        this.$emit('add', event.target); //Trigger the event add on the current instance food (the add method bound to the food component on the goods component)
        Vue.set(this.selcurfood, 'count', 1);
     },
     addFood(target) { //The addFood method associated with add
        this.$emit('add', event.target); // Trigger the event add on the current instance food (the add method bound to the food component on the goods component)
    }
Reference: The event add that triggers the current instance twice is because both operations are the same action. This action is the add method bound to the food component, and the food component will be directed in the goods component < food: selcurfood ='selectedfoods'@add = "addFood" ref = "food"> </food>. In the goods component, the addFood method will point to the method _drop of the current goods component, and then use s. Hopcart's spherical parabola animation is this.$refs.shopcart.drop(target);, which implements the effect of calling methods across components.

IV. Commodity Evaluation

(1) Selection of evaluation types

<ratingselect  
    :selectType="usrseleType"
    :onlyContent="isonlyContent" 
    :curdesc="foodDesc"
    :ratings="selcurfood.ratings"
    @usrselect='usrseleRating'
    @toggleSwitch='toggleContent' >						
</ratingselect>

data(){
   return {
   	foodtoShow :false,   //  Define the initial state of the merchandise details page to start hiding
   	usrseleType: ALL,    //  Default type
    isonlyContent: true, //  Whether to only look at the content of the evaluation by default do not look
    foodDesc: {          //  Type object
      all: 'whole',
      positive: 'Recommend',
      negative: 'Make complaints'
    }
  }
}
 usrseleRating (type){ // Events passed from subcomponents
      this.usrseleType = type
      this.$nextTick(() => { // dom refreshes asynchronously every time a type is changed
      this.scroll.refresh();
     });
    },
  toggleContent(){ //  Evaluation of whether there is content in switching display
      this.isonlyContent=!this.isonlyContent
      this.$nextTick(() => { //bscroll needs to be refreshed when switching
      this.scroll.refresh();
        });
    },
  needShow(type,txt) { 
    if (this.isonlyContent && !txt) { // // Returns false if only content is displayed and there is no content
      return false;
    }
    if (this.usrseleType === ALL) { //Display all types of evaluations
      return true;
    } else { // Display the corresponding type of evaluation
      return type === this.usrseleType;
    }
  }
usrseleRating and toggleContent use asynchronous $nextTick because vue updates the DOM asynchronously. When vue attributes are changed, the current DOM is not updated immediately (which causes page height to change, but bscroll can't update, affecting the rolling experience), but will be placed in the asynchronous update queue to wait for updates, even if the queue's waiting time is not long, but not immediately. Update dom, so force the queue to refresh with $nextTick
In food.vue component, usrseleRating and toggleContent are used to update the properties of food.vue component, but not in ratingSelect, because Vue restricts the properties of the child component from changing the properties of the parent component, so the method of calling the parent component is changed by using something like this.$emit('select', type);

(2) Evaluation Time Conversion

Filters using vue
<div class="time">{{rating.time | formatDate}}</div>
filters: {
  formatDate(time) { 
    let date = new Date(time); 
    //Call formatDate function of curTime module to parse time
    return formatDate(date, 'yyyy-MM-dd hh:mm');
  }
}
//Under es6, the import of export function needs to be written as follows
import { formatDate } from '../../common/js/date'; //Import custom date module
formatDate.js is a custom JS component, not a vue component. The directory is located at: src/common/js, which is written to practice modular programming of js.
Write a single function as a module
export Derived Functions
Import functions through import
export function formatDate(date, fmt) { //Derive a function under es6
//Matching one or more y to replace the year in which it is matched (four bits per year, so special processing is required)
  if (/(y+)/.test(fmt)) {
    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
  }
  let o = {
    'M+': date.getMonth() + 1, //The month of js is calculated from zero, so add 1
    'd+': date.getDate(),
    'h+': date.getHours(),
    'm+': date.getMinutes(),
    's+': date.getSeconds()
  };
  //Match and replace the months, days, hours, minutes and seconds (these are two, can be processed together)
  for (let k in o) {
    if (new RegExp(`(${k})`).test(fmt)) { //Matching to key s such as MM
      let str = o[k] + ''; //Then o['MM'] is date. getMonth ()+1
      
      //If the matching time is 1 digit, such as M, then the value of date. getMonth ()+1 is used directly.
      //If it's a two-digit number, fill in 0 just ahead, using the padLeftZero function
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str)); 
    }
  }
  return fmt;
};

//Add two zeros first, and then intercept them according to length (because the longest is the length of two zeros).
function padLeftZero(str) {
  return ('00' + str).substr(str.length);
}

That's about the end of the food component.

Posted by NewbieBryan on Sun, 19 May 2019 11:50:53 -0700