36 Skills to Know in Vue Development [Nearly 1W Words]

Posted by robert.access on Wed, 09 Oct 2019 17:26:19 +0200

Preface

Re-Alpha version of Vue 3.x. There should be Alpha, Beta and other versions in the future. It is expected that the official version of 3.0 will not be released until at least the first quarter of 2020.
So we should take advantage of the fact that we haven't yet come out to lay a good foundation for Vue2.x.
The basic usage of vue is easy to use, but you may not know many optimized ways of writing. This article lists 36 vue development techniques.
Continuous updates after Vue 3.x comes out.

1.require.context()

Scenario: If the page needs to import multiple components, the original writing:

import titleCom from '@/components/home/titleCom'
import bannerCom from '@/components/home/bannerCom'
import cellCom from '@/components/home/cellCom'
components:{titleCom,bannerCom,cellCom}

2. This creates 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

This method can be used regardless of how many components are introduced into the page.

3.API Method

In fact, it's a web pack approach. vue engineering is generally based on Web pack, so you can use it
require.context(directory,useSubdirectories,regExp)
Three parameters are received:
directory: Describes the directories to be retrieved
 useSubdirectories: Whether to retrieve subdirectories
 regExp: A regular expression that matches a file, usually a file name

2.watch

2.1 Common Uses

Scenario: Initially the table comes in and needs to investigate the query interface getList(), and then the input change will be re-queried.

created(){
  this.getList()
},
watch: {
  inpVal(){
    this.getList()
  }
}

2.2 Immediate implementation

2. You can use watch's immediate and handler attributes to abbreviate directly

watch: {
  inpVal:{
    handler: 'getList',
      immediate: true
  }
}

2.3 Deep Monitoring

3.watch's deep attribute, deep listening, that is, listening for complex data types

watch:{
  inpValObj:{
    handler(oldVal,newVal){
      console.log(oldVal)
      console.log(newVal)
    },
    deep:true
  }
}

It is found that the oldVal is the same as the newVal.
Because they index the same object/array, Vue does not retain a copy of the previous value.
So deep listening can monitor the change of the object, but it can't monitor the change of the attribute in the specific object.

3. 14 Kinds of Component Communication

3.1 props

This should be very attributes, that is, the attributes of the father and the son;
The props value can be an array or an object;

// Array: Not recommended
props:[]

// object
props:{
  type:Number, //Input Value Restriction Type
  // type values can be String,Number,Boolean,Array,Object,Date,Function,Symbol
  // type can also be a custom constructor and checked by instanceof
  required: true, //Is it necessary to pass on
  default:200,  //Default values, object or array defaults must be obtained from a factory function such as default:() =>[]
  validator:(value) {
    // This value must match one of the following strings
    return ['success', 'warning', 'danger'].indexOf(value) !== -1
  }
}

3.2 $emit

This should also be very attributed, triggering custom events for parent components, which is actually the parent-descendant approach.

// Parent component
<home @title="title">
// Subcomponents
this.$emit('title',[{title:'This is title'}])

3.3 vuex

1. This is also very common. vuex is a state manager.
2. It's a separate plug-in, suitable for projects with more data sharing, because if it's just simple communication, it will be heavier to use.
3.API

State: Defines a warehouse for storing data that can be accessed through this.$store.state or mapState
 Getter: Gets the store value, which can be regarded as the computed attribute of the store, and can be accessed by this.$store.getter or
       mapGetters access
 Mutation: Synchronization changes store values, why is it designed to be synchronized, because mutation changes store values directly?
         vue records the operation, and if it is asynchronous, it cannot track the change. It can be invoked through mapMutations
 action: Asynchronously call a function to perform mutation and then change the store value by this.$dispatch or mapActions
       Visit
 Modules: Modules, if too many states, can be split into modules, and finally introduced at the entrance through... Deconstruction

3.4 $attrs and $listeners

2.4.0 Added
These two are uncommon attributes, but high-level usage is common.
1.$attrs
Scenario: If the parent and the child have many values, then multiple props need to be defined in the child component
Solution: $attrs gets values that are not defined in props in the child heir

// Parent component
<home title="This is the title." width="80" height="80" imgUrl="imgUrl"/>

// Subcomponents
mounted() {
  console.log(this.$attrs) //{title:'This is the title', width:'80', height:'80', imgUrl:'imgUrl'}
},

Correspondingly, if the subcomponent defines props, the printed value is to exclude the defined properties.

props: {
  width: {
    type: String,
    default: ''
  }
},
mounted() {
  console.log(this.$attrs) //{title:'This is the title', height:'80', imgUrl:'imgUrl'}
},

2.$listeners
Scenario: A child component needs to call a parent component's method
Solution: The parent component approach can be passed into the internal component via v-on="$listeners" -- very useful in creating higher-level components

// Parent component
<home @change="change"/>

// Subcomponents
mounted() {
  console.log(this.$listeners) //You can get the change event
}

If a grandchild component wants to access the attributes and invocation methods of its parent component, it can be passed down directly at the first level.

3.inheritAttrs

// parent component
 <home title= "This is the title" width= "80" height= "80" imgUrl= "imgUrl"/>

// Subcomponents
mounted() {
  Console.log (this. $attrs)/{title: "This is the title", "width:" 80","height:"80", "imgUrl:" imgUrl"}
},

The default value of inheritAttrs is true, which means that the attributes on the parent component are displayed on the root component.
If set to false, it will be hidden

3.5 provide and inject

2.2.0 Added
Description:
Provide and inject mainly provide use cases for high-level plug-in/component libraries. Direct use in application code is not recommended.
And this option needs to be used together.
To allow an ancestor component to inject a dependency into all its descendants, no matter how deep the component hierarchy is, and to remain in effect for the time when the upstream and downstream relationship is established.

//Parent component:
provide: { //provide is an object that provides an attribute or method
  foo: 'This is foo',
  fooMethod:()=>{
    console.log('Parent component fooMethod Called')
  }
},

// Sons or grandchildren components
inject: ['foo','fooMethod'], //Arrays or objects, injected into subcomponents
mounted() {
  this.fooMethod()
  console.log(this.foo)
}
//inject is available to all child components under the parent component

The provide and inject bindings are not responsive. This was deliberately done by the authorities.
However, if you pass in a listenable object, its attributes are responsive, because the object is a reference type.

//Parent component:
provide: { 
  foo: 'This is foo'
},
mounted(){
  this.foo='This is new. foo'
}

// Sons or grandchildren components
inject: ['foo'], 
mounted() {
  console.log(this.foo) //Does the subcomponent print'This is foo'
}

3.6 $parent and $children

Parent: parent instance
children: Subinstance

//Parent component
mounted(){
  console.log(this.$children) 
  //Attributes and methods for first-level subcomponents are available
  //So you can change the data directly, or call the methods method method
}

//Subcomponents
mounted(){
  console.log(this.$parent) //You can get parent attributes and methods
}

$children and $parent do not guarantee order or responsiveness
Only first-level parent and child components are available

3.7 $refs

// Parent component
<home ref="home"/>

mounted(){
  console.log(this.$refs.home) //You can get an instance of the sub-component, and you can directly manipulate data and methods.
}

3.8 $root

// Parent component
mounted(){
  console.log(this.$root) //Get the root instance, and finally all components are mounted on the root instance
  console.log(this.$root.$children[0]) //Get the primary subcomponent of the root instance
  console.log(this.$root.$children[0].$children[0]) //Getting the secondary subcomponent of the root instance
}

3.9 .sync

At vue@1.x, it existed as a bidirectional binding function, that is, the child component can modify the value in the parent component;
In vue@2.0, the design against a single data stream was abolished.
This. sync modifier was reintroduced in vue@2.3.0+and above.

// Parent component
<home :title.sync="title" />
//When compiled, it will be extended to
<home :title="title"  @update:title="val => title = val"/>

// Subcomponents
// So subcomponents can be changed by triggering update method with $emit
mounted(){
  this.$emit("update:title", 'This is new title')
}

3.10 v-slot

2.6.0 Added
1.slot,slot-cope,scope were discarded in 2.6.0, but not removed.
2. The function is to pass the template of the parent component into the child component.
3. Slot classification:
A. Anonymous slot (also known as default slot): No name, there is and only one;

// parent component
<todo-list> 
    <template v-slot:default>
       Arbitrary content
       <p> I'm an anonymous slot.</p>
    </template>
</todo-list> 

// Subcomponents
 <slot>I am the default value </slot>
// v-slot:default is more uniform in its sense of writing and its name is easy to understand, or it can be written without writing.

B. Named slots: relatively anonymous slot components with name tags;

// Parent component
<todo-list> 
    <template v-slot:todo>
       //Arbitrary content
       <p>I'm an anonymous slot. </p>
    </template>
</todo-list> 

//Subcomponents
<slot name="todo">I am the default</slot>

C. Scope slot: Data in a child component can be retrieved from the parent page (resolving that data can only be passed from the parent page to the child component)

// Parent component
<todo-list>
 <template v-slot:todo="slotProps" >
   {{slotProps.user.firstName}}
 </template> 
</todo-list> 
//slotProps can be named at will
//slotProps receives all v-bind:user="user" from the set of attribute data on the sub-component label slot

// Subcomponents
<slot name="todo" :user="user" :test="test">
    {{ user.lastName }}
 </slot> 
data() {
    return {
      user:{
        lastName:"Zhang",
        firstName:"yue"
      },
      test:[1,2,3,4]
    }
  },
// {user.lastName}} is the default data v-slot:todo is not the parent page (= "slotProps")

3.11 EventBus

1. To declare a global Vue instance variable EventBus, which stores all communication data and event monitoring on this variable;
2. Similar to Vuex. But this approach applies only to very small projects.
3. The principle is to use $on and $emit and instantiate a global vue for data sharing.

// In main.js
Vue.prototype.$eventBus=new Vue()

// Value Passing Component
this.$eventBus.$emit('eventTarget','This is eventTarget The value passed in')

// Receiving component
this.$eventBus.$on("eventTarget",v=>{
  console.log('eventTarget',v);//This is the value passed from EvetTarget.
})

4. Level and nested components can be implemented, but the corresponding event name EvetTarget must be globally unique.

3.12 broadcast and dispatch

vue 1.x has two methods, event broadcast and dispatch, but vue 2.x has been deleted
Here's the encapsulation of two methods

function broadcast(componentName, eventName, params) {
  this.$children.forEach(child => {
    var name = child.$options.componentName;

    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params));
    } else {
      broadcast.apply(child, [componentName, eventName].concat(params));
    }
  });
}
export default {
  methods: {
    dispatch(componentName, eventName, params) {
      var parent = this.$parent;
      var name = parent.$options.componentName;
      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;

        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    },
    broadcast(componentName, eventName, params) {
      broadcast.call(this, componentName, eventName, params);
    }
  }
}

3.13 Routing Reference

1. Programme I

// Routing Definition
{
  path: '/describe/:id',
  name: 'Describe',
  component: Describe
}
// Page Reference
this.$router.push({
  path: `/describe/${id}`,
})
// Page acquisition
this.$route.params.id

2. Programme II

// Routing Definition
{
  path: '/describe',
  name: 'Describe',
  omponent: Describe
}
// Page Reference
this.$router.push({
  name: 'Describe',
  params: {
    id: id
  }
})
// Page acquisition
this.$route.params.id

3. Programme III

// Routing Definition
{
  path: '/describe',
  name: 'Describe',
  component: Describe
}
// Page Reference
this.$router.push({
  path: '/describe',
    query: {
      id: id
  `}
)
// Page acquisition
this.$route.query.id

4. Comparison of three schemes
Parametric page refresh after scheme 2 will be lost
One parameter of the scheme is stitched in the back, ugly and revealing information.
Scheme 3 will not splice parameters in the back and refresh parameters will not be lost.

3.14 Vue.observable

2.6.0 Added
Usage: Make an object responsive. Vue uses it internally to process objects returned by data functions.

The returned objects can be directly used in rendering functions and computational attributes, and the corresponding updates will be triggered when changes occur.
It can also be used as minimal cross-component state memory for simple scenarios.

The principle of communication is essentially to realize a simple vuex by using Vue.observable

// File path - / store/store.js
import Vue from 'vue'

export const store = Vue.observable({ count: 0 })
export const mutations = {
  setCount (count) {
    store.count = count
  }
}

//Use
<template>
    <div>
        <label for="bookNum">Number</label>
            <button @click="setCount(count+1)">+</button>
            <span>{{count}}</span>
            <button @click="setCount(count-1)">-</button>
    </div>
</template>

<script>
import { store, mutations } from '../store/store' // Vue2.6 Added API Observable

export default {
  name: 'Add',
  computed: {
    count () {
      return store.count
    }
  },
  methods: {
    setCount: mutations.setCount
  }
}
</script>

4.render function

Scenario: Some of the code in the template will repeat a lot, so the render function will be useful at this time.

// Generate labels based on props
// primary
<template>
  <div>
    <div v-if="level === 1"> <slot></slot> </div>
    <p v-else-if="level === 2"> <slot></slot> </p>
    <h1 v-else-if="level === 3"> <slot></slot> </h1>
    <h2 v-else-if="level === 4"> <slot></slot> </h2>
    <strong v-else-if="level === 5"> <slot></slot> </stong>
    <textarea v-else-if="level === 6"> <slot></slot> </textarea>
  </div>
</template>

// Optimized version, using render function to reduce code repetition rate
<template>
  <div>
    <child :level="level">Hello world!</child>
  </div>
</template>

<script type='text/javascript'>
  import Vue from 'vue'
  Vue.component('child', {
    render(h) {
      const tag = ['div', 'p', 'strong', 'h1', 'h2', 'textarea'][this.level]
      return h(tag, this.$slots.default)
    },
    props: {
      level: {  type: Number,  required: true  } 
    }
  })   
  export default {
    name: 'hehe',
    data() { return { level: 3 } }
  }
</script>

2. Contrast between render and template
The former is suitable for complex logic, while the latter is suitable for simple logic.
The latter belongs to declaration and rendering, while the former belongs to self-defined Render function.
The former has higher performance, while the latter has lower performance.

5. Asynchronous components

Scenario: Too large a project can lead to slow loading, so asynchronous component implementation on-demand loading is what must be done.
1. Asynchronous registration component
Three methods

// Factory functions perform resolve callbacks
Vue.component('async-webpack-example', function (resolve) {
  // This particular `require'grammar will tell webpack
  // Automatically cut your build code into multiple packages
  // Load through Ajax request
  require(['./my-async-component'], resolve)
})

// Factory function returns Promise
Vue.component(
  'async-webpack-example',
  // This `import'function returns a `Promise' object.
  () => import('./my-async-component')
)

// Factory function returns a configurable component object
const AsyncComponent = () => ({
  // Components that need to be loaded (should be a `Promise'object)
  component: import('./MyComponent.vue'),
  // Components used when loading asynchronous components
  loading: LoadingComponent,
  // Components used when loading fails
  error: ErrorComponent,
  // Show the delay time of the component when loading. The default value is 200 (milliseconds)
  delay: 200,
  // If a timeout is provided and component loading is timed out,
  // The components used when the load fails are used. The default value is: `Infinity'.`
  timeout: 3000
})

The rendering of asynchronous components is essentially to perform rendering twice or more. First, the current component is rendered as a comment node. When the component is loaded successfully, the rendering is performed through forceRender. Or render it as a comment node and then as a loading node, rendering the component that is completed for the request

2. On-demand loading of routing

webpack< 2.4 Time
{
  path:'/',
  name:'home',
  components:resolve=>require(['@/components/home'],resolve)
}

webpack> 2.4 Time
{
  path:'/',
  name:'home',
  components:()=>import('@/components/home')
}

import()Method by es6 It is proposed that: import()The method is to load dynamically and return one Promise Objects, then The parameter of the method is the module loaded. Be similar to Node.js Of require Method, main import()The method is loaded asynchronously.

6. Dynamic components

Scenario: A tab switch involves dynamic loading of components

<component v-bind:is="currentTabComponent"></component>

But every time a component is reloaded, it consumes a lot of performance, so keep-alive works.

<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

In this way, the switching effect has no animation effect, and there is no need to worry about it. The built-in <transition> can be used.

<transition>
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>
</transition>

7. Recursive Components

Scenario: If you develop a tree component whose level is determined by background data, you need to use dynamic components at this time.

// Recursive Components: Components can recursively call themselves in their templates, as long as the name component is set to the component.
// Setting up so that House can be used recursively in the component template, but it should be noted that,
// A condition must be given to limit the number, otherwise an error will be thrown: max stack size exceeded
// Component recursion is used to develop independent components with specific unknown hierarchical relationships. For example:
// Joint selector and tree control 

<template>
  <div v-for="(item,index) in treeArr">
      //Subcomponent, current hierarchical value: {{index} <br/>
      <!-- Recursive call itself, Background judgement whether there is no change in value -->
      <tree :item="item.arr" v-if="item.flag"></tree>
  </div>
</template>
<script>
export default {
  // name must be defined for recursive invocation within a component
  name: 'tree',
  data(){
    return {}
  },
  // Receive external incoming values
  props: {
     item: {
      type:Array,
      default: ()=>[]
    }
  }
}
</script>

Recursive components must set name and end thresholds

8. Functional components

Definition: Stateless, unable to instantiate, without any lifecycle approach in-house
Rule: In versions prior to 2.3.0, the props option is required if a functional component wants to receive prop.

In versions 2.3.0 or above, you can omit the props option, and features on all components are automatically and implicitly resolved to prop.
In versions 2.5.0 and above, if you use a single file component (that is, a normal. vue file), you can declare function directly on the template.
Everything a component needs is passed through the context parameter

The context attribute has:
1.props: Provides all prop objects
2. Children: array of vnode children
3.slots: A function that returns the object containing all slots
4.scopedSlots: (2.6.0+) An object that exposes an incoming scoped slot. Normal slots are also exposed in the form of functions.
5.data: The entire data object passed to the component is passed into the component as the second parameter of the createElement
6.parent: Reference to parent components
7.listeners: (2.3.0+) An object that contains all event listeners registered by the parent component for the current component. This is an alias for data.on.
8.injections: (2.3.0+) If the inject option is used, the object contains attributes that should be injected

<template functional>
  <div v-for="(item,index) in props.arr">{{item}}</div>
</template>

9.components and Vue.component

Components: Locally registered components

export default{
  components:{home}
}

Vue.component: Global Register Component

Vue.component('home',home)

10.Vue.extend

Scenario: Some elements in the vue component need to be mounted on the element, and extension works at this point.
Is a grammar that constructs a component
Writing:

// Create constructors
var Profile = Vue.extend({
  template: '<p>{{extendData}}</br>The data passed in by the instance is:{{propsExtend}}</p>',//The outer layer of the label corresponding to template must have only one label
  data: function () {
    return {
      extendData: 'This is extend Extended data',
    }
  },
  props:['propsExtend']
})

// The constructor created can be mounted on elements or registered with components or Vue.component().
// Mounted on an element. It can be transmitted through propsData.
new Profile({propsData:{propsExtend:'I am the data passed in by the instance.'}}).$mount('#app-extend')

// Register through components or Vue.component()
Vue.component('Profile',Profile)

11.mixins

Scenario: Some components have some repetitive js logic, such as checking mobile phone validation code, parsing time, etc., mixins can achieve this kind of mixing.
The mixins value is an array

const mixin={
    created(){
      this.dealTime()
    },
    methods:{
      dealTime(){
        console.log('This is mixin Of dealTime Inside the method');
      }
  }
}

export default{
  mixins:[mixin]
}

12.extends

Extensions is very similar to mixins in usage, except that the parameters received are simple option objects or constructors, so extends can only extend one component at a time.

const extend={
    created(){
      this.dealTime()
    },
    methods:{
      dealTime(){
        console.log('This is mixin Of dealTime Inside the method');
      }
  }
}

export default{
  extends:extend
}

13.Vue.use()

Scenario: When we use element, we import first, then Vue.use(), which is actually registering components and triggering the install method.
This is often used in component calls.
It automatically organizes multiple registrations of the same plug-in.

14.install

Scenario: In Vue.use(), executing this method triggers install
The first parameter of this method is the Vue constructor, and the second parameter is an optional option object (optional).

var MyPlugin = {};
  MyPlugin.install = function (Vue, options) {
    // 2. Adding global resources, the second parameter passes a value corresponding to update by default.
    Vue.directive('click', {
      bind(el, binding, vnode, oldVnode) {
        //Prepare for binding, add time monitoring
        console.log('instructions my-directive Of bind Execution');
      },
      inserted: function(el){
      //Get the bound element
      console.log('instructions my-directive Of inserted Execution');
      },
      update: function(){
      //Perform corresponding updates based on the new values obtained
      //It will also be called once for the initial value.
      console.log('instructions my-directive Of update Execution');
      },
      componentUpdated: function(){
      console.log('instructions my-directive Of componentUpdated Execution');
      },
      unbind: function(){
      //Clean up
      //For example, event listeners that are bound when bind is removed
      console.log('instructions my-directive Of unbind Execution');
      }
    })

    // 3. Injection components
    Vue.mixin({
      created: function () {
        console.log('Injected component created Called');
        console.log('options The value is',options)
      }
    })

    // 4. Adding Instance Method
    Vue.prototype.$myMethod = function (methodOptions) {
      console.log('Example method myMethod Called');
    }
  }

  //Call MyPlugin
  Vue.use(MyPlugin,{someOption: true })

  //3. Mounting
  new Vue({
    el: '#app'
  });

Please stamp the operations of extend, mixins, extends, components, and install in vue for more details.

15. Vue.nextTick

2.1.0 Added
Scenario: Page loading requires text boxes to get focus
Usage: Delayed callbacks are performed after the end of the next DOM update cycle. Use this method immediately after modifying the data to obtain the updated DOM

mounted(){ //Because the mounted stage dom is not rendered, you need $nextTick
  this.$nextTick(() => {
    this.$refs.inputs.focus() //Get dom through $refs and bind the focus method
  })
}

16.Vue.directive

16.1 Use

Scenario: Officials have given us a lot of instructions, but if we want to turn text into a specified color and define instructions to use, we need to use Vue.directive at this time.

// Global Definition
Vue.directive("change-color",function(el,binding,vnode){
  el.style["color"]= binding.value;
})

// Use
<template>
<div v-change-color>{{message}}
</div>
</template>
<script>
  export default{
    data(){
      return{
        color:'green'
      }
    }
  }
</script>

16.2 Life Cycle

1.bind is invoked only once, when the instruction is first bound to an element. With this hook, you can define an initialization action to be performed once at the time of binding.
2. insert: Called when the bound element is inserted into the parent node (the parent node exists, but does not need to exist in the document)
3.update: Called when the binding is updated with the template where the element is located, and by comparing the binding values before and after the update, ignoring unnecessary template updates, regardless of whether the binding values have changed or not.
4. CompoonentUpdate: Called when the template of the bound element completes an update cycle
5.unbind: Called only once, when instructing the month element to unbind

17. Vue.filter

Scenario: Time stamp conversion to adult month day is a common method, so it can be extracted into filters for use

// Use
// In double brackets
{{ message | capitalize }}

// In `v-bind'
<div v-bind:id="rawId | formatId"></div>

// Global registration
Vue.filter('stampToYYMMDD', (value) =>{
  // processing logic
})

// Local registration
filters: {
  stampToYYMMDD: (value)=> {
    // processing logic
  }
}

// Global registration of multiple filters
// /src/common/filters.js
let dateServer = value => value.replace(/(\d{4})(\d{2})(\d{2})/g, '$1-$2-$3') 
export { dateServer }
// /src/main.js
import * as custom from './common/filters/custom'
Object.keys(custom).forEach(key => Vue.filter(key, custom[key]))

18.Vue.compile

Scenario: Compile Template Strings in render functions. Effective only when built independently

var res = Vue.compile('<div><span>{{ msg }}</span></div>')

new Vue({
  data: {
    msg: 'hello'
  },
  render: res.render,
  staticRenderFns: res.staticRenderFns
})

19.Vue.version

Scenario: Some development plug-ins need to be compatible with different vue versions, so Vue.version will be used.
Usage: Vue.version() can get vue version

var version = Number(Vue.version.split('.')[0])

if (version === 2) {
  // Vue v2.x.x
} else if (version === 1) {
  // Vue v1.x.x
} else {
  // Unsupported versions of Vue
}

20.Vue.set()

Scenario: When you use an index to set an array item directly or when you modify the length of the array, the data is not updated responsively due to the limitation of the Object.defineprototype() method.

However, vue.3.x will use proxy to solve this problem.

Solution:

// Using set
this.$set(arr,index,item)

// Using array push(),splice()

21.Vue.config.keyCodes

Scenario: Custom key modifier alias

// Define keycode 113 as f2
Vue.config.keyCodes.f2 = 113;
<input type="text" @keyup.f2="add"/>

22.Vue.config.performance

Scenario: listening performance

Vue.config.performance = true

Only for development patterns and browsers that support the performance.mark API

23.Vue.config.errorHandler

Scenarios: Processing functions that specify components that do not capture errors during rendering and observation
2. Rules:

  Starting from 2.2.0, this hook also captures errors in the component lifecycle hook. Similarly, when the hook is undefined, the captured error is output through console.error to avoid application crash
  Since 2.4.0, this hook will also catch errors inside the Vue custom event handler.
  Starting from 2.6.0, this hook will also catch errors thrown inside the v-on DOM listener. In addition, if any overwritten hook or processing function returns a Promise chain (such as an async function), then errors from its Promise chain are also handled.

3. Use

Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // ` info ` is a Vue-specific error message, such as the life-cycle hook where the error is located
  // Only 2.2.0 + Available
}

24.Vue.config.warnHandler

2.4.0 Added
Scenario: Give a custom handler for Vue runtime warnings, which only works in the developer environment
2. Usage:

Vue.config.warnHandler = function (msg, vm, trace) {
  // ` trace `is component inheritance tracing
}

25.v-pre

Scenario: vue is a responsive system, but some static tags do not need to be compiled many times to save performance

<span v-pre> {this will not be compiled} </span> shows {this will not be compiled}}
<span v-pre>{{msg} </span> Even if MSG is defined in data, {msg} is still displayed here.

26.v-cloak

Scenario: When using vue to bind data at a slow network speed, variable flicker occurs when rendering pages
Usage: This instruction remains on the element until the associated instance is compiled. When used with CSS rules such as [v-cloak] {display: none}, this instruction hides uncompiled Museache tags until the instance is ready

// In template
<div class="#app" v-cloak>
    <p>{{value.name}}</p>
</div>

// In css
[v-cloak] {
    display: none;
}

This will solve the flicker, but there will be a white screen, which can be used in combination with the skeleton screen.

27.v-once

Scenario: Some template s have static dom unchanged, which only needs to be rendered once to reduce performance overhead

<span v-once> At this point, you only need to load the label once</span>

The difference between v-once and v-pre:
v-once renders only once; v-pre does not compile and outputs as it is

28. Event modifiers

stop: Prevent bubbles
 prevent: prevent default behavior
 self: Bind only the element itself to trigger
 once: 2.1.4 added, triggered only once
 Passive: Added 2.3.0, the default behavior of rolling events (i.e. rolling behavior) will be triggered immediately and cannot be used with. prevent

29. Key modifiers and key codes

Scenario: Sometimes you need to monitor the keyboard behavior, such as pressing enter to query the interface, etc.

// Corresponding keywords on keyboard
.enter
.tab
 Delete (capture delete and backspace keys)
.esc
.space
.up
.down
.left
.right

30.Vue-router

Scenario: Vue-router is an officially provided routing plug-in

30.1 Caching and Animation

Routing is the use of official component vue-router, the use of methods I believe you are very familiar with;
Here I will describe the routing cache and animation.

<transition>
  <keep-alive v-if="aliveFlag"> //Because some pages, such as trying data statistics, need to refresh in real time, so there is no need for caching.
    <router-view/> //Routing label
  </keep-alive>
  <router-view v-else/>
</transition>

30.2 Global Routing Hook

1.router.beforeEach

router.beforeEach((to, from, next) => {
  console.log('Global Front Guard: beforeEach -- next Need to call') //This is commonly used for login interception, also known as navigation hook guard.
  if (path === '/login') {
    next()
    return
  }
  if (token) {
    next();
  } 
})

2.router.beforeResolve (v 2.5.0+)
Similar to beforeEach, the difference is that the parsing guard is invoked before the navigation is validated and after the guard and asynchronous routing components in all components are parsed.
Called after beforeEach

3.router.afterEach
Global post hook
Called at the end of all routing hops
These hooks will not accept the next function nor change the navigation itself.

30.3 Component Routing Hook

1.beforeRouteEnter
Called before rendering the corresponding routing of the component is confirmed, the usage and parameters are similar to router. beforeeast, and next needs to be invoked actively
At this point, the component instance has not been created and cannot access this
Component instances can be accessed by passing a callback to next. Callbacks are performed when navigation is validated, and component instances are taken as parameters of the callback method

beforeRouteEnter (to, from, next) {
  // There is no access to the component instance, this === undefined
  next( vm => {
    // Accessing component instances through `vm'
  })
}

2.beforeRouteUpdate (v 2.2+)
When the current routing changes and the component is reused, the instance can be accessed through this. next needs to be invoked actively and cannot be called back.

3.beforeRouteLeave
Called when navigation leaves the corresponding routing of the component, component instance this can be accessed. next needs to be invoked actively and cannot be called back.

30.4 Routing Mode

Set the mode attribute: hash or history

30.5 Vue.$router

this.$router.push(): jump to different url s, but this method adds a record back to the history stack and clicks back to return to the previous page
 this.$router.replace(): No record
 this.$router.go(n):n can be positive or negative. Positive number returns to the previous page, similar to window.history.go(n)

30.6 Vue.$route

Represents the routing object that is currently jumping, with the following attributes:
Name: Route name
path: path
query: Reference Received Value
params: Reference Received Value
FulPath: Completed parsed URL with query parameters and the full path of hash
matched: copy of routing record
redirectedFrom: The name of the route for the redirected source if there is a redirection

this.$route.params.id: Gets parameters passed through params or /: ID
 this.$route.query.id: Gets parameters passed through query

30.7 router-view key

Scenario: Because Vue reuses the same components, i.e. / page / 1 = > / page / 2 or / page? Id = 1 = > / page? Id = 2, when a link jump is made, hooks such as created, mounted, etc. will not be executed.

<router-view :key="$route.fullpath"></router-view>

In this way, both created and mounted components will be executed.

31.Object.freeze

Scenario: A long list of data, usually unchanged, but vue does the conversion of getter and setter
Usage: A new feature of ES5 that freezes an object and prevents it from being modified
Support: vue 1.0.18 + supports it. For objects frozen with freeze in data or vuex, vue does not convert getter to setter.
Note: Freezing is just a single property inside the freeze, and the reference address can be changed.

new Vue({
    data: {
        // vue does not bind object s in list s to getter or setter
        list: Object.freeze([
            { value: 1 },
            { value: 2 }
        ])
    },
    mounted () {
        // The interface will not respond because a single property is frozen
        this.list[0].value = 100;

        // In both cases, the interface responds.
        this.list = [
            { value: 100 },
            { value: 200 }
        ];
        this.list = Object.freeze([
            { value: 100 },
            { value: 200 }
        ]);
    }
})

32. Debugging template

Scenario: In the process of Vue development, you often encounter the problem of JavaScript variable error when template rendering. At this time, you may debug through console.log.
At this point, you can mount a log function in the development environment

// main.js
Vue.prototype.$log = window.console.log;

// Component internals
<div>{{log(info)}}</div>

33.vue-loader tips

33.1 preserveWhitespace

Scenario: Developing vue code usually has spaces, at which time packing compression will increase the volume of the package if the spaces are not removed.
Configuring preserveWhitespace reduces package size

{
  vue: {
    preserveWhitespace: false
  }
}

33.2 transformToRequire

Scenario: In the past, when writing Vue, I used to write code like this: require the picture ahead of time to a variable and then to the component.

// page code
<template>
  <div>
    <avatar :img-src="imgSrc"></avatar>
  </div>
</template>
<script>
  export default {
    created () {
      this.imgSrc = require('./assets/default-avatar.png')
    }
  }
</script>

Now: by configuring transformToRequire, you can configure it directly, so that vue-loader will automatically require the corresponding properties and pass them to the component

// The default configuration of vue-cli 2.x in vue-loader.conf.js is
transformToRequire: {
    video: ['src', 'poster'],
    source: 'src',
    img: 'src',
    image: 'xlink:href'
}

// Configuration file, if vue-cli2.x is modified in vue-loader.conf.js
  avatar: ['default-src']

// vue-cli 3.x in vue.config.js
{
  vue: {
    transformToRequire: {
      avatar: ['default-src']
    }
  }
}

// The page code can be simplified to
<template>
  <div>
    <avatar img-src="./assets/default-avatar.png"></avatar>
  </div>
</template>

34. Set aliases for paths

Scenario: In the development process, we often need to introduce various files, such as images, CSS, JS, etc. In order to avoid writing long relative paths (. /), we can configure an alias for different directories.

2.vue-cli 2.x configuration

// Add alias to the resolve configuration item in webpack.base.config.js
resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },

3.vue-cli 3.x configuration

// Create vue.config.js in the root directory
var path = require('path')
function resolve (dir) {
  console.log(__dirname)
  return path.join(__dirname, dir)
}
module.exports = {
  chainWebpack: config => {
    config.resolve.alias
      .set(key, value) // key,value defines itself, such as. set ('@', resolve ('src / components'))
  }
}

35.img failed to load

Scene: Sometimes the background return image address may not be able to open, so a default image should be added at this time.

// page code
<img :src="imgUrl" @error="handleError" alt="">
<script>
export default{
  data(){
    return{
      imgUrl:''
    }
  },
  methods:{
    handleError(e){
      e.target.src=reqiure('Picture Path') //Of course, if the project is configured with transformToRequire, refer to 27.2 above.
    }
  }
}
</script>

36.css

36.1 Local Style

1. The scoped attribute of style tag in Vue indicates that its style only acts on the current module and is style privatization.

2. Rules/Principles of Rendering:
Add a non-repetitive data attribute to the DOM node of HTML to represent uniqueness
Add a data attribute selector for the current component at the end of the corresponding CSS selector to privatize the style, such as:.demo[data-v-2311c06a] {}
If less or sass is introduced, it will only be set on the last element

// Original code
<template>
  <div class="demo">
    <span class="content">
      Vue.js scoped
    </span>
  </div>
</template>

<style lang="less" scoped>
  .demo{
    font-size: 16px;
    .content{
      color: red;
    }
  }
</style>

// Browser rendering effect
<div data-v-fed36922>
  Vue.js scoped
</div>
<style type="text/css">
.demo[data-v-039c5b43] {
  font-size: 14px;
}
.demo .content[data-v-039c5b43] { //There is no data attribute added to. demo
  color: red;
}
</style>

36.2 deep attribute

// Add A / deep to the above style/
<style lang="less" scoped>
  .demo{
    font-size: 14px;
  }
  .demo /deep/ .content{
    color: blue;
  }
</style>

// After compiling browser
<style type="text/css">
.demo[data-v-039c5b43] {
  font-size: 14px;
}
.demo[data-v-039c5b43] .content {
  color: blue;
}
</style>

Afterword

The original codeword is not easy, welcome star!

Topics: Javascript Vue Attribute Webpack less