• Web前端-Vue2+Vue3基础入门到实战项目-Day5(路由进阶, 案例 - 面经基础版)


    路由进阶

    路由模块封装

    • 优点: 拆分模块, 利于维护
    • 如何快速引入组件: 基于@指代src目录, 从src目录出发找组件
    • 拆分步骤:
      1. 新建router/index.js, 写入路由模块代码
      2. index.js, 开头加入import Vue from 'vue', 结尾加入export default router
      3. main.js中加入import router from './router/index'

    声明式导航

    导航链接

    需求: 实现导航高亮效果

    • 使用vue-router提供的全局组件router-link(取代a标签)
      • 能跳转, 配置to属性指定路径(必须). 本质还是a标签, to无需#
      • 能高亮, 默认就会提供高亮类名, 可以直接设置高亮样式
    <template>
      <div>
        <div class="footer_wrap">
          <router-link to="/find">发现音乐router-link>
          ...
        div>
        ...
      div>
    template>
    <style>
    .footer_wrap a.router-link-active {
      background-color: blue;
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    模糊 & 精确 匹配

    router-link-active 模糊匹配
    to="/find" => 地址栏 /find /find/one /find/two ...
    
    router-link-exact-active
    to="/find" => 地址栏 /find
    
    • 1
    • 2
    • 3
    • 4
    • 5
    router-link-active {
      background-color: blue;
    }
    router-link-exact-active {
      background-color: blue;
    } */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    自定义匹配类名

    const router = new VueRouter({
      ...
      // link自定义高亮类名
      linkActiveClass: 'active', // 配置模糊匹配的类名
      linkExactActiveClass: 'exact-active' // 配置精确匹配的类名
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    跳转传参

    • 查询参数传参 (适合传多个参数)
      • 跳转: to="/path?参数名1=值&参数名2=值"
      • 获取: $route.query.参数名
    • 动态路由传参 (适合传单个参数)
      • 配置动态路由: path: "/path/参数名
      • 跳转: to="/path/参数名
      • 获取: $route.params.参数名
      • 参数可选符: /path/:words?表示参数可传可不传

    Vue路由

    重定向

    • 问题: 开始的默认路径是/路径, 未匹配到组件会出现空白
    • 解决:
      const router = new VueRouter({
      routes: [
          { path: '/', redirect: '/home'},
          ...
      ]
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

    404

    • 作用: 当路径找不到匹配时, 给出提示页面
    • 位置: 配在路由最后
    const router = new VueRouter({
      routes: [
        ...
        { path: '*', component: NotFind}
      ]
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    模式设置

    • hash路由(默认): 路径中带有#
    • history路由(常用): 路径中没有#, 但是上线后需要服务器端支持
    const router = new VueRouter({
      mode: 'history',
      ...
    })
    
    • 1
    • 2
    • 3
    • 4

    编程式导航

    基本跳转

    <script>
    export default {
      ...
      methods: {
        goSearch () {
          // 1. 通过路径的方式跳转
          //    简写
          // this.$router.push('/search') 
          //    完整写法
          // this.$router.push({
          //   path: '/search'
          // })
    
          // 2. 通过命名路由的方式跳转 (需要给路由命名, 适合长路由)
          this.$router.push({
            name: 'search'
          })
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    路由传参

    <script>
    export default {
      name: 'FindMusic',
      methods: {
        goSearch () {
          // 1. 通过路径的方式跳转
          //    简写
          //    query传参
          this.$router.push('/search?key1=val1&key2=val2')
          //    动态路由传参
          this.$router.push('/search/val')
          //    完整写法
          //    query传参
          this.$router.push({
            path: '/search',
            query: {
              key1: 'val1',
              key2: 'val2'
            }
          })
          //    动态路由传参
          this.$router.push({
            path: '/search/val',
          })
    
          // 2. 通过命名路由的方式跳转 (适合长路由)
          //   query传参
          this.$router.push({
            name: 'search',
            query: {
              key1: 'val1',
              key2: 'val2'
            }
          })
          //   动态路由传参
          this.$router.push({
            name: 'search',
            params: {
              key1: 'val1',
              key2: 'val2'
            }
          })
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    案例 - 面经基础版

    • App.vue
      <template>
        <div class="h5-wrapper">
          
          <keep-alive :include="keepArray">
            <router-view>router-view>
          keep-alive>
        div>
      template>
      
      <script>
      export default {
        name: "h5-wrapper",
        data () {
          return {
            keepArray: ['LayoutPage']
          }
        }
      }
      script>
      
      <style>
      body {
        margin: 0;
        padding: 0;
      }
      style>
      <style lang="less" scoped>
      .h5-wrapper {
        .content {
          margin-bottom: 51px;
        }
        .tabbar {
          position: fixed;
          left: 0;
          bottom: 0;
          width: 100%;
          height: 50px;
          line-height: 50px;
          text-align: center;
          display: flex;
          background: #fff;
          border-top: 1px solid #e4e4e4;
          a {
            flex: 1;
            text-decoration: none;
            font-size: 14px;
            color: #333;
            -webkit-tap-highlight-color: transparent;
            &.router-link-active {
              color: #fa0;
            }
          }
        }
      }
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
    • router/index.js
      import Vue from 'vue'
      import VueRouter from "vue-router"
      
      import Article from '@/views/Article'
      import ArticleDetail from '@/views/ArticleDetail'
      import Layout from '@/views/Layout'
      import Collect from '@/views/Collect'
      import Like from '@/views/Like'
      import User from '@/views/User'
      
      Vue.use(VueRouter)
      
      const router = new VueRouter({
        routes: [
          { 
            path: '/', 
            component: Layout,
            redirect: '/article',
            // 通过children配置项, 可以配置嵌套子路由
            // 1. 在children配置项中, 配规则
            // 2. 准备二级路由出口
            children: [
              { path: '/article', component: Article },
              { path: '/collect', component: Collect },
              { path: '/like', component: Like },
              { path: '/user', component: User },
            ]
          },
          { path: '/detail/:id', component: ArticleDetail },
          
        ]
      })
      
      export default router
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34

    views

    • Article.vue
      <template>
        <div class="article-page">
          <div class="article-item" 
            v-for="item in list" :key="item.id"
            @click="$router.push(`/detail/${item.id}`)">
            <div class="head">
              <img :src="item.creatorAvatar" alt="" />
              <div class="con">
                <p class="title"> {{item.stem}} p>
                <p class="other"> {{item.creatorName}} | {{item.createdAt}} p>
              div>
            div>
            <div class="body">
              {{ item.content }}
            div>
            <div class="foot">点赞 {{item.likeCount}} | 浏览 {{item.views}} div>
          div>
        div>
      template>
      
      <script>
      import axios from 'axios'
      // 请求地址: https://mock.boxuegu.com/mock/3083/articles
      // 请求方式: get
      export default {
        name: 'ArticlePage',
        data () {
          return {
            list: []
          }
        },
        async created () {
          const res = await axios.get('https://mock.boxuegu.com/mock/3083/articles')
          this.list = res.data.result.rows
          // console.log(this.list)
        },
        methods: {
          
        }
      }
      script>
      
      <style lang="less" scoped>
      .article-page {
        background: #f5f5f5;
      }
      .article-item {
        margin-bottom: 10px;
        background: #fff;
        padding: 10px 15px;
        .head {
          display: flex;
          img {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            overflow: hidden;
          }
          .con {
            flex: 1;
            overflow: hidden;
            padding-left: 15px;
            p {
              margin: 0;
              line-height: 1.5;
              &.title {
                text-overflow: ellipsis;
                overflow: hidden;
                width: 100%;
                white-space: nowrap;
              }
              &.other {
                font-size: 10px;
                color: #999;
              }
            }
          }
        }
        .body {
          font-size: 14px;
          color: #666;
          line-height: 1.6;
          margin-top: 10px;
          overflow: hidden;
          text-overflow: ellipsis;
          display: -webkit-box;
          -webkit-line-clamp: 2;
          -webkit-box-orient: vertical;
        }
        .foot {
          font-size: 12px;
          color: #999;
          margin-top: 10px;
        }
      }
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
    • ArticleDetail.vue
      <template>
        <div class="article-detail-page" v-if="article.id">
          <nav class="nav"><span @click="$router.back()" class="back"><span> 面经详情nav>
          <header class="header">
            <h1> {{article.stem}} h1>
            <p> {{article.createdAt}} | {{article.views}} 浏览量 | {{article.likeCount}} 点赞数p>
            <p>
      
              <img
                :src="article.creatorAvatar"
                alt=""
              />
              <span> {{article.creatorName}} span>
            p>
          header>
          <main class="body">
            {{article.content}}
          main>
        div>
      template>
      
      <script>
      
      // 请求地址: https://mock.boxuegu.com/mock/3083/articles/:id
      // 请求方式: get
      import axios from 'axios'
      export default {
        name: "ArticleDetailPage",
        data() {
          return {
            article: {}
          }
        },
        async created () {
          const res = await axios.get(`https://mock.boxuegu.com/mock/3083/articles/${this.$route.params.id}`)
          this.article = res.data.result
          // console.log(this.article);
        }
      }
      script>
      
      <style lang="less" scoped>
      .article-detail-page {
        .nav {
          height: 44px;
          border-bottom: 1px solid #e4e4e4;
          line-height: 44px;
          text-align: center;
          .back {
            font-size: 18px;
            color: #666;
            position: absolute;
            left: 10px;
            top: 0;
            transform: scale(1, 1.5);
          }
        }
        .header {
          padding: 0 15px;
          p {
            color: #999;
            font-size: 12px;
            display: flex;
            align-items: center;
          }
          img {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            overflow: hidden;
          }
        }
        .body {
          padding: 0 15px;
        }
      }
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
    • Layout.vue
      <template>
        <div class="h5-wrapper">
          <div class="content">
            
            <router-view>router-view>
          div>
          <nav class="tabbar">
            <router-link to="/article">面经router-link>
            <router-link to="/collect">收藏router-link>
            <router-link to="/like">喜欢router-link>
            <router-link to="/user">我的router-link>
          nav>
        div>
      template>
      
      <script>
      export default {
        // 组件名, 如果没有配置name, 才会找文件名作为组件名
        name: "LayoutPage",
        // 组件缓存后, created和mounted只会执行一次, 且不执行destroyed
        // 但是提供了 activated 和 deactivated
        activated () {
          alert('回到首页')
          console.log('activated');
        },
        deactivated() {
          console.log('deactivated');
        },
      }
      script>
      
      <style>
      body {
        margin: 0;
        padding: 0;
      }
      style>
      <style lang="less" scoped>
      .h5-wrapper {
        .content {
          margin-bottom: 51px;
        }
        .tabbar {
          position: fixed;
          left: 0;
          bottom: 0;
          width: 100%;
          height: 50px;
          line-height: 50px;
          text-align: center;
          display: flex;
          background: #fff;
          border-top: 1px solid #e4e4e4;
          a {
            flex: 1;
            text-decoration: none;
            font-size: 14px;
            color: #333;
            -webkit-tap-highlight-color: transparent;
          }
          a.router-link-active {
            color: orange;
          }
        }
      }
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66

    来源

    黑马程序员. Vue2+Vue3基础入门到实战项目

  • 相关阅读:
    java计算机毕业设计新生报到管理系统源程序+mysql+系统+lw文档+远程调试
    RISC-V函数调用约定 ABI
    使用python库自动为pdf增加目录
    二叉树根节点到叶子节点的所有路径和
    什么是三层工业交换机?
    “Can‘t open workbook - unsupported file type: XML“
    jenkins使用注意问题
    某大厂开发和测试干了一架,还用鼠标线勒脖子...
    kotlin 音频播放,多音轨同时播放,音频播放期间,可以随时设置播放速度
    代理IP与Socks5代理:跨界电商智能爬虫的引擎与安全壁垒
  • 原文地址:https://blog.csdn.net/Y_cen/article/details/134040997