owned this note
owned this note
Published
Linked with GitHub
# 前後端整合 - 學習 jQuery 與 Bootstrap
###### tags: `Tag(jQuery 與 Bootstrap)`
## 什麼是 SPA
Single Page Application 想增進使用者體驗,而出現的一種==在前端利用 Ajax 達成不換頁的方法==。
##### `優點`
```c
* 後端只負責輸出資料,前端來負責抓資料跟渲染畫面。
* 後端變成了一個單純的 API,可以給不同的前端做調用。
* 把前後端完完全全的切開,就算後端壞掉,前端還是看得到畫面
* 前端壞掉,後端還是能安穩的輸出資料供其他服務使用。
```
##### `缺點`
```c
* 檢視 SPA 頁面的原始碼,會發現沒有畫面上看到的內容的程式碼,
這是因為畫面的渲染是由 JavaScript 動態產生的,這樣會使網站的 SEO 表現很差
* 如果從伺服器抓取的資料比較多的話,第一次載入頁面的速度可能會比較慢。
```
## 怎麼樣用 PHP 自己寫出 API
##### `範例:作業`
###### `拿儲存到資料庫的todolist的 API`
```c
<?php
require_once('conn.php');
// 輸出jason資料
header('Content-type:application/json;charset=utf-8');
header('Access-Control-Allow-Origin: *');
// 錯誤處理 - 如果前端的資料是空的
if (empty($_GET['id'])) {
$json = array(
'ok' => false,
'message' => 'Please provide a list ID'
);
// 把資料變成jason的格式
$response = json_encode($json);
echo $response;
die();
}
// 錯誤處理完之後可以拿資料
$id = intval($_GET['id']);
//拿完資料後可以新增到資料庫裡面
$sql = "SELECT * FROM ruofan_todos WHERE id=?";
$stmt = $conn->prepare($sql);
$stmt->bind_param('i', $id);
$result = $stmt->execute();
//執行完之後可以根據內容來看有沒有成功
if(!$result) {
$json = array(
'ok' => false,
'message' => $conn->error
);
$response = json_encode($json);
echo $response;
die();
}
// 判斷完錯誤處理後要把東西拿回來
$result = $stmt->get_result();
$row = $result->fetch_assoc();
// 如果成功有資料 產生一個陣列
$json = array(
'ok' => true,
'data' => array(
'id' => $row["id"],
'todo' => $row["todo"]
)
);
// 把物件用json_encode這個function變成json的字串後輸出,這樣client就可以接收到
$response = json_encode($json);
echo $response;
?>
```
###### `把前端todolist的資料存到資料庫的 API`
```c
<?php
require_once('conn.php');
// 輸出jason資料
header('Content-type:application/json;charset=utf-8');
header('Access-Control-Allow-Origin: *');
// 錯誤處理 - 如果前端post的資料是空的
if (empty($_POST['todo'])){
$json = array(
'ok' => false,
'message' => 'no todos.'
);
$response = json_encode($json);
echo $response;
die();
}
// 錯誤處理完之後可以拿資料
$todo = $_POST['todo'];
//拿完資料後可以新增到資料庫裡面
$sql = "INSERT INTO ruofan_todos(todo) VALUES (?)";
$stmt = $conn->prepare($sql);
$stmt->bind_param('s', $todo);
$result = $stmt->execute();
//執行完之後可以根據內容來看有沒有成功 - 如果沒有資料
if(!$result){
$json = array(
'ok' => false,
'message' => 'no todos.'
);
// 把資料變成jason的格式
$response = json_encode($json);
echo $response;
die();
}
// 如果成功有資料 產生一個陣列
$json = array(
"ok" => true,
"message" => "success",
"id" => $conn->insert_id
);
// 把物件用json_encode這個function變成json的字串後輸出,這樣client就可以接收到
$response = json_encode($json);
echo $response;
?>
```
## 如何在前端與自己開的 API 串接
##### `範例:作業`
###### `把資料存到資料庫`
```javascript=
// 儲存功能
$('.save').click(() => {
// 先從UI拿到要存到資料庫的內容
let todos = [];
$('.card').each((i, element) => {
const check = $(element).find('.check-btn')
const content = $(element).find('.content')
// 把拿到的資料放到todos這個陣列裡
todos.push({
id: check.attr('id').replace('todo-', ''),
content: content.text(),
done: check.hasClass('checked')
})
})
// 把陣列轉成JSON格式的字串
const data = JSON.stringify(todos)
// 把todo的資料存到資料庫
$.ajax({
type: 'POST',
url: `http://localhost:8080/ruofan_php/to-do-list/save_lists.php`,
data: {
todo: data
},
success: function (res) {
const resId = res.id
window.location = 'http://localhost:8080/ruofan_php/to-do-list/todolist.html?id=' + resId
alert('儲存成功')
},
error: function () {
alert('尚未成功')
}
})
})
```
###### `帶入id載入之前存在資料庫的資料`
```javascript=
// 當輸入html標籤時,會印出標籤
function escapeHtml (todo) {
return todo
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
const template = `
<div class="card d-flex">
<div class="card-body">
<div class="add-todo">
<div class="check-btn {todoClass}" id="todo-{id}">⬜</div>
<div for="todo-{id}" id="{id}" class="content">{content}</div>
</div>
<div class="edit-todo">
<i class="far fa-trash-alt delete"></i>
<i class="fas fa-pencil-alt edit" data-toggle="modal" data-target="#edit-content"></i>
</div>
</div>
</div>
`
// 載入資料的功能
var searchParams = new URLSearchParams(window.location.search);
const todoId = searchParams.get('id')
// 載入 id對應的資料
if (todoId){
$.getJSON('http://localhost:8080/ruofan_php/to-do-list/get_lists.php?id=' + todoId, function(data){
const todos = JSON.parse(data.data.todo)
restoreTodos(todos)
})
}
function restoreTodos(todos){
console.log(todos) // 可以印出todos 看一下資料長什麼樣子
for(let i=0; i<todos.length; i++){
const todo = todos[i]
$('.comments').prepend(
template
.replace('{content}', escapeHtml(todo.content))
.replace(/{id}/g, todo.id)
.replace('{todoClass}', todo.done ? 'checked' : '')
)
if (todo.done) {
$('#todo-' + todo.id).prop('checked', true)
$('#todo-' + todo.id).html('✔️')
$('#todo-' + todo.id).next().toggleClass('line-through')
}
}
}
```
## 在 server 與在 client render 的差別
>[React | 用實作了解 Server-Side Rendering 的運作原理](https://medium.com/starbugs/react-%E7%94%A8%E5%AF%A6%E4%BD%9C%E4%BA%86%E8%A7%A3-server-side-rendering-%E7%9A%84%E9%81%8B%E4%BD%9C%E5%8E%9F%E7%90%86-c6133d9fb30d)
#### `client side render`
在執行期間「動態」去跟後端伺服器拿資料,當前端拿到資料以後,才用 JavaScript 動態的把那些內容填到網頁上面。
```css=
前端透過 ajax 去跟後端的 API 互動,後端判斷資料是否正確,並把存到資料庫中,
並透過 API 把成功或失敗的 response 回傳給前端,而前端拿到的 response 後,
再由 JavaScript 來決定要渲染什麼畫面,所渲染的畫面是透過 JavaScript
操控 DOM 元素而動態產生的
```
#### `server side render`
Server 會用 URL 的 path 來決定要 Render 什麼畫面,然後顯示在前端頁面上
###### `優點`
```css=
* SEO
SSR 在第一次載入時就會有內容在了,搜尋引擎表示非常滿意。
* 效能更好:
第一次 Render 的所有事情(包含 call API)都是 Server 做的,
Client 端就比較沒有負擔。
```
###### `缺點`
```c
- 所有內容都在伺服器端處理、組裝完成後才將完整的HTML/CSS/JavaScript 檔案
回傳給客戶端。也因為 HTML 檔(包含資料)是在伺服器上組裝完成才回傳給瀏覽器,
所以每次載入新資料的時候都需要換頁。
```
###### `範例`
```css=
當想要訪問文章列表這個頁面的時候,瀏覽器會送 request 到 server
,然後經過 controller 與 model,最後把資料帶給 view。
view 再回傳一份完整的 HTML 檔案(這個動作就叫做 render)
,而瀏覽器拿到之後,只要顯示出來就好。因為 render 在 server side
```
## jQuery 是做什麼的 ? 與 vanilla js 的差別 ?
>[淺談 JQuery](https://ithelp.ithome.com.tw/articles/10092592)
>[jQuery 簡單介紹](https://jw310.github.io/2020/01/16/jQuery-base/#%E4%BD%BF%E7%94%A8-jQuery)
是一個 JavaScript 函式庫 (Javascipt Framework),加速網頁程式開發速度的工具,可以==解決跨瀏覽器的問題,也可以簡化語法==
###### `範例` `讀取網頁中的單選按鈕「radio Button」`
```cs
1 找出所有 input 元素
2 當元素是 radio button 且屬於某個 group
3 確認某個選項已經被勾選了
4 將勾選的值指派給 checkValue 變數
```
###### `JavaScript`
```javascript
var checkValue;
var elements = document.getElementsByTagName(‘input’);
for (var n = 0; n < elements.length; n++){
if (elements[n].type == ‘radio’ && elements[n].name == ‘RadioGroup’ && elements[n].checked){
checkedValue = elements[n].value;
}
```
###### `jQuery`
```javascript=
var checkValue = $('[name="radioGroup"]:checked').val();
```
##### `使用 jQuery`
```c
// 選取元素
$("div") // 選取所有 <div> 元素
$("#menu") // 選取 id 為 menu 的元素
$(".content") // 選取 class 為 content 的元素
$("div#body") // 選取 id 為 body 的 <div>
$('ul').children.eq(3).text(); // 取得第index個子節點: eq(index) 取得第三個子節點
-------------------------------------------------------------------
// 操作元素
// 讀取和修改一個元素的HTML內容: html()
$("p").html(); // 讀取 <p> 元素的內容
$("p").html("Hello <b>world</b>!"); // 修改 <p> 元素的內容
// 讀取和修改一個元素的純文本內容: text()
$("Element").text(); // 讀取 Element 的文本內容
$("Element").text("Hello <b>world</b>!"); // 修改 Element 的文本內容,Element 的 content 是 Hello <b>world</b>! 是文字格式,不是標籤元素
-------------------------------------------------------------------
// 讀取和修改一個表單元素的 value 值: val()
// 若是多個元素,只能讀取第一個元素的內容。要使用 for 或 each 來讀取多個。
// 讀取每一個被 checked 的值
$('input:checkbox[name=size]:checked').each(function()
{
alert($(this).val());
});
$("Element").val(value); // 修改
-------------------------------------------------------------------
// 元素節點末端加入純文字或 HTML 語法(增加元素): append
$("a[target]").append("(Opens in New Window)"); // 選取所有有 target 屬性的 `<a>`,並且在其節點下加入一段文字。
$(div).prepend("first"); // 元素節點前端加上純文字或 HTML 語法(增加元素): prepend()
$("#test").addClass("aaa"); // class的新增: addClass()
class的移除: removeClass() // $("#test").removeClass("aaa");
-------------------------------------------------------------------
// 事件 點選元素: click
// //當 user 點選 id 為 open 的連結時,顯示 id 為 menu 的區塊,並回傳 false 避免瀏覽器真的換頁。
$("a#open").click(function() {
$("#menu").show();
return false;
});
-------------------------------------------------------------------
// 切換: toggle()
// 按下 Hello 元素第一次會文字會是綠,第二次會是藍色
$('#mydiv').toggle(
function(){
$(this).css({"color": "green"});
},
function(){
$(this).css({"color": "blue"});
},
);
-------------------------------------------------------------------
// ajax
$.ajax({
type: "GET", //指定method
url: 'ajax/test.html',
success: function(data) {
$('.result').html(data);
alert('Load was performed.');
}
});
// 取得 HTML: load()
$("#htmDoc").load("test.html");
// 取得 JSON 格式的資料: getJSON()
$.getJSON("test.json", function(data){
for (var idx in data)
$("#menu").append("<li>" + data[idx] + "</li>");
});
// document ready 事件
// 網頁下載完成後立即執行 alert()
$(document).ready(function() {
alert('Hello');
});
```
## 什麼是 Bootstrap ? 原理及如何應用?
>[Bootstrap 初學介紹 ](https://medium.com/@weilihmen/bootstrap-%E5%88%9D%E5%AD%B8%E4%BB%8B%E7%B4%B9-%E9%9D%9C%E6%85%8B%E7%AF%87-f20500235b33)
>[Bootstrap](https://jw310.github.io/2019/12/14/bootstrap-base/)
>[淺談Bootstrap](http://yenchic-blog.logdown.com/posts/257912-a-brief-talk-on-bootstrap)
前端框架,含HTML、CSS及JS等內容的框架,可以快速開發出一個網頁版型(包含響應式網頁)。
:::warning
![](https://i.imgur.com/ZG91ZYw.png)
:::
###### `navbar 範例`
:::warning
![](https://i.imgur.com/6mS26mU.png)
:::
###### `alert 範例`
:::warning
![](https://i.imgur.com/uXvwBOF.png)
:::
###### `調整alert的寬度`
```html
<div class="row mt-4"> <!--這邊的mt-4 是margin-top:4px;的縮寫 -->
<div class="col-12"> <!--這邊的col-12 是指直接讓alert滿格 -->
<div class="alert alert-primary" role="alert">
這是我的 todo 小作品!
</div>
</div>
</div>
```
###### `form 範例`
:::warning
![](https://i.imgur.com/Cy5TU8w.png)
:::
###### `調整 form的寬度`
```html
<div class="row">
<div class="col-12 col-md-8">
<div class="form-group">
<input type="text" placeholder="請輸入待辦事項" class="form-control" id="exampleInputPassword1">
</div>
</div>
<div class="col-12 col-md-4">
<button class="btn btn-primary btn-block">新增</button> <!--這邊的btn-block 讓button寬度可以滿格 -->
</div>
</div>
```
###### `card 範例`
:::warning
![](https://i.imgur.com/Rudhc4A.png)
:::
###### `調整 card的寬度`
```html
<div class="card"> <!--原本的 style="width: 18rem; 刪掉,card的寬度就可以滿格 -->
<div class="card-header">
Featured
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">Cras justo odio</li>
<li class="list-group-item">Dapibus ac facilisis in</li>
<li class="list-group-item">Vestibulum at eros</li>
</ul>
</div>
```
###### `Badges 範例`
:::warning
![](https://i.imgur.com/do56sty.png)
:::
###### `bootswatch - 提供不同主題顏色`
:::warning
![](https://i.imgur.com/FBauPG5.png)
:::
###### `套用方式 - 在header加上連結`
:::warning
![](https://i.imgur.com/vTDH6oB.png)
:::