一共两个页面:首页和详情页(一级路由),
其中,首页由新闻列表组成,点其中一个可以进入详情页,详情页有返回首页的按钮
底部导航能切换:列表,收藏,喜欢,我的(嵌套二级路由)
views目录下创建:
routes:[
{
path:"/home",
component:Home,
children:[
{path:"/list",component:List},
...
{path:"/user",component:User}
]
}
]
App.vue
中,同理嵌套在首页的二级路由的出口可以写在首页Home.vue中//Home.vue
<router-view><router-view>
routes:[
...(接上面代码)...
{path:"/",redirect:"/list"},//路由重定向
{path:"*",component:NotFound};//再新建一个NotFound.vue
],
mode:"history",//去除井号
router-link
标签替换a
标签(一开始直接不用a标签) <div class="h5-wrapper">
<div class="content">
<router-view>router-view>
div>
<nav class="tabbar">
<router-link to="/list">列表router-link>
<router-link to="/collect">收藏router-link>
<router-link to="/like">喜欢router-link>
<router-link to="/user">我的router-link>
nav>
div>
/* 基础布局 */
.h5-wrapper {
height: 100vh;
display: flex;
flex-direction: column;
}
.content {
flex: 1;
overflow-y: auto;
}
/* 底部导航栏样式 */
.tabbar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 50px;
background: #fff;
display: flex;
border-top: 1px solid #eee;
box-shadow: 0 -2px 10px rgba(0,0,0,0.05);
}
.tabbar a {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
color: #666;
text-decoration: none;
font-size: 14px;
transition: all 0.3s;
}
/* 激活状态样式 */
.tabbar a.router-link-active {
color: orange;
font-weight: bold;
}
/* 点击反馈效果 */
.tabbar a:active {
background: rgba(0,0,0,0.05);
}
*由于路由重定向,此处首页的渲染请求,实际上就是对嵌套二级路由List.vue的渲染
npm install axios -g
//List.vue
import axios from "axios"
export default from {
async created(){
const res=await axios.get("https://mock.boxuegu.com/mock/3083/articles")
//console.log(res);
this.newsList=res.data.result.rows//根据res的结构逐渐获取想要的数据
}
data(){
return{
newsList:[]
}
}
}
<div
v-for="item in newsList"
:key="item.id"
@click="$router.push(`/detail/${item.id}`)">//传参,后面讲
<img :src="item.img" alt="">
<h3 class="title">{{item.title}}h3>
<div class="body">{{item.source}}div>
<div class="meta-info">
文章点击量:{{item.cmtcount}} | 编辑于{{item.time}}
div>
div>
查询参数:
父组件传参:@click="this.$router.push('/detail? 名1=值1&名2=值2')"
子组件接收:this.$route.query.名1
动态路由:
需先改造路由:{path:"/detail/:参数名",...}
父组件传参:@click='this.$router.push("/detail/参数值")'
子组件接收::this.$route.params.参数名
//父组件(首页):List.vue
<template>
<div class="wrapper div-list-page">
<div
v-for="item in newsList"
:key="item.id"
@click="$router.push(`/detail/${item.id}`)">
<img :src="item.img" alt="">
<h3 class="title">{{item.title}}</h3>
<div class="body">{{item.source}}</div>
<div class="meta-info">
文章点击量:{{item.cmtcount}} | 编辑于{{item.time}}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
newLists:null
};
},
async created() {
const res = await this.$axios.get(`http://hmajax.itheima.net/api/news`)
this.newsList = res.data.data
//console.log("新闻列表:",this.newsList);
},
};
</script>
<style scoped>
/* 外层容器 */
.wrapper {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
/* 单个新闻项 */
.list-page {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-top: 24px;
padding: 20px;
transition: box-shadow 0.3s ease;
}
/* 悬停效果 */
.list-page:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
/* 新闻图片 */
.list-page img {
width: 100%;
max-width: 600px;
height: auto;
border-radius: 4px;
margin-bottom: 16px;
}
/* 标题样式 */
.title {
font-size: 1.5rem;
color: #333;
margin-bottom: 12px;
font-weight: 600;
line-height: 1.3;
}
/* 正文内容 */
.body {
color: #666;
line-height: 1.6;
margin-bottom: 16px;
}
/* 页脚元信息 */
.meta-info {
color: #999;
font-size: 0.9rem;
border-top: 1px solid #eee;
padding-top: 12px;
}
</style>
*********************************************************************
//子组件(详情页):Detail.vue
<nav class="nav" >
//点击返回首页,用到了实例对象$router的back方法
<span class="back" @click="$router.back()">首页</span>
<p>我是详情页</p>
我获取到id了----{{$route.params.id}}
</nav>
步骤和首页一样,略
详情页组件在获取参数后需要异步加载数据,在数据返回前页面没有内容,除此之外,也受限于
v-if=list.id
,如果没有数据则不渲染,没有数据时使用骨架屏内容<div>
<div v-if="loading" class="skeloton">
div>
<div v-else>
<! -- 获取数据,渲染内容 -->
div>
div>
从首页进度条下拉的新闻列表中点击其中一条新闻,进入详情页然后返回首页,发现自动回到了首页的进度条顶部位置
点进详情页又返回,首页数据重新加载了.即:路由跳转后,组件被销毁了,返回来后组件又重建了,导致数据被重新加载
使用keep-alive将组件缓存下来
//App.vue
<keep-alive :include="['Home.vue']">
<router-view>router-view>
keep-alive>
keep-alive是Vue的内置组件,用来包裹动态组件,使其缓存不活动的组件实例,而非销毁组件
keep-alive是一个抽象组件,它自身不会渲染成一个DOM元素,也不会出现在父组件中
在组件切换的过程中,把切换出去的组件保留在内存中,避免重复渲染DOM,
减少加载时间和性能消耗,提高用户体验
在上例中,首页被缓存时我们所需要的,详情页却不是,此时需要用到keep-alive的属性对这两个一级路由选择性缓存
*注意组件名数组和文件名(Detail.vue
)的不同,有些组件文件会配置name属性:name:DetailPage
首先来验证一下keep-alive的缓存效果:
//Home.vue
created(){consol.log("组件被加载了...")},
mounted(){console.log("DOM渲染完了...")},
destroyed(){console.log("组件被销毁了...")}
结果:除第一次进入组件时触发前两个钩子外,第二次返回页面时不会再触发
接下来,写入actived和deactived看效果:
activeed(){console.log("组件激活了...")},
deactived(){console.log("组件失活了...")}
结果,组件切换的过程中会触发