内容简介:router,路由,我理解的其实就是,让不同的路径对应的不同的视图。在vue里,其实视图就相当于组件。也就是让不同的路径对应不同的组件。换言之,router就是规定了路径和组件一一对应。这句可能是理解vue-touter的核心。怎么用render函数替换template呢?
- router其实就是让路径和组件一一对应
- 即便不使用vue-router也可以实现跳转,但总是手动处理历史记录
- vue-router的使用好处:历史记录、参数处理、路由钩子、权限控制、记录滚动条位置
- vue-router指南 和 vue-router的API
-
坑:历史模式懒加载的时候注意名字、子路由一般不用
/
router到底是什么
router,路由,我理解的其实就是,让不同的路径对应的不同的视图。在vue里,其实视图就相当于组件。也就是让不同的路径对应不同的组件。换言之,router就是规定了路径和组件一一对应。这句可能是理解vue-touter的核心。
先说说render,为下个标题铺垫
vue官网对render解释的很清楚 ,这边我简单的说下。 一般我们写vue组件的时候,会写template,但任何template都可以用render函数代替,事实上,vue就是把template转换为render函数的,之所以我们用template,是因为其易读易写。
怎么用render函数替换template呢?
简单的举个例子,你的template是 <h1 :title="blogTitle">{{ blogTitle }}</h1>
,对应的render函数如下
render: function (createElement) {
// `createElement`的参数一般有三个,第一个必填就是标签名或者组件名,第二个是这个标签的属性,第三个就是子节点。
return createElement('h1', {attrs:{title:this.blogTitle}}, [this.blogTitle])
}
复制代码
createElement
其实更准确的名字是 createNodeDescription
,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。也就是“虚拟节点 (virtual node)”,简写为“VNode”。“虚拟 DOM”是对由 Vue 组件树建立起来的整个 VNode 树的称呼。
即便不用vue-router,也可以实现单页面跳转的
开始总以为,要想不同路径就必须要 vue-router
,其实不必。 vue官方文档有个很好的demo
,这边挪用下逻辑。如果你只是需要简单的路由,也是可以直接这么用的。
// <div id="app"><div>
const Home = { template: "<p>home page</p>" };
const About = { template: "<p>about page</p>" };
const NotFound = { template: "<p>Page not found</p>" };
// 路由 路径和组件一一对应
const routes = {'/':Home,'about':About}
var app = new Vue({
el: "#app",
data: {
// 拿到地址栏路径
currentRoute: window.location.pathname
},
computed: {
// 由routes得到路径对应的组件
ViewComponent() {
return routes[this.currentRoute] || NotFound;
}
},
// 这边用render了
render(h) {
return h(this.ViewComponent);
}
});
// 历史记录的处理
window.addEventListener('popstate', () => {
app.currentRoute = window.location.pathname
})
复制代码
用vue-router有什么好处
- 自己写上面一套繁琐哇
- 不同路径很轻易对应不同组件,而且人家处理好了历史记录
- 轻易解决传参数问题
- 有路由钩子,控制什么情况去什么路径,比如不登录的话就去登录页面
- 甚至可以记住滚动条的位置
官网就是很好的学习路径
vue-router官网,以下我简单的总结下。代码示例统一在末尾。
-
vue-router分两种模式,history模式和hash模式(地址栏有#),hash模式利用#不会跳转,history模式利用pushState和popState。 -
vue-router增加两个组件
router-link和router-view,<router-link to="/foo">Go to Foo</router-link>相当于<a href="/foo">Go to Foo</a>,事实上也的确会被渲染成a标签。router-view是占位符的感觉,会将路径匹配的组件显示在这里。 -
任何组件内都可以通过
this.$router访问所有路由,访问当前路由this.$route,多个r就是多的意思,这么记着吧,打印可以看看这两个 -
动态路由也就是不同的路径对应同一个视图
。
path: '*'匹配所有路由,通常放在最后匹配404(感觉像express)。使用通配符的时候,this.$route.params.pathMatch = *所表示的部分 -
嵌套路由其实就是
/user/create /user/list这种 。注意的坑是,以/开头的嵌套路径会被当作根路径,所以一般嵌套的路由是不要/ -
js里跳转到不同的路径的话
,
router.push(location, onComplete?, onAbort?)相当于<router-link to="/foo">,replace会替换掉当前的历史记录,go(n)表示前进或者后退。如果 history 记录不够用,那就默默地失败呗。 -
如果同个组件里有多个router-view,怎么显示
,
router-view跟slot相似,不写name的话,默认name是default,对应的router文件里,components变成对象,{name:组件} -
别名也就是a路径的时候想要显示b路径的视图,换言之a路径也是b路径的别名
,
{ path: '/b', component: B, alias: '/a' } -
重定向也就是a路径的时候想要跳转到b路径,从而显示b路径的视图
,
{ path: '/a', redirect: '/b' } - history模式下前进后退是需要服务器作支持的
-
导航守卫就是希望去某个路径的时候能做些什么事,路由钩子的感觉
,注意的是,参数或查询的改变并不会触发进入/离开的导航守卫,可以通过
watch $route对象来应对这些变化,或在组件内使用beforeRouteUpdate。一旦用钩子,请一定确保要调用next方法,否则钩子就不会被resolved。想要去每一个路径都要判断时用router.beforeEach(to,from,next),next('/user')可以直接中断去另外的路径,next(false)中断跳转。如果只是想在去某个路径的时候做些事,可以在对应的路径下,写beforeEnter(to,from,next)。如果想要禁止用户在还未保存修改前突然离开,可以在组件内设置beforeRouteLeave (to, from , next),这里注意next的路径最好不是to.path不然会死循环=。=。 -
有些路径是需要登录才能进去的就需要配置meta了
,routes 配置中的每个路由对象为 路由记录,路由记录可以是嵌套的(有children的时候),因此,当一个路由匹配成功后,他可能匹配多个路由记录。
/foo/bar这个 URL 将会匹配父路由记录以及子路由记录。meta取的方式 遍历$route.matched 来检查路由记录中的 meta 字段 -
去不同路径的时候想要切换的特效
,能用
<transition name="slide">解决的就用这个吧 - 跳转路径的时候,希望用路径上面的id请求数据,这个可以在跳转前完成也可以在跳转后完成 ,如果请求很快的话,可以在跳转前,请求慢的话可以在跳转后,根据需要来。
-
控制滚动条的位置
,
scrollBehavior (to, from, savedPosition) { // return 期望滚动到哪个的位置 }
怎么根据路径显示不同组件的的
-
vue拿到 地址栏的路径(如
/user/user-list) -
=> 找routes 那边的配置,从上到下找 (如
path:'/user'),拿到components,(如找到{default:Foo,a:Bar}) -
=> 因为/user就是第一级路径,所以直接将app.vue里面的
<router-view/>替换成Foo组件,<router-view name="a"/>替换成Bar组件 -
=> 再继续,找
path:'/user'下面的children,发现目标path:'user-list',拿到components,找到{default:Second,a:Zoo} -
=> 因为
user-list是user的children,所以将user.vue里面的<router-view/>替换成Second组件,<router-view name="a"/>替换成Zoo组件 - 找不到的话会报错,当然一般都会配置404
示例代码
<!-- 示例1 -->
<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">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<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>
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)
// 1. 定义 (路由) 组件。也就是视图!!!!
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 2. 定义路由。也就是什么路径显示什么视图(组件)!!!
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
// 懒加载模式,会在合适的时机加载 bar.js,webpackChunkName就是将此组件的代码命名为bar.js 看控制台的network
{ path: '/bar', component: () => import(/* webpackChunkName: "bar" */ './views/Bar.vue'), },
// 注意 404
{ path: '*', component: () => import(/* webpackChunkName: "404" */ './views/404.vue'), },
]
]
// 3. 创建 router 实例,然后传 `routes` 配置。
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})
// 4. 创建和挂载根实例。!!!挂载在根实例下,也就是任何组件内都可以通过this.$router知道内容
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app')
// 现在,应用已经启动了!
</script>
复制代码
// 示例1 js
// Home.vue
export default {
computed: {
username () {
// 我们很快就会看到 `params` 是什么
return this.$route.params.username
}
},
methods: {
goBack () {
window.history.length > 1
? this.$router.go(-1)
: this.$router.push('/')
}
}
}
复制代码
/* 示例2:有嵌套路由的话 */
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
}
]
}
]
/* 示例3:router.push使用 */
// push的两种参数情况,尽量用路径的形式,用name的话有时候子路由可能不太方便
// -> /user/123
router.push({ path: `/user/${userId}` })
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { userId }})
// replace
router.replace({ path: 'register', query: { userId }})
router.go(1)
router.go(-1)
/* 示例4:router-view多个的情况 */
<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>
{
path: '/',
components: {
default: Foo,
a: Bar,
b: Baz
}
}
/* 示例5:重定向和别名 */
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' }
// { path: '/b', component: B, alias: '/a' }
]
})
/* 示例6:导航守卫 */
const router = new VueRouter({ ... })
// router上面的钩子
router.beforeEach((to, from, next) => {
next()
// next(false)
// next('/')
})
router.afterEach((to, from) => {
// ...
})
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
// route上的钩子
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`
}
}
/* 示例7:meta的使用 */
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// a meta field
meta: { requiresAuth: true }
}
]
}
]
})
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()
}
})
/* 示例8:跳转路径的特效 */
<transition>
<router-view></router-view>
</transition>
const Foo = {
template: `
<transition name="slide">
<div class="foo">...</div>
</transition>
`
}
/* 示例9:根据路径的参数去请求数据 这边显示跳转之后请求数据 */
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
}
})
}
}
}
/* 示例10:控制滚动条的位置 */
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0 }
}
}
复制代码
写例子来实践
需求:
- 现在总共有四个页面 home profile user login,profile是个人中心的意思
- 然后 user下面有 create-user user-list
- 然后设置 只有登录之后 才能去 profile user 否则就跳转到 login
- 每个页面都有导航条
1.加四个视图和对应的路由
vue create router-apply router-link router-view
2.user那边增加子页面
- views增加 create-user user-list
- router那边配置路径
- user.vue那边增加router-view
3.user子页面能相互跳转,增加的用户跳转的时候传递到user-list
- create-user 有input框和跳转按钮,跳转的时候,带着值,用query的方式
-
顺便还可以设置
/user路径的时候跳转到/user/create-user
4.设置只有登录才能去profile和user
beforeEach
核心代码展示
// main.js
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.needLogin)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!isLogin) {
next({
path: '/login',
// 方便登录之后返回来
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // 确保一定要调用 next()
}
})
// router.js
{
path: '/user',
name: 'user',
component: () => import(/* webpackChunkName: "user" */ './views/User.vue'),
children: [
{
path: 'create-user',
alias: '',
component: () => import(/* webpackChunkName: "createUser" */ './views/CreateUser.vue')
},
{
path: 'user-list',
component: () => import(/* webpackChunkName: "userList" */ './views/UserList.vue')
}
],
meta: {
needLogin: true
}
}
复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 大白话 Laravel 中间件
- 大白话讲梯度下降法(一)
- 大白话讲梯度下降法(二)
- 大白话理解和初步使用vuex
- JAVA-大白话探索JVM-类加载过程(二)
- JAVA-大白话探索JVM-运行时内存(三)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
How Tomcat Works
Budi Kurniawan、Paul Deck / BrainySoftware / 2004-4-1 / USD 54.95
A Guide to Developing Your Own Java Servlet Container一起来看看 《How Tomcat Works》 这本书的介绍吧!