大白话理解和初步使用vue-router

简介: 大白话理解和初步使用vue-router

大白话理解和初步使用vue-router


TL;DR

  • 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拿到 地址栏的路径(如/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 }
  }
}

写例子来实践

这里直接查看

github地址

需求:

  • 现在总共有四个页面 home profile user login,profile是个人中心的意思
  • 然后 user下面有 create-user user-list
  • 然后设置 只有登录之后 才能去 profile user 否则就跳转到 login
  • 每个页面都有导航条

1.加四个视图和对应的路由

  • vue create router-apply,先选择history模式好了
  • views增加 每个页面的视图
  • router那边配置路径
  • app那边就可以写导航条了 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

  • profile和user路径设置meta
  • 在router那边增加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
  }
}


目录
相关文章
|
3月前
|
缓存 移动开发 JavaScript
查漏补缺方为上策!!两万六字总结vue的基本使用和高级特性,周边插件vuex和vue-router任你挑选
该文章全面总结了Vue.js的基本使用方法与高级特性,并介绍了Vue周边的重要插件Vuex和Vue-Router的使用技巧。
查漏补缺方为上策!!两万六字总结vue的基本使用和高级特性,周边插件vuex和vue-router任你挑选
|
7月前
|
存储 JavaScript 前端开发
搞懂Vue一篇文章就够了
搞懂Vue一篇文章就够了
52 0
|
7月前
|
JavaScript
vue读书笔记
vue读书笔记
|
7月前
|
缓存 JavaScript 前端开发
vue灵魂拷问
vue灵魂拷问
62 3
|
7月前
|
JavaScript IDE 前端开发
【第12期】学习Vue的捷径找到啦
【第12期】学习Vue的捷径找到啦
35 0
|
前端开发
前端学习笔记202304学习笔记第十七天-vue3.0-vue-router4.0x的基本使用
前端学习笔记202304学习笔记第十七天-vue3.0-vue-router4.0x的基本使用
77 0
|
前端开发
前端学习笔记202304学习笔记第十七天-vue3.0-什么是vue-router
前端学习笔记202304学习笔记第十七天-vue3.0-什么是vue-router
79 0
|
前端开发
前端学习笔记202304学习笔记第十七天-vue3.0-vue-router的基本用法2
前端学习笔记202304学习笔记第十七天-vue3.0-vue-router的基本用法2
68 0
|
前端开发
前端学习笔记202304学习笔记第十七天-vue3.0-vue-router的基本用法1
前端学习笔记202304学习笔记第十七天-vue3.0-vue-router的基本用法1
65 0
|
JavaScript 前端开发
🌵vue基础—第一节
🌵vue基础—第一节
97 6
🌵vue基础—第一节