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

Solution to the problem of installing MySQL compressed version zip

There was a problem when installing the compresse...

About WSL configuration and modification issues in Docker

https://docs.microsoft.com/en-us/windows/wsl/wsl-...

js object-oriented method to achieve drag effect

This article shares the specific code for impleme...

Interpretation of syslogd and syslog.conf files under Linux

1: Introduction to syslog.conf For different type...

MySQL uninstall and install graphic tutorial under Linux

This is my first time writing a blog. I have been...

HTML meta usage examples

Example Usage Copy code The code is as follows: &l...

Basic JSON Operation Guide in MySQL 5.7

Preface Because of project needs, the storage fie...

Randomly generate an eight-digit discount code and save it to the MySQL database

Currently, many businesses are conducting promoti...

Brief analysis of the MySQL character set causing database recovery errors

Importing data with incorrect MySQL character set...

Using cursor loop to read temporary table in Mysql stored procedure

cursor A cursor is a method used to view or proce...

Web page html special symbols html special characters comparison table

Special symbols Named Entities Decimal encoding S...

Implementation of debugging code through nginx reverse proxy

background Now the company's projects are dev...

Ajax jquery realizes the refresh effect of a div on the page

The original code is this: <div class='con...