Vue3 TypeScript 的 Vue-i18n mulitional languages

在Vue3 TypeScript專案內安裝 Vue-i18n

安裝指令

1
npm install vue-i18n@next --save

在 src/ 目錄底下,新增 lang資料夾,並新增zh-TW.json,en-US.json 檔案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//en-US.json
{
"nav_menu":{
"home":"Home",
"login":"Login"
}
}
//zh-TW.json
{
"nav_menu":{
"home":"首頁",
"login":"登入"
}
}

在 src/ 目錄底下,新增 languages/i18n.ts,並設定語系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { createI18n } from 'vue-i18n'
import zh from '../lang/zh-TW.json'
import en from '../lang/en-US.json'

type MessageSchema = typeof zh

const i18n = createI18n<[MessageSchema], 'zh-TW' | 'en-US'>({
legacy: false, // 要把 legacy 設為 false,才可以使用 Composition API
locale: 'zh-TW',
fallbackLocale: 'zh-TW',
globalInjection: true,
messages: {
'zh-TW': zh,
'en-US': en
}
})

export default i18n

在 main.ts 引入 Vue-i18n

1
2
3
4
5
6
7
//引入plugins/i18n
import i18n from './plugins/i18n'

const app = createApp(App)
//使用use i18n
app.use(i18n)
app.mount('#app')

在App.vue 載入語系測試使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<div>
<div>切換語言:</div>
<select @change="changeLang">
<option value="zh-TW">中文</option>
<option value="en-US">English</option>
</select>
</div>
<p>
{{ $t('nav_menu.home') }}
</p>
</div>
</template>

<script setup lang="ts">
//載入vue-i18n
import { useI18n } from 'vue-i18n'
const { locale } = useI18n()
//改變語系切換
const changeLang = (e) => {
locale.value = e.target.value
}
</script>

另一種寫法:pinia

在sores新增nav.ts

  • pinia載入
  • vue 方法 ref, computed 載入
  • vue-i18n載入
  • 數據的Ts撰寫homeMenuType 與載入
1
2
3
4
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import { useI18n } from "vue-i18n";
import { homeMenuType } from "../types/all";

在types新增all.ts
轉寫
homeMenuType

1
2
3
4
5
export interface homeMenuType{
name?: string |null |any,
id?: string |null |any,
link: string | null | any,
}
  • 使用computed 解析nav_menu.home
  • 放入陣列homeMenu
  • 寫函式 changeLang改變語系
  • return homeMenu,changeLang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//useNavbarStore 
export const useNavbarStore = defineStore('navbar', () => {
const { locale } = useI18n();
const i18n = useI18n();

const i18nPlatform = computed(() => i18n.t("nav_menu.home"))
const i18nCompany = computed(() => i18n.t("nav_menu.login"))

const homeMenu=ref<homeMenuType[]>([
{ name: i18nPlatform, id: '001', link: '/index' },
{ name: i18nCompany, id: '002', link: '/aboutus' }
])


const changeLang = (e: any) => {
console.log(e)
locale.value = e.target.value
console.log(locale.value)
}
watch(locale, newlocale => {
localStorage.setItem("locale", newlocale);
});

return {
homeMenu, changeLang
}
})

在頁面使用
  • 載入pinia storeToRefs
  • 宣告store = useNavbarStore()
  • 解構
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<template>
<div>
<div>
切換語言:
<select @change="changeLang">
<option value="zh-TW">
中文
</option>
<option value="en-US">
English
</option>
</select>
</div>
<ul>
<li v-for="(item, id) in homeMenu"
:key="id">
{{ item.name }}
</li>
</ul>
<router-view />
</div>
</template>

<script setup lang="ts">
//載入pinia storeToRefs
import { storeToRefs } from 'pinia';
import { useNavbarStore } from './stores/nav';
//宣告store = useNavbarStore()
const store = useNavbarStore();
//解構
const { homeMenu } = storeToRefs(store);
const { changeLang } = store;
</script>

<style lang="scss" scoped>
ul{
display: flex;
li {
display : flex;
padding:10px;

}
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

MySql CHECK 檢查限制 (SQL CHECK Constraint)

CHECK 檢查限制 (SQL CHECK Constraint)

CHECK 限制用來約束欄位中的可用值,以保證該欄位中的資料值都會符合您設定的條件。

1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TABLE customer (
C_Id INT NOT NULL CHECK (C_Id>0),
Name VARCHAR(50) NOT NULL,
Address VARCHAR(255),
Phone VARCHAR(20)
);
CREATE TABLE customer (
C_Id INT NOT NULL,
Name VARCHAR(50) NOT NULL,
Address VARCHAR(255),
Phone VARCHAR(20),
CHECK (C_Id>0)
);

在 MySQL 增加 CHECK 限制不會有錯誤,但是沒有用,CHECK 並不會被執行喔!

1
2
3
4
5
6
7
CREATE TABLE customer (
C_Id INT NOT NULL,
Name VARCHAR(50) NOT NULL,
Address VARCHAR(255),
Phone VARCHAR(20),
CONSTRAINT chk_Customer CHECK (C_Id>0 AND Name!='XXX')
);

更改資料表限制 ALTER TABLE…

1
ALTER TABLE customer ADD CHECK (C_Id>0);

替主鍵命名與多欄位的組合鍵:

1
2
ALTER TABLE customer
ADD CONSTRAINT chk_Customer CHECK (C_Id>0 AND Name!='XXX');

移除資料表限制 ALTER TABLE…

1
ALTER TABLE customer DROP CONSTRAINT chk_Customer;

MySql DEFAULT 預設值限制 (SQL DEFAULT Constraint)

DEFAULT 預設值限制 (SQL DEFAULT Constraint)

DEFAULT 限制用來設定欄位的預設值。當你在 INSERT 資料時若該欄位沒指定值則會採用預設值。

1
2
3
4
5
6
CREATE TABLE customer (
C_Id INT NOT NULL,
Name VARCHAR(50) NOT NULL,
Address VARCHAR(255) DEFAULT '未知',
Phone VARCHAR(20)
);

更改資料表限制 ALTER TABLE…

1
ALTER TABLE customer ALTER COLUMN Address SET DEFAULT '未知';

SQL Server

1
ALTER TABLE customer ADD DEFAULT '未知' FOR Address;

移除資料表限制 ALTER TABLE…

1
ALTER TABLE customer ALTER COLUMN Address DROP DEFAULT;

SQL Server

1
ALTER TABLE table_name DROP constrain_name;

Oracle

1
ALTER TABLE table_name MODIFY column_name DEFAULT NULL;

Vite element-plus ts 表單驗證

Vite element-plus ts 表單驗證

types資料夾新增 forms.ts

1
2
3
4
5
6
7
export interface ruleFormType {
email: string,
password: string,
checkPass?: string,
verification?: string,
}

在使用的頁面載入

  • 載入ruleFormType
  • 載入ElForm,type定義ElForm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import { ref, onMounted,watchEffect } from 'vue'
import { ruleFormType } from '../types/forms.ts'
import type { ElForm } from 'element-plus'
//找不到 ‘element-plus’ 不得使用命名空間 ‘FormInstance’ 作為類型
type FormInstance = InstanceType<typeof ElForm>
const ruleFormRef = ref<FormInstance>()
//定義表單
const ruleForm = ref<ruleFormType>({
email : '',
password : '',
checkPass: '',
verification:''
})
//驗證規則
const rules = ref<FormRules<ruleFormType>>({
email: [
{
required: true,
message : '請輸入電子信箱',
trigger : 'blur',
},
{
type : 'email',
message: '電子信箱格式不符',
trigger: [
'blur',
'change'
],
},
],
password : [{ validator: validatePassword, trigger: 'blur' }],
checkPass: [{ validator: checkPassword, trigger: 'blur' }],
})

驗證的規則與函式
一 密碼為空時,密碼不為空時驗證確認密碼
二 密碼與確認密碼不相同時
三 點擊送出沒有值時出現
四 重置表單

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<template>
<div>
<el-form ref="ruleFormRef"
:model="ruleForm"
:rules="rules"
label-width="120px"
class="demo-ruleForm">
<el-form-item prop="email"
label="電子郵件">
<el-input v-model="ruleForm.email" />
</el-form-item>
<el-form-item label="密碼"
prop="password">
<el-input v-model="ruleForm.password"
type="password"
autocomplete="off" />
</el-form-item>
<el-form-item label="確認密碼"
prop="checkPass">
<el-input v-model="ruleForm.checkPass"
type="password"
autocomplete="off" />
</el-form-item>
<!---->
<el-form-item>
<el-button @click="resetForm(ruleFormRef)">
重置
</el-button>
<el-button type="primary"
@click="submitForm(ruleFormRef)">
送出
</el-button>
</el-form-item>
</el-form>
</div>
</template>

<script setup lang="ts">
// @ts-ignore
import { ref, onMounted } from 'vue';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import type { ElForm } from 'element-plus'
// @ts-ignore
import { ruleFormType } from '../types/forms.ts'

//找不到 ‘element-plus’ 不得使用命名空間 ‘FormInstance’ 作為類型
type FormInstance = InstanceType<typeof ElForm>
const ruleFormRef = ref<FormInstance>()

const ruleForm = ref<ruleFormType>({
email : '',
password : '',
checkPass: '',
verification:''
})
//驗證密碼
const validatePassword = (_rule: any, value: any, callback: any) => {
if (value === '') {
//如果空值時驗證
callback(new Error('請輸入密碼'))
} else {
//如果密碼不等於空
if (ruleForm.value.checkPass !== '') {
if (!ruleFormRef.value) return
ruleForm.value.validateField('checkPass', () => null)
}
callback()
}
}
// 檢查密碼是否兩次相同
const checkPassword= (_rule: any, value: any, callback: any) => {
if (value === '') {
callback(new Error('請再輸入一次密碼'))

} else if (value !== ruleForm.value.password) {
callback(new Error('兩次密碼不相同!'))
} else {
callback()
}
}
//驗證規則
type FormRules = InstanceType<typeof ElForm>
const rules = ref<FormRules>({
email: [
{
required: true,
message : '請輸入電子信箱',
trigger : 'blur',
},
{
type : 'email',
message: '電子信箱格式不符',
trigger: [
'blur',
'change'
],
},
],
password : [{ validator: validatePassword, trigger: 'blur' }],
checkPass: [{ validator: checkPassword, trigger: 'blur' }],
})

const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
console.log('submit!')
} else {
console.log('驗證', fields)
}
})
}
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
}
onMounted(() => {

});
</script>

Github 專案說明
element-plus form validation

MySql CROSS JOIN 關鍵字 (SQL CROSS JOIN Keyword) - 交叉連接

CROSS JOIN 關鍵字 (SQL CROSS JOIN Keyword) - 交叉連接

交叉連接為兩個資料表間的笛卡兒乘積 (Cartesian product),兩個資料表在結合時,不指定任何條件,即將兩個資料表中所有的可能排列組合出來,以下例而言 CROSS JOIN 出來的結果資料列數為 3×5=15 筆,因此,當有 WHERE、ON、USING 條件時不建議使用。

1
2
3
4
5
6
7
8
9
10
SELECT table_column1, table_column2...
FROM table_name1
CROSS JOIN table_name2;
//or
SELECT table_column1, table_column2...
FROM table_name1, table_name2;
//or
SELECT table_column1, table_column2...
FROM table_name1
JOIN table_name2;

Example

1
2
3
SELECT customers.Name, orders.Order_No
FROM customers
CROSS JOIN orders;

MySql FULL JOIN 即為 LEFT JOIN 與 RIGHT JOIN 的聯集,它會返回左右資料表中所有的紀錄,不論是否符合連接條件。

FULL JOIN 即為 LEFT JOIN 與 RIGHT JOIN 的聯集

FULL JOIN 即為 LEFT JOIN 與 RIGHT JOIN 的聯集,它會返回左右資料表中所有的紀錄,不論是否符合連接條件。

1
2
3
4
SELECT table_column1, table_column2...
FROM table_name1
FULL JOIN table_name2
ON table_name1.column_name=table_name2.column_name;

Example

1
2
3
4
SELECT customers.C_Id,customers.Name,customers.Address,customers.Phone,customers.Salary,orders.Order_No,orders.Product,orders.Product,orders.Quantity
FROM `customers`
RIGHT JOIN `orders`
ON customers.C_Id =orders.C_Id
LEFT JOIN 會返回左側資料表中所有資料列,就算沒有符合連接條件,而右側資料表中如果沒有匹配的資料值就會顯示為 NULL。

MySql CREATE INDEX 敘述句 (SQL CREATE INDEX Statement)

CREATE INDEX 語法 (SQL CREATE INDEX Syntax)

索引 (index)

1
CREATE INDEX index_name ON table_name (column_name);

建立多欄位索引 (Multiple-Column Index)

什麼時候建立多欄位索引比較合適?如果您常對一張資料表查詢 WHERE column_name1=’xxx’ AND column_name2=’yyy’,這時你就可以對 column_name1 及 column_name2 這兩個欄位建立一個共同索引。

1
CREATE INDEX index_name ON table_name (column_name1, column_name2...);

DROP INDEX 敘述句 (SQL DROP INDEX Statement)

移除索引

1
ALTER TABLE table_name DROP INDEX index_name;