我的原文:https://www.hijerry.cn/p/33462.html
側邊導航
我們現在知道,單頁應用中的每一頁對應到一個vue組件,那麼總會有一些公共組件,例如導航,那這些公共組件在單頁中應該怎麼實現呢。我們先直接把導航的代碼寫出來試試。
版本1:先實現導航功能
html:
<div id="app">
<h1>導航</h1>
<ul class="menu">
<li>
<router-link to="/user">用戶管理</router-link>
</li>
<li>
<router-link to="/course">課程管理</router-link>
</li>
</ul>
<div>
<h2>首頁</h2>
<router-view></router-view>
</div>
</div>
app.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
const UserPage = () => import('./modules/User')
const CoursePage = () => import('./modules/Course')
Vue.use(VueRouter)
const routes = [
{ path: '/user', component: UserPage },
{ path: '/course', component: CoursePage }
]
const router = new VueRouter({
base: '/',
routes // (縮寫)相當於 routes: routes
})
const app = new Vue({
el: '#app',
router
});
此時已經可以通過導航來切換不同的頁面了。
我們可以發現這裏少了兩個東西:導航菜單沒有點亮、導航標題沒有根據路由變化來進行切換。
版本2:點亮菜單項
爲了方便,我們把導航單獨做成組件放在 components/particals/Sidebar.vue
文件中,把路由做成模塊放在 router
目錄下,把 導航標題
做成組件放在 components/particals/Header.vue
,完成後結構如下:
.
├── app.js
├── bootstrap.js
├── components
│ ├── ExampleComponent.vue
│ └── particals
│ ├── NavHeader.vue
│ └── Sidebar.vue
├── modules
│ ├── Course.vue
│ └── User.vue
└── router
└── index.js
此時app.js內容爲:
require('./bootstrap');
import Vue from 'vue'
import router from './router'
Vue.component('sidebar', () => import('./components/particals/Sidebar'))
Vue.component('nav-header', () => import('./components/particals/NavHeader'))
const app = new Vue({
el: '#app',
router
});
我們觀察生成的html頁面,發現生成的路由鏈接中,會自動的掛上一些標記:
這其實是vue-router的一個功能:https://router.vuejs.org/zh-cn/api/options.html#linkactiveclass
所以,我們只需在 app.scss
文件中添加如下代碼即可:
.menu a.router-link-active, .menu a.router-link-exact-active {
color: #0a6cd6;
}
.menu a{
color: #000;
}
版本3:切換標題
我們先來看看 NavHeader.vue
文件:
<template>
<div>
<h2 v-text="title"></h2>
</div>
</template>
<script>
export default {
data() {
return {
title: '首頁'
}
}
}
</script>
可以看到,組件內有一個 title
變量,我們在切換路由時,如果可以改變這個變量值就好了,Prop可以做到這一點:https://cn.vuejs.org/v2/guide/components.html#Prop
我們需要把 NavHeader.vue
script標籤內代碼改成:
export default {
props: ['title']
}
在 spa.blade.php
前端模板文件中,傳入 title
值:
<nav-header title="首頁2"></nav-header>
現在這個值只是一個字面量,我們把它改成動態值。先修改 app.js
,在裏面加上navTitle
變量:
const app = new Vue({
el: '#app',
data() {
return {
navTitle: '首頁'
}
},
router
});
修改模板文件,將 title
綁定爲 navTitle
變量:
<nav-header :title="navTitle"></nav-header>
好了,在路由切換時怎麼變更標題呢?在router/index.js
中加入以下代碼:
router.beforeEach((to, from, next) => {
if (to.fullPath == '/user') {
this.a.app.navTitle = '用戶管理'
} else if (to.fullPath == '/course') {
this.a.app.navTitle = '課程管理'
}
next()
})
beforeEach
函數會在路由切換時觸發
vuex
在公共組件過多時,公共組件在各個狀態之間時會變得比較混亂,而vuex就是爲解決這個問題而誕生的,我們現在使用vuex來實現 導航標題
的切換。
爲了方便起見,我們將導航作爲配置項,放在 config
目錄下,並通過 name
屬性來引用頁面:
config/menu.js
:
export default [
{
text: '用戶管理',
uri: { name: 'user'}
}, {
text: '課程管理',
uri: { name: 'course'}
}
]
同時修改 Sidebar.vue
內容爲:
<template>
<ul class="menu">
<li v-for="item in menus">
<router-link :to="item.uri" v-text="item.text"></router-link>
</li>
</ul>
</template>
<script>
import menu from "../../config/menu";
export default {
data() {
return {
menus: menu
}
}
}
</script>
同時在定義路由時,爲他們添加導航標題(meta.title
):
const routes = [
{
path: '/user',
name: 'user',
meta: { title: '導航標題:用戶管理' },
component: () => import('../modules/User')
},
{
path: '/course',
name: 'course',
meta: { title: '導航標題:課程管理' },
component: () => import('../modules/Course')
}
]
安裝
npm install vuex
使用
我們在建立 vuex/store.js
文件,用來保存一些公共的狀態:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
navTitle: '首頁'
},
mutations: {
changeNavTitle(state, title) {
state.navTitle = title
}
}
})
export default store
上述代碼定義了一個狀態 navTitle
表示導航標題,並提供了一個函數 changeNavTitle
來修改這個狀態。
在 app.js
中,將期引入到Vue中去:
...
import store from './vuex/store'
...
const app = new Vue({
...
store
...
});
當然也需要修改 NavHeader.vue
讓他把狀態 navTitle
顯示出來:
(記得把前端模板文件 spa.blade.php
裏面的 :title="navTitle"
去掉)
<template>
<div>
<h2 v-text="title"></h2>
</div>
</template>
<script>
export default {
computed: {
title() {
return this.$store.state.navTitle
}
}
}
</script>
隨路由切換
我們修改 beforeEach
函數:
...
import store from '../vuex/store'
...
router.beforeEach((to, from, next) => {
store.commit('changeNavTitle', to.meta.title)
next()
})
...
store.commit
函數會調用在 store.js
中 mutation
定義的方法,這也是官方推薦的修改狀態的方式。
意思是,你也可以使用 store.state.navTitle = to.meta.title
來直接修改狀態,但官方不推薦這麼做。
最後附上項目文件結構:
.
├── app.js
├── bootstrap.js
├── components
│ ├── ExampleComponent.vue
│ └── particals
│ ├── NavHeader.vue
│ └── Sidebar.vue
├── config
│ └── menu.js
├── modules
│ ├── Course.vue
│ └── User.vue
├── router
│ └── index.js
└── vuex
└── store.js