Vue Router路由--潘登同学的前端笔记
安装Vue Router
<!-- 注意:要在cd vue-router-demo下 -->
cnpm install vue-router --save
<!-- 上面那个不行就用下面的 -->
npm install vue-router --save
save操作能将依赖写入package.json
然后增加路由配置(在src下main.js文件中)
import VueRouter from 'vue-router'
Vue.use(VueRouter)
启动
npm run serve
Router的基础使用
(均在main.js下进行操作)
- 1.导入组件(页面)
import Home from "./pages/Home.vue"
import User from "./pages/User.vue"
- 2.定义路由(
path
key表示跳转后页面link的显示)
const routes = [
{path:"/",component:Home},
{path:"/User",component:User},
]
- 3.创建路由对象
const router = new VueRouter({
routes
})
- 4.挂载路由 将路由对象挂载到Vue的实例对象当中
new Vue({
router,
render: h => h(App),
}).$mount('#app')
- 5.最后回到
APP.vue
在主容器下,定义路由出口
<router-view></router-view>
- 6.导航效果(在
APP.vue
在主容器下)
to
属性与之前的path属性对应
<router-link to="/">Go to Home</router-link>
<router-link to="/User">Go to User</router-link>
动态匹配路由
(在user后面加上用户id不同用户不同页面信息)
- 1.修改上面第二步
// useid是一个key不是固定写法,且传入参数没有限制
const routes = [
{path:"/",component:Home},
{path:"/User/:useid/:name",component:User},
]
- 2.在跳转的页面传递值
<router-link to="/User/100001/Pandeng">Go to User</router-link>
- 3.在对应的页面获取数据
<div>
<h3>用户中心{{ $route.params.useid }}--{{ $route.params.name }}</h3>
</div>
文件分离
因为main.js是整个项目的主入口文件,所有东西都放进去不好;
在assets同级目录下,新建一个router文件夹,新建一个index.js
将路由相关的语句转到新文件中
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from "../pages/Home.vue"
import User from "../pages/User.vue"
Vue.use(VueRouter)
// 定义路由
// useid是一个key不是固定写法
const routes = [
{ path: "/", component: Home },
{ path: "/User/:useid/:name", component: User },
]
// 创建路由对象
const router = new VueRouter({
routes,
})
// 挂载路由 导出路由
export default router
回到main.js中, 导入即可
import router from "./router"
// 挂载路由 将路由对象挂载到Vue的实例对象当中
new Vue({
router,
render: h => h(App),
}).$mount('#app')
路由嵌套
- 1.在
New.vue
同级目录下创建新文件夹newsub
<!-- 创建新闻向下子目录页面(sports_new.vue,entertainment_new.vue) -->
<div>
<h3>体育新闻</h3>
</div>
<div>
<h3>娱乐新闻</h3>
</div>
- 2.回到index.js文件中添加子页面
import Sports_new from "../pages/newsub/sports_new.vue"
import Entertainment_new from "../pages/newsub/entertainment_new.vue"
// 在New对象新增children的key
{ path: "/News", component: News,
children:[
{path: "Sports_new", component: Sports_new,},
{path: "Entertainment_new", component: Entertainment_new,},
]},
- 3.去到New.vue文件中,添加子目录
<div>
<h3>新闻页面</h3>
<router-link to="/News/Sports_new">Go to Sports</router-link> |
<router-link to="/News/Entertainment_new">Go to Entertainment</router-link>
<!-- 路由出口 -->
<router-view></router-view>
</div>
编程式导航
前面的路由跳转,在页面时都会被渲染成a标签,如果我们想通过事件跳转,比如点击按钮
// 在User.vue下
<button @click="clikeHandle">回首页</button>
methods:{
clikeHandle() {
this.$router.push("/");
// this.$router.replace("/"); 也能跳转
// 区别:push可以叠加缓存,从a跳转到b,能返回a
// replace不能退换原页面
}
}
命名路由
修改跳转方式
// 在main.js下
{ path: "/User/:useid/:name", component: User,name:"User" },
// 在APP.vue下
<router-link :to="{ name:'User', params:{useid:100001, name:'pandeng'}}">Go to User</router-link> |
对编程式导航也能实现跳转
methods:{
clikeHandle() {
this.$router.push({name:"Home"});
}
}
命名视图
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar
(侧导航) 和 main
(主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view
没有设置名字,那么默认为 default
。
具体业务: 想在各个页面都增加一个广告
<!-- 在pages下创建新文件AD.vue -->
<div>
<h3>广告页面</h3>
</div>
<!-- 在index.js下导入ad -->
import Advertisement from "../pages/AD.vue"
<!-- 修改想要插入页面的component,将其改为components,如果想应用到全部页面,就把所有的components都改一遍 -->
{
path: "/",
components: {
default:Home,
Ad: Advertisement,
},
name:"Home"
},
<!-- 在APP.vue下新增一个出口,这里的name对应回刚才修改components中Advertisement的key--Ad -->
<router-view name="Ad"></router-view>
重定向与别名
“重定向”的意思是,当用户访问 /a
时,URL 将会被替换成 /b
,然后匹配路由为 /b
具体业务:现在当我们打开News页面的时候,既不显示体育新闻也不显示娱乐新闻,我们想让他默认显示一个东西
// 在index.js文件中 与path: "/News", 同级对象下
redirect:"/News/Sports_new",
/a
的别名是 /b
,意味着,当用户访问 /b
时,URL 会保持为 /b
,但是路由匹配则为 /a
,就像用户访问 /a
一样。
业务逻辑:用户不小心输出页面,将Home输为home,但是我们仍能让其访问
// 在index.js 与path: "/", 同级下
alias:"/home",
HTML5的History模式
现在我们的页面默认是带有#
的,我们想去掉这个可以在路由中设置mode
// 创建路由对象
const router = new VueRouter({
mode:"history",
// mode:"hash", 默认hash模式
routes,
})
当你使用 history 模式时,URL 就像正常的 url,例如 http://localhost:8080/News/Sports_new
,也好看!
不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://localhost:8080/News/Sports_new
就会返回 404,这就不好看了。
所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
报错解决
如果报错 Error:Can‘t resolve ‘vue/types/umd‘ in ......
可能是main.js中出现这一行,删掉即可
Router进阶
路由导航
“导航”表示路由正在发生改变。vue-router
提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。
全局前置守卫
// 在index.js创建路由对象下
router.beforeEach((to,from,next) =>{
console.log(from); // 当前导航正要离开的路由
console.log(to); // 即将要进入的目标 路由对象
next(); // 允许跳转
})
next函数,是一个钩子函数,执行效果依赖 next
方法的调用参数。
next()
: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。next(false)
: 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。next('/')
或者next({ path: '/' })
: 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向next
传递任意位置对象,且允许设置诸如replace: true
、name: 'home'
之类的选项以及任何用在router-link
的to
prop 或router.push
中的选项。next(error)
: (2.4.0+) 如果传入next
的参数是一个Error
实例,则导航会被终止且该错误会被传递给router.onError()
注册过的回调。
全局解析守卫
可以用 router.beforeResolve
注册一个全局守卫。这和 router.beforeEach
类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
全局后置钩子
前置是跳转之前发生,后置是跳转之后发生
// 在index.js创建路由对象下
router.afterEach((to,from) =>{
console.log(to,from);
})
路由独享的守卫
可以在路由配置上直接定义 beforeEnter
守卫
// 在index.js的想要设置路由的配置上(与path: "/", 同级)
beforeEnter:(to,from,next)=>{
console.log(to,from);
next();
},
组件内的守卫
可以在路由组件内直接定义以下路由导航守卫
- beforeRouteEnter
- beforeRouteUpdate
- beforeRouteLeave
// 在Home.vue中与data()同级下
beforeRouteEnter(to, from,next){
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
console.log(to,from);
next();
},
beforeRouteUpdate(to, from,next){
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
console.log(to,from);
next();
},
beforeRouteLeave(to, from,next){
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
console.log(to,from);
next();
},
完整的导航解析流程
- 1.导航被触发。
- 2.在失活的组件里调用 beforeRouteLeave 守卫。
- 3.调用全局的 beforeEach 守卫。
- 4.在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 5.在路由配置里调用 beforeEnter。
- 6.解析异步路由组件。
- 7.在被激活的组件里调用 beforeRouteEnter。
- 8.调用全局的 beforeResolve 守卫 (2.5+)。
- 9.导航被确认。
- 10.调用全局的 afterEach 钩子。
- 11.触发 DOM 更新。
- 12.调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
路由原信息
定义路由的时候可以配置 meta 字段
具体业务:用户登录了才能进入用户首页,不登录进不去
// 在index.js中,User路由下,与path: "/User/:useid/:name", 同级下
meta:{
isLogin:true,
}
// 然后在下方全局前置守卫处
router.beforeEach((to,from,next) =>{
// console.log(from); // 当前导航正要离开的路由
// console.log(to); // 即将要进入的目标 路由对象
if(to.meta.isLogin){
// 判断用户是否已经登录
const token = true;
if(token){
next(); // 允许跳转
}else{
next("/Login");
}
}else {
next();
}
})
路由懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
具体业务: 我们加载首页的时候其实不需要加载新闻下的路由,可以等到点进新闻界面再加载
// 在index.js下,去掉原本的import
// import Sports_new from "../pages/newsub/sports_new.vue"
// import Entertainment_new from "../pages/newsub/entertainment_new.vue"
// 在News路由下
children:[
{path: "Sports_new",
component:() => import("../pages/newsub/sports_new.vue"),},
{path: "Entertainment_new",
component:() => import("../pages/newsub/entertainment_new.vue"),},
]