As the company’s front-end began to shift to vue.js, recently began to use this framework for development, encountered some problems recorded for future use. I mainly write some problems that are not written in the official manual, but will be encountered in the actual development, which requires a certain knowledge base.

Involved Technology stack

  • CLI: Vue-CLI
  • UI: Element
  • HTML: Pug(Jade)
  • CSS: Less
  • JavaScript: ES6

Polyfill and transform – runtime

First, vue-CLI automatically added the babel-plugin-transform-Runtime plug-in, which works fine most of the time and can transform most of the ES6 syntax. However, there are two problems:

(1) Redundant polyfill code occurs when loading components asynchronously. (2) No polyfill for global functions and instance methods is supported. Both problems are due to babel-plugin-transform-Runtime sandbox compiling our code. Do not modify the built-in objects of the host environment.

Because asynchronous components will eventually be compiled into a separate file, even if the same new feature is used in multiple components (for example: Object.keys()), there will be a Polyfill copy of the new feature in each compiled file. If the project is small, you can consider not using asynchronous loading, but the pressure of the first screen will be large. No support for global functions (such as: Promise, Set, Map), Set and Map these two data structures should be used less, less impact. But promises can have a bigger impact. Instance methods (e.g. ‘ABC ‘.include(‘b’), [‘1’, ‘2’, ‘3’].find((n) => n < 2), and so on) are not supported, a limitation that almost disables most strings and about half of the new array features.

In general, babel-plugin-transform-Runtime can meet most of the requirements. When the requirements are not met, it is recommended to use the complete babel-Polyfill.

First, remove the dependency from the project by removing the babel-plugin-transform-Runtime:

npm un babel-plugin-transform-runtime -D
Copy the code

Modify the Babel configuration file

// .babelrc
{
  //...
  "plugins": / / / -"transform-runtime"] / /... }Copy the code

Then, install the Babel-Polyfill dependency:

npm i babel-polyfill -D
Copy the code

Finally, import in the entry file

// src/main.js
import 'babel-polyfill'
Copy the code

ES6 import reference problem

In ES6, import and export of module system USES a reference to export and import (not the simple data types), that is, if in a module defines an object and export, import when used in other modules, the imported is a variable reference (pointer), if you modify attributes of the object, will affect the use of other modules. In general, when the system size is small, we can simply use json.parse (json.stringify (STR)) to generate a new deep copy of the data object. However, when there are many components and a high degree of reuse of data objects, performance issues are obvious, and we can consider using Immutable.

For this reason, when exporting complex data types, you need to be aware of the problems that may occur if multiple components import the same data object and modify the data. In addition, even if a module defines a variable or function using a let instead of a const, it becomes read-only when imported and cannot be reassigned. The effect is the same as declaring a const.

Use Pug and Less in Vue

Install dependencies

In Vue, vue-loader is used to automatically determine the required loader according to the lang attribute, so there is no need to configure additional loader, but related dependencies need to be manually installed:

npm i pug -D
npm i less-loader -D
Copy the code

Still quite convenient, don’t need to manually modify webpack configuration file to add loader can be used

Use puG or pug-loader? How to set the loader syntax of sass? — For details, see Preprocessor · Vue-Loader

use

<! -- xxx.vue --> <style lang="less">
  .action {
    color: #ddd;ul { overflow: hidden; // Front-end full stack development ac circle: 866109386 li {// For 1-5 years front-end developersfloat: left; // Break through technology and improve thinking. Welcome to enter. } } } </style> <template lang="pug">
  .action(v-if='hasRight'</template> <script>export default {
    data () {
      return {
        hasRight: true
      }
    }
  }
</script>
Copy the code

Define global functions or variables

Many times you need to define global functions or variables to handle frequent operations (see AJAX exception handling for an example). But in Vue, each single-file component has a separate context (this). Usually in exception handling, we need to access this object in view, but the context of the global function is usually window, which requires some special handling.

Simple and bold

The simplest way to do this is to define a global method directly on the Window object, using bind, call, or apply to change the context when used within the component. Define a global exception handling method:

// errHandler.js
window.errHandler = function() {// Arrow functions cannot be usedif(err.code && err.code ! == 200) { this.$store.commit('err'.true)}else{/ /... }}Copy the code

Import in the import file:

// src/main.js
import 'errHandler.js'&emsp; &emsp; Use: // xxx.vue in componentsexport default {
  created () {
    this.errHandler = window.errHandler.bind(this)
  },
  method: {
    getXXX () {
      this.$http.get('xxx/xx').then(({ body: result }) => {
        if (result.code === 200) {
          // ...
        } else {
          this.errHandler(result)
        }
      }).catch(this.errHandler)
    }
  }
}
Copy the code

Elegant safety type

In massively multiplayer projects, it is not appropriate to contaminate Window objects. In particular, some of the more personalized global methods (which you may use almost everywhere in the component you write, but which others may not need). It is recommended to write a module, which is more elegant, safe, and natural. The only drawback is that every component that needs to use this function or method needs to be imported. The method of use is much the same as the one before, so it will not be introduced.  ̄

Custom path alias

Some of you may have noticed that the vue-CLI-generated template uses this syntax when importing components:

import Index from '@/components/Index'
Copy the code

What is this @ thing? Later when I changed the configuration file, I found that this was one of the webPack configuration options: the path alias. We can also add our own path alias to the base configuration file, such as the following one which sets ~ to the path SRC /components alias:

// build/webpack.base.js
{
  resolve: {
    extensions: ['.js'.'.vue'.'.json'].alias: {
      'vue$': 'vue/dist/vue.esm.js'.The '@': resolve('src'),
      '~': resolve('src/components')}}}Copy the code

Then when we import the component, we can write:

// import YourComponent from 'YourComponent'
// import YourComponent from './YourComponent'
// import YourComponent from '.. /YourComponent'
// import YourComponent from '/src/components/YourComponent'
import YourComponent from '~/YourComponent'
Copy the code

Not only solved the path is too long trouble, but also solved the relative path trouble, convenient a lot of it!

CSS scopes and modules

In-component style

In general, the style in the tag of a component is global, which can affect the style of the UI library when using a third-party UI library such as Element. We can make the style in style apply only to the current component by adding the scoped property:

<style lang="less" scoped>
  @import 'other.less'; The title {the font - size: 1.2 rem; } </style>Copy the code

Importing other styles within a style tag with the scoped attribute will also be scoped into a component-style style. This is not recommended for highly reusable styles. In addition, element selectors should be avoided in in-component styles because they can degrade performance when combined with attribute selectors. — Tests two combinatorial selectors: classes Selector and elements Selector

Import the style

Sometimes we also need to add global styles as opposed to intra-component styles when style uses the scoped attribute. Of course we can write a global style without scoped. However, the following is more recommended:

< span style = "box-sizing: border-box! Important; word-wrap: break-word! Important; }. Title {font-size: 1.4rem; font-weight: bolder; }Copy the code

Then import the global style in the entry file:

// src/main.js
import 'style-global.less'
Copy the code

Gets the form control value

Usually we can bind form controls to data directly using the V-Model, but sometimes we need to get the current value as the user enters it (for example, to verify the validity of the current input control content in real time).

At this point we can bind our own handler with @input or @change events and pass in a $event object to get the input value of the current control:

<input type='text' @change='change($event)'>
Copy the code
change (e) {
  let curVal = e.target.value
  if (/^\d+$/.test(curVal)) {
    this.num = +curVal
  } else {
    console.error('%s is not a number! ', curVal)
  }
}
Copy the code

Of course, it would be simpler if the UI framework adopted Element, whose event callbacks pass in the current value directly.

Use tips for V-for

The V-for directive is powerful. It can be used not only to iterate over groups of numbers, objects, but even over a number or string.

I’ll skip the basic syntax, but here are some tips:

The index value

When using V-for to generate the DOM from objects or arrays, you sometimes need to know the current index. We can do this:

<ul>
  <li v-for='(item, key) in items' :key='key'> {{ key }} - {{ item }}
</ul>
Copy the code

Note, however, that the value of a number starts at 1 and the key starts at 0:

<ul>
  <li v-for='(v, k) in 3' :key='k'> {{ k }}-{{ v }} <! -- output to be 0-1, 1-2, 2-3 --> </ul>Copy the code

In version 2.2.0+, keys are now required when using V-for in components.

The unique root node of the template

As with JSX, a template in a component can have only one root node, which is an error:

<template> <h1>Title</h1> <article>Balabala... </article> </template>Copy the code

We need to wrap it around a block-level element:

<template> <div> <h1>Title</h1> <article>Balabala... </article> </div> </template>Copy the code

Project Path Configuration

Since vuE-CLI configured projects provide a built-in static server, there are few problems during the development phase. However, when we put code on the server, we often run into static resource reference errors that leave the interface blank.

This is because the vue-CLI default configuration of Webpack is a file referenced in the site root directory, however sometimes we may need to deploy the project to a subdirectory.

We can change the relative path of the file reference using config/index.js:

  build.assetsSubDirectory: 'static'
  build.assetsPublicPath: '/'

  dev.assetsSubDirectory: 'static'
  dev.assetsPublicPath: '/'
Copy the code

We can see that build and dev have assetsSubDirectory and assetsPublicPath in the exported object.

AssetsSubDirectory refers to the static resource folder, that is, the folder where packed JS, CSS, images and other files are placed. This default is generally not a problem.

AssetsPublicPath refers to the reference path of the static resource. The default value is /, that is, the root directory of the website. When combined with assetsSubDirectory, the complete reference path of the static resource is /static.

The solution is obvious at this point, just change the root directory to a relative directory:

  build.assetsSubDirectory: 'static'
  build.assetsPublicPath: '/'
Copy the code

That’s right! It is a question of. Reference: blog.csdn.net/q3254421/ar…