目录
一、实现功能需求及步骤
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"><</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钩子,帮我们实现业务需求。