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

Web前端-Vue2+Vue3基础入门到实战项目-Day5

  • 路由进阶
    • 路由模块封装
    • 声明式导航
      • 导航链接
      • 模糊 & 精确 匹配
      • 自定义匹配类名
      • 跳转传参
    • Vue路由
      • 重定向
      • 404
      • 模式设置
    • 编程式导航
      • 基本跳转
      • 路由传参
  • 案例 - 面经基础版
    • views
  • 来源

路由进阶

路由模块封装

  • 优点: 拆分模块, 利于维护
  • 如何快速引入组件: 基于@指代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>

模糊 & 精确 匹配

router-link-active 模糊匹配
to="/find" => 地址栏 /find /find/one /find/two ...

router-link-exact-active
to="/find" => 地址栏 /find
router-link-active {
  background-color: blue;
}
router-link-exact-active {
  background-color: blue;
} */

自定义匹配类名

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

跳转传参

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

Vue路由

重定向

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

404

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

模式设置

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

编程式导航

基本跳转

<script>
export default {
  ...
  methods: {
    goSearch () {
      // 1. 通过路径的方式跳转
      //    简写
      // this.$router.push('/search') 
      //    完整写法
      // this.$router.push({
      //   path: '/search'
      // })

      // 2. 通过命名路由的方式跳转 (需要给路由命名, 适合长路由)
      this.$router.push({
        name: 'search'
      })
    }
  }
}
</script>

路由传参

<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>

案例 - 面经基础版

  • 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>
    
  • 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
    

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>
    
  • 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>
    
  • 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>
    

来源

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

你可能感兴趣的:(Web前端,前端,javascript,开发语言,vue路由,axios,vue.js,keep-alive)