--- 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> ```