二、vue3学习笔记:路由高级

一、路由组件传参:

1. 布尔模式

  • /view/argu.vue
<template>
  <div>
    <!--$route代表当前加载的路由对象,包含params参数,它是一个对象,里面包含一个叫做name的值-->
    {{ name }}
  </div>
</template>

<script>
  export default {
    props: {
      name: {
        type: String,
        default: 'sun'
      }
    }
  }
</script>
  • /router/router.js
{
    // 动态路由参数,不管参数是什么,匹配到的都是这个路由对象
    path: '/argu/:name',
    name: 'argu',
    component: () => import('@/views/argu.vue'),
    // true表示里面的参数,它会使用router的params作为组建的属性,此时params中
    // 有一个name('/argu/:name'),它就会把name传入argu的属性里
    props: true
  },

2. 普通页面模式

  • /view/About.vue
<template>
  <div class="about">
    <h1>This is an about page</h1>
    <b>{{ food }}</b>
  </div>
</template>
<script>
  export default {
    props: {
      food: {
        type: String,
        default: 'apple'
      }
    }
  }
</script>
  • /router/router.js
{
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    // 懒加载
    component: () => import(/* webpackChunkName: "about" */ '@/views/About.vue'),
    props: {
      food: 'banana'
    }
  }

3. 函数模式

  • router/router.js
{
    path: '/',
    // 定义别名
    alias: '/home_page',
    name: 'home',
    component: Home,
    // 函数模式
    props: router => {

    }
  }
  • /views/Home.vue
<template>
  <div class="home">
    <b>{{ food }}</b>
    <img alt="Vue logo" src="../assets/img/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
    <button @click="handleClick('back')">返回上一页</button>
    <button @click="handleClick('push')">跳转parent</button>
    <button @click="handleClick('replace')">替换到parent</button>

  </div>
</template>

<script>
  // @ is an alias to /src
  import HelloWorld from '@/components/HelloWorld.vue'

  export default {
    name: 'home',
    components: {
      HelloWorld
    },
    props: {
      food: {
        type: String,
        default: 'apple'
      }
    },
    methods: {
      handleClick(type) {
        // 路由实例,可在main.js中进行查看,此处-1为返回上一页,1为返回下一页   back()功能相同
        if (type === 'back') this.$router.back()         // this.$router.go(-1)
        else if (type === 'push') {
          const name = 'sun'
          // this.$router.push('/parent')
          this.$router.push({
              // name可以把参数带过去,而path不能
              path: `/argu/${name}`
              // name: 'argu',
              // params: {
              //   name: 'sun'
              // }
            // name: 'parent',
            // query: {
            //   // 在地址后面会多一个参数:http://localhost:8080/#/parent?name=sun
            //   name: 'sun'
            // }
          })
        }
        else if (type === 'replace')
          this.$router.replace({
            name: 'parent'
          })
      }
    }
  }
</script>

网址 : http://localhost:8080/#/?food=banana

  • 结果如图:
    在这里插入图片描述

二、html5 history模式

  • 使用history的一些api来做无刷新页面的一些跳转,没有#
    如果使用history模式,所有匹配不到url的静态资源都会指向index.html
    应该在router.js里面增加一个匹配所有路径的路由
  • router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './router'

// Router作为一个插件,需要使用Vue.use()方式将其加载进来
Vue.use(Router)

// Router有两个参数:routes和mode
export default new Router({
  // 模式
  // 在url的# 号后面作变化,页面是不会刷新的
  // mode: 'hash',
  /* 使用history的一些api来做无刷新页面的一些跳转,没有#
  如果使用history模式,所有匹配不到url的静态资源都会指向index.html
  应该在router.js里面增加一个匹配所有路径的路由 */
  mode: 'history',
  // 路由
  routes: routes
})

  • router/router.js
// 根据优先级原则,定义在越上面的,优先级越高,因此,应该定义在最下面
{
  path: '*',
  component: () => import('@/views/error_404.vue')
}
  • views/error_404.vue
<template>
    <div>
      404
    </div>
</template>

<script>
    export default {
        name: ""
    }
</script>

<style scoped>

</style>

三、导航守卫

完整的导航解析流程:

1.导航被触发
2.在失活的组件(即将离开的页面组件)里调用离开守卫 beforeRouteLeave
3.调用全局的前置守卫 beforeEach
4.在重用的组件里调用 beforeRouteUpdate
5.调用路由独享
6.解析异步路由组件
7.在被激活的组件(即将进入的页面组件)里调用 beforeRouteEnter
8.调用全局解析守卫 beforeResolve
9.导航被确认
10.调用全局的后置守卫 afterEach
11.触发DOM更新
12.用创建好的实例调用beforeRouterEnter守卫里传给next的回调函数

1. 全局守卫

1)router.beforeEach : 全局前置守卫
  • router/router.js
{
    path: '/login',
    name: 'login',
    component: () => import('@/views/login.vue')
  },
  • router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './router'

// Router作为一个插件,需要使用Vue.use()方式将其加载进来
Vue.use(Router)

// 拎出来单独定义
const router = new Router({
  routes
})

const HAS_LOGINED = true

// 注册一个全局前置守卫
// to,from,next都是路由对象,to代表即将跳转的页面,from是即将离开的路由对象,next是一个函数
router.beforeEach((to, from, next) => {
  if (to.name !== 'login') {
    // 如果已经登陆则跳转
    if (HAS_LOGINED) next()
    // 如果为登陆,则先登录,里面可以传入name对象,或path,或路径
    else next({ name: 'login' })
  } else {
    if (HAS_LOGINED) next({ name: 'home' })
    else next()
  }
})

// Router有两个参数:routes和mode
// 模式
// 在url的# 号后面作变化,页面是不会刷新的
// mode: 'hash',
/* 使用history的一些api来做无刷新页面的一些跳转,没有#
如果使用history模式,所有匹配不到url的静态资源都会指向index.html
应该在router.js里面增加一个匹配所有路径的路由 */
// mode: 'history',
// 路由
export default router

  • views/login.vue
<template>
    <div>
      Login page
    </div>
</template>

<script>
    export default {
        name: ""
    }
</script>

<style scoped>

</style>
2)后置钩子
  • router/index.js
// 后置钩子,在路由跳转之后进行一些操作,它不能对跳转的页面进行操作,控制,它只是能够处理一些简单逻辑
router.afterEach((to, from) => {
  // logining = false
})

2. 专供于页面的守卫

1)beforeRouteEnter
  • views/Home.vue
  • beforeRouteEnter : 组件在确认前被调用
import Home from '@/views/Home'

export default [
  {
    path: '/',
    // 定义别名
    alias: '/home_page',
    name: 'home',
    component: Home,
    // 函数模式 route为参数,代表当前路由对象  如果想要返回一个对象,则以这种方式填写:({})
    props: route => ({
      food: route.query.food
    }),
    // 专供于home页的守卫
    // to,from,next都是路由对象,to代表即将跳转的页面,from是即将离开的路由对象,next是一个函数
    beforeEnter: (to, from, next) => {
      if (from.name === 'about') alert('这是从about来的')
      else alert('这不是从about来的')
      // 注意调用next()跳转页面
      next()
    }
  },
  {
    path: '/login',
    name: 'login',
    component: () => import('@/views/login.vue')
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    // 懒加载
    component: () => import(/* webpackChunkName: "about" */ '@/views/About.vue'),
    props: {
      food: 'banana'
    }
  },
  {
    // 动态路由参数,不管参数是什么,匹配到的都是这个路由对象
    path: '/argu/:name',
    name: 'argu',
    // 参数
    params: {
      name: 'lison'
    },
    component: () => import('@/views/argu.vue'),
    // true表示里面的参数,它会使用router的params作为组建的属性,此时params中
    // 有一个name('/argu/:name'),它就会把name传入argu的属性里
    props: true
  },
  // 嵌套路由
  {
    path: '/parent',
    name: 'parent',
    component: () => import('@/views/parent.vue'),
    // children代表着嵌套在parent里面的子集页面,路径不用写斜线,作为子集会自动补全
    children: [
      {
        path: 'child',
        component: () => import('@/views/child.vue')
      }
    ]
  },
  {
    path: '/named_view',
    // 注意有个s
    components: {
      // 没有命名则加载default
      default: () => import('@/views/child.vue'),
      email: () => import('@/views/email.vue'),
      tel: () => import('@/views/tel.vue')
    }
  },
  // 重定向路由
  {
    path: '/main',
    // redirect: '/'
    // redirect: to => {
    //   console.log(to)
    // }
    // redirect: 'home'
    // redirect: to => {
    //   return {
    //     name: 'home'
    //   }
    // }
    redirect: to => {
      return '/'
    }
  },
  // 根据优先级原则,定义在越上面的,优先级越高,因此,应该定义在最下面
  {
    path: '*',
    component: () => import('@/views/error_404.vue')
  }
]

  • views/Home.vue : 打印出当前所有实例
	// 组件在确认前被调用
    beforeRouteEnter(to, from, next) {
      next(vm => {
        // 打印出当前所有实例
        console.log(vm);
      })
      // 跳转至下一页
      next()
    },   
2) 页面后置钩子:beforeRouteLeave
  • src/views/Home.vue :页面后置钩子
// 页面后置钩子
beforeRouteLeave(to, from, next) {
  const leave = confirm('您确定要离开吗?')
  if (leave) next()
  else next(false)
},
  • src/views/argu.vue : 在路由发生变化,组件被复用的情况时被调用
<template>
  <div>
    <!--$route代表当前加载的路由对象,包含params参数,它是一个对象,里面包含一个叫做name的值-->
    {{ name }}
  </div>
</template>

<script>
  export default {
    props: {
      name: {
        type: String,
        default: 'sun'
      }
    },
    // 在路由发生变化,组件被复用的情况时被调用
    beforeRouteUpdate(to, from, next) {
      console.log(to.name,from.name);
    }
  }
</script>

四、路由源信息

  meta里面可以存放一些需要定义的信息,比如页面是否需要一些权限,或者一些其他信息,然后在路由前置守卫里做一些处理。

  • 以下是一个更改about的title为“关于”,其他页面为“admin”的例子:
  • src/lib/util.js
export const setTitle = (title) => {
  window.document.title = title || 'admin'
}
  • src/router/router.js
 {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    // 懒加载
    component: () => import(/* webpackChunkName: "about" */ '@/views/About.vue'),
    props: {
      food: 'banana'
    },
    meta: {
      title: '关于'
    }
  },
  • src/router/index.js
// 注册一个全局前置守卫
// to,from,next都是路由对象,to代表即将跳转的页面,from是即将离开的路由对象,next是一个函数
router.beforeEach((to, from, next) => {
  to.meta && setTitle(to.meta.title)
  if (to.name !== 'login') {
    // 如果已经登陆则跳转
    if (HAS_LOGINED) next()
    // 如果为登陆,则先登录,里面可以传入name对象,或path,或路径
    else next({ name: 'login' })
  } else {
    if (HAS_LOGINED) next({ name: 'home' })
    else next()
  }
})

五、路由的切换动效

页面的切换就是一个组件注销,一个组件加载,在vue基础里面有提到组件的过渡,能够为一个组件的显示
和隐藏都设置一个过度效果,同样也能为一个页面设置一个过渡效果。多个组件使用过渡效果需要使用
<transition-group></transition-group>(只需要包住一个视图渲染组件则只需要)包住视图渲染组件<router-view/>

1. 所有页面动效

  • src/App.vue
<!--一个示例,即运行vue时的页面-->
<template>
  <div id="app">
    <div id="nav">
      <!--封装了一个a标签,里面有一个重要属性:to,它指定的值是一个路径-->
      <router-link v-bind:to="{name: 'home'}">Home</router-link> |
      <!--命名路由,可以通过指定name来跳转到相应界面-->
      <router-link v-bind:to="{name: 'about'}">About</router-link>
    </div>
    <transition-group name="router">
    <!--是一个视图渲染组件-->
    <router-view key="default"/>
    <!--命名视图-->
    <router-view name="email" key="email"/>
    <router-view name="tel" key="tel"/>
    </transition-group>
  </div>
</template>

<style lang="less">
/*可以通过css来制作添加动态效果*/
/*首先设置页面进入的效果*/
/*router-enter代表页面没有显示,但即将显示的状态*/
.router-enter {
  /*设置透明度为零*/
  opacity: 0;
}
/*设置组件从没有到有的过程的动态的效果*/
.router-enter-active {
  /*使用transition来给opacity添加效果,时间设置1s ease效果*/
  transition: opacity 1s ease;
}
/*router-enter-to来设置页面完全显示之后的效果 让其透明度变为1*/
.router-enter-to {
  opacity: 1;
}

/*在此处设置页面离开的效果*/
.router-leave {
  /*设置透明度为零*/
  opacity: 1;
}
/*设置组件从没有到有的过程的动态的效果*/
.router-leave-active {
  /*使用transition来给opacity添加效果,时间设置1s ease效果*/
  transition: opacity 1s ease;
}
/*router-enter-to来设置页面完全显示之后的效果 让其透明度变为1*/
.router-leave-to {
  opacity: 0;
}


#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
#nav {
  padding: 30px;
  a {
    font-weight: bold;
    color: #2c3e50;
    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
</style>

2. 单独页面动效

  • src/App.vue
<!--一个示例,即运行vue时的页面-->
<template>
  <div id="app">
    <div id="nav">
      <!--封装了一个a标签,里面有一个重要属性:to,它指定的值是一个路径-->
      <router-link v-bind:to="{name: 'home'}">Home</router-link> |
      <!--命名路由,可以通过指定name来跳转到相应界面-->
      <router-link v-bind:to="{name: 'about'}">About</router-link>
    </div>
    <transition-group :name="routerTransition">
    <!--是一个视图渲染组件-->
    <router-view key="default"/>
    <!--命名视图-->
    <router-view name="email" key="email"/>
    <router-view name="tel" key="tel"/>
    </transition-group>
  </div>
</template>

<script>
  export default {
    watch: {
      // 监听路由对象的变化,to代表当前路由对象
      '$route' (to) {
        // 先判断to里是否有query字段 && 在to的query里找专门为这个页面设置的动效的name值 && 如果前面的
        //都满足,则将routerTransition改为query里的transitionName
        // 通过http://localhost:8080/#/about?transitionName=router 将transitionName=router
        //传入query,就有了动效
        to.query && to.query.transitionName && (this.routerTransition = to.query.transitionName)
      }
    }
  }
</script>

<style lang="less">
/*可以通过css来制作添加动态效果*/
/*首先设置页面进入的效果*/
/*router-enter代表页面没有显示,但即将显示的状态*/
.router-enter {
  /*设置透明度为零*/
  opacity: 0;
}
/*设置组件从没有到有的过程的动态的效果*/
.router-enter-active {
  /*使用transition来给opacity添加效果,时间设置1s ease效果*/
  transition: opacity 1s ease;
}
/*router-enter-to来设置页面完全显示之后的效果 让其透明度变为1*/
.router-enter-to {
  opacity: 1;
}

/*在此处设置页面离开的效果*/
.router-leave {
  /*设置透明度为零*/
  opacity: 1;
}
/*设置组件从没有到有的过程的动态的效果*/
.router-leave-active {
  /*使用transition来给opacity添加效果,时间设置1s ease效果*/
  transition: opacity 1s ease;
}
/*router-enter-to来设置页面完全显示之后的效果 让其透明度变为1*/
.router-leave-to {
  opacity: 0;
}


#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
#nav {
  padding: 30px;
  a {
    font-weight: bold;
    color: #2c3e50;
    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值