HackMD
  • New!
    New!  Markdown linter lands.
    Write with consistency! Enable markdown linter that hints better markdown styling you can take. Click the lightbulb on the editor status bar 💡
    Got it
      • Create new note
      • Create a note from template
    • New!  Markdown linter lands.
      New!  Markdown linter lands.
      Write with consistency! Enable markdown linter that hints better markdown styling you can take. Click the lightbulb on the editor status bar 💡
      Got it
      • Options
      • Versions and GitHub Sync
      • Transfer ownership
      • Delete this note
      • Template
      • Save as template
      • Insert from template
      • Export
      • Dropbox
      • Google Drive
      • Gist
      • Import
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
      • Download
      • Markdown
      • HTML
      • Raw HTML
      • ODF (Beta)
      • Sharing Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • More (Comment, Invitee)
      • Publishing
        Everyone on the web can find and read all notes of this public team.
        After the note is published, everyone on the web can find and read this note.
        See all published notes on profile page.
      • Commenting Enable
        Disabled Forbidden Owners Signed-in users Everyone
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
        • Everyone
      • Invitee
      • No invitee
    Menu Sharing Create Help
    Create Create new note Create a note from template
    Menu
    Options
    Versions and GitHub Sync Transfer ownership Delete this note
    Export
    Dropbox Google Drive Gist
    Import
    Dropbox Google Drive Gist Clipboard
    Download
    Markdown HTML Raw HTML ODF (Beta)
    Back
    Sharing
    Sharing Link copied
    /edit
    View mode
    • Edit mode
    • View mode
    • Book mode
    • Slide mode
    Edit mode View mode Book mode Slide mode
    Note Permission
    Read
    Owners
    • Owners
    • Signed-in users
    • Everyone
    Owners Signed-in users Everyone
    Write
    Owners
    • Owners
    • Signed-in users
    • Everyone
    Owners Signed-in users Everyone
    More (Comment, Invitee)
    Publishing
    Everyone on the web can find and read all notes of this public team.
    After the note is published, everyone on the web can find and read this note.
    See all published notes on profile page.
    More (Comment, Invitee)
    Commenting Enable
    Disabled Forbidden Owners Signed-in users Everyone
    Permission
    Owners
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Invitee
    No invitee
       owned this note    owned this note      
    Published Linked with GitHub
    Like BookmarkBookmarked
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 前後端整合 - 學習 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, "&amp;") .replace(/</g, "&lt;") .replace(/>/g, "&gt;") .replace(/"/g, "&quot;") .replace(/'/g, "&#039;"); } 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) :::

    Import from clipboard

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lost their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template is not available.
    All
    • All
    • Team
    No template found.

    Create a template

    Delete template

    Do you really want to delete this template?

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in via Google

    New to HackMD? Sign up

    Help

    Documents

    Tutorials
    YAML Metadata
    Slide Example
    Book Example

    Contacts

    Talk to us
    Report an issue
    Send us email

    Cheatsheet

    Example Syntax
    Header # Header
    • Unordered List
    - Unordered List
    1. Ordered List
    1. Ordered List
    • Todo List
    - [ ] Todo List
    Blockquote
    > Blockquote
    Bold font **Bold font**
    Italics font *Italics font*
    Strikethrough ~~Strikethrough~~
    19th 19^th^
    H2O H~2~O
    Inserted text ++Inserted text++
    Marked text ==Marked text==
    Link [link text](https:// "title")
    Image ![image alt](https:// "title")
    Code `Code`
    var i = 0;
    ```javascript
    var i = 0;
    ```
    :smile: :smile:
    Externals {%youtube youtube_id %}
    LaTeX $L^aT_eX$

    This is a alert area.

    :::info
    This is a alert area.
    :::

    Versions

    Versions and GitHub Sync

    Sign in to link this note to GitHub Learn more
    This note is not linked with GitHub Learn more
     
    Add badge Pull Push GitHub Link Settings

    Version named by    

    More Less
    • Edit
    • Delete

    Note content is identical to the latest version.
    Compare with
      Choose a version
      No search result
      Version not found

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub

        Please sign in to GitHub and install the HackMD app on your GitHub repo. Learn more

         Sign in to GitHub

        HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully