用 Vue CLI 3 + Vuetify 製作說明頁面

用 Vue CLI 3 + Vuetify 製作說明頁面
用 Vue CLI 3 + Vuetify 製作說明頁面

2022.10.10 更新:這個專案用的套件,很多都有大幅度的更新,GitHub 的機器人也常常跳安全性有漏動,主動要求更新套件版本。本篇最後產出的 Demo 頁在今天關閉,程式碼留在 GitHub 上當一個紀錄跟練習。

關於「套件集合站」

集合站是寫給同事看的,有一些網站常用的功能不一定要前端手刻才可以使用,網路上很多猛人寫了套件後開放給大家使用,而那些套件的說明文件跟 Demo 有些都蠻齊全的。

通常對於使用套件會遇到的問題就是,同一個功能,比方輪播,就有很多人有出套件:Slick、Owl Carousel、Swiper……等,或是說明文件都英文,參數又多,等研究完了前端也差不多寫好了。

當初會製作這個套件集合站就是為了解決這二個問題。

首先,從常用的套件中挑出一個覺得好用的、常用的出來,比方輪播就選用了 Slick。

接著,附上要引用的 JS、CSS 的 CDN 網址,並加入一鍵 copy 路徑的功能。

最後,在 CodePen 上寫個使用的範例,iframe到頁面中。

原本的頁面是用 Vue CLI 2 開發,UI 是用 Vuetify 1.5.x 版。最近在看 Vue CLI 3,又發現 Vuetify 升到 2.0.5 版了,就想說不然來更新一下集合站,當作練習,也順便記錄一下開發的過程。


本篇使用資源

本篇用到的資源如下:

本文最後會附上套件集合站整理過的原始碼。


安裝 Vue CLI 3

安裝 Vue CLI 3 之前,必須先安裝 Node.js,官方是推薦 8.11.0 以上的版本。

裝完 Node.js 後,開啟終端機,輸入以下命令:

$ npm install -g @vue/cli

Mac 的話前面要多輸入「sudo」。

安裝完後,要檢查有沒有安裝成功,就在終端機輸入:

$ vue --version

如果有出現版本號就代表成功了。


建立 Vue CLI 3 專案

在目錄底下開啟終端機,輸入:

$ vue create 專案名稱

接著選擇「Manually select features」,就會出現安裝的選項:

Vue CLI 3 安裝選項
Vue CLI 3 安裝選項

這邊就簡單的用編 ES6 的 Babel 跟控各頁網址的 Router。按下 Enter 後就會問 3 個問題。

Router 用 history mode。

config 一起寫進 package.json 裡。

要不要設成預設選項之一,就看自己未來的需求。

三個問題都回答後,就開始安裝專案。安裝完後會出現如何開啟服務的說明。

Vue CLI 3 專案安裝完成訊息
Vue CLI 3 專案安裝完成訊息

點進資料夾裡的 README.md,可以看到使用的命令,以下 2 個是比較常用的部份:

Compiles and hot-reloads for development

$ npm run serve

Compiles and minifies for production

$ npm run build

輸入 npm run serve 後,預設的網址是 http://localhost:8080/,打開就可以看見初始的頁面:

Vue CLI 3 安裝完後的初始頁面
Vue CLI 3 安裝完後的初始頁面

因為有選擇裝 Router,所以頁面預設有 2 頁:Home、About,點選頂部的導覽列可以切換。

看到設定的路由檔案,有一招是用 CLI 2 時沒看到的,就是對 Component 做 lazy-load:

{
  path: '/about',
  name: 'about',
  component: () => import('./views/About.vue')
}

以前還真的不知道可以這樣用,長知識了。


安裝 Vuetify

Vuetify 是走 Google Material Design的UI framework,裡面包了很多常用的 UI,裝了以後就不用花時間自己刻樣式。

Vue CLI 3 可以安裝插件,也有提供命令:

$ vue add 插件來源

Vuetify 安裝說明 中,也有說明怎麼在 Vue CLI 3 上安裝,只要在終端機上輸入:

$ vue add vuetify

裝完後會出現自定義安裝的選項,文件中說預設 Default 就有提供導覽列的 App,這邊就選 Default。

安裝完 Vuetify 後,會出現哪些檔案被更動的訊息:

Vuetify更動檔案的訊息
Vuetify 更動檔案的訊息

執行「npm run serve」打開頁面後,會看見首頁整個不一樣了:

裝完Vuetify後的首頁
裝完 Vuetify 後的首頁

Vue CLI 3 裝完了,Vuetify 也裝完了,接下來就是製作頁面跟接資料。


製作頁面模版

製作一個頁面,一開始很花時間的就是做出一個模版給其它頁套用,模版中要包含天地跟導覽列。

而 Vuetify 在 Application 這段就有提供導覽列在側邊的版型,版型中也包了天地,因此就 copy 下來修改,把用按鈕控制側邊導覽列的部份也寫進去,整個模版的架構如下(App.vue):

側邊導覽列的部份綁一個 v-model="drawer",用 app-bar-nav-icon 去控制 true / false,就可以打開/關閉側邊導覽列了。

抓 Firebase 資料

選單的項目用 v-for 處理,資料放在 Firebase 上,這邊用 Realtime Database。

Firebase 的規則設定,如果 read 設成 true,就可以直接 GET 資料回來,Request URL 在 Database 的灰底那塊(第一個紅框處):

firebase GET Url
Firebase GET Url

比方這邊資料分成 article、nav,我們想抓的是 nav 的那個 JSON,那 URL 就是:

https://xxxxxxxxx.firebaseio.com/nav.json

抓回來後的資料在放寫 v-for 就行了。

這邊的資料架構是這樣:

firebase上的資料架構
Firebase 上的資料架構

article 是給內文用的,nav 是導覽列用,下一層都是每一個套件的id名稱。

之所以會這樣子用,就是為了方便路由抓 id。

August 的路由是這樣寫:

<v-list-item
   v-for="(n, v) in asideNav" :key="v"
   :to="'/plugin-' + v"
>

用「plugin-」當開頭是為了路由可以判斷要渲染哪一個 Component。

「v」就是 ajaxLoading、alert…… 等等的 key。

因此當點擊了導覽列,進到頁面後,就可以抓到那一頁的 id 是什麼,用 id 去GET:

https://xxxxxxxx.firebaseio.com/article/${this.id}.json

這樣就可以抓到這個套件在 article 裡的資料。

這邊有踩到一個坑,說是坑,不如說是當初學 Vue Router 時,文件沒看仔細。

Vue Router:id、pathMatch

內文頁的路由是設這樣:

{
  path: '/plugin-*',
  name: 'plugin',
  component: () => import('./views/Plugins.vue')
}

之前在抓路由的 id 時,都是這樣抓:

this.$route.params.id

這邊一樣用相同方式抓時,就發現報錯,console.log 後又發現 params 裡沒有 id,卻有一個 pathMatch。

翻了一下文件後,才發現當路由path設成「*」,要抓任意路徑時,$route.params 會提供的參數就是 pathMatch。詳情可以看文件說明:

捕獲所有路由或 404 Not found 路由

模版頁最後的原始碼在本文最後的原始檔中可以看到。


製作頁面

整個站的頁面就兩種版型:首頁、內文頁。

首頁主要是網站說明跟放公告,而內文頁都是針對路由給出的不同 id 去抓不同的資料回來渲染。

其實當模版頁完成後,做首頁、內文頁就快多了。

上段中有說資料庫的架構可以讓我從路由上判斷要去抓哪個資料了,因此做頁面的部份就是把抓到的資料塞進去而己。

這段要特別說明的是,因為用的是 Vue Router,所以實際頁面並不會重新讀取一次,這會造成一個問題,就是 GA 的數據不會因為進到不同頁面而 Page View +1。

為了解決頁面瀏覽量可以確實進到 GA,必需手動寫 PV + 1,寫在路由變動後執行的 methods 裡就行,如下:

gtag('config', 'UA-xxxxxxxx-x', {
  'page_title': 頁面title,
  'page_location': location.origin,
  'page_path': location.pathname
});

然後又會遇到另一個坑,就是因為首頁也是路由的一個網址,埋 GA code 時預設是 PV + 1 了,如果又因為在 methods 我們手動發 PV + 1,就會造成首頁的流量每次都多計一次。

解決這問題很簡單,就是把 GA 提供的追蹤碼,埋碼時刪掉 config 那句就行。

一般 GA 提供要埋的追蹤碼是這樣:

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-xxxxxxxx-x"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'UA-xxxxxxxx-x');
</script>

gtag('config', 'UA-xxxxxxxx-x') 這行,因為我們在 method 裡有寫了,這行就要刪掉,就解決了瀏覽數重複計算的問題。


build 產出原始碼

code 都寫好後,最後一步就是打包原始碼傳到主機。

打包的命令是:

$ npm run build

在 Vue CLI 3 上,有一些打包上的 config 可以使用,可以參考 官方文件

首先,要先新增一個檔案,檔名為「vue.config.js」,目前比較常用的設定是以下:

module.exports = {
  publicPath: '',
  outputDir: 'plugin-lib', // 產出的資料夾名稱
  assetsDir: 'dist', // 靜態檔的資料夾名稱
  filenameHashing: true // bundle出來的檔案是否要有hash值
}

由於有改變產出的資料夾名稱,在 build 後,會看到的資料夾結構如下:

build出來後的資料夾結構
build 出來後的資料夾結構

一開始看到 build 出來,會 build 成一個獨立的資料夾,覺得蠻好的,這樣就可以開發、發行兩個分別控管。如果要跟後端合作時,也只要提供 build 後的資料夾,那就會是很乾淨的版本。


vue-router 用 history mode 的注意事項

把 build 的檔案傳到主機上,遇到了一個錯誤。

August 的 router 是用 history mode,當我點開其他頁面,然後按下重新整理時,就會出現 error500 的伺服器錯誤。

這點是沒想到的,因為在開發時沒這問題,上到主機後就有了。

看了一下 vue-router 的文件說明,上面有提到:

這種模式要玩好,還需要後台配置支持。
因為我們的應用是個單頁客戶端應用,如果後台沒有正確的配置,當用戶在瀏覽器直接訪問
http://oursite.com/user/id就會返回404,這就不好看了。
所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果URL匹配不到任何靜態資源,則應該返回同一個
index.html頁面,這個頁面就是你app依賴的頁面。

HTML5 History模式

照著說明新增 .htaccess 的檔案後,就沒出現這個錯誤了。

但……還是不知道原因啊!?希望對 Server 了解的大大可以開示一下。


本篇原始碼

本篇套件集合站的原始碼,整理上傳到 GitHub 了:

https://github.com/letswritetw/letswrite-plugin-lib

Summary
用 Vue CLI 3 + Vuetify 製作說明頁面
Article Name
用 Vue CLI 3 + Vuetify 製作說明頁面
Description
用Vue CLI 3 + Vuetify 製作說明頁面 本篇大綱:關於「套件集合站」、本篇使用資源、安裝Vue CLI 3、建立Vue CLI 3專案、安裝Vuetify、製作頁面模版、抓firebase資料、Vue Router:id、pathMatch、製作頁面、build 產出原始碼、本篇原始碼。
August
Let's Write
Let's Write
https://letswritetw.github.io/letswritetw/dist/img/logo_512.png
訂閱
通知
guest

2 Comments
最舊
最新
Inline Feedbacks
看所有留言
Denny
Denny
5 年 之前

關於 Server error,提供淺見但不一定正確,供參考。

Vue Router 在 hash 模式下 URL 會多出 # 號,
不論 # 號後面的值,都還算是同一個 page file,
因此 refresh,server 都維持跑 index.html 檔,再由 Vue router 依據 # 號來判斷路由。

而在 history 模式時少了 # 號,如果還未設置 server 端的 URL 跳轉設定,
頁面 refresh 時,會用一般 server 跑 file path 方式去讀檔案,
如 /about ,就會因找不到 about 這個實體檔案,而出 error,
Vue router 所需的 server rewrite 規則,就是不論 URL 為何,
都讓它統一跑 index.html (或 index.php 之類),再由 Vue router 配置路由~