1.典型組件模板
<template>
</template>
<script>
import store from '../vuex/store';
import nvHeader from '../components/header.vue';
import {isLogin, setUserInfo} from '../vuex/actions';
import {getLoginState, getUserInfo} from '../vuex/getters';
export default {
data : function(){
return {
strToken : ''
}
},
methods : {
login : function() {
},
components : {
'nv-header' : nvHeader
},
computed: {
a: function(){
return 1+3;
}
},
store : store,
vuex : {
actions : {
userLogin : isLogin,
setUserInfo : setUserInfo
},
getters : {
userLoginState : getLoginState,
getUserInfo : getUserInfo
}
}
}
</script>
<style lang="sass">
</style>
2.路由
<div id="app">
<p>
<router-link to="/user/foo">/user/foo</router-link>
<router-link to="/user/foo/profile">/user/foo/profile</router-link>
<router-link to="/user/foo/posts">/user/foo/posts</router-link>
</p>
<router-view></router-view>
</div>
const User = {
template: `
<div class="user">
<h2>User {{ $route.params.id }}</h2>
<router-view></router-view>
</div>
`
}
const UserHome = { template: '<div>Home</div>' }
const UserProfile = { template: '<div>Profile</div>' }
const UserPosts = { template: '<div>Posts</div>' }
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User,
children: [
// UserHome will be rendered inside User's <router-view>
// when /user/:id is matched
{ path: '', component: UserHome },
// UserProfile will be rendered inside User's <router-view>
// when /user/:id/profile is matched
{ path: 'profile', component: UserProfile },
// UserPosts will be rendered inside User's <router-view>
// when /user/:id/posts is matched
{ path: 'posts', component: UserPosts }
]
}
]
})
頁面跳轉
// 字符串
router.push('home')
// 對象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 帶查詢參數,變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
(同級)展示多個視圖,而不是嵌套展示,例如創建一個布局,有 sidebar(側導航) 和main(主內容) 兩個視圖,這個時候命名視圖就派上用場了
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<div id="app">
<h1>Named Views</h1>
<ul>
<li><router-link to="/">/</router-link></li>
<li><router-link to="/other">/other</router-link></li>
</ul>
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
</div>
</div>
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const Baz = { template: '<div>baz</div>' }
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/',
// a single route can define multiple named components
// which will be rendered into <router-view>s with corresponding names.
components: {
default: Foo,
a: Bar,
b: Baz
}
},
{
path: '/other',
components: {
default: Baz,
a: Bar,
b: Foo
}
}
]
})
new Vue({
router,
el: '#app'
})
導航鉤子
(1)全局鉤子
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
每個鉤子方法接收三個參數:
**to: Route
**: 即將要進入的目標 路由對象
**from: Route
**: 當前導航正要離開的路由
**next: Function
**: 一定要調用該方法來 resolve 這個鉤子。執行效果依賴 next
方法的調用參數。
**next()
**: 進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 **confirmed**
(確認的)。
**next(false)
**: 中斷當前的導航。如果瀏覽器的 URL 改變了(可能是用戶手動或者瀏覽器后退按鈕),
那么 URL 地址會重置到 from 路由對應的地址。
**next('/')
或者 next({ path: '/' })
**: 跳轉到一個不同的地址。當前的導航被中斷,然后進行一個新的導航。
(2)某個路由獨享的鉤子
你可以在路由配置上直接定義 beforeEnter 鉤子:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
(3)組件內的鉤子
最后,你可以使用 beforeRouteEnter 和 beforeRouteLeave,在路由組件內直接定義路由導航鉤子,
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) => {
// 在渲染該組件的對應路由被 confirm 前調用
// 不!能!獲取組件實例 `this`
// 因為當鉤子執行前,組件實例還沒被創建
},
beforeRouteLeave (to, from, next) => {
// 導航離開該組件的對應路由時調用
// 可以訪問組件實例 `this`
}
}
beforeRouteEnter 鉤子 不能 訪問 this,因為鉤子在導航確認前被調用,因此即將登場的新組件還沒被創建。
不過,你可以通過傳一個回調給 next來訪問組件實例。在導航被確認的時候執行回調,并且把組件實例作為回調方法的參數。
beforeRouteEnter (to, from, next) => {
next(vm => {
// 通過 `vm` 訪問組件實例
})
}
可以 在 beforeRouteLeave 中直接訪問 this。這個 leave 鉤子通常用來禁止用戶在還未保存修改前突然離開。可以通過 next(false) 來取消導航。
路由元信息,用于登錄驗證
定義路由的時候可以配置 meta 字段:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// a meta field
meta: { requiresAuth: true }
}
]
}
]
})
下面例子展示在全局導航鉤子中檢查 meta 字段:
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!auth.loggedIn()) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // 確保一定要調用 next()
}
})
動態路由的一個demo
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const Home = {
template: `
<div class="home">
<h2>Home</h2>
<p>hello</p>
</div>
`
}
const Parent = {
data () {
return {
transitionName: 'slide-left'
}
},
// dynamically set transition based on route change
watch: {
'$route' (to, from) {
const toDepth = to.path.split('/').length
const fromDepth = from.path.split('/').length
this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
}
},
template: `
<div class="parent">
<h2>Parent</h2>
<transition :name="transitionName">
<router-view class="child-view"></router-view>
</transition>
</div>
`
}
const Default = { template: '<div class="default">default</div>' }
const Foo = { template: '<div class="foo">foo</div>' }
const Bar = { template: '<div class="bar">bar</div>' }
const router = new VueRouter({
mode: 'history',
base: __dirname,
routes: [
{ path: '/', component: Home },
{ path: '/parent', component: Parent,
children: [
{ path: '', component: Default },
{ path: 'foo', component: Foo },
{ path: 'bar', component: Bar }
]
}
]
})
new Vue({
router,
template: `
<div id="app">
<h1>Transitions</h1>
<ul>
<li><router-link to="/">/</router-link></li>
<li><router-link to="/parent">/parent</router-link></li>
<li><router-link to="/parent/foo">/parent/foo</router-link></li>
<li><router-link to="/parent/bar">/parent/bar</router-link></li>
</ul>
<transition name="fade" mode="out-in">
<router-view class="view"></router-view>
</transition>
</div>
`
}).$mount('#app')
假設我們有一個 Post 組件,需要基于 $route.params.id 獲取文章數據:
導航完成之后獲取:先完成導航,然后在接下來的組件生命周期鉤子中獲取數據。在數據獲取期間顯示『加載中』之類的指示。
導航完成之前獲取:導航完成前,在路由的 enter
鉤子中獲取數據,在數據獲取成功后執行導航。
<template>
<div class="post">
<div class="loading" v-if="loading">
Loading...
</div>
<div v-if="error" class="error">
{{ error }}
</div>
<div v-if="post" class="content">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
</div>
</template>
export default {
data () {
return {
loading: false,
post: null,
error: null
}
},
created () {
// 組件創建完后獲取數據,
// 此時 data 已經被 observed 了
this.fetchData()
},
watch: {
// 如果路由有變化,會再次執行該方法
'$route': 'fetchData'
},
methods: {
fetchData () {
this.error = this.post = null
this.loading = true
// replace getPost with your data fetching util / API wrapper
getPost(this.$route.params.id, (err, post) => {
this.loading = false
if (err) {
this.error = err.toString()
} else {
this.post = post
}
})
}
}
}
在導航完成前獲取數據
export default {
data () {
return {
post: null,
error: null
}
},
beforeRouteEnter (to, from, next) {
getPost(to.params.id, (err, post) =>
if (err) {
// display some global error message
next(false)
} else {
next(vm => {
vm.post = post
})
}
})
},
// 路由改變前,組件就已經渲染完了
// 邏輯稍稍不同
watch: {
$route () {
this.post = null
getPost(this.$route.params.id, (err, post) => {
if (err) {
this.error = err.toString()
} else {
this.post = post
}
})
}
}
}
路由信息對象的屬性
$route.path
類型: string
字符串,對應當前路由的路徑,總是解析為絕對路徑,如 "/foo/bar"
。
$route.params
類型: Object
一個 key/value 對象,包含了 動態片段 和 全匹配片段,如果沒有路由參數,就是一個空對象。
$route.query
類型: Object
一個 key/value 對象,表示 URL 查詢參數。例如,對于路徑 /foo?user=1
,則有$route.query.user == 1
,如果沒有查詢參數,則是個空對象。
$route.hash
類型: string
當前路由的 hash 值 (不帶 #
) ,如果沒有 hash 值,則為空字符串。
$route.fullPath
類型: string
完成解析后的 URL,包含查詢參數和 hash 的完整路徑。
$route.matched
類型: Array<RouteRecord>
一個數組,包含當前路由的所有嵌套路徑片段的 路由記錄 。路由記錄就是 routes
配置數組中的對象副本(還有在 children
數組)。
const router = new VueRouter({
routes: [
// 下面的對象就是 route record
{ path: '/foo', component: Foo,
children: [
// 這也是個 route record
{ path: 'bar', component: Bar }
]
}
]
})
當 URL 為 /foo/bar,$route.matched
將會是一個包含從上到下的所有對象(副本)。
$route.name
當前路由的名稱,如果有的話。(查看 命名路由)