讓你一看就明白的$nextTick講解

1.功能描述

今天我們要實現這個一個小功能;頁面渲染完成後展示一個div元素;當點擊這個div元素後;div元素消失;出現一個input元素;並且input元素聚焦,想必大傢覺得簡單,我們一起來看看~

創建一個組件,組件名稱NextTick.vue;

在頁面中引入註冊

2.父組件

<template>
  <div>
    <next-tick></next-tick>
  </div>
</template>

<script lang="ts">
import NextTick from "../components/NextTick.vue"
export default {
  name:"About",
  components:{
    NextTick
  },
}
</script>

3.子組件NextTick.vue

<template>
    <div>
        <div>我是組件</div>
        <div v-if="flag" class="sun" @click="handerClick">顯示input</div>
        <input v-else ref="inputRef" class="yuelaing"/>
    </div>
</template>
<script>
export default {
    data(){
        return{
            flag:true,
        }
    },
    methods: {
        handerClick(){
            this.flag=false;
            this.$refs.inputRef.focus();
        },
    },
}
</script>

4為什麼是undefined

this.flag=false;
this.$refs.inputRef.focus();

當執行頁面操作的時候,this.$refs.inputRef.focus();

是需要消耗時間的(還沒有還得及刷新;還是舊的頁面)

此時還沒有獲取到dom元素。

所以會報錯。

解決方式1:

因此隻要讓頁面能夠獲取元素就行;使用setTimeout

setTimeout(()=>{
      this.$refs.inputRef.focus();
},100)

這樣來處理這個問題,是可以的;

但是顯得非常的不專業;

解決方式2:

//當組件根據最新的data數據,重新在視圖上完成渲染後,在執行裡面的函調函數
this.$nextTick(()=>{
    this.$refs.inputRef.focus();
})

5.將v-if更改為v-show可以獲取焦點嗎?

有人說:因為v-if是動態創建和銷毀;在創建和銷毀的過程中,是需要時間的!所以才會使用v-if獲取不到元素節點,用v-show就可以避免。

感覺說的有點道理?

我們嘗試一下將v-if換成v-show

<template>
    <div>
        <div>我是組件</div>
        <div v-show="flag" class="sun" @click="handerClick">顯示input</div>
        <input v-show="!flag" ref="inputRef" class="yuelaing"/>
    </div>
</template>
<script>
export default {
    data(){
        return{
            flag:true,
        }
    },
    methods: {
        handerClick(){
            this.flag=false;
            console.log( this.$refs.inputRef);
            this.$refs.inputRef.focus();
        },
    },
}
</script>

6.實際結果

我們發現雖然是頁面沒有報錯,但是還沒有聚焦;改為v-show明顯也不能夠解決這個問題

之所以會出現這個問題,是因為子組件中將this.flag=false後,立刻去執行瞭下面的代碼

this.$refs.inputRef.focus();

而在執行的時候,視圖還沒沒有來得及刷新;還是舊的頁面,此時還不能夠獲取到dom元素,因此出現瞭undefined;也就是為什麼我們加上延時後就可以聚焦瞭;

當組件根據最新的data數據,重新在視圖上完成渲染後,在執行裡面的函調函數

這就是$nextTick的基本用法

this.$nextTick(()=>{
    this.$refs.inputRef.focus();
})

7.將組件變成頁面可以獲取焦點嗎?

又有人說:因為是子組件,子組件比父組件後渲染。所以沒有獲取到元素節點。

這也是理由….

感覺還沒有上一個小夥伴說的對,為瞭解決疑惑。我們決定將子組件變成頁面在看看

<template>
  <div>
    <div>我是組件</div>
    <div v-show="flag" class="sun" @click="handerClick">顯示input</div>
    <input v-show="!flag" ref="inputRef" class="yuelaing"/>
  </div>
</template>
<script>
export default {
  data(){
    return{
        flag:true,
    }
  },
  methods: {
      handerClick(){
        this.flag=false;
        this.$refs.inputRef.focus();
      },
  },
}
</script>

我們發現仍然不可以;這就充分說明瞭:更新data的數據後,vue並不是實時更新的。

數據更新到顯示到頁面有時間差,我們在時間差內調用頁面數據,當然獲取不到。

也就是說:Vue在更新 DOM 時是異步執行的

8.為什麼會有$nextTick

之所以會有$nextTick;因為在vue中數據發生變化後;視圖上的dom並不會立刻去跟新;dom的跟新是需要時間的

下面我們通過一個小實驗來看一下

<template>
  <div>
    <div ref="unique">
      <h1>{{ cont }}</h1>
    </div>
    <div  class="sun" @click="handerClick">改變值</div>
  </div>
</template>
<script>
export default {
  data(){
    return{
      cont:'我是默認值'
    }
  },
  methods: {
      handerClick(){
        this.cont='我改變瞭默認值';
        console.log('1==>',this.$refs.unique.innerText);
        this.$nextTick(()=>{
          console.log('2==>',this.$refs.unique.innerText);
        })
      },
  },
}
</script>

我們發現,第一次的值和第二次的值,是不一樣的;因為視圖上dom的跟新是需要之間的;我們在這個之間差內去獲取元素值;仍然是舊值;所以第一次的值是最初的值;第二次的值才是改變後的值;

由於我們希望跟新數據後,仍然可以立刻獲取dom上的值

所以vue提供瞭$nextTick就可以解決這個問題

9.Vue.nextTick和this.$nextTick差別

Vue.nextTick是全局方法

this.$nextTick( [callback] ) 是實例方法。

我們都知道一個頁面可以有多個實例,也就是說this.$nextTick可以精確到某個實例上。其實本質上兩個是一樣的。
隻是一個是全局,一個是精確到某一個實例。精確度不一樣而已。

10.使用 nextTick的一個小技巧

我們都知道在生命周期mounted渲染的時候,不能百分百保證所有的子組件都能夠被渲染,因此我們可以在mounted裡面使用 this.$nextTick,這樣就能保證所有的子組件都能被渲染到。

mounted鉤子在服務器端渲染期間不被調用。

mounted: function () {
  this.$nextTick(function () {
    //在數據發生變化,
    //重新在視圖上完成渲染後,在執行裡面的方法
    //這一句話等同與:
   //將回調延遲到下次 DOM 更新循環之後執行
   //等同於:在修改數據之後,然後等待 DOM 更新後在執行
  })
}

總結

到此這篇關於$nextTick的文章就介紹到這瞭,更多相關$nextTick講解內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: