review

In the previous

Recently, I received messages from some front-end partners looking forward to sharing an unfinished practical case of mobile e-commerce project. As expected, it’s fresh. But because my energy is limited, writing level is general, unearthed quality is not high, wang Haihan. If you have the basics of web front-end HTML + CSS + JS + VUE, you can skip the previous article and read this article directly. Next to talk about, but also the most important page function development stage. The completion stage of the whole project is divided into: demand analysis, prototype discussion, UI design, front and back end development, testing and online. Without further ado, let’s get to the point.

Essential for mobile development

  1. Use rem unit for mobile adaptation, add the following code to the path/SRC /assets/js/common.js as a common JS method, easy to call on each page.
// The page unit is rem
rem: function () {
    var docEl = document.documentElement,
    resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
    recalc = function () {
        var clientWidth = docEl.clientWidth;
        if(! clientWidth)return;
        if (clientWidth >= 750) {
            docEl.style.fontSize = '100px';
        } else {
            docEl.style.fontSize = 100 * (clientWidth / 750) + 'px'; }}; recalc();window.addEventListener(resizeEvt, recalc, false);
}
Copy the code

This is the core code for the REM layout. If the page width is more than 750px, the font size of the HTML on the page should be 100px. Otherwise, the font size of the HTML in the page is: 100 * (current page width / 750). The average UI designer will provide a design with a width of 640px or 750px, but I’ll use 750px for easy calculation, so when converting rem, pixel /100 is equal to REM. For example: image width 100px, 100px/100=1rem.

  1. Disable a, button, input, select, textarea labels, such as dark background, direct in/SRC/assets/CSS/common CSS, add the following code:
// Remove the translucent overlay (iOS) or dotted (Android) of click links and textbox objects
a, button, input, optgroup, select, textarea {
    -webkit-tap-highlight-color: rgba(0.0.0.0);
}
Copy the code
  1. Meta set
// The page window automatically adjusts to the device width and prevents the user from zooming in and out of the page
<meta name="viewport" content="Width = device - width, initial - scale = 1.0, the minimum - scale = 1.0, the maximum - scale = 1.0, user - scalable = 0">
Copy the code

Basic meanings of attributes:

attribute meaning
width=device-width Controls the viewPort size
device-width Width of equipment
initial Initial scaling
minimun-scale The minimum scale to which the user is allowed to zoom
maximun-scale Maximum scale to which the user is allowed to zoom
user-scalable Whether users can manually zoom in and out

More meta:

// Encoding format
<meta charset="UTF-8">
// Use the latest version of IE and Chrome first
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>   
// High-speed mode compatible with domestic browsers<meta name="renderer" content="webkit"> // UC force full screen <meta name=" full-screen "content=" yes "> // Ignore numbers in pages as phone numbers <meta <meta name="format-detection" content="email=no"> <meta name="apple-touch-fullscreen" content="yes" /> Safari <meta Name ="apple-mobile-web-app-capable" content="yes"> // Optional default, black, black-always <meta name="apple-mobile-web-app-status-bar-style" <meta name="description" Content =" not exceeding 150 characters "/> // <meta name="keywords" content=""/> // Prevent 404 requests <link rel="shortcut icon" href="/favicon.ico">Copy the code
  1. Webkit form input box placeholder color changed
input::-webkit-input-placeholder{
   color: red;
}
Copy the code
  1. Remove the native look and add this property on iOS phones to give custom styling to buttons and input fields
input, textarea {
  -webkit-appearance: none;
}
Copy the code
  1. Disable the pop-up menu when long pressing a page on iOS
a, img {
  -webkit-touch-callout: none;
}
Copy the code
  1. Calc basic syntax, support addition, subtraction, multiplication, division; In the mobile phone terminal is very useful when a knowledge point. The advantages are as follows:

    (1) Support the use of “+”, “-“, “*”, “/” four operations (2) Can use percentage (%), PX, EM, REM as a unit for calculation

    Browser compatibility: IE9+, FF4.0+, chrome19+, safari6+

    Usage:

    .box {
       	width: calc(100% - 20px - 2em);
    }
    <div class="box"> Test text </div>Copy the code
  2. Flex elastic layout, the container’s six properties, is generally excellent with REM.

    (1) flex-direction (2) flex-wrap (3) flex-flow (4) justify-content (5) align-items (6) align-content

Above 6 attributes, specific how to use, recommend Ruan Yifeng teacher flex layout tutorial, read + practice. www.ruanyifeng.com/blog/2015/0…

Page component development

The main body of the whole website includes home page, commodity list page, commodity search page, commodity details page, get coupons and other pages.

To create a static interface from the UI designer’s draft, let’s first analyze the scene design or interaction effects of the home page. The previous article has introduced what the home page looks like, you can say the head navigation, search box, share popup button, wheel map, item category, item list page, back to the top button, preload animation. Other pages you can also start thinking about their scene design or interactive effects, thinking more harvest.

Think again, is it possible to carry out front-end componentization and modular thinking development? Answer: Definitely.

Perhaps some partners have a little understanding, some are very strange, and some often hear the interviewer to raise these conceptual questions. In fact, it is easy to understand that the purpose of front-end architecture design is to set standards, improve quality and efficiency. That reasonable architecture includes engineering, componentization, modularization, standardization.

However, front-end componentization and modularization can help us solve what problems?

Componentization focuses more on the UI. Each part of the page, such as the header navigation, the search box, the list of items and even the return button to the top, can become a component, and each component has its own HTML, CSS, and JS code. It can be placed anywhere on the page as needed, or it can be combined with other components to form new components. A page is a combination of components that can be assembled as needed.

Modularization focuses on function encapsulation, mainly for Javascript code, isolation, organization of duplicated Javascript code, it is packaged into a module with specific functions. (for example, used in ES6 module)

In front of these, or did not understand the word, you can go online to find relevant information.

On the right track

Due to time constraints, I will choose several functions to focus on in detail. First, I will take a look at the composition of the home page template: index.html, index.js, index.vue three files as shown below: Home page effect pictureAfter understanding each component of the page, the page layout can be carried out, the static interface can be developed, and finally the business logic and back-end interface can be written. As mentioned before, front-end component-based thinking can be used according to actual project requirements. After analysis, generally head or bottom navigation, commodity classification, commodity list, back to the top button, loading preloading animation and so on can be extracted to make components, and all components can be stored in SRC /components/ position. For example, the header navigation is a common parent component that contains a search box that can be pulled out to make a common child component. Because the author is very lazy, did not realize to pull out, directly write in the template page. Friends can try to change the component form at their own time.

Since we want to do front-end componentization development, take commodity classification as an example. Create categoryList.vue under SRC /components/ and write the layout in the Template TAB as shown below:The style is written in the style tag, and if you want to privatize the style, only for the current module, you can add it to the style tagScoped attributes. The code is shown below:Vue instance obtains commodity classification data, and implements data initialization in the export default module of script label. Since it is an object array, we define the object array in the data() function to initialize data. The code is as follows:

<script>
export default {
  data () {
    return {
      categoryList: [{id: "1".category: 2.name: "Men's".sort: "100".imgUrl: require('.. /assets/img/category/nanzhuang.png')}, {id: "2".category: 1.name: "Women's".sort: "100".imgUrl: require('.. /assets/img/category/nvzhuang.png')}, {id: "3".category: 6.name: "Home".sort: "100".imgUrl: require('.. /assets/img/category/jujia.png')}, {id: "4".category: 4.name: "Mother".sort: "100".imgUrl: require('.. /assets/img/category/muying.png')}, {id: "5".category: 3.name: "Underwear".sort: "100".imgUrl: require('.. /assets/img/category/meizhuang.png')}, {id: "6".category: 7.name: "Shoes package".sort: "100".imgUrl: require('.. /assets/img/category/xiebao.png')}, {id: "Seven".category: 5.name: "Beauty".sort: "100".imgUrl: require('.. /assets/img/category/meizhuang.png')}, {id: "8".category: 0.name: "More".sort: "100".imgUrl: require('.. /assets/img/category/more.png'}]}}}Copy the code

Initialize the array of objects in the template template, using the V-for loop through the array of objects as follows:

<ul class="category fix">
  <li v-for="item in categoryList">
    <a href="javascript:;" @click="gotoSearch(item.category)" target="_blank">
      <img :src="item.imgUrl" :alt="item.name" :title="item.name">
      <span class="category-tit">{{item.name}}</span>
    </a>
  </li>
</ul>
Copy the code

To mention Vue’s common click events, you can listen for DOM events with the V-ON directive and run some JavaScript code when triggered.

v-on:click = handleClick  // The name of the handleClick method
// OR 
@click = handleClick  // Click the event abbreviation
Copy the code

The custom method name called in the click event is written in the methods property as follows:

methods: {
  handleClick () {
    console.log('Click me'); }}Copy the code

The complete code of commodity classification component is as follows:

<template>
  <div class="category-list">
      <div class="floor-area">
          <ul class="category fix">
              <li v-for="item in categoryList">
                <a href="javascript:;" @click="gotoSearch(item.category)" target="_blank">
                  <img :src="item.imgUrl" :alt="item.name" :title="item.name">
                  <span class="category-tit">{{item.name}}</span>
                </a>
              </li>
          </ul>
      </div>
  </div>
</template>

<script>

export default {
  data () {
    return {
      categoryList: [{id: "1".category: 2.name: "Men's".sort: "100".imgUrl: require('.. /assets/img/category/nanzhuang.png')}, {id: "2".category: 1.name: "Women's".sort: "100".imgUrl: require('.. /assets/img/category/nvzhuang.png')}, {id: "3".category: 6.name: "Home".sort: "100".imgUrl: require('.. /assets/img/category/jujia.png')}, {id: "4".category: 4.name: "Mother".sort: "100".imgUrl: require('.. /assets/img/category/muying.png')}, {id: "5".category: 3.name: "Underwear".sort: "100".imgUrl: require('.. /assets/img/category/meizhuang.png')}, {id: "6".category: 7.name: "Shoes package".sort: "100".imgUrl: require('.. /assets/img/category/xiebao.png')}, {id: "Seven".category: 5.name: "Beauty".sort: "100".imgUrl: require('.. /assets/img/category/meizhuang.png')}, {id: "8".category: 0.name: "More".sort: "100".imgUrl: require('.. /assets/img/category/more.png')}]}},methods: {
    gotoSearch (category) {
      window.location.href = `.. /search? category=${category}` ;
    }
  },
  created () {},
  mounted () {}
}
</script>
  
<style scoped>
.floor-area {
    background: #fff;
    text-align: center;
    overflow: hidden;
    padding-top:.2rem;
    border-top: 1px solid #eee;
}
.floor-area li {
    width: 25%;
    display: block;
    float: left;
    margin-bottom:.2rem;
}
.floor-area li a {
  display: block;
}
.floor-area li img {
    width: 1rem;
    height: 1rem;
    display: block;
    margin: 0 auto;
}
.floor-area li .category-tit {
    font-weight: 400;
    display: block;
    text-align: center;
    padding-top:.1rem;
    font-size:.24rem;
}
</style>
Copy the code

After the product classification component is developed, how to introduce custom components is as follows:

<template>
  <div id="app">// Use components in the template<category-list></category-list>// The second way<category-list>/ / slot custom slots content, specific usage, reference Vue website: https://cn.vuejs.org/v2/guide/components-slots.html</category-list>// The third way<categoryList />
  </div>
</template>

<script>
// Import components
import categoryList from '@/components/categoryList'

export default {
	components: { categoryList }, // Register the component
	data() {
		return {
			// Set the initialization data}},methods: {},
	created() {},
	mounted() {}
}
</script
Copy the code

Now talk about the home page rotation map effect has automatic play, sliding around, click on the picture to jump inside or outside the chain and so on. If you want to hand-write Vue rotation graphics effects no problem, spend a little more time can be completed, but if you rush the project, you can find some very mature open source free plug-ins on the market, directly into your project. I directly use CDN to import swiper plug-in, and the operation is as follows:

// Start with the following external links in the index.html file on the home page
<link rel="stylesheet" href="https://unpkg.com/swiper/css/swiper.css">
<link rel="stylesheet" href="https://unpkg.com/swiper/css/swiper.min.css">
<script src="https://unpkg.com/swiper/js/swiper.js"> </script>
<script src="https://unpkg.com/swiper/js/swiper.min.js"> </script>
Copy the code

Used in the template templateInitialize initSwiper in the Methods attribute of the Script tag, and then call initSwiper in the Mounted life cycle function to make the rotation diagram take effect, as shown in the following figure:For details on how to use Swiper, see the official website API and DEMO:swiperjs.com/

Dynamically retrieving data calls the API interface

The above mentioned development of commodity classification component data acquisition method is static, if the commodity list to dynamically obtain data, how to operate. As the project adopts the technology of front and back end separation, dynamic data is obtained by calling the API interface provided by the back end. The front and back end are required to be developed synchronously, but before the back end is completed, there is no data returned to the front end for use temporarily. If you write the static state first and then change it, there will be internal friction of repeated work. So we need a simple and fast module or management tool to simulate data, so that we can provide or modify the interface ourselves. Here are two ways to do it, and the blogger suggests the second is easier.

Mock files

  • Install MockJS and Axios
npm install -D mockjs
npm install -S axios
Copy the code
  • Create a mock folder under SRC and create an index.js file with the following structure:

  • The contents of the index.js file and the data structure returned are as follows (Note: The returned data structures can be written as separate JS files for different functional modules) :
import Mock from 'mockjs'

let shopData = {
	'success|1': [true.false].'msg': function() { 
		if (this.success) {
			return 'Call successful';
		} else {
			return 'Call failed'; }},'pageNum': 1.'pageSize': 10.'data': function() {
		if (this.success) {
			return this.result;
		} else {
			return this.result = []; }},'result|1-10': [{
		'id|+1': 1.'GoodsId': '@guid'.'GoodsName|1': [Zhejiang special handmade glutinous rice cake osmanthus cake 250g.'[Buy one get One free] Summer Frosted Men's trousers Casual trousers'."Renhe red bean coix Seed Tea Dispelling Wet tea Pouch"].'actDate': '@now'.'sales|0-100': 10.'ShopName|1': ['Hanlanto Flagship Store'.'Wu Yuyuan Flagship Store'.'Shuaiqu Flagship Store'].'ImgUrl': '@image("200x200", "#00405d", "#FFF", "Mock.js")'.'GoodsPrice | 1-200.1': 50.'GoodsLink': '@url'}].'totalNum': function() {
		return this.data.length; }},// Format: Mock. Mock (url, post/get, returned data)
Mock.mock('/api/shoplist', shopData)

export default Mock
Copy the code
  • Add a get method to the SRC /js/api.js file that simulates the commodity list interface as follows:
// Mockjs simulates the commodity list interface
export function getMockData() {
  return network({
    url: '/shoplist'.method: 'get'
  });
}
Copy the code
  • Add the following code to the SRC /js/url.js file to make sure it matches the mock data URL, as shown below:

  • Verify the mock interface, used directly in the index.vue file on the home page
// Introduce defined mock interface methods under the script tag
import { getMockData } from '@/assets/js/api'

methods: {
	// Encapsulates mock interface method calls
	getMockList() {
      getMockData().then(res= > {
        console.log('mockData===', res)
      }).catch(err= > {
        console.log(err)
      })
    }
}

mounted () {
    this.getMockList(); // Initialize the mock data
}
Copy the code
  • The result is shown below:

Second, YAPI management tool

  • Official website: yapi.demo.qunar.com/

Let’s talk briefly about why I choose YAPI. Please look at the screenshot above or check the official website. Is it based onmockjsAnd jSON5, visual interface operation, github small stars, indicating that many people use,The only drawback is the inability to use the MockJS function functionality. Too much bullshit. Just get to work. First go to the official website to register an account, and then enter the background management interface. The diagram below:

  • Create a project

The first time I came in, I did not have my project, so I needed to create the project by myself, as explained in the screenshot above. Next, click Add Project to enter the new project page. The diagram below:Generally fill in a project name, other default, submit can be done.

  • Add an interface

After the above configuration is complete, click the save button and return to the preview interface. The diagram below:Directly open Postman and test the API interface. If the call is successful, it indicates that the simulated data interface configuration is effective, as shown in the following figure:To learn more about the features of YAPI, please check out the documentation on the official website:hellosean1025.github.io/yapi

Parent and child components pass values to each other

Let’s start with two concepts:

  • The parent component passesProps attributePass values to child components
  • The parent component listens on the child componentThis.$emit(' event name ', argument) methodGet the value

Now take the project example to explain the above two functions. For example, the home page index.vue is the parent component, and the qr code public number bullet frame is the child component, as shown below:The parent component passes the value to the child component. First define the initial isPopup value in the parent component data, and then bind isPopup to the child component as follows:

<template>
  <div id="app">
    <div class="wrap">

      <qrcode-pop :isPopup="isPopup" @showPopper="closeBtn">
        <h3>Wechat open long press the QR code to follow the public account</h3>
        <div class="qrcode-img">
          <img src=".. /.. /assets/img/qrcode.jpg" class="qrcode">
        </div>
        <div class="close-btn" @click="closeBtn">Shut down</div>
      </qrcode-pop>

    </div>
  </div>
</template>

<script>
import qrcodePop from '@/components/qrcodePop'

export default {
  components: {
    qrcodePop
  },
  data () {
    return {
      isPopup: false}},methods: {
    closeBtn () {
      this.isPopup = false; }}}</script>

<style scoped>

</style>
Copy the code

The child component uses the props property to receive a pass of the parent component’s isPopup state. You can set the default pass type. The code is as follows:

<template>
	// Qr code pop-up prompt
	<div id="qrcodePop" class="qrcodePop" v-show="isPopup">
		<div class="qrcode-box">
			<slot></slot>
		</div>
		<div id="mask" @click="closeBtn"></div>
	</div>
</template>

<script>

export default {
	data () {
		return{}},props: {
		isPopup: Boolean
	},
	methods: {
		closeBtn () {
			this.$emit('showPopper'); }}}</script>

<style scoped>
#mask {
	position: fixed;
	top: 0;
	left: 0;
	bottom: 0;
	right: 0;
	height: 100%;
	width: 100%;
	z-index: 9999;
	background: rgba(0.0.0.7);
}
.qrcode-box {
	position: fixed;
	top: 50%;
	left: 50%;
	width: 6rem;
	height: 7rem;
	margin-top: -3.5 rem;
	margin-left: -3rem;
	display: flex;
    justify-content: space-between;
    flex-direction: column;
	background: #fff;
	border-radius:.2rem;
	z-index: 10000;
	overflow: hidden;
    text-align: center;
}
.qrcode-box h3 {
	width: 100%;
	height: auto;
	padding:.2rem 0;
	font-size:.32rem;
	color: #fff;
	background: #fc0786; 
	text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
}
.qrcode-box img {
	width: 5.16 rem;
	height: 5.16 rem;
}
.qrcode-box .close-btn { 
    width: 100%;
    height: auto;
    padding:.2265rem 0;
    font-size:.32rem;
    border-top: 1px solid #ddd;
    background: #f2f2f2;
}

.layer-cont {
	padding:.2rem .3rem 0 .3rem;
	line-height:.44rem;
    text-align: center;
}
.kouling-cont {
    position: relative;
    background: #fff4f8;
    padding:.2rem;
    margin: 0 auto;
    display: flex;
	align-items: center;
	justify-content: center;
}

#textarea {
	display: block;
    font-size:.24rem;
    width: 100%;
    height: 2.2 rem;
    line-height:.28rem;
    color: #fc0786;
    background: #fff;
    resize: none;
    border: none;outline: none;overflow-x: hidden;
    word-wrap: break-word;
    word-break: break-all;
} 
.better-change{
	display: flex;
	align-items: center;
	justify-content: space-around;
}
.onecopy {
	width: 50%;
	padding:.25rem .0;
    background: #f8285c;
    text-align: center;
    margin: 0 auto;
    color: #fff;
    cursor: pointer;
    border-top: 1px solid #ddd;
    font-size:.32rem;
}
.kouling-tips p {
	display: block;
    border-bottom: 1px dotted #e5e5e5;
    padding:.15rem 0;
    text-align: justify;
    font-size:.28rem;
}
.kouling-tips i {
	color: #dd514c;
}
.kouling-tips p.nber {
	border-bottom: none;
}
</style>
Copy the code

The child component passes the value to the parent component, define the method name closeBtn in the parent component, and add the custom event name @showpopper to the child component, as shown below: Place the this.$emit() method in the closeBtn click function of the child component to trigger the parent component event to pass the isPopup status value, as shown below:The transfer of values between parent and child components has been completed. Finally, it is added that REM adaptation takes effect on the mobile page, which needs to be introduced on each Vue template page. The code is as follows:

<script>
import Export from '@/assets/js/export'

export default {
	data() {
		return{}},methods: {},
	created () {
    	Export.rem(); // Call the REM phone page adaptation method
  	},
  	mounted () {}
  }
}
</script>
Copy the code

The function points involved in the project are basically finished. If you want to see the effect of the whole site or the source code, please go to Github to view or download it. Attached address: github.com/jackchen012…

If the above explanation is helpful to you, please also triple punch (like – comment – attention), if there is any mistake, welcome to criticize and correct, we exchange and learn together, common progress.

Like can pay attention to the author public number [lazy code farmers], we learn together progress…