$nextTick詳細講解保證你一看就明白

本文已參與好文召集令活動,點擊查看:後端、大前端雙賽道投稿,2萬元獎池等你挑戰!前端

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>
複製代碼

01.gif

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>
複製代碼

02.gif

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>
複製代碼

03.png

咱們發現,第一次的值和第二次的值,是不同的;
由於視圖上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 更新後在執行
  })
}
複製代碼
相關文章
相關標籤/搜索