[ASP.NET Core MVC][Vue3] 統一欄位格式定義及驗證設計範例 – 前端驗證 #CH2
在開發網站系統設計階段,對於欄位格式定義 (Data Annotation) 及驗證 (Validate) 就要先設計好,讓相同欄位在不同頁面使用時,都能維持相同的格式驗證,當欄位格式有異動時,也只需要修改一個地方就好,讓所有使用到的頁面都能一致同步修改。
在上一篇文章我們完成了後端驗證,接著這一篇文章會繼續完成前端驗證。
此範例環境使用 ASP.NET Core MVC 版本是 .NET6,前端使用 Vue3 框架,後端使用 Dapper 套件連接 SQL Server 2019,文末有範例可以下載。
此前端範例我會先在 View 頁面實作範例內容,最後再將方法抽離至共用區裡面。
我建立的前端驗證方法跟 ASP.NET MVC 前端驗證方法有所不同,這是適用在 Vue 3 的統一驗證方法,有興趣的人可以多學一種前端驗證。
Contents
前端欄位建立控制物件
在上一篇文章裡面,我宣告欄位時是直接將欄位宣告為值,所以在 <input>
時直接將值放在欄位上。
這裡要做一點修改,我們改成將欄位宣告成一個物件,而物件裡面包含名稱、格式、長度、值等屬性,這樣就可以透過屬性來檢查輸入內容。
在 \Views\Home\Index.cshtml 的 Vue3 方法,我們將 data 區,改成以下語法:
1 2 3 4 5 6 7 8 9 |
data() { return { ColumnDefines: {} , addForm: { name: 'addForm' , ColumnList: ['StudentID', 'PID', 'Name', 'Marks', 'Email', 'Mobile', 'CreateDate'] } } } |
然後新增 Create() 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
, created() { var self = this; // 產生控制物件 self.CreateFormControl(self.addForm); // 附加 ColumnDD 設定 self.ColumnDefines = JSON.parse('@Html.Raw(ViewData["ColumnDefines"])'); self.BindColumnDefine(self.addForm); // 設定欄位必填 self.addForm.StudentID.required = true; self.addForm.PID.required = true; self.addForm.Name.required = true; self.addForm.Marks.required = true; self.addForm.Email.required = true; self.addForm.Mobile.required = true; self.addForm.CreateDate.required = true; } |
這裡我們將原本的 addForm 改成宣告欄位陣列,目的要依陣列呼叫 CreateFormControl()
方法產生控制物件。
產生控制物件後,我們再取得資料庫的 ColumnDefine
欄位定義,將每個欄位附加該有的定義。
ColumnDefines
會由 Controller
傳送。
這裡有兩個新的方法 CreateFormControl()
與 BindDDFormat()
,我們在下方的 methods 加上此方法:
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 |
// 產生控制物件 , CreateFormControl(form) { for (idx in form.ColumnList) { // 欄位控制物件 let control = { id: form.name + '.' + form.ColumnList[idx], value: '', name: '', format: '', maxLength: '', minLength: '', rangeStart: '', rangeEnd: '', required: false } form[form.ColumnList[idx]] = control; } } // 綁定欄位定義 , BindColumnDefine(form) { var self = this; for (idx in form.ColumnList) { let dd = $.grep(self.ColumnDefines, function (o) { return o.ColumnID === form.ColumnList[idx] }); if (dd.length > 0) { let control = form[form.ColumnList[idx]]; control.name = dd[0].ColumnName;// 欄位名稱 control.format = dd[0].ColumnFormat;// 欄位格式 control.maxLength = dd[0].ColumnMaxLength;// 最大長度 control.minLength = dd[0].ColumnMinLength;// 最小長度 control.rangeStart = dd[0].ColumnRangeStart;// 數字最小範圍 control.rangeEnd = dd[0].ColumnRangeEnd;// 數字最大範圍 } } } |
Controller 增加回傳欄位定義
語法 JSON.parse('@Html.Raw(ViewData["ColumnDefines"])');
是接收 Controller 傳來的資料,這裡我們打開 \Controllers\HomeController.cs 在 public IActionResult Index()
裡面增加回傳 ColumnDefines
。
1 2 3 |
// 回傳 ColumnDD 格式 List<ColumnDefine> ColumnDefines = ColumnDefine.GetList(); ViewData["ColumnDefines"] = JsonConvert.SerializeObject(ColumnDefines); |
對於想要將此語法抽離至共用區也是可以的,可以宣告一個類別,繼承 Controller
,然後覆寫 public override void OnActionExecuting(ActionExecutingContext context)
方法,然後將此語法放在裡面。
然後將 HomeController
繼承新類別就可以了。
修改輸入欄位
接著將上面的各個 <input>
欄位也修改一下,改成讀取欄位控制物件,修改語法如下:
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 |
<div id="AddPanel" class="card"> <div class="card-header"> 新增 </div> <div class="card-body"> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.StudentID.id" class="col-form-label">{{addForm.StudentID.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.StudentID.value" v-bind:maxlength="addForm.StudentID.maxLength" v-on:blur="Validate(addForm, 'StudentID')" v-bind:id="addForm.StudentID.id" v-bind:ref="addForm.StudentID.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.Name.id" class="col-form-label">{{addForm.Name.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.Name.value" v-bind:maxlength="addForm.Name.maxLength" v-on:blur="Validate(addForm, 'Name')" v-bind:id="addForm.Name.id" v-bind:ref="addForm.Name.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.PID.id" class="col-form-label">{{addForm.PID.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.PID.value" v-bind:maxlength="addForm.PID.maxLength" v-on:blur="Validate(addForm, 'PID')" v-bind:id="addForm.PID.id" v-bind:ref="addForm.PID.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.Marks.id" class="col-form-label">{{addForm.Marks.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.Marks.value" v-bind:maxlength="addForm.Marks.maxLength" v-on:blur="Validate(addForm, 'Marks')" v-bind:id="addForm.Marks.id" v-bind:ref="addForm.Marks.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.Email.id" class="col-form-label">{{addForm.Email.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.Email.value" v-bind:maxlength="addForm.Email.maxLength" v-on:blur="Validate(addForm, 'Email')" v-bind:id="addForm.Email.id" v-bind:ref="addForm.Email.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.Mobile.id" class="col-form-label">{{addForm.Mobile.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.Mobile.value" v-bind:maxlength="addForm.Mobile.maxLength" v-on:blur="Validate(addForm, 'Mobile')" v-bind:id="addForm.Mobile.id" v-bind:ref="addForm.Mobile.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.CreateDate.id" class="col-form-label">{{addForm.CreateDate.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.CreateDate.value" v-bind:maxlength="addForm.CreateDate.maxLength" v-on:blur="Validate(addForm, 'CreateDate')" v-bind:id="addForm.CreateDate.id" v-bind:ref="addForm.CreateDate.id"> </div> </div> </div> <div class="card-footer"> <button type="button" class="btn btn-primary" v-on:click="AddSave()">儲存</button> </div> </div> |
在每個 <input>
輸入資料時,都會呼叫 Validate()
檢查方法,所以我們在下方的 methods 加入此方法:
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 |
// 檢查資料格式 , Validate(form, id) { if (form[id].value.length > 0) { let msg = ''; let name = ''; if (form[id].name) { name = "[" + form[id].name + "] "; } if (form[id].format === 'INT') { let re = /[^0-9]/; if (re.test(form[id].value)) { msg = "整數格式錯誤"; } } else if (form[id].format === 'NUM') { if (isNaN(form[id].value)) { msg = "數字格式錯誤"; } } else if (form[id].format === 'DATE') { var dateStr = form[id].value.replace(/\/0+/g, '/'); var accDate = new Date(dateStr); var tempDate = accDate.getFullYear() + "/"; tempDate += (accDate.getMonth() + 1) + "/"; tempDate += accDate.getDate(); if (dateStr !== tempDate) { msg = "日期格式錯誤"; } } else if (form[id].format === 'PID') { let check = true; if (form[id].value.length !== 10) { check = false; } if (check) { tab = "ABCDEFGHJKLMNPQRSTUVXYWZIO"; A1 = new Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3); A2 = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5); Mx = new Array(9, 8, 7, 6, 5, 4, 3, 2, 1, 1); if (form[id].value.length !== 10) { check = false; } i = tab.indexOf(form[id].value.charAt(0)); if (i === -1) { check = false; } sum = A1[i] + A2[i] * 9; for (i = 1; i < 10; i++) { v = parseInt(form[id].value.charAt(i)); if (isNaN(v)) { check = false; } sum = sum + v * Mx[i]; } if (sum % 10 !== 0) { check = false; } } if (!check) { msg = '身份證字號格式錯誤'; } } else if (form[id].format === 'EMAIL') { if (form[id].value.indexOf("@") === -1 || form[id].value.indexOf(".") === -1 || form[id].value.split('@').length > 2 || form[id].value.length <= 4) { msg = 'E-Mail 格式錯誤'; } } else if (form[id].format === 'PHONE') { let regExp = /^[\s()+-]*([0-9][\s()+-]*){6,20}$/; if (form[id].value.match(regExp) === null) { msg = '電話格式錯誤'; } } if (msg == '') { //長度檢查 if (form[id].maxLength != '') { if (form[id].value.length > form[id].maxLength) { msg = '長度最多 ' + form[id].maxLength + ' 字元'; } } if (form[id].minLength != '') { if (form[id].value.length < form[id].minLength) { msg = '長度最少 ' + form[id].maxLength + ' 字元'; } } } if (msg == '') { //數字範圍檢查 if (form[id].rangeStart != '') { if (parseFloat(form[id].value) < parseFloat(form[id].rangeStart)) { msg = '數字範圍最小為 ' + form[id].rangeStart; } } if (form[id].rangeEnd != '') { if (parseFloat(form[id].value) > parseFloat(form[id].rangeEnd)) { msg = '數字範圍最大為 ' + form[id].rangeEnd; } } } if (msg !== '') { alert(name + msg); form[id].value = ''; this.$refs[form[id].id].focus(); } } } |
這裡的 Validate()
方法跟後端的 Validate()
其實在做一樣的事情,就是驗證資料內容,而這裡是針對前端欄位的 onblur
事件立即檢查內容,當檢查失敗時則清空內容並設定 focus()
。
檢查必填欄位
接下來驗證前端欄位的必填屬性,這做法類似後端的 [Required]
設定。
我剛剛在 created()
裡面有設定了欄位為必填,語法是 self.addForm.StudentID.required = true;
接著修改一下 AddSave()
方法,在送出資料到後端之前,先驗證欄位是否已必填。
1 2 3 4 5 6 |
// 檢查欄位是否必填 let msg = self.CheckRequired(self.addForm); if (msg != '') { alert(msg); return false; } |
語法 CheckRequired()
是新方法,接著在 methods 增加此方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// 檢查是否必填 , CheckRequired(form) { let msg = ''; for (idx in form) { if (form[idx].required) { if (form[idx].value == '') { let name = ''; if (form[idx].name) { name = "[" + form[idx].name + "] "; } msg += name + "欄位不可空白\n"; } } } return msg; } |
測試範例
做到這裡已完成所有的語法,可以按 F5 執行一下專案,當所有欄位都沒有輸入時,按下「儲存」則會顯示需要必填的欄位訊息。
當單一欄位輸入後離開欄位焦點觸發 onblur
事件,即會檢查內容是否符合驗證,當驗證失敗就會顯示錯誤內容。
建立 Vue3 前端共用方法
當我們在後端驗證資料時,會透過在 ModelBase
類別裡面的 Validate()
方法統一檢查輸入資料,而我們在前端驗證資料時,也會建立一個共用方法,讓不同頁面可以共用呼叫。
在 Vue3 要建立共用方法可以使用到 mixins 的混合功能,mixins 可以將 data, method 及生命週期事件抽離至外部檔案再引用,很適合做為共用元件。
當我們在 created()
內所呼叫的方法 CreateFormControl()
, BindColumnDefine()
以及前端欄位輸入資料的方法 Validate()
, CheckRequired()
很適合放在共用區,接著就來實作這個共用方法。
執行「wwwroot > js > 按右鍵 > 加入 > 新增項目」。
選擇「JavaScript 檔」,輸入名稱「vueMixin.js」,按「新增」。
接著把剛剛在 methods 裡面這 4 個方法還有 ColumnDefines
抽離至 vueMixin.js 裡面,直接輸入以下語法:
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 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
const mixin = { data() { return { ColumnDefines: {} } }, methods: { // 產生控制物件 CreateFormControl(form) { for (idx in form.ColumnList) { // 欄位控制物件 let control = { id: form.name + '.' + form.ColumnList[idx], value: '', name: '', format: '', maxLength: '', minLength: '', rangeStart: '', rangeEnd: '', required: false } form[form.ColumnList[idx]] = control; } } // 綁定欄位定義 , BindColumnDefine(form) { var self = this; for (idx in form.ColumnList) { let dd = $.grep(self.ColumnDefines, function (o) { return o.ColumnID === form.ColumnList[idx] }); if (dd.length > 0) { let control = form[form.ColumnList[idx]]; control.name = dd[0].ColumnName;// 欄位名稱 control.format = dd[0].ColumnFormat;// 欄位格式 control.maxLength = dd[0].ColumnMaxLength;// 最大長度 control.minLength = dd[0].ColumnMinLength;// 最小長度 control.rangeStart = dd[0].ColumnRangeStart;// 數字最小範圍 control.rangeEnd = dd[0].ColumnRangeEnd;// 數字最大範圍 } } } // 檢查資料定義 , Validate(form, id) { if (form[id].value.length > 0) { let msg = ''; let name = ''; if (form[id].name) { name = "[" + form[id].name + "] "; } if (form[id].format === 'INT') { let re = /[^0-9]/; if (re.test(form[id].value)) { msg = "整數格式錯誤"; } } else if (form[id].format === 'NUM') { if (isNaN(form[id].value)) { msg = "數字格式錯誤"; } } else if (form[id].format === 'DATE') { var dateStr = form[id].value.replace(/\/0+/g, '/'); var accDate = new Date(dateStr); var tempDate = accDate.getFullYear() + "/"; tempDate += (accDate.getMonth() + 1) + "/"; tempDate += accDate.getDate(); if (dateStr !== tempDate) { msg = "日期格式錯誤"; } } else if (form[id].format === 'PID') { let check = true; if (form[id].value.length !== 10) { check = false; } if (check) { tab = "ABCDEFGHJKLMNPQRSTUVXYWZIO"; A1 = new Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3); A2 = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5); Mx = new Array(9, 8, 7, 6, 5, 4, 3, 2, 1, 1); if (form[id].value.length !== 10) { check = false; } i = tab.indexOf(form[id].value.charAt(0)); if (i === -1) { check = false; } sum = A1[i] + A2[i] * 9; for (i = 1; i < 10; i++) { v = parseInt(form[id].value.charAt(i)); if (isNaN(v)) { check = false; } sum = sum + v * Mx[i]; } if (sum % 10 !== 0) { check = false; } } if (!check) { msg = '身份證字號格式錯誤'; } } else if (form[id].format === 'EMAIL') { if (form[id].value.indexOf("@") === -1 || form[id].value.indexOf(".") === -1 || form[id].value.split('@').length > 2 || form[id].value.length <= 4) { msg = 'E-Mail 格式錯誤'; } } else if (form[id].format === 'PHONE') { let regExp = /^[\s()+-]*([0-9][\s()+-]*){6,20}$/; if (form[id].value.match(regExp) === null) { msg = '電話格式錯誤'; } } if (msg == '') { //長度檢查 if (form[id].maxLength != '') { if (form[id].value.length > form[id].maxLength) { msg = '長度最多 ' + form[id].maxLength + ' 字元'; } } if (form[id].minLength != '') { if (form[id].value.length < form[id].minLength) { msg = '長度最少 ' + form[id].maxLength + ' 字元'; } } } if (msg == '') { //數字範圍檢查 if (form[id].rangeStart != '') { if (parseFloat(form[id].value) < parseFloat(form[id].rangeStart)) { msg = '數字範圍最小為 ' + form[id].rangeStart; } } if (form[id].rangeEnd != '') { if (parseFloat(form[id].value) > parseFloat(form[id].rangeEnd)) { msg = '數字範圍最大為 ' + form[id].rangeEnd; } } } if (msg !== '') { alert(name + msg); form[id].value = ''; this.$refs[form[id].id].focus(); } } } // 檢查是否必填 , CheckRequired(form) { let msg = ''; for (idx in form) { if (form[idx].required) { if (form[idx].value == '') { let name = ''; if (form[idx].name) { name = "[" + form[idx].name + "] "; } msg += name + "欄位不可空白\n"; } } } return msg; } } } |
當 4 個方法及 ColumnDefines
抽離至 vueMixin 之後,就可以從 Vue3 物件裡面拿掉了。
加入 vueMixin.js 引用
打開「\Views\Shared\_Layout.cshtml」,在下方的 Javascript 引用區加入引用:
<script src="~/js/vueMixin.js"></script>
接著回到 \Views\Home\Index.cshtml,在 Vue3 加入 mixins 引用:
mixins: [mixin],
當共用方法抽離至共用區之後,前端的語法就會變的簡單,這裡貼上完整 Index.cshtml 的語法:
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 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
<h1>統一欄位格式定義及驗證設計範例</h1> <div id="AddPanel" class="card"> <div class="card-header"> 新增 </div> <div class="card-body"> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.StudentID.id" class="col-form-label">{{addForm.StudentID.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.StudentID.value" v-bind:maxlength="addForm.StudentID.maxLength" v-on:blur="Validate(addForm, 'StudentID')" v-bind:id="addForm.StudentID.id" v-bind:ref="addForm.StudentID.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.Name.id" class="col-form-label">{{addForm.Name.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.Name.value" v-bind:maxlength="addForm.Name.maxLength" v-on:blur="Validate(addForm, 'Name')" v-bind:id="addForm.Name.id" v-bind:ref="addForm.Name.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.PID.id" class="col-form-label">{{addForm.PID.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.PID.value" v-bind:maxlength="addForm.PID.maxLength" v-on:blur="Validate(addForm, 'PID')" v-bind:id="addForm.PID.id" v-bind:ref="addForm.PID.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.Marks.id" class="col-form-label">{{addForm.Marks.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.Marks.value" v-bind:maxlength="addForm.Marks.maxLength" v-on:blur="Validate(addForm, 'Marks')" v-bind:id="addForm.Marks.id" v-bind:ref="addForm.Marks.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.Email.id" class="col-form-label">{{addForm.Email.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.Email.value" v-bind:maxlength="addForm.Email.maxLength" v-on:blur="Validate(addForm, 'Email')" v-bind:id="addForm.Email.id" v-bind:ref="addForm.Email.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.Mobile.id" class="col-form-label">{{addForm.Mobile.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.Mobile.value" v-bind:maxlength="addForm.Mobile.maxLength" v-on:blur="Validate(addForm, 'Mobile')" v-bind:id="addForm.Mobile.id" v-bind:ref="addForm.Mobile.id"> </div> </div> <div class="row"> <div class="col-sm-2"> <label v-bind:for="addForm.CreateDate.id" class="col-form-label">{{addForm.CreateDate.name}}</label> </div> <div class="col-auto"> <input type="text" class="form-control" v-model="addForm.CreateDate.value" v-bind:maxlength="addForm.CreateDate.maxLength" v-on:blur="Validate(addForm, 'CreateDate')" v-bind:id="addForm.CreateDate.id" v-bind:ref="addForm.CreateDate.id"> </div> </div> </div> <div class="card-footer"> <button type="button" class="btn btn-primary" v-on:click="AddSave()">儲存</button> </div> </div> @section scripts { <script> const app = Vue.createApp({ mixins: [mixin], data() { return { addForm: { name: 'addForm' , ColumnList: ['StudentID', 'PID', 'Name', 'Marks', 'Email', 'Mobile', 'CreateDate'] } } } , created() { var self = this; // 產生控制物件 self.CreateFormControl(self.addForm); // 附加 ColumnDD 設定 self.ColumnDefines = JSON.parse('@Html.Raw(ViewData["ColumnDefines"])'); self.BindColumnDefine(self.addForm); // 設定欄位必填 self.addForm.StudentID.required = true; self.addForm.PID.required = true; self.addForm.Name.required = true; self.addForm.Marks.required = true; self.addForm.Email.required = true; self.addForm.Mobile.required = true; self.addForm.CreateDate.required = true; } , methods: { // 新增儲存 AddSave() { var self = this; // 檢查欄位是否必填 let msg = self.CheckRequired(self.addForm); if (msg != '') { alert(msg); return false; } // 組合表單資料 var postData = {}; postData['StudentID'] = self.addForm.StudentID.value; postData['PID'] = self.addForm.PID.value; postData['Name'] = self.addForm.Name.value; postData['Marks'] = self.addForm.Marks.value; postData['Email'] = self.addForm.Email.value; postData['Mobile'] = self.addForm.Mobile.value; postData['CreateDate'] = self.addForm.CreateDate.value; // 使用 jQuery Ajax 傳送至後端 $.ajax({ url: '@Url.Content("~/Home/AddSave")', method: 'POST', dataType: 'json', data: { inModel: postData, __RequestVerificationToken: $('@Html.AntiForgeryToken()').val() }, success: function (datas) { if (datas.ErrMsg) { alert(datas.ErrMsg); return; } alert(datas.ResultMsg); }, error: function (err) { alert(err.status + " " + err.statusText + '\n' + err.responseText); } }); } } }); const vm = app.mount('#AddPanel'); </script> } |
前端語法變簡潔了,該共用的語法移至共用區,你可以再按 F5 檢查一下驗證功能是否都正常運作。
以上我的教學並非是主流方式,而是我個人發展出來的專案架構,幫助想要達成統一驗證的人一種思考方式,如果此做法有盲點或是 Bug,歡迎指教,謝謝。
範例下載
推薦課程
相關學習文章
- [ASP.NET Core MVC + Vue3 + Dapper] 前後台網站公告範例 – 後台查詢頁面教學 #CH1
- [ASP.NET MVC] 免費公司形象網站範本套版教學 #CH1 (附範例)
如果你在學習上有不懂的地方,需要諮詢服務,可以參考站長服務,我想辨法解決你的問題
如果文章內容有過時、不適用或錯誤的地方,幫我在下方留言通知我一下,謝謝