Vue复习三(路由)

https://router.vuejs.org/zh/installation.html

 <router-link to="/foo">Go to Foo</router-link>
  <router-view></router-view>

动态ID

/one/:id
this.$route.params.id
问号传参
this.$route.query

props 拿到动态的id值

const User = {
  props: ['id'],
  template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User, props: true },

    // 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项:
    {
      path: '/user/:id',
      components: { default: User, sidebar: Sidebar },
      props: { default: true, sidebar: false }
    }
  ]
})

props 被设置为 trueroute.params 将会被设置为组件属性

函数的形式

 { path: '/search', component: SearchUser, props: (route) => ({ query: route.query})
  
  props:['query']
  
  ?name=333
  this.query
  // {name:333}

响应路由的变化

watch:{
            $route(to, from) {
                // 现在的, 之前的
                console.log(to, from);
            }
        },

匹配条件

	// 匹配所有路径
  path: '*'
路由导航
// 给出一个路由 { path: '/user-*' }
this.$router.push('/user-admin')
this.$route.params.pathMatch // 'admin'

可选
/optional-params/:foo?
案例
/optional-params
/optional-params/foo

限定id的条件
// 一个参数后面可以跟一个正则表达式模式的括号
//只有当:id为所有数字时,该路由才会匹配
/params-with-regex/:id(\\d+)
也就是id只有是数字的时候才能匹配
                         
// 星号可以匹配任何东西
 { path: '/asterisk/*' }      
 // 括号中的内容是可选的                      
/optional-group/(foo/)?bar

嵌套路由

  routes: [
    { path: '/user/:id', component: User,
        children: [
        {
          // 相对的跟angular类似
            path:'posts'
          component: UserProfile
        },
   ]}
      

编程式导航

声明式 编程式
<router-link :to="..."> router.push(...)
// 字符串, 绝对的
router.push('home')

// 对象的形式是相对的, 如果是'two/three' => 'two/three'
router.push({ path: 'home' })
// 问好传参
router.push({path:'/two/three',query:{age:'gsg'}})

替换

替换掉当前的 history 记录

声明式 编程式
<router-link :to="..." replace> router.replace(...)

退后,前进

类似 window.history.go(n)

// 后退一步记录,等同于 history.back()
router.go(-1)
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)

Vue Router 的导航方法 (pushreplacego)

在各类路由模式 (historyhashabstract) 下表现一致。

router.push(location, onComplete?, onAbort?)
router.push(location).then(onComplete).catch(onAbort)
router.replace(location, onComplete?, onAbort?)
router.replace(location).then(onComplete).catch(onAbort)
router.go(n)
router.back()
router.forward()

命名视图

就是多视图

案例

   <router-view></router-view>
   <router-view name="three"></router-view>

		 {
                path: 'three/:id',
                components: {
                    default:()=>import('@/components/FourChild.vue'),
                    three:()=>import('@/components/ThreeChild.vue')
                }
            }

路由点击多次报错

禁止全局的路由错误处理

const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (location) {
    return originalPush.call(this, location).catch(err => err)
} 

命名路由

就是不用写那么多配置,快捷的跳转

const router = new VueRouter({
  routes: [
    {
      path: '/user/:userId',
      name: 'user',// 快捷跳转方式
      component: User
    }
  ]
})

html跳转方式
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
如果你想独立显示的,就单独写一个吧

重定向

 { path: '/a', redirect: '/b' }
// 快捷重定向到命名路由
{ path: '/a', redirect: { name: 'foo' }}
//方法
   { path: '/a', redirect: to => {
      // 方法接收 目标路由 作为参数
      // return 重定向的 字符串路径/路径对象
    }}

别名

{ path: '/a', component: A, alias: '/b' }

/a 的别名是 /b
就是/b 访问的也是 /a 但是当前地址也是/b 本来不变, 类似一个别名

History 模式

默认hash模式, 设置history前台后台就需要配置

路由守卫

全局前置守卫 beforeEach

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中

router.beforeEach((to, from, next) => {
  // ...
})

to: Route: 即将要进入的目标

from: Route: 当前导航正要离开的路由

next:Function

  • next() 进行管道中的下一个钩子

  • next(false) 中断当前导航

  • next('/') 或者next({path:'/'}) 跳转到不同的地址

    replace: true
    name: 'home' 比较自由
    
  • next(error) 报错了, 会把错误传递到router.onError() 注册回调

next() 严格上调用一次

router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  else next()
})

路由独享的守卫 beforeEnter

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

组件内的守卫

{
    data(){
        return {
            
        }
    },
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  } 
}

传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 通过 `vm` 访问组件实例
  })
}

这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消

beforeRouteLeave (to, from, next) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (answer) {
    next()
  } else {
    next(false)
  }
}

全局解析守卫 beforeResolve

在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后

全局后置钩子

注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身

router.afterEach((to, from) => {
  // ...
})

导航解析流程

默认

  • beforeEach 全局前置守卫(登录)
    • beforeEnter 路由独享的守卫
      • beforeRouteEnter 组件内守卫(当守卫执行前)
      • beforeRouteUpdate 组件内复用守卫(:id /1 /2)
      • beforeRouteLeave 离开守卫,例如未保存
  • beforeResolve 全局解析守卫
  • afterEach 全局后置钩子

router.onError

router.onError(error=>{
    console.log(error)
})

注册一个回调,该回调会在路由导航过程中出错时被调用。注意被调用的错误必须是下列情形中的一种:

  • 错误在一个路由守卫函数中被同步抛出;
  • 错误在一个路由守卫函数中通过调用 next(err) 的方式异步捕获并处理;
  • 渲染一个路由的过程中,需要尝试解析一个异步组件时发生错误。

元数据 meta

    {
          path: 'bar',
          component: Bar,
          // a meta field
          meta: { requiresAuth: true }
    }

this.$route.meta
// { requiresAuth: true }

过渡

<transition>
  <router-view></router-view>
</transition>

动态的
当前路由与目标路由的变化关系,
<!-- 使用动态的 transition name -->
<transition :name="transitionName">
  <router-view></router-view>
</transition>
// watch $route 决定使用哪种过渡
watch: {
  '$route' (to, from) {
    const toDepth = to.path.split('/').length
    const fromDepth = from.path.split('/').length
    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
  }
}

数据获取

导航完成后获取数据

  data () {
    return {
      loading: false
    }
  },
  created () {
    // 当视图被创建并且数据被创建时,获取数据
    this.fetchData()
  },
  watch: {
    // 如果路由发生变化,再次调用该方法
    '$route': 'fetchData'
  },
  methods: {
      // 数据请求
    fetchData () {
    }
  }

导航前获取

就使用 路由组件内守卫进行操作

滚动

自定义滚动

scrollBehavior函数接收tofrom路由对象。第三个参数,savedPosition仅在通过popstate导航(由浏览器的后退/前进按钮触发)时才可用。也是history 模式

const router = new VueRouter({
  routes: [...],
  scrollBehavior (to, from, savedPosition) {
    // 返回对象 { x: number, y: number }
       return { x: 0, y: 0 }      
     
  }
})

滚动到锚点

scrollBehavior (to, from, savedPosition) {
  if (to.hash) {
    return {
      selector: to.hash
    }
  }
}

平滑滚动

scrollBehavior (to, from, savedPosition) {
  if (to.hash) {
    return {
      selector: to.hash,
      behavior: 'smooth',
    }
  }
}

异步滚动

scrollBehavior (to, from, savedPosition) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ x: 0, y: 0 })
    }, 500)
  })
    
    500ms 后滚动

延迟加载路线

const Foo = () => import('./Foo.vue')
{ path: '/foo', component: Foo }

将同一块中的组件分组

命名块

const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')

*导航失败

3.4.0 新功能

使用router-link组件时,这些故障均不会记录错误

有点蒙蔽, 不太懂

router-link

<!-- 字符串 -->
<router-link to="home">Home</router-link>
<!-- 绑定数据 -->
<router-link :to="'home'">Home</router-link>
<!-- 命名的路由 -->
									<!-- 动态ID :userId 的值-->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
<!-- 带查询参数,下面的结果为 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}"
  >Register</router-link>

replace 替换

<router-link :to="{ path: '/abc'}" replace></router-link>

append 相对

设置 append 属性后,则在当前 (相对) 路径前添加基路径

本来  /one/1
跳转后   /one/2
<router-link :to="{ path: 2}" append></router-link>

tag 更改标签名

<router-link to="/foo" tag="li">foo</router-link>
<!-- 渲染结果 -->
<li>foo</li>

active-class 激活的路由class

  • 类型: string
  • 默认值: "router-link-active"
 <router-link :to="{path:'2'}"  active-class="aaa">222</router-link>

axact 完全匹配

<!-- 这个链接只会在地址为 / 的时候被激活 -->
<router-link to="/" exact></router-link>

event 事件促发的条件

  • 类型: string | Array<string>
  • 默认值: 'click'

可以是一个字符串或是一个包含字符串的数组

<router-link :to="{path:1}"  tag="input" event="blur">
    222
</router-link>
改成input 失去焦点触发

exact-active-class 精准匹配class

router-view

<transition>
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</transition>

name 用于命名视图

Router

routes

interface RouteConfig = {
  path: string,
  component?: Component,
  name?: string, // 命名路由
  components?: { [name: string]: Component }, // 命名视图组件
  redirect?: string | Location | Function,
  props?: boolean | Object | Function,
  alias?: string | Array<string>,
  children?: Array<RouteConfig>, // 嵌套路由
  beforeEnter?: (to: Route, from: Route, next: Function) => void,
  meta?: any,// 元数据

  // 2.6.0+
  caseSensitive?: boolean, // 匹配规则是否大小写敏感?(默认值:false)
  pathToRegexpOptions?: Object // 编译正则的选项
}

外部的配置

 new VueRouter({
    routes,
     // 下面都是全局
    mode:'history',
    base:'/app/sex/' // 前缀
     // 默认的激活的class   默认值: "router-link-exact-active"
	linkActiveClass:'ccc'
     // 默认精确激活的class 默认值: "router-link-exact-active"
     linkExactActiveClass:"aaa"

})

parseQuery / stringifyQuery

提供自定义查询字符串的解析/反解析函数。覆盖默认行为。

其实提供这两种用法,是针对问号传参进行加密解决的作用

https://www.codenong.com/cs107092308/


// https://github.com/ljharb/qs
import qs from 'qs';

const router = new Router({
    routes: [
        // ...
    ],
    // 反序列化
    parseQuery(query) {
        return qs.parse(query);
    },
    //序列化
    stringifyQuery(query) {
        var result = qs.stringify(query);

        return result ? ('?' + result) : '';
    }
});

router.app vue实例

// 拿到vue 实例
    console.log(this.$router.app);

router.currentRoute 当前路由信息对象

    console.log(this.$router.currentRoute);

## router.getMatchedComponents 当前路由匹配的组件数组

通常在服务端渲染的数据预加载时使用

全局后置路由守卫
router.beforeResolve((to, from, next) => {
   // 拿到当前匹配的数组
    console.log(router.getMatchedComponents(to));
    next()
})

路由对象Route

// 当前路由的路径,总是解析绝对路径
$route.path
// 动态ID
$route.params
// 问号传参
$route.query
// hash
$route.hash
// 解析后URL,包括查询参数和hash的完整路径
$route.fullPath
// 一个包含从上到下的所有对象 (副本)   又叫路由记录
$route.matched
// 当前路由的名称, 命名路由
$route.name
// 如果存在重定向,即为重定向来源的路由的名字, (别名还想也可以)
$route.redirectedFrom

posted @ 2021-02-11 20:19  猫神甜辣酱  阅读(374)  评论(0编辑  收藏  举报