---
tags: 教育訓練
---
[TOC]
# Vue3 學習整理
## 頁面開發
目標: 將頁面切成數個小元件(vue),控制每個vue檔最大不超過300~500行
### 開發元件
```javascript=
元件架構範例(Example.vue)
<template>
...
</template>
<script setup>
import {defineProps, defineEmits, defineExpose, toRefs} from
// 定義參數
const props = defineProps({
p1: {type: String, required: true},
p2: {type: String, required: false}
})
// 定義事件
const emit = defineEmits(['event1, event2'])
// 保留參數的reactive特性,例如想使用watch去監看參數的變化,
// 如果只想取值則可直接使用porps.p1
const { p1 } = toRefs(props)
watch (p1, (newValue)=>{...})
const onClicked = (value) => {
...
//發布事件'event1'
emit('event1', value)
}
const var1;
const doSomething = () => {...}
// 開放對外存取變數或函式
defineExpose({
var1,
doSomething,
})
</script>
```
### 在頁面中引用界面元件
```javascript=
在Overview頁面中引用上述"Example.vue"
<template>
<button @click="btnClick" />
<Example :p1="open" :p2="status" @event1="onEvent1" ref="exampleRef" />
</template>
<script setup>
//此為靜態載入,一開始Example.vue就載入
import Example from '@/components/Overview/Example.vue'
//取得Example元件的參考
const exampleRef = ref()
//傳入Example的參數
const open = ref()
const status = ref()
//收到Example的事件
const onEvent1 = (value) => {
console.log('收到 event1')
}
const btnClick = () => {
//執行Example中的函式
exampleRef.value.doSomething()
}
</script>
```
### 動態載入元件
如果元件一開始不需要被載入,例如被v-if限制,可使用動態載入功能,加速頁面載入
```javascript=
<template>
<Example v-if="enabled" />
</template>
<script setup>
import { defineAsyncComponent } from "vue";
const Example = defineAsyncComponent(() => import("@/components/Overview/Example.vue"))
const enabled = ref(false)
enabled.value = true // <-- 此時 Example才會載入
</script>
```
### 專案檔案架構配置(參考)
```
|
|
+-components/
| |
| +- Global/
| | |
| | +- (多個頁面會使用到的元件放在這)
| |
| +- Overview/ <--- 範例: Overview頁面的小元件放在這
| |
| +- Example.vue
|
+-views
|
+- Overview.vue
```
## Vee-Validate 表格驗証
```javascript=
範例模板
<template>
<form @submit="onSubmit">
<input v-model="formName"/>
<small><i>{{ errors.name }}</i></small>
<input v-model="formAddress"/>
<small><i>{{ errors.value }}</i></small>
</form>
</template>
<script setup>
import { useField, useForm } from 'vee-validate'
import * as yup from 'yup'
// 方法1: 使用yup驗証欄位
const formSchema = yup.object({
//label表示當錯誤時,用設定字串顯示欄位
name: yup.string().trim().required().label('My Name'),
address: yup.string().trim().required().label('My Address'),
})
// 方法2: 自訂驗証欄位
const formSchema = {
name(value) {
//return true or 'error message'
},
address(value) {
//return true or 'error message'
},
}
// meta: form詳細狀態(例如: meta.valid ...)
// errors: form驗証錯誤結果
// handleSubmit: 預設submit函式,不需再加prevent
// resetForm: form 重設
// setValues: 從程式中,設定值至欄位中
const { meta, errors, handleSubmit, resetForm, setValues } = useForm({
validationSchema: formSchema,
})
//form中的欄位名稱name,解構value值至formName變數中
const { value: formName } = useField('name')
const { value: formAddress } = useField('address')
// 上述的順序似乎會影響結果,先form再field
//當無效的submit發生時,如何處理(例如:跳到第一個錯誤的欄位),非必要,可忽略
function onInvalidSubmit({ values, errors, results }) {
console.log(values); // current form values
console.log(errors); // a map of field names and their first error message
console.log(results); // a detailed map of field names and their validation results
}
// submit函式,委由handleSubmit處理,不需再加prevent,values包括欄位的資料
// 亦可使用formName.value等方式處理
// onInvalidSubmit: (Optional)視需求使用
const onSubmit = handleSubmit(values => {
alert(JSON.stringify(values, null, 2));
}, onInvalidSubmit);
</script>
```
## Promise Dialog
對話框範例:
```javascript=
<template>
<CModal
:visible="dlgVisible"
@close="onClicked(0)">
<CModalFooter>
<button @click="onClicked(1)">OK</button>
</CModalFooter>
</CModal>
</template>
<script setup>
import { ref, defineExpose } from 'vue'
const dlgVisible = ref(false)
let promiseResolve = null
const onClicked = (value) => {
promiseResolve(value)
dlgVisible.value = false
}
const show = () => {
dlgVisible.value = true
return new Promise((resolve) => {
promiseResolve = resolve
})
}
defineExpose({
show,
})
</script>
```
使用方式:
```javascript=
<template>
<MessageBox ref="messageBoxRef" />
</template>
<script setup>
const messageBoxRef = ref()
let value = await messageBoxRef.value.show()
</script>
```