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 }
]
}
]
})
頁(yè)面跳轉(zhuǎn)
// 字符串
router.push('home')
// 對(duì)象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 帶查詢參數(shù),變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
(同級(jí))展示多個(gè)視圖,而不是嵌套展示,例如創(chuàng)建一個(gè)布局,有 sidebar(側(cè)導(dǎo)航) 和main(主內(nèi)容) 兩個(gè)視圖,這個(gè)時(shí)候命名視圖就派上用場(chǎng)了
<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'
})
導(dǎo)航鉤子
(1)全局鉤子
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
每個(gè)鉤子方法接收三個(gè)參數(shù):
**to: Route
**: 即將要進(jìn)入的目標(biāo) 路由對(duì)象
**from: Route
**: 當(dāng)前導(dǎo)航正要離開(kāi)的路由
**next: Function
**: 一定要調(diào)用該方法來(lái) resolve 這個(gè)鉤子。執(zhí)行效果依賴 next
方法的調(diào)用參數(shù)。
**next()
**: 進(jìn)行管道中的下一個(gè)鉤子。如果全部鉤子執(zhí)行完了,則導(dǎo)航的狀態(tài)就是 **confirmed**
(確認(rèn)的)。
**next(false)
**: 中斷當(dāng)前的導(dǎo)航。如果瀏覽器的 URL 改變了(可能是用戶手動(dòng)或者瀏覽器后退按鈕),
那么 URL 地址會(huì)重置到 from 路由對(duì)應(yīng)的地址。
**next('/')
或者 next({ path: '/' })
**: 跳轉(zhuǎn)到一個(gè)不同的地址。當(dāng)前的導(dǎo)航被中斷,然后進(jìn)行一個(gè)新的導(dǎo)航。
(2)某個(gè)路由獨(dú)享的鉤子
你可以在路由配置上直接定義 beforeEnter 鉤子:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
(3)組件內(nèi)的鉤子
最后,你可以使用 beforeRouteEnter 和 beforeRouteLeave,在路由組件內(nèi)直接定義路由導(dǎo)航鉤子,
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) => {
// 在渲染該組件的對(duì)應(yīng)路由被 confirm 前調(diào)用
// 不!能!獲取組件實(shí)例 `this`
// 因?yàn)楫?dāng)鉤子執(zhí)行前,組件實(shí)例還沒(méi)被創(chuàng)建
},
beforeRouteLeave (to, from, next) => {
// 導(dǎo)航離開(kāi)該組件的對(duì)應(yīng)路由時(shí)調(diào)用
// 可以訪問(wèn)組件實(shí)例 `this`
}
}
beforeRouteEnter 鉤子 不能 訪問(wèn) this,因?yàn)殂^子在導(dǎo)航確認(rèn)前被調(diào)用,因此即將登場(chǎng)的新組件還沒(méi)被創(chuàng)建。
不過(guò),你可以通過(guò)傳一個(gè)回調(diào)給 next來(lái)訪問(wèn)組件實(shí)例。在導(dǎo)航被確認(rèn)的時(shí)候執(zhí)行回調(diào),并且把組件實(shí)例作為回調(diào)方法的參數(shù)。
beforeRouteEnter (to, from, next) => {
next(vm => {
// 通過(guò) `vm` 訪問(wèn)組件實(shí)例
})
}
可以 在 beforeRouteLeave 中直接訪問(wèn) this。這個(gè) leave 鉤子通常用來(lái)禁止用戶在還未保存修改前突然離開(kāi)。可以通過(guò) next(false) 來(lái)取消導(dǎo)航。
路由元信息,用于登錄驗(yàn)證
定義路由的時(shí)候可以配置 meta 字段:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// a meta field
meta: { requiresAuth: true }
}
]
}
]
})
下面例子展示在全局導(dǎo)航鉤子中檢查 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() // 確保一定要調(diào)用 next()
}
})
動(dòng)態(tài)路由的一個(gè)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')
假設(shè)我們有一個(gè) Post 組件,需要基于 $route.params.id 獲取文章數(shù)據(jù):
導(dǎo)航完成之后獲取:先完成導(dǎo)航,然后在接下來(lái)的組件生命周期鉤子中獲取數(shù)據(jù)。在數(shù)據(jù)獲取期間顯示『加載中』之類(lèi)的指示。
導(dǎo)航完成之前獲取:導(dǎo)航完成前,在路由的 enter
鉤子中獲取數(shù)據(jù),在數(shù)據(jù)獲取成功后執(zhí)行導(dǎo)航。
<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 () {
// 組件創(chuàng)建完后獲取數(shù)據(jù),
// 此時(shí) data 已經(jīng)被 observed 了
this.fetchData()
},
watch: {
// 如果路由有變化,會(huì)再次執(zhí)行該方法
'$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
}
})
}
}
}
在導(dǎo)航完成前獲取數(shù)據(jù)
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
})
}
})
},
// 路由改變前,組件就已經(jīng)渲染完了
// 邏輯稍稍不同
watch: {
$route () {
this.post = null
getPost(this.$route.params.id, (err, post) => {
if (err) {
this.error = err.toString()
} else {
this.post = post
}
})
}
}
}
路由信息對(duì)象的屬性
$route.path
類(lèi)型: string
字符串,對(duì)應(yīng)當(dāng)前路由的路徑,總是解析為絕對(duì)路徑,如 "/foo/bar"
。
$route.params
類(lèi)型: Object
一個(gè) key/value 對(duì)象,包含了 動(dòng)態(tài)片段 和 全匹配片段,如果沒(méi)有路由參數(shù),就是一個(gè)空對(duì)象。
$route.query
類(lèi)型: Object
一個(gè) key/value 對(duì)象,表示 URL 查詢參數(shù)。例如,對(duì)于路徑 /foo?user=1
,則有$route.query.user == 1
,如果沒(méi)有查詢參數(shù),則是個(gè)空對(duì)象。
$route.hash
類(lèi)型: string
當(dāng)前路由的 hash 值 (不帶 #
) ,如果沒(méi)有 hash 值,則為空字符串。
$route.fullPath
類(lèi)型: string
完成解析后的 URL,包含查詢參數(shù)和 hash 的完整路徑。
$route.matched
類(lèi)型: Array<RouteRecord>
一個(gè)數(shù)組,包含當(dāng)前路由的所有嵌套路徑片段的 路由記錄 。路由記錄就是 routes
配置數(shù)組中的對(duì)象副本(還有在 children
數(shù)組)。
const router = new VueRouter({
routes: [
// 下面的對(duì)象就是 route record
{ path: '/foo', component: Foo,
children: [
// 這也是個(gè) route record
{ path: 'bar', component: Bar }
]
}
]
})
當(dāng) URL 為 /foo/bar,$route.matched
將會(huì)是一個(gè)包含從上到下的所有對(duì)象(副本)。
$route.name
當(dāng)前路由的名稱(chēng),如果有的話。(查看 命名路由)