day【11】Vuex+router

本文介绍了如何在Vue.js中使用动态组件切换,结合v-if和动态数组实现组件的切换,并探讨了keep-alive的用法,包括缓存策略。同时,详细阐述了VueRouter的配置,包括路由规则、路由组件、嵌套路由、路由传参、命名视图以及导航守卫的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

APP.vue

<template>
  <div id="app">
    <!-- <Singer></Singer>
    <Song></Song> -->
    <!-- 可以使用v-if来切换Singer和Song
      也可以使用动态数组来实现
    -->
   <component :is="componentId"></component>
   <button @click="bool = !bool">修改bool</button>
  </div>
</template>

<script>
import Song from './components/song.vue';
import Singer from './components/singer.vue';
export default {
  name: 'App',
  components: {
    Song,
    Singer
  },
  data(){
    return{
      bool:true,
    }
  },
  computed:{
    componentId(){
     
      return this.bool ? "Singer":"Song";
    }
  },
  mounted(){
     console.log(this.bool)
  }
}
</script>

<style>


</style>

song.vue

<template>
    <div class="song">
        song:<input type="text"/>
    </div>
</template>
<script>
  export default{
    name:"Song",

  }

</script>

singer.vue

<template>
    <div class="singer">
        singer:<input type="text"/>
    </div>
</template>
<script>
  export default{
    name:"Singer",
  
  }

</script>

缓存动态组件

    <!-- 默认缓存所有的动态组件 -->
    <keep-alive>
       <component :is="componentId"></component>
    </keep-alive>
  只缓存 Song组件
  <!-- 默认缓存所有的动态组件 -->
    <keep-alive include="Song">//值是组件的name名
       <component :is="componentId"></component>
    </keep-alive>

     不缓存 Song组件
  <!-- 默认缓存所有的动态组件 -->
    <keep-alive exclude="Song">//值是组件的name名
       <component :is="componentId"></component>
    </keep-alive>
  

router

router/index.js

配置 路由规则
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home'
import About from '@/views/About'

Vue.use(VueRouter)

const routes = [
  /// 在这里配置路由规则 
]

const router = new VueRouter({
  mode: 'history',
  routes
})

export default router

main .js

import Vue from 'vue'
import App from './App.vue'
import router from './router'


Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

点击 切换路由的 router-link
app.vue内

<router-link to="/home">跳转home</router-link> |
<router-link to="/about">跳转about</router-link>
配置路由规则
const routes = [
  {
    path: '/home',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: About
  }
]
路由跳转组件的显示位置
app.vue内 
<router-view></router-view> 

当我们点击 router-link时  对应的路由组件将会在 router-view 里面出现 展示 
$route $router

每个组件 vc上都有 ¥route 里面存储自己的路由信息
整个应用 只有一个$router

一般组件和路由组件的区别

一般组件 通过import引入到父组件中一般放components文件夹内
导入—> 注册 -----> 使用



<template>
  <divv class="home">
    <h1>我是home组件</h1>
    <list></list>
  </divv>
</template>
<script>
  import list from '@/components/list.vue'
  export default{
    name:"Home",
    components:{
      list
    }
  }
</script>

路由组件 通过 在路由规则中 配置具体的路由 导入组件 展示在router-view位置
一般放在views文件夹内 /pages文件夹内

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home'
import About from '@/views/About'

Vue.use(VueRouter)

const routes = [
  {
    path: '/home',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: About
  },

]

const router = new VueRouter({
  mode: 'history',
  routes
})

export default router

嵌套路由

App.vue

<template>
  <div id="app">
   <router-link to="/home">跳转home</router-link> <br>
   <router-link to="/about">跳转about</router-link>
    <hr>
   <router-view></router-view>
    <hr>
   

  </div>
</template>

<script>

export default {
  name: 'App',
  components: {
   
  },
  data(){
  
  },
  computed:{
  
   
  },
 
}
</script>

<style>


</style>

home.vue

<template>
    <div class="home">
      <h1>我是home组件</h1>
      <router-link to="/home/singer">歌手</router-link>
      <router-link to="/home/song">歌曲</router-link>
      <hr/>
      <router-view></router-view>
    </div>
  </template>
  <script>
  export default {
    name: "Home",
    mounted() {
    console.log(this)
  },

};

  </script>
  <style lang="sass" scoped></style>

Singer.vue

<template>
    <div class="singer">
     <ul>
      <li v-for="item in singerList" :key="item.id">
      <a href="/home/singer/detail">{{ item.name }}</a></li>
     </ul>
    </div>
</template>
<script>
  export default{
    name:"Singer",
    data(){
      return {
        singerList:[
          {id:"001",name:"歌手1"},
          {id:"002",name:"歌手2"},
          {id:"003",name:"歌手3"},
          {id:"004",name:"歌手4"}

        ]
      }
    }
  
  }

</script>

Song.vue

<template>
    <div class="song">
     <ul>
      <li v-for="item in  songList" :key="item.id">
    <router-link to="/home/song/detail">{{ item.name }}</router-link>
   
</li>
     </ul>
     <router-view></router-view>
    </div>
</template>
<script>
  export default{
    name:"Singer",
    data(){
      return {
        songList:[
          {id:"001",name:"好汉"},
          {id:"002",name:"甜蜜蜜"},
          {id:"003",name:"爱你"},
          {id:"004",name:"不要"}

        ]
      }
    }
  
  }

</script>

detail.vue

<template>
    <div class="detail">
    编号:<br />
    名称:
    </div>
</template>
<script>
  export default{
    name:"Detail",
    data(){
      return {
        
        
      }
    }
  
  }

</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AT4htzlM-1686019007125)(D:\桌面\图片\3.png)]

路由传参

需求:song.vue中点击router-link把对应点击的 对象的id 和name 传给detail组件

 song.vue
<ul>
      <li v-for="item in  songList" :key="item.id">
    <router-link to="/home/song/detail?id=001&name='歌手1'">{{ item.name }}</router-link>
   
</li>
     </ul>
上面的写法  不符合需求  因为to 就写死了 没法灵活传递数据

动态绑定属性值  :to

  <div class="song">
     <ul>
      <li v-for="item in  songList" :key="item.id">
    <router-link 
    
        :to="`/home/song/detail?id=${item.id}&name=${item.name}`">{{ item.name }}</router-link>
 缺点: 写法混乱  不利于维护  
</li>
     </ul>
     <router-view></router-view>
    </div>
detail.vue

<template>
    <div class="detail">
    编号:{{ $route.query.id }}<br />
    名称:{{ $route.query.name }}
    </div>
</template>
<script>
  export default{
    name:"Detail",
    data(){
      return {
        
        
      }
    },
    mounted(){
        console.log(this)
    }
  
  
  }

</script>


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pCfCIyu1-1686019007126)(D:\桌面\图片\4.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6tkiFvKd-1686019007127)(D:\桌面\图片\5.png)]

方便维护!!!!

<div class="song">
     <ul>
      <li v-for="item in  songList" :key="item.id">
    <router-link 
    
        :to="{
            path:`/home/song/detail`,
            query:{
                id:item.id,
                name:item.name

            }
        }">
        {{ item.name }}</router-link>
   
    
</li>
     </ul>
     <router-view></router-view>
    </div>

获取 query

<template>
    <div class="detail">
    编号:{{ $route.query.id }}<br />
    名称:{{ $route.query.name }}
    </div>
</template>
<script>
  export default{
    name:"Detail",
    data(){
      return {
        
        
      }
    },
    mounted(){
        console.log(this)
    }
  
  
  }

</script>

路由命名

  children:[
          {
            path:'detail',
            name:'detail' ,//可以通过name进行  路由的跳转
            // 懒加载
            component:()=> import('../views/Detail.vue'),
          }
        ]
              
 Song.vue             
     <template>
    <div class="song">
     <ul>
      <li v-for="item in  songList" :key="item.id">
    <router-link 
    
        :to="{ 
            // path:`/home/song/detail`,
            name:'detail',//只允许对象写法,才能使用name, path和name不能同时使用
            query:{
                id:item.id,
                name:item.name

            }
        }">
        {{ item.name }}</router-link>
   
    
</li>
     </ul>
     <router-view></router-view>
    </div>
</template>
<script>
  export default{
    name:"Song",
    data(){
      return {
        songList:[
          {id:"001",name:"好汉"},
          {id:"002",name:"甜蜜蜜"},
          {id:"003",name:"爱你"},
          {id:"004",name:"不要"}

        ]
      }
    },
 
  }

</script>

动态路由

传递params参数
 children:[
          {
            path:'detail/:id/:name',
            name:'detail' ,//可以通过name进行  路由的跳转
            // 懒加载
            component:()=> import('../views/Detail.vue'),
          }
        ]
传递参数
 <div class="song">
     <ul>
      <li v-for="item in  songList" :key="item.id">
    <router-link 
    
        to="/home/song/detail/001/歌手1">
        {{ item.name }}</router-link>
   
    
</li>
     </ul>
     <router-view></router-view>
    </div>
这里写死了
缺点:写法混乱,不利于维护

但是不允许  使用path 只能使用 name

<template>
    <div class="song">
     <ul>
      <li v-for="item in  songList" :key="item.id">
    <!-- <router-link 
    
        :to="`/home/song/detail/${item.id}/${item.name}`">
        {{ item.name }}</router-link> -->
        <router-link :to="{
         name:'detail',
          params:{
            id:item.id,
            name:item.name
          }
        }"> {{ item.name }}</router-link>
   
    
</li>
     </ul>
     <router-view></router-view>
    </div>
</template>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JodZRwmI-1686019007127)(D:\桌面\图片\6.png)]

接收params
<template>
    <div class="detail">
    <!-- 编号:{{ $route.query.id }}<br />
    名称:{{ $route.query.name }} -->
    编号:{{ $route.params.id }}<br />
    名称:{{ $route.params.name }}
    </div>
</template>
路由的props配置

把参数处理为props路由组件 可以通过props属性接收

   component:()=> import('../views/Song.vue'),
        children:[
          {
            path:'detail',
            name:'detail' ,//可以通过name进行  路由的跳转
            // 懒加载
            component:()=> import('../views/Detail.vue'),
            props:{
              id:'001',
              name:"歌曲1"
            }
          }
        ]//数据被写死了

接收  detail组件内
<template>
    <div class="detail">
    <!-- 编号:{{ $route.query.id }}<br />
    名称:{{ $route.query.name }} -->
    <!-- 编号:{{ $route.params.id }}<br />
    名称:{{ $route.params.name }} -->
    编号:{{ id }}<br />
    名称:{{ name }}
    </div>
</template>
    props:["id","name"]


第二个写法
index.js
{
        // 访问的时候 实际/home/singer  写·的·时候·不要·写·成·/singer
        path:'song',
        // 懒加载
        component:()=> import('../views/Song.vue'),
        children:[
          {
            path:'detail',
            name:'detail' ,//可以通过name进行  路由的跳转
            // 懒加载
            component:()=> import('../views/Detail.vue'),
            // 把路由组件收到的所有的  params参数  以props的形式 传给dejtail组件
            props:true
          }
        ]

      }


song.vue
<template>
    <div class="song">
     <ul>
        <router-link :to="{
         name:'detail',
          params:item,
         
        }"> {{ item.name }}</router-link>    
</li>
     </ul>
     <router-view></router-view>
    </div>
</template>

接收detail组件内
props:["id","name"]

上面的只能配合params用,不能query用


如果传递的是params  依旧需要  定义动态路由  以及进行传参
  props($route){
              return{
                id:$route.params.id,
                name:$route.params.name
              }
接收 detail组件内
props:["id","name"]
      
query形式  依旧需要  传递query参数
  <router-link :to="{
         name:'detail',
         query:item,
         
        }"> {{ item.name }}</router-link>
 props:["id","name"]  

replace属性

替换 路由记录

  1. 默认方式 push(追加历史记录)

  2. replace(替换当前历史记录)

    <router-link replace :to="{

​ name:‘detail’,

​ query:item,

​ }"> {{ item.name }}

http://localhost:8081/home

http://localhost:8081/home/song X被替换

http://localhost:8081/home/song/detail?id=004&name=%E4%B8%8D%E8%A6%81

回退 回退到 http://localhost:8081/home

命名视图

同时(同级)展示多个视图 router-view 设置名字 默认default

index.js
{
    path: '/about',
    name: 'About',
    // component: About
    // 换成 components 接收{}
    components:{
      default:About,
      pageA:()=>import('../views/Singer.vue'),
      pageB:()=>import('../views/Song.vue')
    }
  },
      
      
APP.vue
<template>
  <div id="app">
   <router-link to="/home">跳转home</router-link> <br>
   <router-link to="/about">跳转about</router-link>
    <hr>
    <!-- 默认展示default -->
   <router-view></router-view>
   <router-view name="pageA"></router-view>
   <router-view name="pageB"></router-view>
    <hr>
   

  </div>
</template>
编程式导航
 <ul>
      <li v-for="item in  songList" :key="item.id" @click="toDetail(item)">
   
        {{ item.name }}
</li>
     </ul>


  methods:{
      toDetail(item){
        // 跳转路由
        this.$router.push(`/home/song/detail?id=${item.id}&name=${item.name}`)
           
        // 第二种写法
       this.$router.push({
        path:"/home/song/detail",
        query:item,
       })
      }
  
    }

replace除了对历史记录是覆盖替换效果    使用上和push一毛一样
 this.$router.replace({
        path:"/home/song/detail",
        query:item,
       })
 
    <button @click="toAbout">前进</button>
methods:{ //历史记录不够用  就跳转失败
    toAbout(){
      // 在历史中前进n步
      this.$router.go(2)

         // 在历史中后退n步  负数
         this.$router.go(-1)
    }
  }

this.$router.forward() //前进
this.$router.back() //后退

缓存路由组件

// vue3有变动 vue3再讲  
<keep-alive>
      <router-view></router-view> 
 </keep-alive>

include(包含)  exclude(不包含) 

子级不会被缓存 

keep-alive 生命周期

<keep-alive>
      <router-view></router-view>
    </keep-alive>
    被keep-alive缓存的路由组件 当访问路由时 路由组件 激活状态
    当切换别的路由时 路由组件 失活状态(没有被销毁)

activated() {
    //当组件被激活时
    console.log("home组件被激活了");
  },
  deactivated() {
    //当组件失活时
    console.log("home组件失活了");
  },

nextTick 钩子函数

<div>
      <button @click="showIpt">点击显示 input框</button>
      <input type="text" v-if="bool" ref="ipt" />
    </div>

showIpt() {
      this.bool = true;
      console.log(this.$refs);
      //使得input具有焦点 得等input渲染完毕之后 再执行

      //dom更新完毕 调用的钩子函数
      this.$nextTick(() => {
        this.$refs.ipt.focus();
      });
    },

路由器的两种 工作模式

// history模式  hash模式   vue3内 稍有变化  
const router = new VueRouter({
  mode: 'hash',
  routes
})

const router = new VueRouter({
  mode: 'history',
  routes
})


hash模式 
http://localhost:8080/#/home/singer 
后端 不会把 /#/home/singer 识别为后端 路由 (不会和后端路由发生冲突 )
优点: 1.不会和后端路由发生冲突  2.hash 兼容性更好 
缺点: 带#不美观   

history 
http://localhost:8080/home/singer
优点: 美观 简洁 
缺点: 兼容性比hash差 会和后端路由发生冲突 需要后端处理 

再次刷新页面 会把 /home/singer 当做后端路由 所以 再次刷新 页面就会丢掉 
后端配合可以 解决  

比如 node 
npm i connect-history-api-fallback
const history = require('connect-history-api-fallback');
app.use(history())  

导航守卫

路由匹配前后的 钩子 给用户操作的空间 
全局前置守卫
// 全局前置守卫  进入路由之前 先在这里执行  beforeEach
router.beforeEach((to, from, next) => {
  //to 去哪个 路由信息对象
  //from 来自哪个 路由信息对象 
  console.log(from);// / 
  console.log(to); // /about 
  if (to.meta.isLogin) {
    //已登录
    next()//执行下一步 放行
  } else {
      //不放行
    next(false)
  }
})

全局后置守卫
// 全局后置守卫  路由跳转完成之后触发  afterEach
router.afterEach((to, from) => {
  console.log('全局后置钩子');
})

只要有路由的修改 前置和后置钩子就会被触发

独享守卫
写到 路由规则里 
{
    path: '/home',
    name: 'Home',
    component: Home,
    beforeEnter(to, from, next) {
      console.log("/home 独享的的路由守卫 ");
      next()//放行
    },
    alias: ['/home1', '/home2'],

    // 定义一些 /home路由的元信息
    meta: { isLogin: true },
}
路由组件守卫
beforeRouteEnter(to, from, next) {
    //进入路由触发
    console.log("detail组件内的 路由进入/detail");
    next();
  },
  beforeRouteLeave(to, from, next) {
    //离开路由触发
    console.log("detail组件内的 路由离开/detail");
    next();
  },
  beforeRouteUpdate(to, from, next) {
    //但是该组件被复用时调用 动态路由时 detail组件不变 数据发生变化 detail组件就是复用的
    console.log("detail组件被复用了");
    //导航守卫可以访问组件实例 `this`
    next();
  },

完整的导航解析流程

// 全局前置守卫  进入路由之前 先在这里执行  beforeEach
router.beforeEach((to, from, next) => {
  console.log('全局前置钩子(守卫)');
  next()

})
// 全局后置守卫  路由跳转完成之后触发  afterEach 唯一不需要带 next 
router.afterEach((to, from) => {
  console.log('全局后置钩子');
})

{
            path: 'detail/:id/:name',
            name: 'detail',
            component: () => import('../views/Detail.vue'),
            props($route) {
              return {
                id: $route.params.id,
                name: $route.params.name
              }
            },
            beforeEnter(to, from, next) {
              console.log("/detail 独享的的路由守卫 ");
              next()//放行
            },

          }

组件内
beforeRouteEnter(to, from, next) {
    //进入路由触发
    console.log("detail组件内的 路由进入/detail");
    next();
  },
  beforeRouteLeave(to, from, next) {
    //离开路由触发
    console.log("detail组件内的 路由离开/detail");
    next();
  },
  beforeRouteUpdate(to, from, next) {
    console.log("detail组件被复用了");
    next();
  },
      
      
 当访问某 detail路由      
 先 全局前置 ==> 独享路由 ==> 组件进入守卫 ==> 全局后置 

当离开 detail路由时 
先 组件内离开路由  => 全局前置 => 全局后置 

当detail 组件复用时
全局前置 ==> 组件复用钩子 ==> 全局后置 

})
// 全局后置守卫  路由跳转完成之后触发  afterEach 唯一不需要带 next 
router.afterEach((to, from) => {
  console.log('全局后置钩子');
})

{
            path: 'detail/:id/:name',
            name: 'detail',
            component: () => import('../views/Detail.vue'),
            props($route) {
              return {
                id: $route.params.id,
                name: $route.params.name
              }
            },
            beforeEnter(to, from, next) {
              console.log("/detail 独享的的路由守卫 ");
              next()//放行
            },

          }

组件内
beforeRouteEnter(to, from, next) {
    //进入路由触发
    console.log("detail组件内的 路由进入/detail");
    next();
  },
  beforeRouteLeave(to, from, next) {
    //离开路由触发
    console.log("detail组件内的 路由离开/detail");
    next();
  },
  beforeRouteUpdate(to, from, next) {
    console.log("detail组件被复用了");
    next();
  },
      
      
 当访问某 detail路由      
 先 全局前置 ==> 独享路由 ==> 组件进入守卫 ==> 全局后置 

当离开 detail路由时 
先 组件内离开路由  => 全局前置 => 全局后置 

当detail 组件复用时
全局前置 ==> 组件复用钩子 ==> 全局后置 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值