iT邦幫忙

2023 iThome 鐵人賽

DAY 26
0
Software Development

30天!玩轉TypeScript開發書單系統系列 第 26

[Day26] 溝通吧!Vue3 元件家族如何講小故事呢?「defineEmits」與「defineProps」的應用

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20231010/20124462tvfhp74wNh.png


引言


今天會繼續實現我們表單中的「自訂資料夾」的功能
所以會用到async component
會把「資料夾」的資料做成 async API
父層是BookForm.vue
子層是AsyncSelectBookFolder.vue
並且包含 Folder Name List


示意圖


https://ithelp.ithome.com.tw/upload/images/20231010/20124462671t7JDlii.png


子元件溝通


檔案AsyncSelectBookFolder.vue
我們會用到defineEmits, defineProps,watch
並且使用Vue 3 的 Composition API 來定義一些組件的邏輯

<script setup lang="ts">
import { ref,watch } from "vue";
import { getBookFolders } from "../firebase";
import { DocumentData } from "firebase/firestore";

const folders = ref(<DocumentData>[]);
folders.value = await getBookFolders();



const selectedFolder = ref(folders.value[0].title);
const emit = defineEmits(["updateSelectFolderName"]);
const sendValueToParent = () => {
  emit("updateSelectFolderName", selectedFolder.value);
};

// 定義接受的 props
const props = defineProps({
  selectFolderName: {
    type: String,
    default: "",
  },
});
watch(() => props.selectFolderName, (forlderName) => {
        selectedFolder.value = forlderName;
});
</script>

這裡定義了一個 ref 叫 folders
並使用 getBookFolders API 非同步地從 Firebase 中取得資料夾資料
然後把取得的資料設定到 folders 的 value


觸發父組件事件


const emit = defineEmits(["updateSelectFolderName"]);
const sendValueToParent = () => {
  emit("updateSelectFolderName", selectedFolder.value);
};

定義了一個觸發事件的函數 emit
以及sendValueToParent方法
可以updateSelectFolderName 事件並
傳遞 selectedFolder.value 到父組件


定義 props 並監控它的改變


const props = defineProps({
  selectFolderName: {
    type: String,
    default: "",
  },
});

watch(() => props.selectFolderName, (folderName) => {
  selectedFolder.value = folderName;
});

做一個下拉選單

<template>
  <div class="mb-2">

    <i class="i-lucide:folder-search">資</i><label>資料夾位置</label>
    <select
      v-model="selectedFolder"
      @change="sendValueToParent"
      class="w-full px-3 py-2 box-border border rounded"
    >
      <option v-for="folder in folders" :key="folder.id" :value="folder.title">
        {{ folder.title }}
      </option>
    </select>
  </div>
</template>

父元件的溝通


這裡是檔案BookForm.vue

import AsyncSelectBookFolder from '../components/AsyncSelectBookFolder.vue';

//....
const handleFolderNameUpdate = (folderName:string) => {
  bookInfo.value.folderName = folderName;
}

寫入子元件

 <Suspense>
      <template #default>
        <!-- <MyAsyncComponent></MyAsyncComponent> -->
        <!-- .... 省略其他表格內容 -->
          <AsyncSelectBookFolder @updateSelectFolderName="handleFolderNameUpdate" :selectFolderName="bookInfo.folderName"></AsyncSelectBookFolder>
      </template>
      <template #fallback>
        <Loading></Loading>
      </template>
    </Suspense>

我們會使用 Vue 3 中的 <Suspense> 元素
用於實現異步加載和處理資料的情況
加載時顯示"Loading..."的效果
並在資料加載完成後顯示實際的內容

如果沒使用Suspense AsyncComponent 可能無法正常顯示

@updateSelectFolderName="handleFolderNameUpdate"
可以監聽子元件 <AsyncSelectBookFolder> 發送的 updateSelectFolderName 事件
當子元件觸發這個事件時
將調用 handleFolderNameUpdate 方法
並將新的 selectFolderName 值作為參數傳遞給它

那我們這一章節就先介紹到這邊
下一篇接續實現其他功能^^


上一篇
[Day25] 建構吧!書單系統「星級評分」與「書籍狀態」的Vue3 功能實現
下一篇
[Day27] 標籤吧!一文掌握Tags功能:Vue 3 + UnoCSS 設計元件
系列文
30天!玩轉TypeScript開發書單系統30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言