目录
前端路由&&后端路由
后端路由
前端路由
vue-router
上手
嵌套路由
路由的懒加载
导航守卫
完整的导航守卫解析流程
全局守卫
路由独享守卫
组件局部守卫
路由的功能包括路由(映射)和转发
后端渲染:相当于把url地址传给服务器,而服务器会根据html+css+后端语言进行网页渲染,然后再返回前端,内容包括HTML+css,当然是包含数据的HTML。
后端路由的步骤:
1:一个页面有对应的网址也就是url
2:url发送到服务器进行匹配,交给一个controller进行处理
3:controller进行各种处理后返回html数据,返回给前端
4:完成一个i/o操作
前端渲染:浏览器中网页显示的大部分内容都是由js在浏览器执行来进行渲染的,当输入某些具体的url地址时,会先去静态资源服务器请求对应的html+css+js代码并下载,然后在去提供API接口的服务端获取数据,通过前端ajax转换后,最终渲染出来。
SPA页面(单页富应用):SPA最主要的特点就是在前后端分离的基础上加了一层前端路由,整个网页只有一个html页面。在SPA中,静态资源服务器内只含有一个html文件,甚至只有一套html+css+js文件,当url发生变化时,会先向js中找到对应的相关代码,并分离进而渲染在客户端。
vue默认开发的就是典型的单页面应用,只有一个html页面在public文件夹下。
前端路由:在前端处理url与页面之间的映射关系。
前端路由的核心是:改变url但不进行整体的页面刷新,没有向服务器进行请求而是使用js。
如何改变url而不进行页面刷新?
1、URL的hash
URL的hash也就是锚点,本质上是改变window.location的href属性。
我们可以通过直接赋值location.hash来改变href,但是页面不发生刷新。
2、HTML5的history
history.pushState({},'','home')
history.pushState相当于栈的操作,先进后出,弹栈和入栈的操作。
history.pushState入栈;
history.back()出栈;
history.go(-1) 相当于 history.back();
history.forward 相当于history.go(1);
history.replaceState():不能返回;
————————————————
版权声明:本文为CSDN博主「哪 吒」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guorui_java/article/details/120626879
<html> <head> <meta charset="utf-8"> <title></title> <script src="./vue.min.js" type="text/javascript" charset="utf-8"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> </head> <body> <div id="app"> <p> <router-link to="/foo">go to foo</router-link> <router-link to="/bar">go to bar</router-link> </p> <router-view></router-view> </div> <script type="text/javascript"> //定义路由组件 var Foo = {template:'<div>foo</div>'}; var Bar = {template:'<div>bar</div>'}; //定义路由 const routes = [ {path:'/foo' , component:Foo}, {path:'/bar' , component:Bar}, ] //创建router实例,传routes配置 const router = new VueRouter({ routes:routes }) //创建根实例并挂载div const app = new Vue({ router }).$mount("#app") </script> </body> </html>
这里实现了一个简单的路由,有以下步骤:
1定义两个路由组件,当中仅有模板
2定理路由配置对象,创建路径与组件的映射关系
3创建router实例,传入配置
4创建根实例,挂载路由
两个基本的标签在html当中使用:router-link,router-view
router-link:
tag:tag可以指定router-link之后渲染成什么组件,比如<router-link tag='button'></router-link>,此时就是一个button了;
replace:增加replace属性,就相当于replaceState;
class:可以为标签增加样式,比如选中的会自动赋值router-link-active;
active-class=“active”:选中的;也可以在router组件中配置linkActiveClass: 'active';
————————————————
版权声明:本文为CSDN博主「哪 吒」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guorui_java/article/details/120626879
router-view:
根据路由映射的组件显示的区域
路由的组件化开发:
在组件化开发里,Vue router都是在router.js统一管理,使用AMD规范将组件引入进来
import downApp from '@/components/downApp.vue'
随后引用Router,再将接口暴露出去,一般使用webpack
构建项目的时候就已经做好这个步骤了
Vue.use(Router) export default new Router({ //历史模式,也就是将页面上链接的主页前面的无用信息过滤掉 mode:'history', routers:[{}...] })
参数分别有path(路径),name(可选,路由名),alias(可选,别名),component(组件名),meta(可选,元数据,多用在导航守卫上),redirect(可选,重定向,多用于导航守卫返回原页面)
组件化开发的index.js大致分为五步:
1,import组件
2,use(Router)因为它是一个插件,所以可以通过Vue.use()来安装路由功能
3,创建路由配置对象
4,创建路由实例并传入路由配置
5,export default router
组件化开发的所有组件基本上放在views当中
组件化开发最终在main.js当中导入路由,并在创建根实例的时候导入即可
借助 vue-router
,使用嵌套路由配置,就可以很简单地表达这种关系。
接着上节创建的 app:
<div id="app"> <router-view></router-view> </div>
const User = { template: '<div>User {{ $route.params.id }}</div>' } const router = new VueRouter({ routes: [{ path: '/user/:id', component: User }] })
这里的 <router-view>
是最顶层的出口,渲染最高级路由匹配到的组件。同样地,一个被渲染组件同样可以包含自己的嵌套 <router-view>
。例如,在 User
组件的模板添加一个 <router-view>
:
const User = { template: ` <div class="user"> <h2>User {{ $route.params.id }}</h2> <router-view></router-view> </div> ` }
要在嵌套的出口中渲染组件,需要在 VueRouter
的参数中使用 children
配置:
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ { // 当 /user/:id/profile 匹配成功, // UserProfile 会被渲染在 User 的 <router-view> 中 path: 'profile', component: UserProfile }, { // 当 /user/:id/posts 匹配成功 // UserPosts 会被渲染在 User 的 <router-view> 中 path: 'posts', component: UserPosts } ] } ] })
要注意,以 /
开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。
你会发现,children
配置就是像 routes
配置一样的路由配置数组,所以呢,你可以嵌套多层路由。
此时,基于上面的配置,当你访问 /user/foo
时,User
的出口是不会渲染任何东西,这是因为没有匹配到合适的子路由。如果你想要渲染点什么,可以提供一个 空的 子路由:
const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ // 当 /user/:id 匹配成功, // UserHome 会被渲染在 User 的 <router-view> 中 { path: '', component: UserHome } // ...其他子路由 ] } ] })
转自官方文档
当打包构建应用时,JavaScript包会变得非常大,影响页面加载。
如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
懒加载的方式:
(1)结合Vue的异步组件和Webpack的代码分析
const Home = resolve => { require.ensure(['../components/Home.vue'],
() => { resolve(require('../components/Home.vue')) })};
(2)amd写法
const About = resolve => require(['../components/About.vue'], resolve);
(3)在ES6中,我们可以有更加简单的写法来组织Vue异步组件和Webpack的代码分割
const Home = () => import('../components/Home.vue')
demo:
// import Home from '../components/Home' // import About from '../components/About' // import User from '../components/User' // 懒加载方式 const Home = () => import('../components/Home') const About = () => import('../components/About') ———————————————— 版权声明:本文为CSDN博主「哪 吒」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/guorui_java/article/details/120626879
beforeRouteLeave
守卫。beforeEach
守卫。beforeRouteUpdate
守卫 (2.2+)。beforeEnter
。beforeRouteEnter
。beforeResolve
守卫 (2.5+)。afterEach
钩子。beforeRouteEnter
守卫中传给 next
的回调函数,创建好的组件实例会作为回调函数的参数传入。router.beforeEach((to, from, next) => { console.log(to) => // 到哪个页面去? console.log(from) => // 从哪个页面来? next() => // 一个回调函数 } router.afterEach(to,from) = {}
每个守卫方法接收三个参数:
to: Route
: 即将要进入的目标 路由对象
from: Route
: 当前导航正要离开的路由
next: Function
: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 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() 注册过的回调。
确保 next
函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错。
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] })
参数与全局守卫相同
const Foo = { template: `...`, beforeRouteEnter(to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate(to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave(to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } }
beforeRouteEnter
守卫 不能 访问 this
,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。
不过,你可以通过传一个回调给 next
来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
一个守卫的实例:
该demo是用于验证当前是否有用户登录,如果没有则会强制跳转到login界面
router.beforeEach((to,from,next)=>{ let user=window.localStorage.getItem("user");//读取是否有登录信息 let token=window.localStorage.getItem("token"); if(user!=null&&token!=null && to.path == '/login'){//如果已经登录并且跳转的路径为login,则不允许 next('/home') } else if(to.path == '/login' || to.path == '/register'){//如果没有登录跳转的路径为login,则放行 next(); }else if(user===null&&token===null){//如果要去的路径不是login,并且没有登陆,则强行跳转登陆窗口 alert('您还没有登录,请先登录'); next('/login'); } else next(); })