preface

As one of the three front-end frameworks, VUE is a necessary skill for front-end developers. Mastering these practical tips will help you get more done with less effort.

1. Lazy route loading makes your first load faster

Lazy route loading allows our packages to load only the routing component of the current page instead of loading all pages at once.

For example, 🌰, if you write it like this, it will all load in.

const router = new VueRouter({
  routes:[
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/about',
      name: 'About',
      component: About
    }
  ]
})
Copy the code

Therefore, you should avoid the above and use lazy loading instead.

Lazy route loading can be written in the following three ways.

  • Vue Asynchronous component

  • The import of es6

  • Webpack provides require.ensure()

    VueRouter({routes:[{path: ‘/about’, name: ‘about’, component: Resolve => reqire([‘path ‘], resolve)}]})

    // 2, es6 import VueRouter({routes:[{path: ‘/about’, name: ‘about’, component: () => import(‘path ‘)}]})

    // 3, require. Ensure () VueRouter({routes:[{path: ‘/about’, name: ‘about’, component: R = > the require. Ensure ([], () = > r (the require (‘ path path)), ‘demo’)}]})

2. Asynchronous components

Asynchronous components allow us to load components when we need them, rather than as soon as they are initialized, which is similar to lazy route loading.

This is how components used to be introduced

Import BureauDetail from './components/ChildFirst' import addBureau from './components/ChildSecond' // in The Comoinents of Vue components: { ChildFirst, ChildSecond }Copy the code

If the component is not loaded in the first place, we can use component lazy loading

// In vue's comoinents components: {BureauDetail: () => import('./components/ChildFirst'), addBureau: () => import('./components/ChildSecond') },Copy the code

There is also a more complete asynchronous component writing

export default { components:{ ChildFirst:()=>({ component:import(/* webpackChunkName: "ChildFirst" */ './Async'), delay:200, default :200 timeout:3000, // timeout after loading a few millimeters, Trigger the error component loading: LoadingComponent, / / component before loading back display error: ErrorComponent / / component displayed when overtime}}}Copy the code

3. Require.context () introduces multiple components

Context (Directory, useSubdirectories, regExp)

Original writing:

/ / writing original import titleCom from '@ / components/home/titleCom' import bannerCom from '@ / components/home/bannerCom' import cellCom from '@/components/home/cellCom' components: { titleCom, bannerCom, cellCom }Copy the code

This is a lot of repetitive code that can be written using require.context

const path = require('path')
const files = require.context('@/components/home', false, /\.vue$/)
const modules = {}
files.keys().forEach(key => {
  const name = path.basename(key, '.vue')
  modules[name] = files(key).default || files(key)
})
components: modules
Copy the code

Introduces a number of common components in main.js, which can be written using require.context

Import Vue from 'Vue' const requireComponents = require.context('.. /views/components', true, /\.vue/) // Print the result // iterate through the path requireComponents.keys().foreach (fileName => {// component instance const reqCom = RequireComponents (fileName) / / clipping paths as components of const reqComName = reqCom. Name | | fileName. Replace (/ \ \ / (. *) \. Vue /, '$1') / / component mounted Vue.component(reqComName, reqCom.default || reqCom) })Copy the code

Listen for the child lifecycle in the parent component

Components such as the father Parent and Child, the Child components if the Parent component listening to Child components mounted mounted do some logic to handle, the conventional method may be as follows:

// Parent.vue
<Child @mounted="doSomething"/>

// Child.vue
mounted() {
  this.$emit("mounted");
}
Copy the code

In addition, there is a very simple way, the child component does not need any processing, only needs to listen to the parent component reference @hook, @hook can also listen for other lifecycle events, code:

<Child @hook:mounted="doSomething" /> 
<Child @hook:updated="doSomething" />
Copy the code

5. Use this? For computed

For a computed attribute, use this. XXX to retrieve data and methods, or use this. Store to retrieve vuex state, commit, and so on. It is also possible to get vuex’s state and commit through this. Store. It is also possible to get vuex’s state and commit through this.

In fact, we can avoid these ugly this, which can even cause us invisible performance problems.

In the implementation, all data that we can access through this is structured on the first parameter of computed.

Export default {watch: {haha({$attrs,$route,$store,$listeners,$ref}){return}}Copy the code

6. When initializing, let watch execute immediately

The Watch performs a callback every time the data it listens to changes.

However, when watch a variable, it is not executed when the page or component is initialized. In the following example, you need to manually call it at created time.

created() {
  this.getList();
},
watch: {
  keyWord: 'getList',
}
Copy the code

We can do that, but it’s a bit cumbersome, but we can add the immediate attribute so that it automatically fires when initialized

Watch has three parameters

  • Handler: The value is a callback function. The function that should be executed when a change is heard

  • Deep: the value is true or false; Confirm whether to listen in. You can use the deep attribute when listening for reference type data such as arrays or objects

  • Immediate: The value is true or false, which determines whether to execute handler’s functions at the current initial value

    watch: { keyWord: { handler(val) {}, immediate: true } }

7. Recursive components call themselves

Recursive component: A component can recursively call itself within its template by naming the component.

Note: a condition must be given to limit the number, otherwise an error will be raised: Max stack size exceeded

<template>
  <div v-for="(item,index) in treeArr"> {{index}} <br/>
      <tree :item="item.arr" v-if="item.flag"></tree>
  </div>
</template>
<script>
export default {
  // 必须定义name,组件内部才能递归调用
  name: 'tree',
  data(){
    return {}
  },
  // 接收外部传入的值
  props: {
     item: {
      type:Array,
      default: ()=>[]
    }
  }
}
</script>
Copy the code

When looking at the Element UI source code, the encapsulated Tree control, cascading selection, is also used this way.

8, Object. Freeze performance optimization

Vue 2.0 will hijack data via object.defineProperty. Arrays and objects will have to loop through all field values to hijack each property.

Vue 3.0 uses Proxy constructors to hijack data to enable views to respond to changes in data

However, sometimes our components are pure data presentation and nothing changes, so we don’t need vue to hijack our data. In large data presentation cases, this can significantly reduce component initialization time.

So, we can freeze an object by using the object.freeze method. Once the object is frozen, vue will not hijack the data.

Object.freeze() freezes an Object. You cannot add new properties to the Object, change the value of existing properties, delete existing properties, or modify the enumerability, configurability, or writability of existing properties of the Object. This method returns the frozen object.

<p v-for="item in list">{{item.value}}</p> export default {data: {// vue does not do getters and setters for objects in list: Object.freeze([{value: 1}, {value: 2}])}, created () {this.list[0].value = 100; This.list = [{value: 100}, {value: 200}]; this.list = Object.freeze([ { value: 100 }, { value: 200 } ]); }}Copy the code

9, modify reference type data, view not updated?

When an object or array (whose values are objects) is declared or assigned in vue’s data, a new property is added to the object. Updating the value of the property does not update the view.

This.$set(target, key, value)

  • Target: The data source to be changed (can be an object or array)

  • Key Specific data to change (index)

  • Value Specifies the value to be assigned

    export default { name: ‘App’, data () { return { items: [ { message: “one”, id: “1” }, { message: “two”, id: }, {message: “three”, id: “3”}]}}, mounted () {this.items[0] = {message:’first’,id:’4′}

    This.set (this.items,0,art)}, methods: {handClick(){let change = this.items[0] change.message=”shen” // Set can trigger update view This.set (this.items,0,change)}}}

10. Sync modifier

.sync provides a way to communicate with the parent component! You are advised to use Sync if you are simply modifying data from a parent component in a child component. It is easy, fast and does not require you to send a custom method to receive it

In vue, we often use v-bind(abbreviated 🙂 to pass parameters to child components. Or we pass a function to the child component, and the child changes the state of the parent component by calling the passed function. Take 🌰 for example

<MyFooter :age="age" @setage ="(res)=> age= res"> </MyFooter> </MyFooter> mounted () { console.log(this.$emit('setAge',1234567)); }Copy the code

Now you can easily update the assigned component’s value by simply using.sync

// The parent passes the age to the child using the.sync modifier. > </MyFooter :age. Sync ="age"> </MyFooter> mounted () {console.log(this.$emit('update:age',1234567)); }Copy the code

Mixin, reuse code

Mixins provide a very flexible way to distribute reusable functionality in Vue components. A mixin object can contain any component option. When a component uses a mixin object, all the options for the mixin object are “mixed” into the component’s own options.

Generally speaking, mixins can define public data, created, methods, computed, watch, etc. Then mix it into your current vUE file.

Another powerful feature of Minxin is the merge option, where the same variable/method names are merged together, and if they have the same name, the variable or method in the current file overwrites the name or method in the mixin file.

  • Data objects are recursively merged internally, and component data takes precedence in the event of a conflict.

  • The hook functions of the same name will be merged into an array and therefore both will be called. Hooks that blend in with an object are called before the component’s own hooks.

  • Options with object values such as methods, Components, and Directives are combined into the same object. When two object key names conflict, the key-value pair of the component object is taken.

1. Define a mixin.js

export default mixin { data() { return { name: 'mixin' } }, created() { console.log('mixin... ', this.name); }, mounted() {}, methods: {// formatDate (FMT = 'YYYY ') {if (! dateTime) { return '' } moment.locale('zh-CN') dateTime = moment(dateTime).format(fmt) return dateTime } } }Copy the code

Use mixins in vue files

import '@/mixin'; Export default {mixins: [mixins], // use data() {return {userName: "adimin", time: This.formatdate (new Date())}}} this.formatdate (new Date())}Copy the code

12, dojo.provide/inject

The common communication mode between parent and child components is that the parent component binding passes the data to the child component. The child component receives the data through the props attribute. Once there are many components in the hierarchy, it is very troublesome to pass the value in this way, and the code is not readable, which is inconvenient for later maintenance.

Vue provides and inject to help us solve multi-level nested nested communication problems. Provide specifies the data to be passed to the descendant component, and the descendant component injects the data passed by the grandfather component.

In fact, provide and Inject mainly provide use cases for higher-level plug-in/component libraries.

When reading the source code of Element UI, we find that many higher-order components use provide and inject, which reduces the workload of parent components communicating with their children and grandchildren.

In the elementUI component library, expose component instances in the El-Form component to descendant components

Inject the el-Form component instance into the el-Form-Item component, and then you can use the methods, variables, and so on of the el-Form component instance

Provide variables in the parent component

<template> <div> <p>{{ title }}</p> <son></son> </div> </template> <script> import Son from "./son" export default { Name: 'Father', components: {Son}, // provide option provides variable provide: {message: Provided by father}, data () {return {title: 'parent'}}, methods: {... } } </script>Copy the code

2, the descendant component can be injected using inject

<template> <div> <p>message: {{message}}</p> </div> </template> <script> export default {name: "morat ", inject: ["message"], data () {return {title: 'sun component'}}, methods: {... }}; </script>Copy the code

More highlights: Please pay attention to javascript art