iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0
Vue.js

業主說給你30天學會Vue系列 第 13

V13_快速檢視Vue的功能(3)_Vue的生命週期與監看

  • 分享至 

  • xImage
  •  

V13_快速檢視Vue的功能(3)_Vue的生命週期與監看

接著從 Try the Tutorial 網頁來開始學習
網址為 https://vuejs.org/tutorial

接續上一篇,接下來是
9. Lifecycle and Template Refs
App.vue

<script setup>
import { ref, onMounted } from 'vue'

const pElementRef = ref(null)

onMounted(() => {
  pElementRef.value.textContent = 'mounted!'
})
</script>

<template>
  <p ref="pElementRef">hello</p>
</template>

https://ithelp.ithome.com.tw/upload/images/20230927/20152098mqOiVA6Ws5.png

在這裡可以看到引入了 ref 的屬性
流程是

先宣告一個ref物件變數 const pElementRef = ref(null) 初始值是 null
然後將 pElementRef 指定給在<template>中的<p>元件的 ref 的屬性
可以看作是透過 <p ref="pElementRef">hello</p>
變數 pElementRef 就綁定到 <p>

這很像之前提到 不同的變數宣告可以綁定到 :id, :class, :key, @click, v-bind, v-if 等等,只是這次綁定的是DOM的元件本身,像是 <p>

在 onMounted()的事件中 看到
pElementRef.value.textContent = 'mounted!'

pElementRef是 綁定<p>的ref物件
pElementRef.value 才是 <p> 本身
所以 pElementRef.value.textContent 指的是 <p>的內容
pElementRef.value.textContent = 'mounted!' 就是 <p>的內容改為 'mounted!'

這樣在 pElementRef.value 所作的操作,就會反應連動到 <p> 元件上了

再來有看到 onMounted() 這個功能,這個前面沒有 加上function,所以是vue物件的事件,就是當vue被掛載的時候觸發的事件,
然後執行 pElementRef.value.textContent = 'mounted!' 的動作

這個 onMounted() 是指 App.vue被掛載到 index.html的
<div id="app"></div>上,
更細部的來說

index.html

<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>

main.js

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

App.vue

<script setup>
import { ref, onMounted } from 'vue'

const pElementRef = ref(null)

onMounted(() => {
  pElementRef.value.textContent = 'mounted!'
})
</script>

<template>
  <p ref="pElementRef">hello</p>
</template>

在index.html執行了main.js
在main.js中 載入了 App.vue 這個vue物件,並命名為App
然後利用 createApp(App).mount('#app')

createApp(App) 建立了App物件,並掛載到 id為app的DOM的元件上
也就是 <div id="app"></div>

這時 App.vue 中的 <script setup>, <template>, <style>就會render 渲染到 <div id="app"></div>中了

因此,在App.vue 在執行 mount('#app') 時,就會觸發 onMounted()事件了。

另外,const pElementRef = ref(null) 中的null,代表pElementRef是null物件,

或是也可以寫成
const pElementRef = ref() 代表 pElementRef是未定物件 undefined ,

直到 <p ref="pElementRef">hello</p> 中的
ref="pElementRef" 綁定後,pElementRef的物件就確定是 <p> 的DOM元件了

//---------------------
接著看到 onMounted() 這個功能其實是vue物件的lifecycle生命週期的其中一個事件
可以參考vue.js官網上的架構圖及說明,稱之為 Lifecycle Hooks
https://vuejs.org/guide/essentials/lifecycle.html

Hooks 字面上是掛勾的意思,
Lifecycle Hooks 可以看做是 vue物件的lifecycle中,有不同的階段,
要監看這些階段的狀態或是事件的觸發,就要掛上掛勾來產生連結,有點像是註冊要監看的項目
最常需要hook的事件有 onMounted 掛載時,onUpdated 狀態更新時, onUnmounted 卸載時

詳細的 Lifecycle Hooks API說明,可參考vue.js官網
Composition API: Lifecycle Hooks
https://vuejs.org/api/composition-api-lifecycle.html

https://ithelp.ithome.com.tw/upload/images/20230927/20152098nosUtqvxbg.png
(圖片來源: https://vuejs.org/guide/essentials/lifecycle.html#lifecycle-diagram)

這個是 onUpdated()的範例

<script setup>
import { ref, onUpdated } from 'vue'

const count = ref(0)

onUpdated(() => {
  // text content should be the same as current `count.value`
  console.log(document.getElementById('count').textContent)
})
</script>

<template>
  <button id="count" @click="count++">{{ count }}</button>
</template>

當按下click時 執行 count++,這時 const count = ref(0) 的數值改變了,
觸發 onUpdated(),接著執行 console.log(document.getElementById('count').textContent)
這時 document.getElementById('count') 呼叫 id為count的 <button>元件
讀取 <button>元件的 textContent內容,同時顯示在console主控台上。

要注意的是,不要在 onUpdated()中,改變count的數值,這樣會引發無窮的 onUpdated() 事件觸發

接下來是
10. Watchers
App.vue

<script setup>
import { ref, watch } from 'vue'

const todoId = ref(1)
const todoData = ref(null)

async function fetchData() {
  todoData.value = null
  const res = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
  )
  todoData.value = await res.json()
}

fetchData()

watch(todoId, fetchData)
</script>

<template>
  <p>Todo id: {{ todoId }}</p>
  <button @click="todoId++">Fetch next todo</button>
  <p v-if="!todoData">Loading...</p>
  <pre v-else>{{ todoData }}</pre>
</template>

https://ithelp.ithome.com.tw/upload/images/20230927/2015209811reBdKaWN.png

在這個範例中 引入了 watch() 的用法
先前是針對 vue 物件的 lifecycle 狀態的監看

現在是要針對宣告的 ref 物件的狀態的監看,
這時就會使用到 watch 的功能了
首先,宣告了2個 ref 物件 todoId 及 todoData

接著宣告了一個非同步的function
async function fetchData()
function中,先執行 todoData.value = null 將 todoData的物件設定為null
接著執行

const res = await fetch(
  `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)

等待 讀取網路資料 網址URL為 `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
這裡使用到 樣版字串的語法,其中 加入變動的數值 ${todoId.value}

因為 const todoId = ref(1) 初值是1
最後 網址URL 變成 https://jsonplaceholder.typicode.com/todos/1

然後再將讀到的網路資料傳給變數 res

await fetch() 這個是指,要等到 fetch()的動作完成才會執行下一步,也就是要等到讀取完網路資料後,才會下一步

todoData.value = await res.json() 是指將res的資料轉換成JSON的資料格式,然後等待轉換完成,再傳到 todoData.value的數值中

接著是

<p v-if="!todoData">Loading...</p>
<pre v-else>{{ todoData }}</pre>

就是 當todoData為null時,代表還沒讀完網路資料,則呈現 <p>Loading...</p>
當讀完資料時,todoData不為null,則呈現 <pre>{{ todoData }}</pre>

<button @click="todoId++">Fetch next todo</button>

是指當 按下button時,觸發click,執行 todoId++,
這時 todoId數值變動了,觸發了 watch(todoId, fetchData)
代表利用 watch 監看 todoId 的狀態,
若 todoId 的狀態改變了,則執行 fetchData,讀取新的網路資料,
再連動到

<p>Todo id: {{ todoId }}</p>
<button @click="todoId++">Fetch next todo</button>
<p v-if="!todoData">Loading...</p>
<pre v-else>{{ todoData }}</pre>

整理一下,流程為
一開始先執行 fetchData(),然後讀取網路資料,渲染<template>呈現
接著監看 todoId 的狀態,
當按下<button>,執行todoId++,todoId狀態改變,
執行fetch(),然後讀取網路資料,更新渲染<template>呈現,
結束這回合

這裡有一個語法
<button @click="todoId++">Fetch next todo</button>

@click="todoId++" 是一種 Inline handlers,
變數 todoId 的運算 不需改成 todoId.value 可以直接寫成 todoId++
反而 todoId.value++ 會產生錯誤

另一種是 Method Handlers

<script setup>
import { ref, watch } from 'vue'

const todoId = ref(1)

function add_todoId() {
  todoId.value++
}

</script>

<template>
  <p>Todo id: {{ todoId }}</p>
  <button @click="add_todoId">Fetch next todo</button>
</template>

按下 click後,執行 add_todoId,在add_todoId中
就要使用 todoId.value++

為了確認想法

<script setup>
import { ref, watch } from 'vue'

const todoId = ref([])
const count = ref(1)

</script>

<template>
  <p>Todo id: {{ todoId }}</p>
  <button @click="todoId.push(count++)">Fetch next todo</button>
</template>

https://ithelp.ithome.com.tw/upload/images/20230927/20152098tgZo203Cie.png

當todoId為陣列時,Inline handlers就可以寫成
@click="todoId.push(count++)"

由這幾篇的發文中,可以發現Vue的架構特色就是各種的綁定,引用,連動,監看
透過 ref() 建立 綁定關係,掌握這個原則,再看Vue的文件時,
就會非常的順手了。


上一篇
V12_快速檢視Vue的功能(2)_v-if條件及v-for迴圈操作
下一篇
V14_快速檢視Vue的功能(4)_Vue元件之間的props、emits與slots
系列文
業主說給你30天學會Vue31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言