1. Update props gracefully

It is not allowed to modify props directly in child components because this does not comply with the principle of one-way data flow and warnings are reported in development mode. So most people will update a prop by sending a custom event via $emit and receiving the value of that event in the parent component.

		//child.vue
export defalut {
    props: {
        title: String  
    },
    methods: {
        changeTitle(){
            this.$emit('change-title', 'hello')
        }
    }
}
Copy the code
		//parent.vue
        <child :title="title" @change-title="changeTitle"></child>

export default {
    data(){
        return {
            title: 'title'
        }  
    },
    methods: {
        changeTitle(title){
            this.title = title
        }
    }
}
Copy the code

There is no problem with this, just updating props. There is no other operation. Using the.sync modifier makes it easy

<child :title.sync="title"></child>

export defalut {
    props: {
        title: String  
    },
    methods: {
        changeTitle(){
            this.$emit('update:title', 'hello')
        }
    }
}

Copy the code

Simply add.sync to the bound property inside the child component to trigger update: property name to update the prop. You can see that it’s really simple and elegant. TIPS: However, it is said that the.sync modifier will no longer be supported in the upcoming VUe3

2.provide/inject

This pair of options needs to be used together to allow an ancestor component to inject a dependency into all of its descendants, regardless of how deep the component hierarchy is, and remain in effect for as long as its upstream and downstream relationships are established.

//app.vue
export default {
    provide() {
        return {
            app: this
        }
    } 
}
Copy the code
Export default {inject: ['app'], created() {console.log(this.app) // app.vue instance}} //Copy the code

If you want to change the name of the inject attribute, use from to indicate the source:

Export default {inject: {myApp: {// Keep the value of from the same as the attribute name of the provide from: 'app', default: () => ({}) } }, created() { console.log(this.myApp) } }Copy the code

3. Small state manager

Data state in large projects can be complex and is generally managed using VUEX. However, in some small projects or projects with simple states, introducing a library to manage several states can be cumbersome. In version 2.6.0+, the new Vue.Observable helps solve this awkward problem by turning an object into a responsive data:

// store.js
import Vue from 'vue'

export const state = Vue.observable({ 
  count: 0 
})
Copy the code
<div @click="setCount">{{count}}</div> // import {state} from '.. /store.js' export default { computed: { count() { return state.count } }, methods: { setCount() { state.count++ } } }Copy the code

Of course, you can also customize mutation to duplicate the state change method:

import Vue from 'vue'

export const state = Vue.observable({ 
  count: 0 
})

export const mutations = {
  SET_COUNT(payload) {
    if (payload > 0) {
        state.count = payload
    } 
  }
}
Copy the code

Use:

import {state, mutations} from '.. /store.js' export default { computed: { count() { return state.count } }, methods: { setCount() { mutations.SET_COUNT(100) } } }Copy the code

3. Uninstall the Watch

Usually we use watch

Export default {data() {return {count: 1}}, watch: {count(newVal) {console.log('count new value: '+newVal)}}}Copy the code

Another way:

export default { data() { return { count: 1}}, created() {this.$watch('count', function(){console.log('count new: '+newVal)})}}Copy the code

It does the same thing, but this way it makes defining the data observation more flexible, and $watch returns a cancel observation function to stop firing the callback:

Let unwatchFn = this.$watch('count', function(){console.log('count new: '+newVal)}) this.count = 2 // log: UnwatchFn () // this.count = 3 // Nothing happened...Copy the code

The third parameter of $watch accepts a configuration option:

This.$watch('count', function(){console.log('count new: '+newVal)}, {immediate: True // Immediately execute watch}) // The first argument is the listening object, then the callback function, and finally the configuration item has' immediate ' 'deep'Copy the code

4. Use opportunely template

If v-if is the most commonly used instruction in development, you’ve probably encountered situations where multiple elements need to be switched under the same switching conditions, usually wrapped in a single element and switched on that element.

<div v-if="status==='ok'">
    <h1>Title</h1>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
</div>
<div v-if="status==='cancel'">
    <h1>Title</h1>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
</div>
Copy the code

A div like the one above has no “meaning” if it exists only for switching conditions and causes the element hierarchy to be nested one more level. We all know that when declaring a page template, all elements need to be inside the

<template> <div> <template v-if="status==='ok'"> <h1>Title</h1> <p>Paragraph 1</p> <p>Paragraph 2</p> </template> </div>  </template>Copy the code

Similarly, we can use the v-for directive on

** 5. Filter reuse **

Filters are used for some common text formatting and are added to the end of expressions, indicated by the “pipe” symbol

<div>{{ text | capitalize }}</div> export default { data() { return { text: 'hello' } }, filters: { capitalize: function (value) { if (! value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } } }Copy the code

Imagine a scenario where this function is not only used in a template, but also in a method. Filters cannot be referenced directly through this, so why define the same function in Methods? Options, so you just need to get this.options, so you just need to get this.options.filters to get the filters in the instance.

use

export default { methods: { getDetail() { this.$api.getDetail({ id: this.id }).then(res => { let capitalize = this.$options.filters.capitalize this.title = capitalize(res.data.title) }) } }}Copy the code

6. Lazy route loading (dynamic chunkName)

Import Vue from 'Vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' import Vue from 'Vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'HelloWorld', component:HelloWorld } ] })Copy the code

As a means of performance optimization, routing lazy loading can give way to component lazy loading. We also typically add a “magic comment” (webpackChunkName) custom package name for lazy-loaded routes, and the route component is packaged separately at packaging time.

Let router = new router ({routes: [{path:'/login', name:'login', component: import(/* webpackChunkName: "login" */ `@/views/login.vue`) }, { path:'/index', name:'index', component: import(/* webpackChunkName: "index" */ `@/views/index.vue`) }, { path:'/detail', name:'detail', component: import(/* webpackChunkName: "detail" */ `@/views/detail.vue`) } ] })Copy the code
Import Vue from 'Vue' import Router from 'vue-router' vue. use(Router) const HelloWorld = ()=>import("@/components/HelloWorld") export default new Router({ routes: [ { path: '/', name: 'HelloWorld', component:HelloWorld } ] })Copy the code
const routeOptions = [ { path:'/login', name:'login', }, { path:'/index', name:'index', }, { path:'/detail', name:'detail', }, ] const routes = routeOptions.map(route => { if (! route.component) { route = { ... route, component: () => import(`@/views/${route.name}.vue`) } } return route }) let router = new Router({ routes })Copy the code
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
  routes: [
        {
          path: '/',
          name: 'HelloWorld',
          component: resolve => require(['@/components/HelloWorld'], resolve)
        }
  ]
}) 
Copy the code

Similarly, our components can be lazily loaded

<template>
  <div class="hello">
  <One-com></One-com>
  1111
  </div>
</template>

<script>
const One = ()=>import("./one");
export default {
  components:{
    "One-com":One
  },
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

Copy the code
<template>
  <div class="hello">
  <One-com></One-com>
  1111
  </div>
</template>

<script>
export default {
  components:{
    "One-com":resolve=>(['./one'],resolve)
  },
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

Copy the code

7. Route parameters are decoupled

Generally, routing parameters are used within components. Most people do this:

export default {
    methods: {
        getParamsId() {
            return this.$route.params.id
        }
    }
}
Copy the code

Using $route in a component makes it highly coupled to its corresponding route, limiting its flexibility by limiting its use to certain urls.

Router = new VueRouter({routes: [{path: '/user/:id', Component: user, props: true})Copy the code

After the props property of the route is set to true, the component can receive the params parameter through the props

export default {
    props: ['id'],
    methods: {
        getParamsId() {
            return this.id
        }
    }
}
Copy the code

8. CSS style penetration

It is common to change third-party component styles during development, but due to the style isolation of the scoped property, you may need to remove scoped or create a different style. All of these have side effects (component style contamination, lack of elegance), and style penetration is only effective when used in CSS preprocessors. We can solve this problem with >>> or /deep/ :

<style scoped> outer >>>. El-checkbox {display: block; font-size: 26px; .el-checkbox__label { font-size: 16px; }} </style> for example <style scoped>.nav >>>. El-checkbox {display: block; font-size: 26px; .el-checkbox__label { font-size: 16px; } } </style> <style scoped> /deep/ .el-checkbox { display: block; font-size: 26px; .el-checkbox__label { font-size: 16px; } } </style>Copy the code

9. Event parameter $event

$event is a special variable of the event object, which in some scenarios gives us more parameters to implement complex functions

<template>
    <div>
        <input type="text" @input="inputHandler('hello', $event)" />
    </div>
</template>

export default {
    methods: {
        inputHandler(msg, e) {
            console.log(e.target.value)
        }
    }
}
Copy the code

Next to continue