In the last article, we wrote and rendered the header module of the project.
In this article, we go further into the project design evaluation component.
Analysis Page
As shown in the figure, when we click on the evaluation, we directly jump to the evaluation page for navigation.
The evaluation page is composed of a column of business scoring, a list of comments, and a list of comments supporting: all, with pictures, comments three kinds of screening.
In summary, we are now starting to design review components:
Create Component Folder
1. Storage of CSS pictures
In view of the variability of the image referenced by the component, we put the image in the component folder for reference. Make components easier to maintain.
2. Path Configuration
In build/webpack.base.conf.js:
alias: { 'vue$': 'vue/dist/vue.esm.js',//Automatic Completion Settings '@': resolve('src'), 'components': resolve('./src/components') }
Components are renamed when importing modules through alias rename settings.
Component Writing Practically Required for Import:
// For example, importing Ratings can be written as import Ratings from 'components/Ratings/Ratings'
After the path configuration is completed, we set up the Ratings folder and enter:
After sorting out the page structure according to the analysis, we build the page structure first.
In Ratings.vue:
//Set up the container to store the comment component <template> <div class="ratings" ref='ratingView'> <div class="ratings-wrapper"> //Refinement of our components </div> </div> </template>
Now we design business scoring, taste, packaging, and other structures as follows:
<div class="overview"> <div class="overview-left"> <div class="comment-score"> <p class="score">{{ratings.comment_score}}</p> <p class="text">Business scoring</p> </div> <div class="other-score"> <div class="quality-score item"> <span class="text">Flavor</span> <Star :score='ratings.quality_score' class='star'></Star> <span class="score">{{ratings.quality_score}}</span> </div> <div class="pack-score item"> <span class="text">Packing</span> <Star :score='ratings.pack_score' class='star'></Star> <span class="score">{{ratings.pack_score}}</span> </div> </div> </div> <div class="overview-right"> <div class="delivery-score"> <p class="score">{{ratings.delivery_score}}</p> <p class="text">Distribution score</p> </div> </div> </div>
Implement the tabs in the comments (all, pictures, comments), list page:
<div class="content"> <div class="rating-select" v-if="ratings.tab"> <span class="item" @click="selectTypeFn(2)" :class="{'active':selectType==2}"> {{ratings.tab[0].comment_score_title}} </span> <span class="item" @click="selectTypeFn(1)" :class="{'active':selectType==1}"> {{ratings.tab[1].comment_score_title}} </span> <span class="item" @click="selectTypeFn(0)" :class="{'active':selectType==0}"> <img src="./icon_sub_tab_dp_normal@2x.png" v-show="selectType!=0" /> <img src="./icon_sub_tab_dp_highlighted@2x.png" v-show="selectType==0" /> {{ratings.tab[2].comment_score_title}} </span> </div> <div class="labels-view"> <span v-for="item in ratings.labels" class="item" :class="{'highligh':item.label_star>0}"> {{item.content}}{{item.label_count}} </span> </div> //Comment List <ul class="rating-list"> <li v-for="comment in selectComments" class="comment-item"> <div class="comment-header"> <img :src="comment.user_pic_url" v-if="comment.user_pic_url" /> <img src="./anonymity.png" v-if="!comment.user_pic_url" /> </div> <div class="comment-main"> <div class="user"> {{comment.user_name}} </div> <div class="time"> {{fotmatDate(comment.comment_time)}} </div> <div class="star-wrapper"> <span class="text">score</span> <Star :score='comment.order_comment_score' class='star'></Star> </div> <div class="c_content" v-html="commentStr(comment.comment)"></div> <div class="img-wrapper" v-if="comment.comment_pics.length"> <img v-for="item in comment.comment_pics" :src="item.thumbnail_url" /> </div> </div> </li> </ul> </div>
The structure is completed, and then we pass in the corresponding data for the component.
Parent-child component communication
Ratings.vue
Import dependent subcomponents:
<script> // Import Star components import Star from 'components/Star/Star' // Import Split components import Split from 'components/Split/Split' // Import BScroll components import BScroll from 'better-scroll'; </script> //Setting tab variables const ALL = 2; // whole const PICTURE = 1; // With pictures const COMMENT = 0; // Comment
Now let's start initializing data and making requests in the create hook.
ratings data section shows:
export default { data() { return { ratings: {},//Store the requested data selectType: ALL,//Default Display All } }, created() { // Initiate get requests through axios let that = this; this.$axios.get('/api/ratings') .then(function(response) { // Access to data var dataSource = response.data; if(dataSource.code == 0) { that.ratings = dataSource.data;//Refer the requested data to data () // Initialize scrolling that.$nextTick(() => { if(!that.scroll) { that.scroll = new BScroll(that.$refs.ratingView, { click: true }); } else { that.scroll.refresh(); } }); } }) .catch(function(error) { // Error handling console.log(error); }); } } </script>
Note that $refs and setting ref='ratingView'in the container we use BScroll to operate dom, so we use vue's ref API
https://cn.vuejs.org/v2/api/#ref
methods: { selectTypeFn(type) { this.selectType = type; // Refresh operation this.$nextTick(() => { this.scroll.refresh(); }); }, fotmatDate(time) { let date = new Date(time * 1000); // Time format let fmt = 'yyyy.MM.dd'; if(/(y+)/.test(fmt)) { // year let year = date.getFullYear().toString(); fmt = fmt.replace(RegExp.$1, year); } if(/(M+)/.test(fmt)) { // month let mouth = date.getMonth() + 1; if(mouth < 10) { mouth = '0' + mouth; } fmt = fmt.replace(RegExp.$1, mouth); } if(/(d+)/.test(fmt)) { // day let mydate = date.getDate(); if(mydate < 10) { mydate = '0' + mydate; } fmt = fmt.replace(RegExp.$1, mydate); } return fmt; }, commentStr(content) { let rel = /#[^#]+#/g; return content.replace(rel, '<i>$&</i>'); } }
In methods, we define:
- Select TypeFn (type) clicks on the switch function executed by the event in the template.
- fotmatDate (time) sets the time display format function;
- commentStr (content) inserts text functions;
Note that within the selectTypeFn function, we refresh the list with scroll using the $nextTick () bar after clicking on the corresponding tab.
$nextTick()https://cn.vuejs.org/v2/guide...
Data is passed into the rating-list template by calculating attributes:
- The value of selectType determines the data content displayed in the comment list
Again, we need to pay attention to the differences between methods and computational attribute invocation methods. We have compared them before. We need to understand them in detail. Please also read the previous articles or official documents.
computed: { selectComments() { if(this.selectType == ALL) { // whole return this.ratings.comments; } else if(this.selectType == PICTURE) { // Figure let arr = []; this.ratings.comments.forEach((comment) => { if(comment.comment_pics.length) { arr.push(comment); } }); return arr; } else { // Comment return this.ratings.comments_dp.comments; } } },
Using the introduced components:
components: { Star, Split, BScroll }
The Split component is the dividing line of the icon above.
Logical Realization of Star Grading
New Star file
Stars are displayed in the form of full stars and half stars. Stars are constructed through the for cycle.
<template> <div class="star"> <!-- itemClass: on,half,off --> <span v-for="itemClass in itemClasses" :class="itemClass" class="star-item"> </span> </div> </template>
Accept the score value from the parent component through props and use it in star.
score in star is processed by calculating attributes.
<script> // Star Length const LENGTH = 5; // Star-to-star correspondence class const CLS_ON = 'on'; const CLS_HALF = 'half'; const CLS_OFF = 'off'; export default{ props: {//Pass in score through the parent component and use it as "data ()" within the star component score: { type: Number//Specified type number } }, computed: { itemClasses() { let result = []; // 4.7 => 4.5 3.9 => 3.5 4.1 => 4.0 // Processing the fraction, take down a multiple of 0.5 let score = Math.floor(this.score*2) / 2; // Decimal, control half-star let hasDecimal = score % 1 !== 0; // Integer, control the whole star let integer = Math.floor(score); // All star for (let i=0; i<integer; i++) { result.push(CLS_ON); } // Half star if(hasDecimal){ result.push(CLS_HALF); } // Make up while(result.length < LENGTH){ result.push(CLS_OFF); } return result; } } } </script>
From the page analysis of the evaluation component, we have dismantled a reasonable template structure. Then we configure pictures and the path of component reference, which saves us time in development. Finally, the most important thing is the rendering of data and the realization of star rating. In the process, we once again deepen our understanding of vue's props, methods, computed, $nextTick().
Above is the whole content of this article. In the next part, we will refine the display page of commodities. See you in the next part.