吳佳鑫
社會觀察者、社會企業家、教育創新者、遊戲人、媒體人、廚師,小人物與您分享眼見耳聞的生活大小事。
Anything will understand slightly a spot, life more color spots
--- 資料表結構 `users`--CREATE TABLE `users` (`name` varchar(20) NOT NULL,`email` text NOT NULL,`password` text NOT NULL,`id` int(11) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;
<!--20201031 by JokerWu20220527 新修-步驟拆解 & 加註版_1=建立資料_2=建立列表_3=互動視窗_4=完整--><!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Vue.js PHP MYSQL</title></head><!--程式中 變數、函式命名有駝峰式命名法每一個單字的首字母都採用大寫字母例如:FirstName、LastName、CamelCase也被稱為Pascal命名法--><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><script src="http://code.jquery.com/jquery-3.6.0.min.js"></script><!--jquery 可以改成 axios套件來處理AJAXAxios是很輕量的套件,只有約13kbjQuery比較笨重 主要是用來處理AJAX所以axios 在vue.js 來說是較好的選擇<script src="https://unpkg.com/axios/dist/axios.min.js"></script>--><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"><script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script><style>table, th, td {border: 1px solid black;border-collapse: collapse;}th, td {padding: 25px;}</style><body><!-- 版面 --><div id="myApp"> <!-- 此處的 id 跟 vue.js //el: 互動 --><div class="container"><!-- .container 是BS5的預設類別, 是一個RWD 固定寬度的內容容器 --><h1 class="text-center">建立資料</h1><div class="row"><div class="col-md-6"><form method="POST" action="create.php" v-on:submit.prevent="doCreate"><!--v-on:submit.preventsubmit ->表單送出.prevent->不換頁刷新頁面doCreate->vue.js 自訂義函式 用來將表單資料 以JSON格式 送出至create.phpv-on:submit.prevent可簡寫為@:submit.prevent--><div class="form-group"><label>姓名</label><input type="text" name="name" class="form-control" /></div><div class="form-group"><label>Email</label><input type="email" name="email" class="form-control" /></div><div class="form-group"><label>密碼</label><input type="password" name="password" class="form-control" /></div><input type="submit" value="建立" class="btn btn-primary" /></form></div></div><!-- 版面 列表頁 --><h1 class="text-center">列表</h1><table class="table"><tr><th>排序ID</th><th>姓名</th><th>Email</th><th>管理</th></tr><!--以下為使用 vue.js for迴圈參考範例 v04.html & v05.html只要把 v-for 放在一個 <li> 上就有 for 的效果item 是參數(你也可為它取別的名字)用來表示陣列元素list 指的是自定義的陣列名稱(陣列元素為數個物件)in 也可以寫成 of,因為這樣更接近原生 JavaScript 疊代器的語法v-for 還支援第二個參數 — — 索引值(index)帶入索引值參數的方法是在原本 item 的位置改寫成 (item, index) 即可此處 v-for 放在一個<tr>內使用陣列元素 以 user 命名 ->代表 資料表內的欄位名稱索引值 以 index 命名 ->表示第幾筆資料而 users 為 從 vue.js 收到JSON資料 解出後 的資料集名稱--><tr v-for="(user, index) in users"><td v-text="user.id"></td><td v-text="user.name"></td><td v-text="user.email"></td><td><button type="button" v-bind:data-id="user.id" v-on:click="showEditUserModal" class="btn btn-primary">編輯</button><!--v-bindv03.html範例雙花括號 填資料的方法,不適用 HTML 屬性 因此應該把 v-bind: 加在 HTML 屬性前面,且在屬性對應的值中放置參數,在 Model 中定義要傳入的值。v-bind 的縮寫是去掉 v-bind、只留下一個冒號 :v-bind 是將狀態綁定到 HTML 元素上因此v-bind:data-id="user.id"此處可改為:data-id="user.id"v-bind:data-id 此處的data-id 是為了帶值到彈出視窗(互動視窗 或叫 Modal)內的 user.id 欄位.getAttribute(''):取得屬性->DOM語法選取元素時用元素的屬性去選 e.target.getAttribute('data-value')btn-primary ->BS5 預設按鈕樣式v-on:click 可參照 v06.html & v06_01.htmlv-on: 事件 = "方法名稱()"v-on: 的縮寫是 @--><form method="POST" action="delete.php" v-on:submit.prevent="doDelete" style="display: contents;"><!--display: contents此處使用暴力法 直接用 Style 處理display->改變元素對外所參與的佈局環境 或 對內佈局環境,提供後面元素佈局的規則也就是 這個form層 不套用CSS格式 但子層套用詳細範例可參照 1.htm--><input type="hidden" name="id" v-bind:value="user.id" /><input type="submit" name="submit" class="btn btn-danger" value="刪除" /></form></td></tr><!-- vue.js for迴圈 End --></table></div><!-- 列表 END --><!-- Modal 互動視窗--><div class="modal fade" id="editUserModal"><div class="modal-dialog" role="document"><!--Bootstrap 一次只支援一個互動視窗。role屬性的目的是識別解析軟件元素及其子元素modal用法modal.show() //顯示 modalmodal.hide() //隱藏 modalmodal.destroy() //移除 Modal 產生的 dom 元素與 event listeners以下為 BS5 modal 結構「data-backdrop="static"」 鎖定背景,點擊背景時不自動關閉視窗「fade」 淡入、淡出的轉場效果「modal-lg」視窗大小,如modal-lg、modal-md、modal-sm「data-dismiss="modal"」 關閉視窗「data-keyboard="true"」 是否用ESC鍵關閉,預設為true-------<div id="OOXX" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true" data-backdrop="static" data-keyboard="true"><div class="modal-dialog modal-lg" ><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal"><span>×</span>-------aria-label = alt (讀螢幕的軟體可以用 無障礙空間 就像 html 的 role屬性<a href="#" title="設置"><img src="gear.png"></a> => title="設置" 不會唸出<a href="#" aria-label="設置"><img src="gear.png"></a> => aria-label="設置" 可唸出詳細 可參照 WAI-ARIA W3C編撰的規格× => X 符號--><div class="modal-content"><div class="modal-header"><h5 class="modal-title">修改資料</h5><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button></div><div class="modal-body"><form method="POST" action="update.php" v-on:submit.prevent="doUpdate" id="form-edit-user" v-if="user != null"><!--v-if 請參照 v10.htm--><input type="hidden" name="id" v-bind:value="user.id" /><div class="form-group"><label>姓名</label><input type="text" name="name" v-bind:value="user.name" class="form-control" /></div><!--class="form-control" =>BS5 form表單控制可以使用 .form-control-lg 和 .form-control-sm 設置高度不然就不要填 用預設--><div class="form-group"><label>Email</label><input type="email" name="email" v-bind:value="user.email" class="form-control" /></div></form></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-dismiss="modal">關閉</button><button type="submit" name="submit" class="btn btn-primary" form="form-edit-user">確定修改</button></div></div></div><!-- Modal 互動視窗 END --><!-- 下方是 頭myApp 跟 內容container 的 div--></div></div><!--直譯式程式即時互動 如 BS.js 、 jQuery、Vue.js一般都放後面--><script src="VueControl.js"></script>
const myApp = new Vue({el: "#myApp", //el: HTML '元素 id'data: { //資料結構 版面要用的那些資料 從這來的users: [],//JSON讀取來的資料 或 view版面過來的 初始宣告 為空的 usersuser: null //初始宣告變數 user 主要是給互動視窗用},methods: {//建立資料函式doCreate: function () {const self = this; //this 關鍵字使用 此處使用 this可方便使用且資料比較不會錯亂const form = event.target; //事件DOM元件 此處使用 可控制表單那些欄位const ajax = new XMLHttpRequest(); //AJAX 通訊初始ajax.open("POST", form.getAttribute("action"), true);//使用AJAX 將 form 表單 的元素 action 建立//意思就是 以AJAX即時不刷新 POST的通訊方式//將form表單資料傳輸至 action="create.php"ajax.onreadystatechange = function () {/*ajax.onreadystatechange當資料有變化時觸發事件AJAXXMLHttpRequest.readyState客戶端物件目前的狀態0 UNSENT 客戶端已被建立,但 open() 方法尚未被呼叫。1 OPENED open() 方法已被呼叫。2 HEADERS_RECEIVED send() 方法已被呼叫,而且可取得 header 與狀態。3 LOADING 回應資料下載中,此時 responseText 會擁有部分資料。4 DONE 完成下載操作。xmlhttp.status的值及解釋:可查表 較常遇到200——成功202——接受和處理、但處理未完成400——錯誤請求,如語法錯誤401——請求授權失敗404——沒有發現檔案、查詢或URl*/if (this.readyState == 4) {if (this.status == 200) {// console.log(this.responseText);const user = JSON.parse(this.responseText);//JSON.parse() 方法把會把一個JSON字串轉換成JavaScript的數值或是物件。//資料處理self.users.unshift(user);/*陣列資料 原型:Array.prototype.unshift()將資料加到第一個例如:array.unshift('老媽');console.log(array); // ["老媽", "小明", "杰倫", "漂亮阿姨", "小美"]與 push() 雷同*/}}};//建立form表單資料傳輸 使用 AJAX 即時刷新const formData = new FormData(form);ajax.send(formData);},//-------建立資料函式 END//取得所有資料 建立列表頁getData: function () {const self = this;const ajax = new XMLHttpRequest();ajax.open("POST", "read.php", true);ajax.onreadystatechange = function () {if (this.readyState == 4) {if (this.status == 200) {// console.log(this.responseText);const users = JSON.parse(this.responseText);self.users = users; //將取得的資料 帶進users 給vue.js data用}}};const formData = new FormData();ajax.send(formData);},//-------//建立 互動視窗函式showEditUserModal: function () {const id = event.target.getAttribute("data-id");//使用AJAX 將 列表頁的 v-bind:data-id="user.id"//傳送接收過來//比對 users 陣列內 有沒有 傳送過來的 user.id 值//有的話 給互動視窗用的變數 user 改成這一個for (var a = 0; a < this.users.length; a++) {if (this.users[a].id == id) {this.user = this.users[a];break;}}$("#editUserModal").modal("show"); //將互動視窗顯示/*modal用法modal.show() //顯示 modalmodal.hide() //隱藏 modalmodal.destroy() //移除 Modal 產生的 dom 元素與 event listeners*/},//-------建立 互動視窗函式 END//更新函式doUpdate: function () {const self = this;const form = event.target;const ajax = new XMLHttpRequest();ajax.open("POST", form.getAttribute("action"), true);//此處AJAX 取得來自互動視窗的 form表單//action="update.php" 從這一頁 產生的 JSON 資料//---資料改變 START --ajax.onreadystatechange = function () {if (this.readyState == 4) {if (this.status == 200) {// console.log(this.responseText);const user = JSON.parse(this.responseText);// console.log(user);//接下來要進行 原本資料排序的資料處理//因為資料更改後 原users陣列資料會與更新的不同//因此先找出來該筆資料 原理與line bot 範例同var index = -1; //為避免麻煩 直接使用本程式不可能出現的數字 如7秒魚範例手法for (var a = 0; a < self.users.length; a++) {if (self.users[a].id == user.id) {index = a;break;}}// 建立暫存陣列 準備進行陣列重整//宣告的暫存資料 等於 JSON來的 更新過陣列資料const tempUsers = self.users;//將取得有變化的陣列索引 改變成 互動視窗用的 user 變數tempUsers[index] = user;// update the local array by removing all old elements and inserting the updated users//清掉 users 成為空陣列//在將 users 變成 暫存的陣列 也就是新的資料self.users = [];self.users = tempUsers;}}};//---資料改變 END --//表單資料 用AJAX 不跳轉頁面傳送const formData = new FormData(form);ajax.send(formData);//隱藏互動視窗$("#editUserModal").modal("hide");},//更新函式 END//刪除函式doDelete: function () {const self = this;const form = event.target;const ajax = new XMLHttpRequest();ajax.open("POST", form.getAttribute("action"), true);ajax.onreadystatechange = function () {if (this.readyState == 4) {if (this.status == 200) {// console.log(this.responseText);//移除 users 陣列的資料for (var a = 0; a < self.users.length; a++) {if (self.users[a].id == form.id.value) {self.users.splice(a, 1);/*使用arr.splice(要插入或刪除的索引位置, 要刪除的元素數量, 要插入的元素內容)此處我們使用 a = 位置 索引值然後再用第二個參數 刪除的元素數量=1一次只刪一個*/break;}}}}};const formData = new FormData(form);ajax.send(formData);},//刪除函式 END//-----},//方法結束//使用AJAX 進行監聽讀取資料 詳細請參照 vue.js 生命週期(lifecycle)圖 mountedmounted: function () {this.getData();}});