The article was first published on a personal blog

preface

When using VUE, you often encounter some problems. In fact, if you read the official documentation carefully, you will find that there are some special points that need to be noted in the documentation. In order to deeply understand the explanation of these problems in the official documents, I consulted some materials, combined with my own understanding, sorted out some common problems; If any aspect of the explanation is not quite reasonable, I hope various gods point out;

The article is long, but practical;

directory

  • In a component, data must be a function
  • Usage scenarios of $set in VUE
  • Vue life cycle details
  • Vue component communication
  • Vue component keep-alive
  • Arrow functions should not be used in life cycle functions /methods/watch
  • methods/computed/watch

1. In a component, data must be a function

The analogical reference data type Object is a reference data type. Each component’s data is the same address in memory.

So how do you make each component’s data independent of each other?

When a component is defined, data must be declared as a function that returns an initial data object, because the component may be used to create multiple instances. If data were still a pure object, all instances would share references to the same data object! By providing the data function, each time a new instance is created, we can call the data function to return a new copy of the original data.

2. Usage scenarios of $set in vue

Scenario 1:

The updated function is not triggered to modify the value of the array by the index of the array.

export default {
    data () {
        return {
            items: ['a'.'b'.'c']}; }, updated () {console.log('Data Update'.this.items[0]);
    },
    methods: {
        changeItem1 () {
            this.items[0] = 'x';
            console.log(111.this.items[0]);
        },
        changeItem2 () {
            this.$set(this.items, 0.'x');
            console.log(222.this.items[0]); }}};Copy the code

Execute changeItem1, console prints 111 ‘x’, no updated, view does not update execute changeItem2, console prints 222 ‘x’, data updates ‘x’; Triggers the updated view to update

Scenario 2: The addition and deletion of object attributes cannot be detected in the VUE

Data () {userProfile: {name: 'xiaoming ',}}Copy the code

Want to add an age attribute to userProfile

addProperty () {
     this.userProfile.age = '12';
     console.log(555, this.userProfile);
}
Copy the code

When the addProperty function is executed, the following is printed

555 {name: 'xiaoming ', age: '12'}Copy the code

But the updated is not triggered and the view is not updated to the one below

addProperty () {
      this.$set(this.userProfile, 'age', '12');
      console.log(666, this.userProfile);
 }
Copy the code

Execute again, data changes, trigger updated, view updates;

Sometimes you want to add multiple attributes to an existing Object, such as using the object.assign () or _.extend() methods to add attributes. However, new attributes added to an object do not trigger updates. In this case, you can create a new object that contains the properties of the original object and the new properties:

// Replace 'object. assign(this.someObject, {a: 1, b: 2})'
this.someObject = Object.assign({}, this.someObject, { a: 1.b: 2 })
Copy the code

This is a typical problem in VUE, use must be careful!

Here’s how it works:

Vue uses object.defineProperty to turn all properties into getters/setters when creating an instance. Let Vue track dependencies and notify properties of changes when they are accessed and modified. So the property must exist on the Data object for Vue to convert it so that it can be responsive.

When you add a newProperty to an object, the newProperty does not have a mechanism for vue to detect data updates (because it is added after initialization). Vue.$set lets vue know that you have added the property, and it will do something for you

3. Detailed explanation of vUE life cycle

1. Vue lifecycle

  • BeforeCreate: the component instance is just created before the component properties, such as the data property, are computed
  • Created: The component instance is created, the property is bound, but the DOM is not complete, and the $EL property does not exist
  • BeforeMount: before a template is compiled or mounted
  • Mounted: Indicates that a template is compiled or mounted
  • BeforeUpdate: Before a component is updated
  • Updated: After the component is updated
  • activated: for keep-aliveCalled when the component is activated
  • deactivated: for keep-aliveIs called when the component is removed
  • BeforeDestroy: Called before component destruction
  • Destoryed: invoked after component destruction

Ps: The following code can be directly copied out for execution

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, <meta HTTP-equiv =" x-UA-compatible "content=" IE =edge"> <title>Document</title> </head> <script Type = "text/javascript" SRC = "https://cdn.jsdelivr.net/vue/2.1.3/vue.js" > < / script > < body > < div id = "app" > {{a}} < / div > <script> var vm = new Vue({el: '#app', data: {a: 'vuejs',}, beforeCreate: function() {console.log(' create before '); console.log(this.a); console.log(this.$el); }, created: function() {console.log(' created after '); console.log(this.a); console.log(this.$el); }, beforeMount: function() {console.log(' beforeMount '); console.log(this.a); console.log(this.$el); }, mounted: function() {console.log(' after '); console.log(this.a); console.log(this.$el); }, beforeUpdate: function() {console.log(' before updating '); console.log(this.a); console.log(this.$el); }, updated: function() {console.log(' update completed '); console.log(this.a); console.log(this.$el); }, beforeDestroy: function() {console.log(' before component is destroyed '); console.log(this.a); console.log(this.$el); }, destroyed: function() {console.log(' after component is destroyed '); console.log(this.a); console.log(this.$el); }, }) </script> </body> </html>Copy the code

BeforeCreated: El and data are not initialized

Created: Data is initialized. El is not beforeMount. Mounted: The EL and data are initialized

Open the command line. On the command line, enter vm.a = 'change'; See the effectCopy the code

4. Vue component communication

1. The parent component passes data to the child component

In vue, props is used to pass data to the child component. 1): The child component creates a property in props to receive the value passed by the parent component. 2): registers the child component in the parent component

2. Child component passes data to parent component

Child components mainly pass data to parent components via events 1), The child component needs to trigger a custom event in some way, such as clicking on the event method. 2) Pass the value as the second argument to $emit, which will be passed as a real argument to the corresponding custom event method. 3) Register the child component in the parent component and bind the custom event listener to the child component tag

3. Child components pass data to child components

Vue find that there is no direct subcomponents child component parameter method, proposal will need to pass the data in the component, are combined into one component, if necessary subcomponents child component parameter, can spread to the parent component first, and then to the child components, in order to facilitate the development, the vue vuex launched a state management tool, can chew the parameters of the realization of the convenient between components recursive

Example code is as follows: Try to pass data from a parent component to a child component in the editor by referring to the relevant code

// The parent passes data to the child<! If you want to get the logo value from the parent, you need to use props[-- MSG is a variable defined in data (parent)'msg'], such as30After adding elements to props, there is no need to add variables to data (subcomponent) --><template>
  <div>
    <child  @transferuser="getUser" :msg="msg"></child>  
    <p>User name :{{user}}(I am the data passed from the child to the parent)</p>  
  </div>
</template>

<script>
    import child from './child.vue';
    export default {
        components: {
            child,
        },
        data() {
            return {
                user: ' '.msg: 'I'm a message from parent to child.'}; },methods: {
            getUser(msg) {
                this.user = msg;
                console.log(msg); ,}}};</script>
Copy the code

The child component passes data to the parent

// The child passes data to the parent<! --1.@ : short for V-on2.The child component passes data to the parent component primarily through events3.When the input value changes, username is passed to parent. Vue, first declaring a setUser, which is called with the change event4.In setUser, $emit is used to iterate over the transferUser event and returnthis. Username, where transferUser is a custom event that functions like a relay.this.username is passed to the parent component through this event --><template>
  <div>
      <div>{{msg}}</div>
      <span>The user name</span>
      <input v-model="username" @change='setUser'>Pass values to the parent component</button>
  </div>
</template>

<script>
    export default {
        data() {
            return {
                username: 'test'}; },props: {
            msg: {
                type: String,}},methods: {
            setUser() {
                this.$emit('transferuser'.this.username); ,}}};</script>
Copy the code

5. Keep-alive of vUE components

this component is related

  • activated: Called when the keep-alive component is activated
  • deactivated: Called when the keep-alive component is disabled

Keep the usage – the alive

  • <keep-alive>When dynamic components are wrapped, inactive component instances are cached rather than destroyed
  • <keep-alive>Is an abstract component: it does not render a DOM element on its own, nor does it appear in the parent component chain
  • When the component in<keep-alive>The inside is switched, it’sactivatedanddeactivatedThe two lifecycle hook functions will be executed accordingly

Specific examples are as follows

  • Is a simple TAB switch that you can try to put<keep-alive>After removing it, compare it, and you’ll see the benefits

test.vue

<template>
    <div class="test">
        <div class="testNav">
            <div :class="{'selected':tab === 1,'testTitle':true}" @click="toTab(1)">A title</div>
            <div :class="{'selected':tab === 2,'testTitle':true}"  @click="toTab(2)">Title 2</div>
        </div>
        <div class="container">
            <keep-alive>
                <Test1 v-if="tab === 1">
                </Test1>
                <Test2 v-else>
                </Test2>
            </keep-alive>
        </div>
    </div>
</template>

<script>
    import Test1 from './test1.vue';
    import Test2 from './test2.vue';
    export default {
        data() {
            return {
                tab: 1}; },components: {
            Test1,
            Test2,
        },
        methods: {
            toTab(index) {
                this.tab = index; }},}</script>

<style lang="less">
.test {
    width: 100%;
    .testNav {
        height: 60px;
        line-height: 60px;
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        .testTitle {
            flex: 1;
            text-align: center;
        }
        .selected {
            color: red; }}}</style>
Copy the code

The test results are as follows: Check the output of the console and the page to see if

works and when the activated and deactivated functions are triggered

  • When you open the page, the following appears

Use setTimeout to simulate the scenario of requesting a back-end interface

  • Click on thetitle2, the following situation occurs

  • Click again on thetitle1In the following case, you will find that the data requested from the back end will be displayed quickly, but if you do not use it at this time

Test1. vue and test2.vue

test1.vue

<template>
  <div class="test1">
      test1
      {{testInfo1}}
  </div>
</template>

<script>
    export default {
        data() {
            return {
                testInfo1: ' '}; },activated() {
            console.log('Test 1 is active');
        },
        deactivated() {
            console.log('Test 1 is cached');
        },
        created() {
            setTimeout(() = > {
                this.testInfo1 = 'This is test one.';
            }, 2000); }},</script>

Copy the code

test2.vue

<template>
  <div>
      test2
      {{testInfo2}}
  </div>
</template>

<script>
    export default {
        data() {
            return {
                testInfo2: ' ',}},activated() {
            console.log('Test 2 is active');
        },
        deactivated() {
            console.log('Test 2 is cached');
        },
        created() {
            setTimeout(() = > {
                this.testInfo2 = 'This is test two.';
            }, 2000); }},</script>
Copy the code

6. Arrow functions should not be used in lifecycle functions /methods/watch

The emergence of the arrow function in ES6 enables us to achieve functions with less code. However, it should be noted that the biggest difference between the arrow function and ordinary function is the pointing problem of this: the this of the arrow function points to the domain where the function is used, while the this of ordinary function points to the caller of the function;

This is already pointed out in a special reminder in the official documentation:

Vue’s lifecycle functions, methods, and Watch automatically bind this context to the instance, so you can access data and perform operations on properties and methods. This means that you can’t define a lifecycle method using the arrow function, because the arrow function is bound to the parent context, so this is different from what you would expect from a Vue instance

7.methods/computed/watch

methods VS computed

We can define the same function as methods or computed, and get the same result with both methods. The difference is that computed properties are cached based on their dependencies, and the computed properties are re-evaluated only when their associated dependencies change.

Applicable scenarios:

If recalculation is expensive, choose computed; Optional methods that do not want caching

computed vs watch

Watch has both old and new values. The calculated property does not, but the calculated property can get the new value from the setter

The computed

For computed properties, the default computed property of vue has only getters, so you need to add a setter if you want to use a getter

export default {
    data () {
        return {
            firstName: '张'.lastName: '三'}; },computed: {
        fullName() {
              return this.firstName + ' ' + this.lastName
        },
    },
    methods: {
        changeFullName () {
            this.fullName = 'four li'; }}}; So the complete code for computed iscomputed: {
   fullName: {
        // getter
        get: function () {
          return this.firstName + ' ' + this.lastName
        },
   }    
},
Copy the code

[Vue WARN]: Computed property “fullame” was assigned to but it has no setter.

We need to add a setter for the compute property fullName

computed: {
   fullName: {
        // getter
        get: function () {
          return this.firstName + ' ' + this.lastName
        },
        // setter
        set: function (newValue) {
          var names = newValue.split(' ')
          this.firstName = names[0]
          this.lastName = names[names.length - 1]}}},Copy the code

conclusion

The above questions can be found in the official vUE documents, of course, to understand why, but also need to start from vUE source analysis;

The next article will try to explain these issues from the source code and understand the overall programming of Vue.

Vue series of articles