实例:面经基础版
(功能)组件缓存 keep-alive
小结
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({ //注入,将路由对象注入到new Vue实例中,建立关联
render: h => h(App),
router
}).$mount('#app')
index.js
import Vue from 'vue'
import VueRouter from "vue-router"; //引入
// import { component } from 'vue/types/umd';
import Layout from '@/views/Layout.vue'
import ArticleDetail from '@/views/ArticleDetail.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';
Vue.use(VueRouter) //安装注册
const router = new VueRouter({ //创建路由对象
//创建需要的组件(view目录),配置路由规则
routes: [
{
path:'/',
// redirect:'/Layout',
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',
// component:ArticleDetail
//动态路由传参路由配置 /路径名/:参数
path:'/detail/:id',
component:ArticleDetail
}
]
})
export default router
App.vue
<template>
<div class="h5-wrapper">
<!-- 包裹了keep-alive 一级路由匹配的组件都会被缓存
Layout (被缓存) -多两个生命周期钩子
- actived 激活时,组件被看到时触发
- deactived 失活时,离开页面组件看不见触发
Detail (未被缓存)
需求:只希望Layout被缓存,include配置 → :include="组件名数组"
-->
<!-- <keep-alive :include="['LayoutPage']"> -->
<keep-alive :include="keepArr">
<router-view></router-view>
</keep-alive>
</div>
</template>
<script>
export default {
name: "h5-wrapper",
data(){
return {
keepArr:['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>
Layout.vue (一级路由 首页)
<template>
<div class="h5-wrapper">
<div class="content">
<!-- 二级路由出口,匹配到的二级路由组件就会展示 -->
<router-view></router-view>
</div>
<nav class="tabbar">
<!-- 导航高亮
1. 将a标签,替换成router-link (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,才会找文件名作为组件名
name: "LayoutPage",
//组件被缓存,就不会执行created,mounted,destroyed等钩子
//所以提供了 activated 和 deactivated
created(){
console.log('组件被加载了')
},
mounted(){
console.log('dom 渲染完了')
},
destroyed(){
console.log('组件被销毁了')
},
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: aqua;
}
}
}
</style>
ArticleDetail.vue(一级路由 详情页)
<template>
<div class="article-detail-page" v-if="articlelist.id" >
<!-- 数据传来再做渲染 -->
<nav class="nav"><span @click="$router.back()" class="back"><</span> 面经详情</nav>
<header class="header">
<h1>{{ articlelist.stem }}</h1>
<p>{{ articlelist.createdAt}} | {{ articlelist.views}} 浏览量 | {{ articlelist.likeCount}} 点赞数</p>
<p>
<img
:src="articlelist.creatorAvatar"
alt=""
/>
<span>{{ articlelist.creatorName}}</span>
</p>
</header>
<main class="body">
{{ articlelist.content }}
</main>
</div>
</template>
<script>
import axios from 'axios'
// 请求地址: https://mock.boxuegu.com/mock/3083/articles/:id
// 请求方式: get
export default {
name: "ArticleDetailPage",
data() {
return {
articlelist:{}
}
},
async created(){
const res = await axios.get(`https://mock.boxuegu.com/mock/3083/articles/${this.$route.params.id}`)
this.articlelist = res.data.result
// console.log(this.$route.query.id) //查询参数传参 接收参数
// console.log(this.$route.params.id) //动态路由传参 接收参数
}
}
</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>
Article.vue(列表页)
<template>
<div class="article-page">
<div
v-for="item in articles"
:key="item.id"
class="article-item"
@click="$router.push(`/detail/${item.id}`)"
>
<!-- @click="$router.push(`/detail?id=${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'
//首页请求渲染
// 1.安装 axios
// 2.看接口文档,确认请求方式,请求地址,请求参数
// 请求地址: https://mock.boxuegu.com/mock/3083/articles
// 请求方式: get
// 3.created中发送请求,获取数据,存起来
// 4.页面动态渲染
//跳转详情页传参 -> 渲染
// 1. 查询参数传参 (更适合多个参数)
// ?参数=参数值 => this.$router.query.参数名
// 2. 动态路由传参 (单个参数更优雅方便)
// 改造路由 => /路径/参数 => this.$router.params.参数名
//修复小bug: (1) 访问 / 重定向 /article (redirect)
// (2) 返回上一页 $router.back
export default {
name: 'ArticlePage',
data(){
return {
articles:[]
}
},
async created() {
const res = await axios.get('https://mock.boxuegu.com/mock/3083/articles')
this.articles = res.data.result.rows
// console.log(this.articles)
},
}
</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>