何为动态路由匹配

当我们需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”来达到这个效果:
动态路由匹配效果
动态导航匹配示例.gif
观察上图的URL你会发现当路径最后的数字修改时,页面会切换当时页面的都是用的一个模板,只是里面的数据更换啦
动态路由实例代码

  1. const User = {
  2. template: '<div>User</div>'
  3. }
  4. const router = new VueRouter({
  5. routes: [
  6. // 动态路径参数 以冒号开头
  7. { path: '/user/:id', component: User }
  8. ]
  9. })
  1. { path: '/user/:id', component: User }

经过这样设置/user/foo 与 /user/bar 都将映射到相同路由。也可说是公用啦一个模板
当路径参数使用冒号 : 标记。当匹配一个路由时(也就是URL) 动态路由的参数会被设置到到$route.params中

案例

效果图
动态导航匹配案例.gif
源码router.rar
示例源码
配置源码
router.js

  1. import Vue from 'vue'
  2. import VueRouter from 'vue-router'
  3. import axios from './http'
  4. Vue.prototype.$axios = axios;
  5. // 使用路由
  6. Vue.use(VueRouter)
  7. Vue.config.productionTip = false
  8. // 定义路由
  9. const routes = [
  10. {
  11. path:'/',
  12. // 当输入域名访问是,将其其路径重定向为/home
  13. redirect:'/home'
  14. },
  15. {
  16. path: '/home',
  17. // 异步加载组件,当标签被点击才会加载组件
  18. component: () => import('./components/views/Home.vue'),
  19. // 别名
  20. // 别名是 URL中的路径是“/home” 但路由匹配的则为“/”
  21. // 但是如何是访问当用于只输入域名没有跟参数时回无效
  22. // 建议使用重定向
  23. // alias:'/'
  24. },
  25. {
  26. path: '/learn',
  27. component: () => import('./components/views/Learn.vue')
  28. },
  29. {
  30. path: '/show',
  31. component: () => import('./components/views/Show.vue')
  32. },
  33. {
  34. path: '/about',
  35. component: () => import('./components/views/About.vue')
  36. },
  37. {
  38. path: '/community',
  39. name:'community',
  40. component: () => import('./components/views/community.vue'),
  41. // 重定向
  42. // 当单击社区时默认选中学术讨论
  43. // 第一种
  44. // redirect:'/community/academic',
  45. // 第二种 通过命令路由
  46. // redirect: { name:'academic'},
  47. // 第三种 通过方法
  48. redirect:to =>{
  49. return {
  50. name:'academic'
  51. }
  52. },
  53. // 路由嵌套
  54. children:[
  55. {
  56. path:'academic',
  57. // 命名路由
  58. name:'academic',
  59. component:()=> import('./components/views/Academic.vue')
  60. },
  61. {
  62. path:'personal',
  63. name:'personal',
  64. component: () => import('./components/views/Personal.vue')
  65. },
  66. {
  67. path:'download',
  68. name:'download',
  69. component: () => import('./components/views/Download.vue')
  70. },
  71. ]
  72. },
  73. {
  74. /**
  75. * 动态路由匹配
  76. * /question/下的参数都将是question.vue 渲染出来的
  77. */
  78. path:'/question/:id',
  79. name:'question',
  80. component:() => import('./components/views/question.vue')
  81. }
  82. ]
  83. // 创建实例
  84. export default new VueRouter({
  85. mode: 'history',
  86. routes,
  87. })

http.js

  1. import axios from 'axios';
  2. /**
  3. * 设置默认请求地址
  4. */
  5. axios.defaults.baseURL = 'http://localhost:8080/';
  6. /**
  7. * 请求拦截
  8. */
  9. axios.interceptors.request.use(request => {
  10. request.url += '.json'
  11. return request;
  12. })
  13. /**
  14. * 响应拦截
  15. */
  16. axios.interceptors.response.use(response =>{
  17. return response.data.data;
  18. })
  19. export default axios;

main.js

  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. import router from './router'
  4. Vue.config.productionTip = false
  5. new Vue({
  6. router,
  7. render: h => h(App),
  8. }).$mount('#app')

vue的代码
academic.vue — 学术讨论页面的源码

  1. <template>
  2. <div>
  3. <ul class="quesiton-warp">
  4. <router-link class="question-item" tag="li" v-for="question in data" :key="question.id" :to="{name:'question',params:{
  5. id:question.id
  6. }}">
  7. {{ question.title}}
  8. </router-link>
  9. </ul>
  10. </div>
  11. </template>
  12. <script>
  13. export default {
  14. data(){
  15. return {
  16. data:null,
  17. }
  18. },
  19. methods:{
  20. getData(){
  21. this.$axios.get('/question').then(res =>{
  22. console.log(res)
  23. this.data = res;
  24. })
  25. }
  26. },
  27. mounted(){
  28. this.getData()
  29. }
  30. }
  31. </script>
  32. <style scoped>
  33. ul,li{
  34. list-style: none;
  35. }
  36. li{
  37. text-align: left;
  38. line-height: 30px;
  39. cursor: pointer;
  40. }
  41. li:hover{
  42. color: #3385ff;
  43. text-decoration: underline;
  44. }
  45. </style>

question.vue — 文章展示页面源码

  1. <template>
  2. <div v-if="data">
  3. <div class="title">
  4. {{ data.title }}
  5. </div>
  6. <div class="option" >
  7. <div class="option-item" @click="handleClick(options.id)" v-for="options in optionQusetinList" :key="options.id" :title="options.title" :class="options.type"> {{ options.title}}</div>
  8. </div>
  9. </div>
  10. </template>
  11. <script>
  12. export default {
  13. data(){
  14. return {
  15. data:null
  16. }
  17. },
  18. computed:{
  19. /**
  20. * 计算属性
  21. * 下一篇文章与上一篇的文章
  22. */
  23. optionQusetinList(){
  24. let arr = []
  25. if(this.data.next){
  26. const {next,nextId} = this.data
  27. arr.push({
  28. type:'next',
  29. title:next,
  30. id:nextId,
  31. })
  32. }
  33. if(this.data.prev){
  34. const {prev ,prevId} = this.data
  35. arr.push({
  36. type:'prev',
  37. title:prev,
  38. id:prevId,
  39. })
  40. }
  41. return arr
  42. }
  43. },
  44. methods:{
  45. /**
  46. * 获取数据
  47. */
  48. getData(){
  49. const { id } = this.$route.params
  50. this.$axios.get(`/question/${id}`).then(res =>{
  51. this.data = res
  52. })
  53. },
  54. /**
  55. * 触发单击事件修改路由
  56. */
  57. handleClick(id){
  58. const { name } = this.$route
  59. this.$router.push({name,params:{id}})
  60. }
  61. },
  62. /**
  63. * 监听路由信息是否被修改
  64. * 当路由信息被修改后重新获取数据
  65. */
  66. watch:{
  67. '$route':{
  68. handler(){
  69. this.getData()
  70. },
  71. immediate: true
  72. }
  73. }
  74. }
  75. </script>
  76. <style scoped>
  77. .option{
  78. width: 80%;
  79. height: 30px;
  80. position: fixed;
  81. left: 0;
  82. right: 0;
  83. bottom: 10px;
  84. margin: 10px auto;
  85. }
  86. .option-item{
  87. width: 200px;
  88. white-space: nowrap;
  89. overflow: hidden;
  90. text-overflow: ellipsis;
  91. color: #3385ff;
  92. cursor: pointer;
  93. }
  94. .option-item:hover{
  95. color: red;
  96. }
  97. .option-item.next{
  98. float: right;
  99. }
  100. .option-item .right{
  101. float: left;
  102. }
  103. </style>