Why nextTick
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>example</title> </head> <body> <div id="app"> <div V-if ="isShow"> <input type="text" ref="userName" /> </div> <button @click="showInput"> </html> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> var app = new Vue({ el: '#app', data: { isShow: false }, methods:{ showInput(){ this.isShow = true this.$refs.userName.focus() } } }) </script>Copy the code
The result is an error, the node could not be found. In other words, when you reach isShow=true, the DOM node has not yet been updated and you have to wait for the DOM to be updated before you can perform focus.
With a MessageChannel implementation
<! DOCTYPE html> <html lang="en-zh"> <head> <meta charset="utf-8" /> <style type="text/css"> </style> </head> <body> <div Id ="app"> <div v-if="isShow"> <input type="text" ref="userName" /> </div> </body> </html> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> var app = new Vue({ el: '#app', data: { isShow: false }, methods: { showInput(){ this.isShow = true; this.myNextTick(() => { this.$refs.userName.focus(); }) }, myNextTick(fanc){ var that = this; const ch = new MessageChannel(); const port1 = ch.port1; const port2 = ch.port2; port2.onmessage = (() => { fanc(); }) port1.postMessage(1); } } }) </script>Copy the code
Use MutationObserver implementation
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>example</title> </head> <body> <div id="app"> <div V-if ="isShow"> <input type="text" ref="userName" /> </div> <button @click="showInput"> </html> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> var app = new Vue({ el: '#app', data: { isShow: false }, methods:{ showInput(){ this.isShow = true this.mynextTick(()=>{ this.$refs.userName.focus() }) }, MynextTick (func){var textNode = document.createTextNode(0) var that = this var callback = function(mutationsList, observer) { func.call(that); / / or / / fanc (); } var observer = new MutationObserver(callback); Observe.observe.observe (textNode,{characterData:true}) TextNode. data = 1Copy the code
Why deprecate MessageChannel and use MutationObserver
Vue2 replaced MessageChannel with MutationObser on December 20, 2018 (many blogs say the opposite, but git timeline looks like this).
Because MutationObserver is a macro task and MessageChannel is a micro task, it must have been chosen for this reason.
<! DOCTYPE html> <html lang="en-zh"> <head> <meta charset="utf-8" /> <style type="text/css"> </style> </head> <body> <div Id ="app"> <div v-if="isShow"> <input type="text" ref="userName" /> </div> </body> </html> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> var app = new Vue({ el: '#app', data: { isShow: false }, methods: { showInput(){ this.isShow = true; this.myNextTick1(() => { this.$refs.userName.focus(); }) this.myNextTick2(() => { this.$refs.userName.focus(); }) }, myNextTick1(fanc){ var that = this; const ch = new MessageChannel(); const port1 = ch.port1; const port2 = ch.port2; port2.onmessage = (() => { console.log('1') fanc(); }) port1.postMessage(1); }, myNextTick2 (fanc) { var that = this; var textNode = document.createTextNode('0'); var callback = function(mutationList, observer){ console.log('2') fanc(); } var observer = new MutationObserver(callback); observer.observe(textNode, {characterData: true}); textNode.data = 1; } } }) </script>Copy the code
Print it out:
2
1
Copy the code
Instead of executing them sequentially, the macro task MutationObserver is followed by the micro task MessageChannel.