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

栏目: 编程语言 · 发布时间: 5年前

内容简介: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拿到 地址栏的路径(如 /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
  }
}
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Squid: The Definitive Guide

Squid: The Definitive Guide

Duane Wessels / O'Reilly Media / 2004 / $44.95 US, $65.95 CA, £31.95 UK

Squid is the most popular Web caching software in use today, and it works on a variety of platforms including Linux, FreeBSD, and Windows. Squid improves network performance by reducing the amount of......一起来看看 《Squid: The Definitive Guide》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具