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

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

内容简介: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
  }
}
复制代码

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

查看所有标签

猜你喜欢:

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

RESTful Web Services Cookbook

RESTful Web Services Cookbook

Subbu Allamaraju / Yahoo Press / 2010-3-11 / USD 39.99

While the REST design philosophy has captured the imagination of web and enterprise developers alike, using this approach to develop real web services is no picnic. This cookbook includes more than 10......一起来看看 《RESTful Web Services Cookbook》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具