達暉資訊
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
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
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 前端導入 Vue 建議事項 ###### tags: `Vue` `SPA` `SEO` `RWD` `Vuex` ## 吃完 Vue 全家餐,實現所有願望 Vue.js 在處理前段架構解決方案時,仿間有一套俗稱「全家餐」的套件,套件組成如下: * vue * vuex(狀態管理) * vue-router(路由) * axios(http請求工具) * vue-cli(建構工具) 另外建議可以使用的插件 * VeeValidate (表單驗證) * Yup (檢核庫) * Nuxt.js (處理SEO的靜態渲染) * Webpack (打包程式) * Bootstrap (模板) * bootstrap-vue (vue專用的bootstrap不須載入jquery) 從瀏覽器發出 Request 處理,到前端處理邏輯驗證,一路到後端 API 存取,一個完整的解決方案,十分推薦! ## 建議導入 SPA 如果網站服務很要求使用者體驗,希望操作起來更順暢,同時能做多工,這時就很推薦導入 SPA, 但導入後,由於 SPA 只有單一頁面,初次載入即下載全部內容,導致首次下載速度變慢,外加 SPA 裡面只有放程式邏輯,會讓 SEO 搜尋不到內容,導致網站排名下滑,故此建議下列解決辦法: * 加快首次下載速度 透過 lazyLoad 的設計,把程式邏輯跟元件延後下載,減輕首次載入負擔 * 不支援 SEO 建議透過 靜態化 套件,將網頁產生靜態頁面,讓 SEO 可搜尋到內容,詳細做法可參閱[連結](#導入-SPA-架構後,解決-SEO-的建議做法) 如何導入 SPA 實際作法如下: * 用vue-cli建立專案 vue-cli 為官方提供的開發工具,用於快速開發大型 SPA 網站,省去瑣碎的工作,快速建立起開發環境 * 建立專案時選用vue-router Vue Router 就是由前端模擬的路由,跟過去不同的是,換頁通常會由後端處理。而 Vue Router 存在就是為了實現 SPA(單頁式應用),當我們切換畫面時候就不需要向後端發出請求。 ## 建議導入狀態管理 Vuex Vuex採用單向數據流的概念,避免系統龐大下數據流混亂的情況,讓資料狀態是清晰可以預測的,便於維護與擴充;當元件遇到多個元件共享狀態,單向數據流的簡潔性很容易被破壞,因此 vuex 將元件的共享狀態抽取出來,以一個**全域單例模式管理** **Vuex的單向數據流** 通過元件執行 Actions , Actions 執行 Mutations , Mutations 更新 State 的狀態,更新後會觸發頁面資料更新,所有的狀態集中管理,所有的元件都能通過這個入口改變 state 中的資料 ![](https://i.imgur.com/BQV5QkP.png) 在 單向數據流中,Vuex 能為我們帶來幾點好處: * 直觀的運用狀態 * 結構清晰 * 防止重新載入元件時重複發送http請求 * 不用擔心元件結構出現多層時導致的數據流混亂 **Q:為何透過 Actions 來更新 Mutations 而不是直接更改 Mutations ?** A:因為 Mutation 只支持同步操作,不支持異步操作,因此所有的異步操作(ex: ajax 請求, setTimeout, Promise 等) 都要放在 Action 中執行。 **Q:為什麼 Mutation 不支持異步操作呢?** A:因為在 devtools 中會紀錄 Mutations 執行時傳進的 payload 以及改變的 state ,當在 Mutations 進行異步操作時,devtools 不知道 State 什麼時候被改變了,會出現資料不同步並且難以追蹤的狀況。 **Q:如果不按照上面兩點來執行,有什麼防範措施?** A:添加 strict: true 使 Vuex 存儲進入嚴格模式,在嚴格模式下,任何變異處理函數以外修改 Vuex state 都會拋出錯誤。 ``` import txtModules form ./product; export default new Vuex.Store({ strict: true, modules: {} }) ``` ## 導入 SPA 架構後,解決 SEO 的建議做法 SPA 會由單一頁面入口,透過 router 決定渲染的內容,在未做優化的情況下爬蟲只會爬到入口頁面的資料,這樣搜尋引擎優化的效果會不盡理想,如果要提高搜尋引擎內的能見度,需要另外將網頁的內容做處理,有以下幾種做法 解決做法如下: * 靜態化 (最推薦) 優點 - 純靜態文件,訪問速度快 - 對比 SSR,不涉及到服務器負載方面問題 - 靜態網頁不易遭到駭客攻擊,安全性更高 缺點: - 如果動態路由參數多的話不適用 * SSR 服務器渲染 * 開發條件所限,瀏覽器特定的代碼,只能在某些 lifecycle hook 中使用,一些 external library 可能需要特殊處理,才能在 Server 渲染應用程序中運行 * 環境和部屬要求更高,需要 Node.js server 運行環境 * 高流量的環境下,請準備對應的服務器負載,並明智地採用緩存 * 預渲染 prerender-spa-plugin 優點 - 改動小,加個插件就完成 缺點 - 無法使用動態路由 - 只適用少量頁面的項目,頁面多達幾百個的情況下,打包會很慢 * 使用 Phantomjs 對爬蟲做處理 優點 - 完全不用改動項目代碼,按原本的 SPA 開發即可,對比開發 SSR 成本小的多 - 對已用 SPA 開發完成的項目,這是不二之選 缺點 - 部屬需要 node 服務器支持 - 爬蟲訪問比網頁訪問要慢一些,因為定時要定時資源加載完成才返回給爬蟲 在不使用 node.js server 的情況下 可以使用靜態化或預渲染 ## UI/UX 套件建議使用 Bootstrap 前端頁面開發時,可以使用 UI/UX 套件減少開發的時間,建議可以使用通用性比較高的bootstrap , bootstrap 有兩大優點: * Grid System * bootstrap 有預設不同尺寸的樣板,在開發上可以針對需求直接使用預設的標籤 * 在設計響應式網頁時,可以依照不同螢幕寬度使用不同的標籤,使排版更精簡 * UI * 避免重工,可以應用一些現成的功能 * 較複雜的響應式設計則很快就可以應用 * 在不同專案中、或是同專案不同開發者 * 可以在開發過程中取得應用及解讀程式碼的一致性 * Bootstrap 也提供了一些速成樣板 * 確保跨瀏覽器的閱讀相容性 Bootstrap 是以 jquery 為基底使用的 如果想要使用 bootstrap 又不想加載 jqeury 可以使用 bootstrap-vue ## 建議導入 Validation schema 前端表單把資料傳到後端前,會檢查資料的正確性,處理這部分的流程建議使用 Validation schema。 傳統的表單驗證,無法處理多欄位連動檢核,外加檢核條件跟表單綁在一起,若在不同表單中有相同驗證邏輯,必須將相同邏輯複製過去,外加日後需要變更時,需要更改不同地方,容易造成遺漏,處理起來很麻煩。 透過 Validation schema + yup + vuex 不僅能做到多欄位連動的檢核,透過 yup 檢核庫自訂的檢核邏輯,同時可檢核多個相同邏輯的資料,減少程式出錯率。 建議做法 * Yup (檢核庫) yup 是針對數值驗證的檢核庫,針對客戶端的資料做驗證,yup 將驗證功能切分成單獨的部分,每個部份可以單獨使用或者合併使用,透過合併使用的方法去做到多欄位連動。 詳細可參考:[連結](https://github.com/jquense/yup) * VeeValidate (表單驗證插件) vee-validate 可以很輕鬆地處理複雜的驗證邏輯,並支持同步、異步驗證,並支援 yup 的 Validation schema 驗證,可輕鬆完成表單驗證。 詳細可參考:[連結](https://vee-validate.logaretm.com/v4/guide/validation) ## 建議導入打包工具 Webpack 現今的很多網頁其實可以看做是功能豐富的應用,它們擁有著複雜的 Javascript 程式碼和一大堆依賴包。為了簡化開發的複雜度,可以使用 webpack 之類的打包工具 建議原因: * 兼容 CommonJS & AMD & ES6 模組規範 * Bundle 效率高 * 可編譯語法和打包資源 (css, img, font…)入 JS 內 * JS 程式碼封裝 * 網路資源豐富、社群強大,Plugin 多 vue cli 提供六種基本樣板如下: - webpack - webpack-simple - browserify - browserify-simple - pwa - simple 多使用 webpack 於新增專案時選擇 webpack 即可 ## 撰寫 Vue 語法上幾個 Tips 俗話說的好,拿別人的錯誤的經驗,就能減少走錯路的機會,程式開發時也是如此,撰寫 Vue 時,有幾條應該要遵守的慣例,描述如下: 注意事項: 1. **在使用 v-for 時,永遠要綁定 key 值** 如果是透過 vue-cli 打造的專案,使用 v-for 卻沒有綁定 key 時,系統會報錯提醒,例如: ``` <div v-for="item in 5"> {{item}}</div> ``` 直到把程式碼修改完成,才會停止錯誤。 ``` <div v-for="item in 5" :key="item.id"> {{item}}</div> ``` 為何會發生這個問題呢?想像一下,當我們不綁定 key 時,如果產生了十個 li 節點,要怎麼只控制其中某個節點,綁定 key 用意,在於 v-for 產生的組件都是**唯一的**,以利日後開發。 1. **維持固定的寫法** 使用 v-on & v-bind 或是 slot 時,常常會搭配對應的縮寫 * '@' -> v-on * ':' -> v-bind * '#' -> slot 這是相當方便、且可讀性高的寫法,但有時候在同一個專案同時出現 v-on:click&@click 的狀況,這就相當惱人,跟 Code Style 依樣,要馬就全部用縮寫,不然就不要使用。 1. **避免 v-for & v-if 使用在同一個組件上** 使用 v-for 時,你想加入一些條件判斷讓他只顯示部份內容,可能程式會這樣撰寫。 ``` <h1>Admin Users</h1> <div v-for='user in users' v-if='uesr.isAdmin'> ``` 但實際運行時,會發覺有些問題,主因是 v-for 優先度高於 v-if,也就是會先迭代所有元素後,最終才檢查 v-if 的部分,如果有類似需求,建議使用 computed 屬性來達到效果。 ``` <div v-for="user in adminUsers" :key="user.key"> {{user.name}} </div> computed: { adminUsers() { return this.users.filter(user=> user.isAdmin) } } ``` 1. **永遠檢查傳入的 props** 父子層溝通時很時常透過 props 屬性,為求方便承接參數時,並不會額外做檢查,就可能寫出這段程式。 ``` props: ['currentUser', 'products'] ``` 但實際上不應該完全相信傳進來的資料,就跟後端會再重新驗證前端傳來的資料是一樣概念,適當的檢查可避免很多錯誤,上述範例建議可改寫為以下 ``` props: { currentUser: { type: Object, default: null, required: true, }, products: { type: Object, default: [], required: true, }, } ``` 1. **不要在 template 中塞入太複雜的邏輯** 很多時候我們使用 view 操作時,在元素上常常會加入一些基本 js 邏輯,例如: ``` <h1> {{user.name}} </h1> ``` 但請避免在 template 中塞入太多複雜得 js 邏輯,像是: ``` <h1> {{user.name.split(' ').reverse().join('')}} </h1> ``` 如同上面 v-for & v-if 情況依樣,最好使用 computed 來處理 ``` <h1> {{reversedName}} </h1> computed: { reversedName() { return this.user.name.split(' ').reverse().join('') } } ``` 1. **避免直接去操作DOM元素** vue 會透過 virtual DOM 的概念去處理資料變動時的畫面刷新,不僅可更有效率的處理刷新,也可節省許多資源,因此我們應該避免直接操作 DOM,如過真的要選取,建議使用 ref 屬性: ``` <h1 ref="title"> Hello World </h1> this.$refs.title // 利用這樣去選取該元素並作需要的操作 ``` ## 後端 API 串接時,建議幾種套件 vue 取得後端資料有以下方法 * vue-resource(原官方函式庫) * Axios * jQuery ($.ajax, $.get, etc.) * Fetch API Vue 原作者推薦使用 axios 替代原本官方的 vue-resource, 現在主要都使用 axios , axios 對 nodejs 的支援度較高 有以下特點 1. 在瀏覽器中發送 XMLHttpRequests 請求 1. 在 node.js 中發送 http請求 1. 支持 Promise API 1. 攔截請求和響應 1. 轉換請求和響應數據 1. 取消請求 1. 自動轉換 JSON 數據 1. 客户端支持保護安全免受 CSRF/XSRF 攻擊 ## 使用 Router 的注意事項 * 如何防止使用者未登入就拜訪頁面: 在 routers 內需要驗證的項目上加上屬性 meta: { requiresAuth: true} * 頁面只異動部分區塊的話可以用嵌套路由,加上 children 屬性 * Component 建議使用 Lazy Loading 的方式加載 例:component: ()=>import("@/view/pageB")

    Import from clipboard

    Paste your markdown or webpage here...

    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 lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    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 with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # 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
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    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.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        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
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

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

        Syncing

        Push failed

        Push successfully