项目目标
完成页面跳转,分清楚一级路由和二级路由的配置。
项目需求
在首页一栏,完成页面跳转,获取异步数据信息导入完成网页信息的浏览体验。
本项目只完成面经详情内容浏览。
项目组成
一级路由
- 导航栏组件Layout.vue,导航内容包括:面经(预览),收藏,喜欢,我的。
- 网页首页显示栏即面经文章页面的预览。
二级路由
面经文章详情内容(ArticleDetail.vue),收藏一栏内容(Collect.vue),喜欢一栏内容(Like.vue),我的一栏内容(User.vue)
项目准备
创建项目:vue create (项目名,选择vue2关键字项目)
启动项目:导入vscode,安装依赖npm install ,运行项目npm run serve,初步运行
需要有插件VueRouter
所涉及vue操作: 路由配置,axios异步操作数据。
代码操作
配置组件:
1.组件代码逻辑:
导航栏Layout.vue
<template>
<!-- 一级路由配置 -->
<div class="h5-wrapper">
<div class="content">
<!-- 二级路由出口,匹配到的二级路由组件就会展示 -->
<router-view></router-view>
</div>
<nav class="tabbar">
<!-- 底部导航栏 -->
<!-- r<outer-link to="路由"></outer-link> -->
<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;
}
a.active{
color: orange;
}
}
}
</style>
面经预览一栏Article.vue
<template>
<!-- 一级路由首页,面经页面一栏 -->
<div class="article-page">
<div class="article-item" v-for="(item) in articles" :key="item.id"
@click="$router.push(`/detail/${item.id}`)">
<!-- @click="$router.push(`/detail/${item.id}`)"
跳转传参:唯一标识id响应数据内容 -->
<div class="head">
<img :src="item.creatorAvatar" alt="">
<div class="con">
<p class="title">{{item.stem}}</p>
<p class="other">{{creatorName}} | {{creatorAt}}</p>
</div>
</div>
<div class="body">
{{item.content}}
</div>
<div class="foot">点赞 {{item.likeCount}} | 浏览 {{item.views}}</div>
</div>
</div>
</template>
<script>
//1,传输数据axios
import axios from 'axios'
export default {
name: 'ArticlePage',
data(){
return{
// 定义一个数组变量,用于接收异步数据
articles:[]
}
},
async created(){
// 2,created中发送请求,获取异步数据,get 网址
const res = await axios.get('https://mock.boxuegu.com/mock/3083/articles');
// 查看所获取数据信息,代码习惯
// console.log(res);
// 3,异步数据赋值操作,获取相关的数据,页面动态渲染
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>
收藏一栏Collect.vue
<template>
<div>二级路由:“收藏”一栏</div>
</template>
<script>
export default {
name: 'CollectPage'
}
</script>
喜欢一栏Like.vue
<template>
<div>二级路由:“喜欢”一栏</div>
</template>
<script>
export default {
name: 'LikePage'
}
</script>
我的一栏User.vue
<template>
<div>二级路由:“我的”一栏</div>
</template>
<script>
export default {
name: 'UserPage'
}
</script>
面经详情一栏ArticleDetail.vue
<template>
<!-- 二级路由 “面经详情”一栏 -->
<div class="article-detail-page" v-if="article.id">
<!-- 返回上一页 @click="$router.back()" -->
<nav class="nav"> <span @click="$router.back()" class="back"><</span> 面经详情</nav>
<header class="header">
<h1>{{article.stem}}</h1>
<p>{{article.creatAdt}} | {{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>
import axios from 'axios'
export default {
name: 'ArticleDetailPage',
data(){
return{
article:{}
}
},
async created(){
// created中发送请求,async获取异步数据,get 网址
const id = this.$route.params.id;// 定义获取唯一标识id
const {data} = await axios.get(`https://mock.boxuegu.com/mock/3083/articles/${id}`)//根据唯一标识id获取对应的数据内容,{data}对象解构写法,直接获取到data数据内容
this.article= 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>
2.路由配置:
配置路径与组件的关系
./router/index.js
import Vue from 'vue'
import VueRouter from "vue-router"
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({
routes: [{
path: '/',
component: Layout,
//重定向redirect,默认网页首页
redirect: '/article',
children: [
{ path: '/article', component: Article },
{ path: '/collect', component: Collect },
{ path: '/like', component: Like },
{ path: '/user', component: User },
]
},
// :id 根据唯一标识id获取对应的数据内容
{ path: '/detail/:id', component: ArticleDetail },
],
linkActiveClass: 'active',
linkExactActiveClass: 'exact-active'
})
export default router
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')
Layout导航组件配置路由出口
根组件App.vue导入渲染:
<template>
<div class="h5-wrapper">
<!-- Layout组件中一有配置name属性,即LayoutPage,配置了name属性优先级于组件文件名称 -->
<keep-alive :include="keepArr">
<router-view></router-view>
</keep-alive>
<!-- keep-alive 当前缓存了一级路由组件,还包括Layout,ArticleDetail组件;
缓存需要的组件使用include属性,只缓存需要缓存的组件,
keep-alive缓存包含 :include="需要缓存的(组件名)或(name属性)或(缓存组件名的数组)"
理解作用,就是返回该页面的时候,页面显示还是上一次浏览的位置,而不是重新回到页面加载 -->
</div>
</template>
<script>
export default {
name: 'h5-wrapper',
data(){
return {
// 缓存组件名的数组
keepArr:['LayoutPage']
}
}
}
</script>
<style>
body{
margin: 0;
padding: 0;
}
</style>
技术总结:
路由配置:
一级路由和二级路由的配置router
const router = new VueRouter({
routes: [{
path: '/',
component: Layout,
//重定向redirect,默认网页首页
redirect: '/article',
children: [
{ path: '/article', component: Article },
{ path: '/collect', component: Collect },
{ path: '/like', component: Like },
{ path: '/user', component: User },
]
},
// :id 根据唯一标识id获取对应的数据内容
{ path: '/detail/:id', component: ArticleDetail },
],
//自定义设置高亮类名
linkActiveClass: 'active',
linkExactActiveClass: 'exact-active'
})
异步获取数据axios:
1.Article组件下获取数据:
<script>
//1,传输数据axios
import axios from 'axios'
export default {
name: 'ArticlePage',
data(){
return{
// 定义一个数组变量,用于接收异步数据
articles:[]
}
},
async created(){
// 2,created中发送请求,获取异步数据,get 网址
const res = await axios.get('https://mock.boxuegu.com/mock/3083/articles');
// 查看所获取数据信息,代码习惯
// console.log(res);
// 3,异步数据赋值操作,获取相关的数据,页面动态渲染
this.articles = res.data.result.rows;
// console.log(this.articles);查看所获取数据信息,代码习惯
}
};
2.动态传参:
在Article页面下点击文章详情,跳转ArticleDetail页面的操作:
<!-- @click="$router.push(`/detail/${item.id}`)" 跳转传参:唯一标识id响应数据内容 -->
在ArticleDetail组件中,内容的展示获取,通过唯一标识id获取数据内容。
<script>
import axios from 'axios'
export default {
name: 'ArticleDetailPage',
data(){
return{
article:{}
}
},
async created(){
// created中发送请求,async获取异步数据,get 网址
const id = this.$route.params.id;// 定义获取唯一标识id
const {data} = await axios.get(`https://mock.boxuegu.com/mock/3083/articles/${id}`)//根据唯一标识id获取对应的数据内容,{data}对象解构写法,直接获取到data数据内容
this.article= data.result//动态渲染详情页内容
// console.log(this.article);
}
};
</script>
3.组件缓存:
在根组件App.vue中配置
keep-alive 当前缓存了一级路由组件,还包括Layout,ArticleDetail组件;
缓存需要的组件使用include属性,只缓存需要缓存的组件,
keep-alive缓存包含 :include="需要缓存的(组件名)或(name属性)或(缓存组件名的数组)"
理解作用,就是返回该页面的时候,页面显示还是上一次浏览的位置,而不是重新回到页面加载
4.返回上一页:
<!-- 返回上一页 @click="$router.back()" -->
页面效果图
该项目参考为黑马练习项目,本人自学分享,有问题希望能够得到指正,欢迎讨论,共同进步。