Detailed explanation of the API in Vue.js that is easy to overlook

Detailed explanation of the API in Vue.js that is easy to overlook

nextTick

nextTick is a function provided by Vue.js, not built-in in the browser. The nextTick function receives a callback function cb, which is executed after the next DOM update cycle. For example, the following example:

<template>
  <div>
    <p v-if="show" ref="node">Content</p>
    <button @click="handleShow">Show</button>
  </div>
</template>
<script>
  export default {
    data () {
      return {
        show:false
      }
    },
    methods: {
      handleShow() {
        this.show = true;
        console.log(this.$refs.node); // undefined
        this.$nextTick(() => {
          console.log(this.$refs.node); // <p>Content</p>
        });
      }
    }
  }
</script>

When show is set to true, the p node has not been rendered yet, so undefined is printed. In the nextTick callback, p has been rendered, so the node can be printed correctly.

The source code of nextTick is at github.com/vuejs/vue/b…. As you can see, Vue.js uses three methods: Promise, setTimeout and setImmediate to implement nextTick. Different methods are used in different environments.

v-model syntax sugar

v-model is often used for two-way binding of data on form elements, such as <input>. In addition to native elements, it can also be used in custom components.

v-model is a syntax sugar that can be broken down into props: value and events: input. That is to say, the component must provide a prop named value and a custom event named input. If these two conditions are met, the user can use v-model on the custom component. For example, the following example implements a number selector:

<template>
  <div>
    <button @click="increase(-1)">Decrease 1</button>
    <span style="color: red;padding: 6px">{{ currentValue }}</span>
    <button @click="increase(1)">Increase 1</button>
  </div>
</template>
<script>
  export default {
    name: 'InputNumber',
    props: {
      value: {
        type: Number
      }
    },
    data () {
      return {
        currentValue: this.value
      }
    },
    watch:
      value (val) {
        this.currentValue = val;
      }
    },
    methods: {
      increase(val) {
        this.currentValue += val;
        this.$emit('input', this.currentValue);
      }
    }
  }
</script>

Props generally cannot be modified within a component, but rather through its parent. Therefore, the implementation of v-model generally has an internal data called currentValue, which gets a value from value initially. When value is modified, it is updated in real time through watch. The component does not modify the value of value, but rather modifies currentValue. It also sends the modified value to the parent component through a custom event input. After receiving the value, the parent component modifies value. Therefore, the above number selector component can be used in the following two ways:

<template>
  <InputNumber v-model="value" />
</template>
<script>
  import InputNumber from '../components/input-number/input-number.vue';

  export default {
    components: { InputNumber },
    data () {
      return {
        value: 1
      }
    }
  }
</script>

or:

<template>
  <InputNumber :value="value" @input="handleChange" />
</template>
<script>
  import InputNumber from '../components/input-number/input-number.vue';

  export default {
    components: { InputNumber },
    data () {
      return {
        value: 1
      }
    },
    methods: {
      handleChange (val) {
        this.value = val;
      }
    }
  }
</script>

If you don't want to use the names value and input, starting from Vue.js 2.2.0, a model option is provided to specify their names, so the number selector component can also be written like this:

<template>
  <div>
    <button @click="increase(-1)">Decrease 1</button>
    <span style="color: red;padding: 6px">{{ currentValue }}</span>
    <button @click="increase(1)">Increase 1</button>
  </div>
</template>
<script>
  export default {
    name: 'InputNumber',
    props: {
      number: {
        type: Number
      }
    },
    model: {
      prop: 'number',
      event: 'change'
    },
    data () {
      return {
        currentValue: this.number
      }
    },
    watch:
      value (val) {
        this.currentValue = val;
      }
    },
    methods: {
      increase(val) {
        this.currentValue += val;
        this.$emit('number', this.currentValue);
      }
    }
  }
</script>

In the model option, you can specify the names of prop and event instead of value and input, because these two names have other uses in some native form elements.

.sync Modifier

If you have used Vue.js 1.x, you must be familiar with .sync. In 1.x, you can use .sync to bind data bidirectionally, which means that both the parent component and the child component can modify the data, and it is bidirectionally responsive. This usage is deprecated in Vue.js 2.x. The purpose is to decouple parent and child components as much as possible to prevent child components from accidentally modifying the state of parent components.

However, in Vue.js version 2.3.0, the .sync modifier was added, but its usage is not exactly the same as 1.x. 2.x's .sync is not a true two-way binding, but a syntax sugar. Data modification is still done in the parent component, not in the child component.

Still using the number selector example, this time we use .sync instead of v-model, and can rewrite it like this:

<template>
  <div>
    <button @click="increase(-1)">Decrease 1</button>
    <span style="color: red;padding: 6px">{{ value }}</span>
    <button @click="increase(1)">Increase 1</button>
  </div>
</template>
<script>
  export default {
    name: 'InputNumber',
    props: {
      value: {
        type: Number
      }
    },
    methods: {
      increase(val) {
        this.$emit('update:value', this.value + val);
      }
    }
  }
</script>

Use Cases:

<template>
  <InputNumber :value.sync="value" />
</template>
<script>
  import InputNumber from '../components/input-number/input-number.vue';

  export default {
    components: { InputNumber },
    data () {
      return {
        value: 1
      }
    }
  }
</script>

It seems to be much simpler than the implementation of v-model, but the effect is the same. There can only be one v-model in a component, but multiple .sync can be set. Although .sync is good, it also has limitations, such as:

  • Cannot be used with expressions (e.g. v-bind:title.sync="doc.title + '!'" is invalid);
  • It cannot be used on literal objects (e.g. v-bind.sync="{ title: doc.title }" will not work properly).

$set

$set has been introduced in the previous section. It is used in two situations:

Due to limitations in JavaScript, Vue cannot detect the following array changes:

  • When setting an item directly using its index, for example: this.items[index] = value;
  • When modifying the length of an array, for example: vm.items.length = newLength.

Due to limitations in JavaScript, Vue cannot detect the addition or removal of object properties.

For example,

// array export default {
  data () {
    return {
      items: ['a', 'b', 'c']
    }
  },
  methods: {
    handler () {
      this.items[1] = 'x'; // not responsive }
  }
}

Using $set:

// array export default {
  data () {
    return {
      items: ['a', 'b', 'c']
    }
  },
  methods: {
    handler () {
      this.$set(this.items, 1, 'x'); // is responsive }
  }
}

Take objects as an example:

// Object export default {
  data () {
    return {
      item:
        a: 1
      }
    }
  },
  methods: {
    handler () {
      this.item.b = 2; // not responsive }
  }
}

Using $set:

// Object export default {
  data () {
    return {
      item:
        a: 1
      }
    }
  },
  methods: {
    handler () {
      this.$set(this.item, 'b', 2); // is responsive }
  }
}

In addition, the following array methods can trigger view updates, which is responsive:

push(), pop(), shift(), unshift(), splice(), sort(), reverse().

Another trick is to copy an array first, then modify it by index, and then replace the entire original array, for example:

handler () {
  const data = [...this.items];
  data[1] = 'x';
  this.items = data;
}

Computed property set

Computed properties are simple and are used a lot, but most of the time, we just use its default get method, which is the usual conventional writing method, to get data that depends on other states through computed. for example:

computed: {
  fullName () {
    return `${this.firstName} ${this.lastName}`;
  }
}

The fullName here can actually be written as an Object instead of a Function. However, in the Function form, we use its get method by default. When written as an Object, we can also use its set method:

computed: {
  fullName:
    get () {
      return `${this.firstName} ${this.lastName}`;
    },
    set (val) {
      const names = val.split(' ');
      this.firstName = names[0];
      this.lastName = names[names.length - 1];
    }
  }
}

Computed properties are mostly only used for reading. After using set, they can be written. For example, in the above example, if this.fullName = 'Aresn Liang' is executed, the computed set will be called, and firstName and lastName will be assigned to Aresn and Liang.

Summarize

This concludes this article about the easily overlooked APIs in Vue.js. For more information about the easily overlooked APIs in Vue.js, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of Vue.js project API and Router configuration splitting practice
  • A comprehensive analysis of nextTick, the global API of vue.js

<<:  MySQL 8.0.20 installation tutorial and detailed tutorial on installation issues

>>:  How to Change Colors and Themes in Vim on Linux

Recommend

js to achieve a simple carousel effect

This article shares the specific code of js to ac...

ReactJs Basics Tutorial - Essential Edition

Table of contents 1. Introduction to ReactJS 2. U...

Discuss the value of Web standards from four aspects with a mind map

I have roughly listed some values ​​to stimulate ...

How to install and configure the Docker Compose orchestration tool in Docker.v19

1. Introduction to Compose Compose is a tool for ...

Implementing CommonJS modularity in browsers without compilation/server

Table of contents introduction 1. What is one-cli...

This article will show you how JavaScript garbage collection works

Table of contents 1. Overview 2. Memory Managemen...

The background color or image inside the div container grows as it grows

Copy code The code is as follows: height:auto !im...

MySQL database basic syntax and operation

MySQL database basic syntax DDL Operations Create...

CentOS 6-7 yum installation method of PHP (recommended)

1. Check the currently installed PHP packages yum...

Differences between ES6 inheritance and ES5 inheritance in js

Table of contents Inheritance ES5 prototype inher...

A simple method to implement Linux timed log deletion

Introduction Linux is a system that can automatic...

The specific use and difference between attribute and property in Vue

Table of contents As attribute and property value...

Detailed steps to install docker in 5 minutes

Installing Docker on CentOS requires the operatin...

Implementation of IP address configuration in Centos7.5

1. Before configuring the IP address, first use i...