入行至今也一段時間啦,雖不是多坎坷但也沒順遂到哪去,踩坑、debug、體驗純靠北工程師上的各種職場鳥事,導致 blog 呈現半放置狀態都是藉口。
回到正題,用 Vue.js 前端框架的理由很多,大概可以另外寫一篇騙文章數,是最近替公司後台頁面做重構,有機會用上現代框架,藉此寫一下開發流程,也讓這裡少長些草。
搭一個Vue app
使用 vue-cli
Vue.js 官方提供快速搭建工具 vue-cli,類似 React.js 的 creat-react-app,Github 上安裝與設定文檔寫得很清楚就不贅述,設定集個人是偏好較乾淨快速、有需求套件自己再裝的webpack-simple
。小黑窗輸入vue init webpack-simple login
建立一個叫做 login 的專案資料夾,再安裝完裡面的套件後就能用npm run dev
讓他跑起來跑起來。
架構
先簡單規劃一下頁面流程:
- 使用者會到 login 頁進行登入
- 登入成功後進到主畫面
- 主畫面包含 header 導航列,能切換主頁與使用者資訊頁,與一個登出鈕
拆分component
Vue.js 很大的優點就是能將頁面 UI 元件模組化。一頁一檔、維護有方。由以上需求,我們在/src
資料夾下建一個/components
資料夾,裡面建立各頁面的 vue 檔長這樣:
1 2 3 4 5
| └ components ├ Login.vue ├ Header.vue ├ Home.vue └ UserInfo.vue
|
而在單頁應用SPA,達成這些頁面的切換就是路由的範疇,是該 vue-router 出場了。
路由必備 vue-router
vue 官方提供 vue-router(文件) 幫助我們實現 routing ,安裝成專案的 dependency:
定義路由
個人傾向將路由規則獨立一個檔案管理,在/src
資料夾下新建一個 routes.js
。裡面先寫好簡單的兩個路由:
routes.js1 2 3 4 5 6 7 8 9 10 11 12 13
| import Login from './components/Login.vue'; import Home from './components/Home.vue';
export const routes = [ { path: '/login', component: Login }, { path: '/', component: Home } ];
|
這段想寫在main.js
裡也行,只要讓 router 帶入正確的 routes array 就好,這裡只是 export 出來
將main.js
改成:
main.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import Vue from 'vue'; import VueRouter from 'vue-router'; import App from './App.vue'; import { routes } from './routes'
Vue.use(VueRouter);
const router = new VueRouter({ routes, mode: 'history' });
new Vue({ el: '#app', router, render: h => h(App) });
|
vue-router 預設使用 # 字模擬 anchor 的 url 導向方式,避免整頁刷新,這裡改成 history mode 以呈現乾淨的 url path,相應的 server 端也必須設定總是回應index.html
的內容,以避免導向錯誤,可以參考文件
所見所得
將App.vue
中頁面加入<router-view>
,路由規則定義的 component 將會 mount 在上面:
App.vue1 2 3 4 5 6 7 8 9 10 11
| <template> <div id="app"> <router-view></router-view> </div> </template>
<script> export default { name: 'app', } </script>
|
然後簡單的寫一下Home.vue
,跑一下npm run dev
,應該就能看到 Home 字出現在瀏覽器中:
Home.vue1 2 3
| <template> <h1>Home</h1> </template>
|
接著編輯登入頁面Login.vue
Login.vue1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <template> <div> <h1>Login Page</h1> <form @submit.prevent="login"> <label>User Name</label> <input type="text" v-model="userName" required> <br> <label>Password</label> <input type="password" v-model="password" required> <br> <button type="submit">Log In</button> </form> </div> </template> <script> export default { data () { return { userName: '', password: '', } }, methods: { login(){ let auth = true;
if( auth ) this.$router.push('/'); else alert('login failed') } } } </script>
|
v-on 綁定<form>
元素的 submit 事件,.prevent
後綴防止原生方法產生頁面重整,而改用自定的login method。
手動在網址後打上 /login
,就能看到登入表格,利用this.$router.push('/')
導向至主頁。
Header.vue1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <template> <div> <router-link to="/">Home</router-link> <router-link to="/userInfo">User Info</router-link> <a href="" @click.prevent="logout">Logout</a> </div> </template> <script> export default { methods: { logout(){ this.$router.push('/login'); } } } </script>
|
template 的 router-link
會 render 成<a href="..."></a>
的超連結,但不會重整頁面,而是改變路由、滑順的 mount 元件上去,SPA 要的就是這個感覺。
命名 router-view
可是瑞凡, Header 是只有登入後才會看到的元件,怎麼辦?
對於路由條件式的掛載元件,簡單的實作是在App.vue
,加上另外指定 name 的<router-view>
1 2 3 4
| <div id="app"> <router-view name="nav"></router-view> <router-view></router-view> </div>
|
然後在路由規則裡,把需要 Header 的路由改成 components ( 加個s )並使用物件, key 名將會自動匹配到指定 name 的 router-view,沒指定的會 fallback 至 default
。
routes.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| import Login from './components/Login.vue'; import Header from './components/Header.vue'; import Home from './components/Home.vue'; import UserInfo from './components/UserInfo.vue';
export const routes = [ { path: '/login', component: Login }, { path: '/', components: { default: Home, nav: Header } }, { path: '/userInfo', components: { default: UserInfo, nav: Header } }, ];
|
順便完成 UserInfo.vue
:
UserInfo.vue1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template> <div> <h1>UserInfo</h1> <h3>user name:</h3> <p>{{ userName }}</p> <h3>ID:</h3> <p>{{ userId }}</p> </div> </template> <script> export default { data () { return { userName: 'Steven Chou', userId: 9527, } } } </script>
|
中場休息
大致完成了半殘的登入系統,各種點擊也能正常作動,但目前直接透過 URL 都能造訪任一個頁面,不用yoyodiy就能繞過登入機制看光光,完全沒卵用。
下一篇將繼續實作完整的登入驗證功能