SPA 单页面应用开发(重点)
SPA 的优势:因为是把页面都合并到一起,所以路由切换时,实际上是在当前页面切换显示,所以不会因网络问题造成页面卡顿、白屏。
SPA 的不足:合并后的文件体积特别的大,所以第一次打开页面时,比较慢。(解决方法是用按需加载)
router 路由(重点)
vue-router 配置基于 vue 的单页面应用(SPA)
// npm install vue-router -S
import VueRouter from 'vue-router';
// 将vue-router注册到全局,这样每一个组件都可以使用router-link和router-view组件了
Vue.use(VueRouter);
// 定义路由规则
var routes = [
{ path: '/', component: ind },
{ path: '/msg', component: msg },
{ path: '/hi', component: hi }
]
// 创建路由实例
var router = new VueRouter({ routes, mode:'history' });
// 将路由实例注入到vue实例中
new Vue({
el:"#app",
router,
render: h => h(App)
});
- router-link 组件:渲染后为a标签,点击这个标签后,浏览器地址栏会发生变化。
- router-view 组件:浏览器地址栏每次发生变化时,会根据路由规则,把匹配到的组件显示到router-view标签上。
<template>
<div>
<router-link to="/">ind</router-link>
<router-link to="/msg">msg</router-link>
<router-link to="/hi">hi</router-link>
<router-view></router-view>
</div>
</template>
router-link组件识别路由后会自动添加style样式
.router-link-exact-active{
color: green !important;
}
也可以自己定义样式
<router-link to="/hi" active-class="xyz" exact-active-class="abc">hi</router-link>
通过tag属性,可以将a标签解析成其他标签。
<router-link to="/hi" tag="li">hi</router-link>
路由模式:mode
- history
- hash(默认值。哈希、网址含#)
- abstract(抽象、网址不变)
var router = new VueRouter({ routes, mode:'history' });
用的较多的是history,每次页面切换的时候,浏览器地址栏看起来就像是传统的网站页面一样。
慎用 abstract,首次打开页面时 router-view 无法匹配 path='/',
所以可以在 app.vue 的 mounted 中执行 this.$router.push('/')
动态路由匹配
在浏览器中访问一个网址时,通常这个网址是有语义的,比如访问:
- news 表示新闻
- 102 表示新闻id
那么怎么配置这种路由呢?
路由规则页面
const routes = [
{
path : '/news/:id',
component: {
// 可以直接创建组件,使用render渲染,不能使用template渲染。
render(createElement){
return createElement('div', 'abc')
},
created(){
// 在js中接收浏览器地址栏中id对应的数据
console.log(this.$route.params)
}
}
}
]
某组件的html页面,由这个页跳转到NewsComponent页面
<router-link to="/news/102">点我跳转页面</router-link>
路由参数
路由中传递数据除了刚才的params外,还可以使用query数据。
路由规则页面
const routes = [
{
path : '/news',
component : NewsComponent
}
]
某组件的html页面,由这个页跳转到NewsComponent页面
<router-link to="/news?id=102">点我跳转页面</router-link>
NewsComponent组件的js部分
// 在js中接收浏览器地址栏中id对应的数据
this.$route.query.id
嵌套路由规则
移动端项目不建议使用嵌套的路由规则,如果必须要用到嵌套路由,通常也不会超过2层。
比如项目中,一级导航有首页和用户,用户页面又有二级导航登录、注册两个页面。
路由规则
const routes = [
{
path: '/',
component: IndexComponent
},
{
path: '/user',
component: UserComponent,
children: [
{ path: '/user/register', component: RegisterComponent },
{ path: '/user/login', component: LoginComponent }
]
}
]
children描述的是UserComponent组件内的路由规则,当根据路由规则匹配出对应的组件后,这个组件在UserComponent组件内,找到router-view渲染。
UserComponent组件
点击嵌套路由的链接时,只会在嵌套路由组件出口显示对应的组件。
<router-link to="/user/register">注册</router-link>
<router-link to="/user/login">登录</router-link>
<router-view></router-view>
声明式导航、编程式导航
- 声明式导航:html中的router-link标签实现页面跳转
- 编程式导航:通过js代码实现页面跳转
向history中添加记录
<router-link to="/">
this.$router.push("/")
this.$router.push({ path: '/html2', query:{a:1,b:2}})
不会向history中添加新纪录
<router-link to="/" replace>
this.$router.replace("/")
历史记录中前进及后退
this.$router.go(1)
路由对象下有2个常用的属性,一个是router:
- route.query、$route.params
- router.push()、router.go() 编程式导航方法都存到了这里
命名路由
给定义的路由规则起个名字,页面跳转时,使用该名字完成路由跳转。
路由规则
const routes = [
{
name: 'abc',
path: '/html1/:a/:b',
component: a
}
]
页面跳转
<router-link :to="{name:'abc',params:{a:1,b:2}}">html1/1/2</router-link>
<router-view></router-view>
this.$router.push({ name: 'abc', params:{a:1,b:2}})
命名视图
一个页面中,有多个路由出口,每个router-view渲染哪个组件呢?
路由规则
const routes = [
{ path: '/a', components: {one:a, two:b} },
{ path: '/b', components: {one:c} }
]
html部分
<router-link to="/a">a</router-link>
<router-link to="/b">b</router-link>
<router-view name="one"></router-view>
<router-view name="two"></router-view>
访问a时,one渲染a组件,two渲染b组件。访问b时,one渲染c组件,two不渲染组件,节点移除。
重定向
当我们访问a时,自动跳转到了b。
const routes = [
{ path: '/a', redirect: '/b' }
]
别名
当我们访问c时,url不变,但实际访问的是a。
const routes = [
{ path: '/a', alias: '/c', component:a }
]
守卫
路由中的守卫就是路由中的生命周期钩子函数。
全局守卫
只要发生页面跳转,无论是什么页面跳转,都会执行该钩子函数。
const router = new VueRouter({routes, mode:"history"})
router.beforeEach((to, from, next) => {
// to 表示到哪里去
// from 表示从哪里来
console.log(to, from);
// next 表示执行跳转
next();
})
路由守卫
在路由规则中,定义该钩子函数,表示渲染该组件之前执行守卫验证,如果有next则把组件渲染出来。
const routes = [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
console.log(to, from);
next();
}
}
]
组件守卫
在组件中定义该钩子函数
{
template: `...`,
beforeRouteEnter (to, from, next) {
// 不能获取组件实例 this 因为当守卫执行前,组件实例还没被创建
// 组件被渲染之前
console.log('beforeRouteEnter')
next()
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 修改路由数据前
console.log('beforeRouteUpdate')
next()
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 组件被移除前
console.log('beforeRouteLeave')
next()
}
}