Table add row,edit row,delete row
jQuery v.s. Vue.js
前言
有時候工作會碰到這種刁鑽的需求,只要遇到jQuery需要組大量html字串時,考慮使用Vue.js就沒錯
實作
後端網頁環境ASP.net Core 2.1
先看jQuery版本,ASP.net Core 的 Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace WebApp_jQueryTableCRUD.Controllers
{
//定義一筆資料當ViewModel
public class User
{
public long v_id { get; set; }
public string userName { get; set; }
public string userJob { get; set; }
public string userSex { get; set; }
public bool isOver18 { get; set; }
}
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(List<long> v_id, List<string> userName, List<string> userJob, IFormCollection form)
{
List<User> users = new List<User>();
int index = 0;
foreach (long uuid in v_id)
{
User user = new User() { v_id=uuid};
user.userName = userName[index] ?? "";
user.userJob = userJob[index] ?? "-1";
if (form.ContainsKey($@"userSex_{uuid}"))
{//使用者有勾
user.userSex = form[$@"userSex_{uuid}"];//取 男 或 女
}
else
{
user.userSex = "";
}
user.isOver18 = form.ContainsKey($@"isOver18_{uuid}") ? true : false;
users.Add(user);
index++;
}
ViewData["result"] = JsonConvert.SerializeObject(users);
//回傳剛剛輸入的資料
return View(users);
}
}
}
View
@using WebApp_jQueryTableCRUD.Controllers
@model List<User>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css"
integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
<title>jQuery 操作Table新增、刪除並儲存</title>
<style type="text/css">
body {
padding-top: 30px;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-12">
<div class="clearfix">
<button class="btn btn-info float-right" id="btnAdd">新增</button>
</div>
<hr />
<form method="post" action="@Url.Action("Index","Home")">
<table class="table table-striped table-bordered table-hover">
<thead class="thead-light">
<tr>
<th>姓名</th>
<th>職業</th>
<th>性別</th>
<th>是否成年</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody">
@if (Model != null)
{
foreach (User user in Model)
{
long v_id = user.v_id;
string trID = $@"tr_{v_id}";
<tr id="@trID"> <!--jQuery刪除 tr 使用這個id-->
<td>
@*給後端識別資料用*@
<input type="hidden" name="v_id" value="@v_id" />
<input type="text" class="form-control" name="userName" placeholder="請輸入姓名" value="@user.userName" />
</td>
<td>
<select class="form-control" name="userJob">
<option value='-1' @(user.userJob == "-1" ? "selected" : "")>請選擇</option>
<option @(user.userJob == "打字員" ? "selected" : "")>打字員</option>
<option @(user.userJob == "工程師" ? "selected" : "")>工程師</option>
</select>
</td>
<td class="text-center align-middle">
<div class="custom-control custom-radio">
<input type="radio" class="custom-control-input" id="userSexMale_@v_id" name="userSex_@v_id" value="男" @(user.userSex == "男" ? "checked" : "")>
<label class="custom-control-label" for="userSexMale_@v_id">男</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" class="custom-control-input" id="userSexFemale_@v_id" name="userSex_@v_id" value="女" @(user.userSex == "女" ? "checked" : "") />
<label class="custom-control-label" for="userSexFemale_@v_id">女</label>
</div>
</td>
<td class="text-center align-middle">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" name="isOver18_@v_id" id="isOver18_@v_id" @(user.isOver18 == true ? "checked" : "") />
<label class="custom-control-label" for="isOver18_@v_id"></label>
</div>
</td>
<td>
<button class="btn btn-danger" onclick="DeleteRow('@trID');">刪除</button>
</td>
</tr>
}//end foreach
}
</tbody>
</table>
<hr />
<div class="clearfix">
<button class="btn btn-primary float-right" id="btnSubmit" type="submit">儲存</button>
</div>
<div>
<pre>
@ViewData["result"]
</pre>
</div>
</form>
</div>
</div>
</div>
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
<script type="text/javascript">
/*jQuery都是操作畫面DOM元素為主*/
$(function () {
$("#btnAdd").on("click", function () {
let v_id = Date.now();//產生一個畫面用的不重複id
//讓新增的欄位id不重複
let trID = `tr_${v_id}`;
let trHtml = `"<tr id="${trID}">
<td>
<input type="hidden" name="v_id" value="${v_id}" />
<input type="text" class="form-control" name="userName" placeholder="請輸入姓名" />
</td>
<td> <select class="form-control" name="userJob">
<option value='-1'>請選擇</option>
<option>打字員</option>
<option>工程師</option>
</select>
</td>
<td class="text-center align-middle">
<div class="custom-control custom-radio">
<input type="radio" class="custom-control-input" id="userSexMale_${v_id}" name="userSex_${v_id}" value="男" >
<label class="custom-control-label" for="userSexMale_${v_id}">男</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" class="custom-control-input" id="userSexFemale_${v_id}" name="userSex_${v_id}" value="女" >
<label class="custom-control-label" for="userSexFemale_${v_id}">女</label>
</div>
</td>
<td class="text-center align-middle">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" name="isOver18_${v_id}" id="isOver18_${v_id}">
<label class="custom-control-label" for="isOver18_${v_id}"></label>
</div>
</td>
<td>
<button class="btn btn-danger" onclick="DeleteRow('${trID}');">刪除</button>
</td>
</tr >`;
$("#tbody").append(trHtml);
});
});
function DeleteRow(trID) {
//移除table的一筆項目
$(`#${trID}`).remove();
}
</script>
</body>
</html>
可以看到jQuery版本最大缺點,在新增時,要組html字串,而且相同html在畫面上寫了兩遍
線上Demo:https://jsfiddle.net/ShadowKao/kLth5mwc/
接著看Vue.js版本
Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace WebApp_jQueryTableCRUD.Controllers
{
//定義一筆資料當ViewModel
public class User
{
public long v_id { get; set; }
public string userName { get; set; }
public string userJob { get; set; }
public string userSex { get; set; }
public bool isOver18 { get; set; }
}
public class HomeController : Controller
{
public IActionResult Index()
{
return View(new List<User>());
}
[HttpPost]
public IActionResult Index(List<User> users)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("<pre>後端接收到:");
foreach (User user in users)
{
sb.AppendLine($@"user.v_id:{user.v_id} ,user.userName:{user.userName},user.userJob:{user.userJob},user.userSex:{user.userSex},user.isOver18:{user.isOver18}");
}
sb.AppendLine("</pre>");
return Content(sb.ToString());
}
}
}
View
@using WebApp_jQueryTableCRUD.Controllers
@using Newtonsoft.Json
@model List<User>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css"
integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
<title>Vue.js 操作Table新增、刪除並Ajax儲存</title>
<style type="text/css">
body {
padding-top: 30px;
}
[v-cloak] {
display:none !important;
}
</style>
</head>
<body>
<div class="container" id="myApp">
<div class="row">
<div class="col-12">
<div class="clearfix">
<button class="btn btn-info float-right" id="btnAdd" v-on:click="AddRow">新增</button>
</div>
<hr />
<form method="post" action="#">
<table class="table table-striped table-bordered table-hover">
<thead class="thead-light">
<tr>
<th>姓名</th>
<th>職業</th>
<th>性別</th>
<th>是否成年</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!--通常迴圈中會處理複雜邏輯,必須小心 v-for不足以應付,複雜邏輯須事先在Controller就處理完畢*/-->
<tr v-for="(user,index) in users" v-cloak>
<td>
<!--後端使用v_id資料識別資料-->
<input type="text" class="form-control" name="userName" placeholder="請輸入姓名" v-model="user.userName" />
</td>
<td>
<select class="form-control" name="userJob" v-model="user.userJob">
<option value='-1'>請選擇</option>
<option>打字員</option>
<option>工程師</option>
</select>
</td>
<td class="text-center align-middle">
<div class="custom-control custom-radio">
<input type="radio" class="custom-control-input" v-bind:id="('userSexMale_'+user.v_id)" v-bind:name="('userSex_'+user.v_id)" value="男" v-model="user.userSex">
<label class="custom-control-label" v-bind:for="'userSexMale_'+user.v_id">男</label>
</div>
<div class="custom-control custom-radio">
<input type="radio" class="custom-control-input" v-bind:id="('userSexFemale_'+user.v_id)" v-bind:name="('userSex_'+user.v_id)" value="女" v-model="user.userSex" />
<label class="custom-control-label" v-bind:for="'userSexFemale_'+user.v_id">女</label>
</div>
</td>
<td class="text-center align-middle">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" v-bind:id="('isOver18_'+user.v_id)" v-bind:name="('isOver18_'+ user.v_id)" v-model="user.isOver18" />
<label class="custom-control-label" v-bind:for="'isOver18_'+user.v_id"></label>
</div>
</td>
<td>
<button class="btn btn-danger" v-on:click="DeleteRow(user,index)" type="button">刪除</button>
</td>
</tr>
</tbody>
</table>
<hr />
<div class="clearfix">
<!--資料都存放在JS裡了,所以使用Ajax送出資料,不仰賴表單提交,因為表單提交動作和畫面的輸入欄位有很大藕合性,但Vue.js就是要讓開發者不用去管畫面的處理-->
<button class="btn btn-primary float-right" id="btnSubmit" type="button" v-on:click="AjaxSubmit">Ajax儲存</button>
</div>
<div v-html="showResult">
</div>
</form>
</div>
</div>
</div>
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
<!--引用Vue.js-->
<script type="text/javascript" src="https://vuejs.org/js/vue.js"></script>
<script type="text/javascript">
/*Vue.js以操作資料為主*/
let users = @Html.Raw(JsonConvert.SerializeObject(Model));
let myApp = new Vue({
el: "#myApp", /*必填*/
data: {
users: users,
showResult:""
},
//事件處理
methods: {
AddRow: function () {
let v_id = Date.now();//產生一個畫面用的不重複id
this.users.push({ v_id: v_id, userName: "", userJob: "-1", userSex: "", isOver18: false });//新增資料到陣列就好,不必組html字串
},
DeleteRow: function (user,index) {
let vm = this;
//要刪除的陣列索引
//let delIndex = vm.users.findIndex(function (item, index) {
// return user.v_id === item.v_id;
// });
let delIndex=index;
//從集合中刪除物件
vm.users.splice(delIndex, 1);//刪除資料,畫面會跟著變動
},
AjaxSubmit: function () {
let vm = this;
$.ajax({
url: "@Url.Action("Index","Home")",
data: { users: vm.users } ,
method: "post",
success: function (result) {
vm.showResult = result;
}
});
//vm.showResult = JSON.stringify(vm.users);
}
}
});
</script>
</body>
</html>
Vue.js不用再組一次Html字串讓程式碼簡潔不少
線上Demo:https://jsfiddle.net/ShadowKao/g0b2xar6/
結語
透過範例比較一下 jQuery 和 Vue.js 兩者處理複雜畫面需求時,誰能讓程式碼簡潔好懂,加快開發速度。