Document some common potholes in development using Vue.

First declare myself a rookie, some descriptions may be biased, big guy light hammer, welcome clap brick.

Little Sunflower’s class begins!

Slot related:slotwithslot-scope

A single slot | anonymous slot

The two names above illustrate what it means:

  • A component can have only one slot of this class
  • Slots of this class are not configurednameattribute
<! -- Parent component -->
<template>
  <div class="father">
    <h3>The parent component</h3>
    <child>
      <div class="tmpl">
        <span>test1</span>
        <span>test2</span>
        <span>test3</span>
      </div>
    </child>
  </div>
</template>

<! -- Subcomponent -->
<template>
  <div class="child">
    <h3>Child components</h3>
    <slot></slot>
  </div>
</template>
Copy the code

The slot defined in the child component is replaced by the HTML template wrapped in the child of the parent component, which is rendered as:

<div class="father">
  <h3>The parent component</h3>
  <div class="child">
    <h3>Child components</h3>
    <div class="tmpl">
      <span>test1</span>
      <span>test2</span>
      <span>test3</span>
    </div>
  </div>
</div>
Copy the code
A named slot

The slot name property is not empty and can occur more than once in a component.

<! -- Parent component -->
<template>
  <div class="father">
    <h3>The parent component</h3>
    <child>
      <div class="tmpl" slot="first">
        <span>test1</span>
        <span>test2</span>
        <span>test3</span>
      </div>
      <div class="tmpl" slot="second">
        <span>test4</span>
        <span>test5</span>
        <span>test6</span>
      </div>
      <div class="tmpl">
        <span>test7</span>
        <span>test8</span>
        <span>test9</span>
      </div>
    </child>
  </div>
</template>

<! -- Subcomponent -->
<template>
  <div class="child">
    <h3>Child components</h3>
     <! -- named slot -->
    <slot name="first"></slot>
     <! -- named slot -->
    <slot name="second"></slot>
     <! -- Anonymous slot -->
    <slot></slot>
  </div>
</template>
Copy the code

An anonymous slot in a component can be used in conjunction with a named slot and:

  • The statementnameThe named slot will be found in the parent component with its corresponding nameslotProperty and willhtmlTemplate replacement into it
  • Not a statementnameWill find the corresponding undeclaredslotProperties of thehtmlTemplate to replace.
Scope slot

As you can see, the content of the HTML template in both slots is specified by the parent component. What if I want to display the content from the child component?

So there is a third type of slot, which we call a scoped slot, also known informally as a data-carrying slot, which, as the name implies, can carry data to the HTML template in the parent component.

<! -- Parent component -->
<template>
  <div class="father">
    <h3>The parent component</h3>
    <child>
      <template slot-scope='scope'>
        <div class="tmpl">
          <span v-for='u in scope.data'>test1</span>
        </div>
      </template>
    </child>
  </div>
</template>

<! -- Subcomponent -->
<template>
  <div class="child">
    <h3>Child components</h3>
     <! -- Scope slot -->
    <slot :data="arr"></slot>
  </div>
</template>
<script>
export default {
  data () {
    return {
      arr: ['test1'.'test2'.'test3']}}}</script>
Copy the code

The child component defines an array of data to the parent component for display. The parent component receives the array from the child component in ${slotScopeName}. Data format for display.

When you want to add a custom parameter to a third-party UI library Event

<el-date-picker v-model="editForm[item.name]" 
    placeholder="Select date"
    :editable="false" style="width:100%"
    @change="(value) => changeHandler(value, item.name)">
</el-date-picker>
Copy the code

As shown above, using the arrow function, return a new custom function and add the desired parameters to the custom changeHandler.

When the same route has different parameters

If jump from app/12345 to app/23456, both routes may be app/: ID, using the same component, so vUE will not go through the life cycle again, resulting in some possible data update bug.

Therefore, a good solution is to monitor route changes to refresh a necessary parameter.

watch: {
    '$route.params': function (newValue) {
      this.init()
    }
}
Copy the code

watch

The above is a common watch, but you may not know that watch has two more practical configurations: deep and immediate.

deep

Deep, the default is false. As the name implies, watch will walk through the OBJ layer by layer, adding listeners to all properties of the object. As you can imagine, the performance cost of this approach is relatively large.

watch: {
    obj: {
        handler (newVal, oldVal) {
            console.log('Obj's properties have changed')},deep: true}},// Recommended
watch: {
    'obj.key': {
        handler (newVal, oldVal) {
            console.log('Obj's property key has changed')}}}Copy the code
immediate

Immediate: The default value is false. The handler method is executed as soon as the handler method is defined.

watch: {
 firstName: {
  handler (newval, oldVal) {
   this.fullName = `${newval} The ${this.lastName}`
  },
  immediate: true}}Copy the code

The timer

Many times we may have a need to write a timer (such as a polling task), and when we leave the page, you will find that the timed task is still running and performance is exploding.

So here’s what we can do:

data() {
    return {
        timer: null
    }
}
methods: {
    timing() {
        this.timer = setInterval((a)= > {
            // dosomething
        }, 100)
    }
}
beforeDestroy() {
    clearInterval(this.timer) // Clear the scheduled task when the component is about to be destroyed
    this.timer = null // Release variables
}
Copy the code

The key is to clear the scheduled task when we leave the page (before the component is destroyed).

Route lazy loading

Vue’s first screen rendering was criticized for being slow.

The reason is that the webPack package is too large, resulting in a large number of files to load when entering the home page.

In this way, we can use lazy loading to split the page (vue-Router supports the asynchronous module loading system built into Webpack, and uses fewer routing components, which are no longer packaged into bundles, but only loaded on demand when the route is accessed), and load the page on demand to reduce the burden of loading the home page.

General non-lazy load route configuration
import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/components/Login'
import Home from '@/components/Home'
import Profile from '@/components/Profile'

Vue.use(Router)

export default new Router({
    routes: [{
        path: '/login'.name: 'Login'.compontent: Login
    }, {
        path: '/home'.name: 'Home'.compontent: Home
    }, {
        path: '/profile'.name: 'Profile'.compontent: Profile
    }]
})

Copy the code
Lazy loading of route configuration

Webpack supports the following three commonly used notations.

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
    routes: [{
        path: '/login'.name: 'Login'.compontent: resolve= > require(['@/component/Login'], resolve)
    }, {
        path: '/home'.name: 'Home'.compontent: (a)= > import(/* webpackChunkName: "home" */  '@/component/Home')}, {path: '/profile'.name: 'Profile'.compontent: r= > require.ensure([], () => r(require('@/component/Profile')), 'profile')}]})Copy the code

Computed

Let’s start with some code:


      
<html>

    <head>
        <meta charset="utf-8">
        <title>Computed</title>

    </head>

    <body>
        <div id="app">
            <label for="">FirstName:<input v-model="firstName"/></label><br>
            <label for="">The LastName:<input v-model="lastName"/></label><br>
            <label for="">NickName<input v-model="nickName"/></label><br>
            <p>Name: {{name}}</p>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
        <script>
            new Vue({
                el: '#app'.data: function() {
                    return {
                        firstName: ' '.lastName: ' '.nickName: ' '}},computed: {
                    name: function() {
                        console.log('Triggered computed')
                        if (this.nickName) {
                            return this.nickName
                        } else {
                            return this.firstName + '. ' + this.lastName
                        }
                    }
                }
            })
        </script>
    </body>
</html>
Copy the code

Naively, we might think that every nickName, firstName, or lastName change would retrigger the name change.

“NickName” = “nickName”, “nickName” = “nickName”, “nickName” = “nickName”, “nickName” = “nickName” When nickName is null again, dependencies on firstName, lastName, and so on are collected.

In other words, dependency collection is dynamic.

Re – render related

Here’s the code:


      
<html>

    <head>
        <meta charset="utf-8">
        <title>Re-render</title>

    </head>

    <body>
        <div id="app">
            <div v-for="(item, index) in items" :key="index">
                <div v-if="index === 0">
                    <input v-model="formData[item.key]">
                </div>
                <div v-else>{{item. Key}}, {{Date. Now ()}}</div>
            </div>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
        <script>
            new Vue({
                el: '#app',
                data: function(a) {
                    return {
                        items: [{
                            key: 'input'
                        }, {
                            key: 'Re-render'
                        }],
                        formData: {
                            input: ' '}}}})</script>
    </body>
</html>
Copy the code

This is probably a common scenario. We would be surprised to see the page re-render with a new timestamp when the value in the input box changes. It’s not hard to see the problem with date.now (), which is a method (though not defined in the instance’s methods), so every time the Template is re-rendered it fires again, causing an unexpected accident.

<div id="app">
    <div>
    	<label>Input:<input v-model="model"/></label>
    </div>
    <div>
    	<child :items="makeItems()"></child>
    </div>
</div>
Copy the code

The above might be more illustrative, but in some scenarios we might use a method to pass props to a child component without thinking about it or subconsciously. When the input value model changes, the parent component template is rerendered. The items of the child are rerendered from method, causing unnecessary trouble.

Therefore, using computed is recommended in some scenarios to avoid this unnecessary hassle, because computed attributes are cached based on their dependencies, whereas Method always executes the function again when it triggers re-rendering without caching.

.

To be continued…