本篇最後會產生的頁面在這:
本篇大綱
關於「套件集合站」
集合站是寫給同事看的,有一些網站常用的功能不一定要前端手刻才可以使用,網路上很多猛人寫了套件後開放給大家使用,而那些套件的說明文件跟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」,就會出現安裝的選項:

這邊就簡單的用編ES6的Babel跟控各頁網址的Router。按下Enter後就會問3個問題。
Router用history mode。
這是廣告,點擊一下可以幫本站多個一點點的廣告收入,謝謝
config一起寫進package.json裡。
要不要設成預設選項之一,就看自己未來的需求。
三個問題都回答後,就開始安裝專案。安裝完後會出現如何開啟服務的說明。

點進資料夾裡的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/,打開就可以看見初始的頁面:

因為有選擇裝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後,會出現哪些檔案被更動的訊息:

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

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的灰底那塊(第一個紅框處):

比方這邊資料分成article、nav,我想抓的是nav的那個json,那url就是:
https://xxxxxxxxx.firebaseio.com/nav.json
抓回來後的資料在放寫v-for就行了。
這邊的資料架構是這樣:

article是給內文用的,nav是導覽列用,下一層都是每一個套件的id名稱。
之所以會這樣子用,就是為了方便路由抓id。
我的路由是這樣寫:
<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。詳情可以看文件說明:
模版頁最後的原始碼在本文最後的原始檔中可以看到。
製作頁面
整個站的頁面就兩種版型:首頁、內文頁。
首頁主要是網站說明跟放公告,而內文頁都是針對路由給出的不同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後的資料夾,那就會是很乾淨的版本。
vue-router用history mode的注意事項
把build的檔案傳到主機上,遇到了一個錯誤。
我的router是用history mode,當我點開其他頁面,然後按下重新整理時,就會出現error500的伺服器錯誤。
這點是沒想到的,因為在開發時沒這問題,上到主機後就有了。
看了一下vue-router的文件說明,上面有提到:
這種模式要玩好,還需要後台配置支持。
HTML5 History模式
因為我們的應用是個單頁客戶端應用,如果後台沒有正確的配置,當用戶在瀏覽器直接訪問http://oursite.com/user/id
就會返回404,這就不好看了。
所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果URL匹配不到任何靜態資源,則應該返回同一個index.html
頁面,這個頁面就是你app依賴的頁面。
照著說明新增 .htaccess 的檔案後,就沒出現這個錯誤了。
但……我還是不知道原因啊!?希望對server了解的大大可以開示一下。
019/08/14補充:
留言區裡的Denny大大有解說,大家可以看一下留言內容,很清楚的解釋。
本篇原始碼
本篇套件集合站的原始碼,整理上傳到Github了:
https://github.com/letswritetw/letswrite-plugin-lib


關於 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 配置路由~
這不是D大嗎~
是本站第一位留言的(灑花)~
謝謝你的意見,有看懂了,也補充在文章中。