[Vue] 引用外部套件
TL;DR
在載入套件的時候,可以使用npm或是cdn的方式引入。
載入後,則是可以透過app.use
或是元件的方式去啟用。
參考資料
- 如何為單一表單(input) 進行驗證 | 六角學院HackMD
相關連結
- vue-axios (app.use範例)
- VeeValidate | 元件範例
- Vite | Official
- create-vue | Github
- random user | 測試用假資料API
CDN載入VeeValidate
官方簡單範例
- html(#app)
- vue
- css
<div id="app">
<!-- 送出表單時,v-form會自動驗證規則是否符合 -->
<v-form @submit="onSubmit">
<!-- name內的名稱可以自訂,會對應錯誤訊息的name (元件需要加上頭尾標籤)-->
<v-field name="name" type="text" placeholder="Who are you" :rules="isRequired"></v-field>
<!-- name對應v-field上的name -->
<error-message name="name"></error-message>
<button>Submit</button>
</v-form>
</div>
const App = {
components: {
// Components were renamed to avoid conflicts of HTML form element without a vue compiler
// 因為使用CDN載入,預設會將套件賦予到VeeValidate這個變數上,我們要將VeeValidate物件下的各個元件給取出
// 為了避免與HTML標籤搞混,這邊加上V前綴做為辨識
VForm: VeeValidate.Form,
VField: VeeValidate.Field,
ErrorMessage: VeeValidate.ErrorMessage,
},
methods: {
isRequired(value) {
if (!value) {
return 'this field is required';
}
return true;
},
onSubmit(values) {
alert(JSON.stringify(values, null ,2));
}
}
}
Vue.createApp(App).mount('#app')
span {
display: block;
margin: 10px 0;
}
button, input {
display: block;
}
因為這邊在Codepen上使用CDN的方式去載入套件,會將VeeValidate賦予到同名稱的變數上。
所以在註冊元件時,需使用VeeValidate.Form
,VeeValidate.Field
,VeeValidate.ErrorMessage
去分別取出三個元件。
並且為了避免元件名稱與html標籤名稱相同,另外賦予一個加上V前綴的名稱( Line:6 ~ Line:8 (Vue))
<v-form @submit="onSubmit" v-slot="all">
{{all}}
<v-field name="name" type="text" placeholder="Who are you" :rules="isRequired">
</v-field>
<error-message name="name"></error-message>
<button>Submit</button>
</v-form>
更多範例
- html(#app)
- vue
<div id="app">
<div class="p-5">
<h3>範例:載入 VeeValidate 驗證套件</h3>
<v-form @submit="onSubmit" v-slot="{errors}">
{{errors}}
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<!-- 使用veevalidate提供的規則,不需動態綁定,使用rule="..."即可,需要多個規則可以使用|隔開(不能加上空白) -->
<v-field id="email" name="email" type="email" class="form-control"
:class="{ 'is-invalid': errors['email'] }"
rules="email|required"
placeholder="請輸入 Email">
</v-field>
<error-message name="email" class="invalid-feedback"></error-message>
</div>
<!-- 自行練習 -->
<div class="mb-3">
<label for="name" class="form-label">姓名</label>
<v-field id="name" name="姓名" type="text" class="form-control"
placeholder="請輸入姓名"></v-field>
<span class="invalid-feedback"></span>
</div>
<div class="mb-3">
<label for="phone" class="form-label">電話</label>
<!-- 使用自己定義的methods時,需要用動態綁定:rules -->
<!-- name可以設定中文,會與errors的屬性名稱相同,所以透過error['電話']的有無可以切換is-invalid的class -->
<v-field id="phone" name="電話" type="text" class="form-control"
:rules="isPhone"
:class="{ 'is-invalid': errors['電話'] }"
placeholder="請輸入電話"
v-model="user.phone"
>
</v-field>
<error-message class="invalid-feedback" name="電話"></error-message>
</div>
<!-- 自行練習 -->
<div class="mb-3">
<label for="region" class="form-label">地區</label>
<select id="region" name="地區" class="form-control">
<option value="">請選擇地區</option>
<option value="台北市">台北市</option>
<option value="高雄市">高雄市</option>
</select>
<span class="invalid-feedback"></span>
</div>
<!-- 自行練習 -->
<div class="mb-3">
<label for="address" class="form-label">地址</label>
<input id="address" name="地址" type="text" class="form-control"
placeholder="請輸入地址">
<span class="invalid-feedback"></span>
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</v-form>
</div>
</div>
VeeValidate.defineRule('email', VeeValidateRules['email']);
VeeValidate.defineRule('required', VeeValidateRules['required']);
VeeValidateI18n.loadLocaleFromURL('./zh_TW.json');
VeeValidate.configure({
generateMessage: VeeValidateI18n.localize('zh_TW'),
validateOnInput: true, // 調整為:輸入文字時,就立即進行驗證
});
const app = Vue.createApp({
data() {
return {
user: {
email: '',
name: '',
address: '',
phone: ''
}
}
},
methods: {
onSubmit(values) {
alert(JSON.stringify(values, null, 2));
},
isPhone(value) {
const phoneNumber = /^(09)[0-9]{8}$/
return phoneNumber.test(value) ? true : '需要正確的電話號碼'
}
},
created() {
console.log(this);
}
});
app.component('VForm', VeeValidate.Form);
app.component('VField', VeeValidate.Field);
app.component('ErrorMessage', VeeValidate.ErrorMessage);
app.mount('#app');
可以直接在v-field
上綁定v-model,會直接修改data內的狀態。
另外也可以如同官方提供的範例,直接在觸發@submit事件時,自訂義要送出時的行為 透過傳入一個values參數,可以將各個參數的值加工後(if needed)傳送到後端。
為單一表單進行驗證(VeeValidate)
VeeValiadation 分為 Cli 與 CDN 版本,本範例以 CDN 為主,觀念上兩者並無太大差異。
文件:
CDN:
- 主套件:https://cdnjs.cloudflare.com/ajax/libs/vee-validate/4.5.8/vee-validate.min.js
- Rules:https://cdn.jsdelivr.net/npm/@vee-validate/rules@4.5.8/dist/vee-validate-rules.min.js
- i18n:https://cdn.jsdelivr.net/npm/@vee-validate/i18n@4.5.8/dist/vee-validate-i18n.min.js
-
載入外部CDN
<script src="https://cdnjs.cloudflare.com/ajax/libs/vee-validate/4.5.8/vee-validate.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@vee-validate/rules@4.5.8/dist/vee-validate-rules.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@vee-validate/i18n@4.5.8/dist/vee-validate-i18n.min.js"></script> -
註冊元件
註冊全域的表單驗證元件(VForm, VField, ErrorMessage)
const app = Vue.createApp({
// ...
});
app.component('VForm', VeeValidate.Form);
app.component('VField', VeeValidate.Field);
app.component('ErrorMessage', VeeValidate.ErrorMessage);
app.mount('#app'); -
定義規則
選擇加入特定規則,全規則可參考連結:官方@vee-validate/rules
VeeValidate.defineRule('email', VeeValidateRules['email']);
VeeValidate.defineRule('required', VeeValidateRules['required']);全部加入
Object.keys(VeeValidateRules).forEach(rule => {
VeeValidate.defineRule(rule, VeeValidateRules[rule]);
});全部加入(CDN 版本)
Object.keys(VeeValidateRules).forEach(rule => {
if (rule !== 'default') {
VeeValidate.defineRule(rule, VeeValidateRules[rule]);
}
}); -
加入多國語系
將外部資源儲存到本地,方便稍後使用。
// 讀取剛剛存取的外部的資源
VeeValidateI18n.loadLocaleFromURL('./zh_TW.json');
// Activate the locale
VeeValidate.configure({
generateMessage: VeeValidateI18n.localize('zh_TW'),
validateOnInput: true, // 調整為:輸入文字時,就立即進行驗證
}); -
套用
v-form
並加入v-slot
<v-form v-slot="{ errors }" @submit="onSubmit" >
備註:v-slot 稱為插槽 Props,可以將驗證結果的回饋資料直接帶入於區塊中
-
套用
v-field
及error-message
常用技巧:
name
為必填,是錯誤驗證的回饋欄位,會與多個項目進行匹配(errors, errors-message …)- 為
v-field
帶入全域設定的規則,可參考相關文件 as
可以改變v-field
的型態,如以下select
範例:class
可運用v-form
帶入的驗證錯誤作為判斷
<v-field
id="email"
name="email"
type="email"
class="form-control"
:class="{ 'is-invalid': errors['email'] }"
placeholder="請輸入 Email" rules="email|required"
v-model="user.email"
></v-field>
<error-message name="email" class="invalid-feedback"></error-message>select範例<v-field
id="name"
name="地區"
class="form-control"
:class="{ 'is-invalid': errors['地區'] }"
placeholder="請輸入地區"
rules="required"
v-model="user.region"
as="select"
>
<option value="">請選擇地區</option>
<option value="台北市">台北市</option>
<option value="高雄市">高雄市</option>
</v-field> -
加入自訂驗證、送出表單等行為
範例:自訂驗證
rules
中可自訂函式來驗證結果
使用v-bind
綁定:rules="isPhone"
<div class="mb-3">
<label for="phone" class="form-label">電話</label>
<v-field
id="phone"
name="電話"
type="text"
class="form-control"
:class="{ 'is-invalid': errors['電話'] }"
placeholder="請輸入電話"
:rules="isPhone"
v-model="user.phone"
></v-field>
<error-message name="電話" class="invalid-feedback"></error-message>
</div>methods: {
isPhone(value) {
const phoneNumber = /^(09)[0-9]{8}$/
return phoneNumber.test(value) ? true : '需要正確的電話號碼'
}
}範例:送出表單
<v-form v-slot="{ errors }" @submit="onSubmit" >
...
<button class="btn btn-primary" type="submit">Submit</button>
</v-form>methods: {
onSubmit() {
// ...
},
},
VueCLI NPM載入VeeValidate
- main.js
- AboutView.vue
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// 匯入 vee-validate 主套件
import { Field, Form, ErrorMessage, defineRule, configure } from 'vee-validate'
// 匯入 vee-validate 相關規則
import { required, email, min } from '@vee-validate/rules'
// 匯入多國語系的功能
import { localize, setLocale } from '@vee-validate/i18n'
// 匯入繁體中文語系檔案
import zhTW from '@vee-validate/i18n/dist/locale/zh_TW.json'
// 定義驗證規則
defineRule('required', required)
defineRule('email', email)
defineRule('min', min)
// 設定 vee-validate 全域規則
configure({
generateMessage: localize({ zh_TW: zhTW }), // 載入繁體中文語系
validateOnInput: true // 當輸入任何內容直接進行驗證
})
// 設定預設語系
setLocale('zh_TW')
const app = createApp(App).use(router)
// 註冊 vee-validate 三個全域元件
// eslint-disable-next-line vue/multi-word-component-names
app.component('Form', Form)
// eslint-disable-next-line vue/multi-word-component-names
app.component('Field', Field)
app.component('ErrorMessage', ErrorMessage)
app.mount('#app')
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
<CardTest></CardTest>
<Form v-slot="{ errors, values, validate }" @submit="onSubmit">
{{ errors }} {{ values }}
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<Field id="email" name="email" type="email" class="form-control" :class="{ 'is-invalid': errors['email'] }"
placeholder="請輸入 Email" rules="email|required" v-model="user.email"></Field>
<error-message name="email" class="invalid-feedback"></error-message>
</div>
<button class="btn me-2 btn-outline-primary" type="button" @click="validate">驗證</button>
<button class="btn btn-primary" type="submit">Submit</button>
</Form>
</template>
<script>
import CardTest from '@/components/CardTest.vue'
export default {
components: {
CardTest
},
data () {
return {
user: {}
}
},
methods: {
onSubmit () {
console.log(this.user)
}
},
created () {
console.log(this)
}
}
</script>
Vite載入vue-axios
安裝vue-axios
npm install --save axios vue-axios
package.json
內容
package.json
內容{
"name": "vite-project",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"axios": "^1.6.2",
"pinia": "^2.1.7",
"vue": "^3.3.10",
"vue-axios": "^3.5.2",
"vue-router": "^4.2.5"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.3.3",
"@vitejs/plugin-vue": "^4.5.1",
"@vue/eslint-config-prettier": "^8.0.0",
"eslint": "^8.49.0",
"eslint-plugin-vue": "^9.17.0",
"prettier": "^3.0.3",
"vite": "^5.0.5"
}
}
調整main.js
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import axios from 'axios'
import VueAxios from 'vue-axios'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(VueAxios, axios)
app.mount('#app')
測試是否載入成功
可以使用Random user來測試是否有正確安裝vue-axios。
到About.vue中,修改如下:
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
{{ user }}
</template>
<script>
export default {
data() {
return {
user: {}
}
},
mounted() {
this.$http.get("https://randomuser.me/api/")
.then((response) => {
this.user=response.data.results[0]
console.log(this.user)
})
}
}
</script>
<style>
@media (min-width: 1024px) {
.about {
min-height: 100vh;
display: flex;
align-items: center;
}
}
</style>
透過vue-axios
取得資料