Bootstrap

第三十八章 章节练习之面经页面

目录

一、实现功能需求及步骤

二、初始结构代码

2.1. main.js

2.2. App.vue

2.3. index.js

2.4. Layout.vue

2.5. Article.vue

2.6. ArticleDetail.vue

2.7. Collect.vue

2.8. Like.vue

2.9. User.vue

三、功能实现

3.1. 配置一二级路由

3.2. 配置路由出口/链接/高亮显示

3.3. 首页请求渲染

3.4. 主页路由跳转详情页传参 

3.5. 默认请求路径跳转设置

​3.6. 详情页跳转返回主页

3.7. 详情页渲染 

​3.8. 增加显示判断

3.9. 详情页返回首页定位到原始位置


一、实现功能需求及步骤

1. 配路由

① 首页 和 面经详情,两个一级路由

② 首页内嵌四个可切换页面 (嵌套二级路由)

2. 实现功能

① 首页请求渲染

跳转传参 到 详情页,详情页渲染

组件缓存,优化性能

 

二、初始结构代码

2.1. main.js

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

Vue.config.productionTip = false

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

2.2. App.vue

<template>
  <div class="h5-wrapper">
    <!-- 路由出口 -->
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "h5-wrapper",
}
</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>

2.3. index.js

import Vue from 'vue'
import VueRouter from "vue-router";
Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    
  ]
})

export default router

2.4. Layout.vue

<template>
  <div class="h5-wrapper">
    <div class="content">
      内容
    </div>
    <nav class="tabbar">
      <a href="#/article">面经</a>
      <a href="#/collect">收藏</a>
      <a href="#/like">喜欢</a>
      <a href="#/user">我的</a>
    </nav>
  </div>
</template>

<script>
export default {
  name: "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;
    }
  }
}
</style>

2.5. Article.vue

<template>
  <div class="article-page">
    <div
      class="article-item"
      >
      <div class="head">
        <img src="http://teachoss.itheima.net/heimaQuestionMiniapp/%E5%AE%98%E6%96%B9%E9%BB%98%E8%AE%A4%E5%A4%B4%E5%83%8F%402x.png" alt="" />
        <div class="con">
          <p class="title">百度前端面经</p>
          <p class="other">青春, 那么骚 | 2022-01-20</p>
        </div>
      </div>
      <div class="body">
         虽然百度这几年发展势头落后于AT,甚至快被京东赶上了,毕竟瘦死的骆驼比马大,面试还是相当有难度和水准的。一面1.询问你的项目经验、学习经历、主修语言(照实答)2.解释ES6的暂时性死区( let 和 var 的区别)3.箭头函数、闭包、异步(老生常谈,参见上文)4.高阶函数(呃……我真不太清楚这是啥,听起来挺像闭包的)5.求N的阶乘末尾有多少个0,在线码代码或讲思路(求因数,统计2、5、10的个数
      </div>
      <div class="foot">点赞 44 | 浏览 315</div>
    </div>
  </div>
</template>

<script>
// 请求地址: https://mock.boxuegu.com/mock/3083/articles
// 请求方式: get
export default {
  name: 'ArticlePage',
  data () {
    return {

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

2.6. ArticleDetail.vue

<template>
  <div class="article-detail-page">
    <nav class="nav"><span class="back">&lt;</span> 面经详情</nav>
    <header class="header">
      <h1>百度前端面经</h1>
      <p>2022-01-20 | 315 浏览量 | 44 点赞数</p>
      <p>
        <img
          src="http://teachoss.itheima.net/heimaQuestionMiniapp/%E5%AE%98%E6%96%B9%E9%BB%98%E8%AE%A4%E5%A4%B4%E5%83%8F%402x.png"
          alt=""
        />
        <span>青春少年</span>
      </p>
    </header>
    <main class="body">
      虽然百度这几年发展势头落后于AT, 甚至快被京东赶上了,毕竟瘦死的骆驼比马大,
      面试还是相当有难度和水准的, 一面.....
    </main>
  </div>
</template>

<script>
// 请求地址: https://mock.boxuegu.com/mock/3083/articles/:id
// 请求方式: get
export default {
  name: "ArticleDetailPage",
  data() {
    return {
      
    }
  }
}
</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>

2.7. Collect.vue

<template>
  <div>Collect</div>
</template>

<script>
export default {
  name: 'CollectPage'
}
</script>

2.8. Like.vue

<template>
  <div>Like</div>
</template>

<script>
export default {
  name: 'LikePage'
}
</script>

2.9. User.vue

<template>
  <div>User</div>
</template>

<script>
export default {
  name: 'UserPage'
}
</script>

三、功能实现

3.1. 配置一二级路由

一级路由包括首页(Layout)和面经详情(ArticleDetail),子路由通过children属性来实现:

import ArticleDetail from '@/views/ArticleDetail.vue';
import Layout from '@/views/Layout.vue';
import Article from '@/views/Article.vue';
import Collect from '@/views/Collect.vue';
import Like from '@/views/Like.vue';
import User from '@/views/User.vue';
import Vue from 'vue'
import VueRouter from "vue-router";
Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    { path: '/', component: Layout,
      // 通过children配置项,可以配置嵌套子路由
      // 1.在children配置项中配置规则
      // 2.准备二级路由出口 
      children: [
        { path: '/article', component: Article },
        { path: '/collect', component: Collect },
        { path: '/like', component: Like },
        { path: '/user', component: User }
      ]
    },
    { path: '/detail', component: ArticleDetail }
  ]
})

export default router

3.2. 配置路由出口/链接/高亮显示

 

<template>
  <div class="h5-wrapper">
    <div class="content">
      <!-- 配置二级路由出口,匹配到的二级路由组件就会在此展示 -->
      <router-view></router-view>
    </div>
    <nav class="tabbar">
      <!-- 
        导航高亮显示效果
        1. 将a标签,替换成router-link 并将 a标签 href属性 改成 to
        2. 结合高亮类名实现高亮效果 router-link-active
      -->
      <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: "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;
    }
    // 自定义 Vue路由高亮类名 的颜色
    a.router-link-active {
      color: orange;
    }
  }
}
</style>

3.3. 首页请求渲染

1. 安装axios

2. 确认请求方式/请求地址/请求参数

3. created中发请求,获取数据并存储

4. 页面动态渲染

 

3.4. 主页路由跳转详情页传参 

下面两种传参形式均可,查询传参适合多个参数传递,动态路由传参适合单个参数传递:

1. 查询参数传参 ?参数=参数值 => this.$route.query.参数名

2. 动态路由传参 改造路由 => /路径/参数 => this.$route.params.参数名

 

3.5. 默认请求路径跳转设置

将首次访问页面定位跳转到Article.vue页面

 3.6. 详情页跳转返回主页

3.7. 详情页渲染 

 3.8. 增加显示判断

当后端请求过来的article数据还未获取到赋值时,不显示,避免页面短暂空白

3.9. 详情页返回首页定位到原始位置

从主页的指定位置A跳转到详情页,返回后定位到首页浏览的原始位置A:

1. 组件缓存 keep-alive

keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而非销毁它们

keep-alive 是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中。

2. keep-alive的优点

在组件切换过程中 把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性。

3. keep-alive的三个属性

① include : 组件名数组,只有匹配的组件会被缓存

② exclude : 组件名数组,任何匹配的组件都不会被缓存

③ max : 最多可以缓存多少组件实例

4. keep-alive的使用会触发两个生命周期函数

activated 当组件被激活(使用)的时候触发 → 进入这个页面的时候触发

deactivated 当组件不被使用的时候触发 → 离开这个页面的时候触发

组件缓存后就不会执行组件的created, mounted, destroyed 等钩子了

所以其提供了actived deactived钩子,帮我们实现业务需求。

;