前言
这期又是后来补上的,忘了写到哪,此时我在写这篇文章的时候,文章详情页面已经写完了,有些细节会忘记,跑不起来还是看项目源码
项目地址:https://github.com/cctyl/sunofbeach_mobile.git (给个star吧)
分析
我们在浏览页面时,发现有篇文章挺不错,想看看,自然而然会点击进去。
所以,肯定需要给 文章列表上的每一个文章,加上一个点击事件。
跳转之后,这个页面到底要展示哪篇文章的数据?这显然需要一个id,所以跳转时需要携带一个id。
跳转之后,就是获取数据,把数据展示到界面上,此时还有一个问题,我们拿到的是富文本,直接用v-html展示,是否美观?效果能否展示出来。
以上是几个基本的问题,之后会一一解决
页面结构
先把页面结构写出来。
最终效果长这样
大家可以自行优化下这个样式。
首先就是一个头部,显示了作者相关信息,点赞数量,观看人数等。
底部是一个工具栏,目前只做样式,动作后续章节再写。
整个文章内容,依然是使用了一个 nut-scroller 进行展示,这样滑动起来舒服一点,但是不是必须的。
<div>
<nut-scroller
:type="'vertical'"
>
<div slot="list" v-if="isLoading">
<row padding="15px 10px 0">
<skeleton-square
width="360px"
height="10px"
:count="2"
></skeleton-square>
</row>
<row slot="list" padding="15px 10px 0">
<skeleton-circle
diameter="50px"
>
</skeleton-circle>
<column>
<skeleton-square
width="300px"
:count="2"
margin="5px 10px 5px 10px"
></skeleton-square>
</column>
</row>
<row slot="list" padding="15px 10px 0">
<column>
<skeleton-square
width="350px"
:count="15"
margin="10px 10px 10px 10px"
></skeleton-square>
</column>
</row>
</div>
<div v-else slot="list" class="article">
<!--标题栏-->
<div class="title">
<h1>
<span class="tit">{{articleInfo.title}}</span>
<span class="type">{{articleInfo.articleType==0?'原创':'转载'}}</span>
</h1>
</div>
<!--文章创建时间以及点赞数-->
<div class="infobox">
<nut-row>
<nut-col :span="12">
<span class="time">{{articleInfo.createTime}}</span>
</nut-col>
<nut-col :span="7">
<span class="viewCount ">
<i class="icon-chakan iconfont"></i>
{{articleInfo.viewCount}}人看过
</span>
</nut-col>
<nut-col :span="5">
<span class="thumbUp ">
<i class="icon-dianzan iconfont"></i>
{{articleInfo.thumbUp}}点赞
</span>
</nut-col>
</nut-row>
</div>
<!-- 文章的作者信息-->
<div class="author">
<nut-row>
<nut-col :span="3">
<div class="imgBox">
<img :src="articleInfo.avatar" alt="">
</div>
</nut-col>
<nut-col :span="16">
<div class="authorDetail">
<p class="authorTop">
<span class="authorName"> {{articleInfo.nickname}}</span>
<!--是否为vip,若为vip则添加vip类名-->
<span class="isVip vip iconfont icon-vip"></span>
</p>
<p class="authorBottom">
<span>{{articleInfo.categoryName}}</span>
</p>
</div>
</nut-col>
<nut-col :span="5">
<div class="focuson">关注</div>
</nut-col>
</nut-row>
</div>
<!-- 文章内容-->
<div class="content markdown-body sob-article-content" v-html="articleInfo.content"></div>
</div>
</nut-scroller>
<!--底部工具栏-->
<div class="footerTool">
<span class="commentText left">
<i class="iconfont icon-pinglun"></i>
写评论
</span>
<span class="dianzan right">
<i class="iconfont tubiao icon-dianzan"></i>
<span>{{articleInfo.thumbUp}}</span>
</span>
<span class="collect right">
<i class="iconfont tubiao icon-shoucang"></i>
<span>收藏</span>
</span>
<span class="share right">
<i class="iconfont tubiao icon-fenxiang"></i>
<span>分享</span>
</span>
</div>
</div>
.nut-scroller {
height: calc(100vh - 40px);
}
.article {
padding: 10px 18px 55px;
}
/*标题*/
.article .title {
min-height: 34px;
background-color: #fff;
}
.article .title .tit {
line-height: 34px;
letter-spacing: 1px;
font-size: 23px;
font-weight: 500;
}
.article .title .type {
display: inline-block;
font-size: 12px;
background-color: #ecf5ff;
color: #409eff;
margin-top: 8px;
vertical-align: top;
padding: 4px 5px;
border-radius: 5px;
margin-left: 10px;
}
/* 文章信息*/
.infobox {
background-color: #fff;
margin-top: 12px;
font-size: 12px;
}
.infobox .time {
color: #999aaa;
height: 22px;
line-height: 22px;
}
.infobox .thumbUp, .viewCount {
border-radius: 11px;
border: 1px solid #fc5531;
color: #fc5531;
padding: 2px 8px;
}
/* 文章作者信息*/
.author {
margin-top: 10px;
background-color: #fff;
}
.imgBox img {
border-radius: 50%;
width: 37px;
height: 37px;
}
.authorDetail {
height: 37px;
display: flex;
flex-direction: column;
}
.authorTop .authorName {
font-size: 20px;
}
.authorTop .isVip {
margin-left: 10px;
}
.vip {
color: #fc5531;
}
.authorBottom {
margin-top: 8px;
font-size: 12px;
color: #666;
}
.focuson {
text-align: center;
line-height: 33px;
vertical-align: middle;
width: 72px;
height: 32px;
border: 1px solid #f15731;
border-radius: 23px;
color: #f15731;
}
/*文章详情*/
.content {
background-color: #fff;
padding: 15px 10px;
height: 100%;
width: 100%;
overflow: hidden;
}
.content image {
width: 100%;
}
/*底部工具栏*/
.footerTool {
height: 53px;
width: 100%;
display: flex;
padding-left: 10px;
position: fixed;
bottom: 0;
background-color: #fff;
border-top: 1px solid #ccc;
}
.commentText {
margin: 10px 0;
width: 180px;
background-color: #f4f4f4;
border-radius: 10px;
text-align: left;
height: 35px;
line-height: 35px;
padding-left: 10px;
color: #bebfc9;
margin-right: 20px;
}
.commentText .icon-pinglun {
font-size: 22px;
}
.dianzan, .collect, .share {
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
margin-right: 40px;
}
.tubiao {
font-size: 20px;
margin-bottom: 5px;
}
数据
要获取数据,先要拿到id,回到文章列表,加上点击事件,携带文章id
/**
* 跳转到文章详情页面
* @param id
*/
toArticleDetail(id) {
this.$router.push({
path: '/detail',
query: {id: id}
})
},
到文章详情页面的mounted方法接收数据
//得到传递过来的文章id
this.id = this.$route.query.id
然后请求接口
/ct/article/detail/${id}
/**
* 查询文章数据,id从data中取出
* @returns {Promise<void>}
*/
async getArticleDetail() {
let result = await api.getArticleDetail(this.id)
this.articleInfo = result.data
},
剩下的就是到页面中填充数据,基本效果就出来了
语法高亮
上面的完成之后你会发现,虽然展示出来了,但是特别的丑。因为没有对语法格式进行优化。
那么怎么对这个markdown语法进行高亮展示?参考断点的这篇文章
https://www.sunofbeach.net/a/1427112523064233985
对文章内容总结修改如下:
//1.首先安装依赖
npm i vue-markdown-loader -D
npm i vue-loader vue-template-compiler -D
npm install highlight.js -D
npm install github-markdown-css
//2.在package.json文件的旁边,创建vue.config.js,内容如下
module.exports = {
chainWebpack: (config) => {
config.module
.rule('markdown')
.test(/\.md$/)
.use('vue-loader')
.loader('vue-loader')
.end()
.use('vue-markdown-loader')
.loader('vue-markdown-loader/lib/markdown-compiler')
.options({
preset: 'default',
breaks: true,
raw: true,
typographer: true,
})
},
}
3.到文章详情的div上,加上几个样式
markdown-body sob-article-content
这两个样式是断点写的
然后加上以下样式:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
max-width: 750px;
min-height: 600px;
width: 100%;
margin: 0 auto;
padding: 20px 20px;
background-color: white;
}
.image-wrap img {
max-width: 100%;
}
.sob-article-content {
max-width: 100%;
}
.sob-article-content pre code {
max-width: 100%;
}
/*img 设置max-width有效*/
.sob-article-content img {
margin-top: 10px;
max-width: 100%;
cursor: zoom-in;
}
/* 大于等于750px作用,同理max-width为小于等于下作用 不同屏幕的特殊处理,下面是例子 */
@media (min-width: 750px) {
.title {
font-size: 24px;
}
}
@media (max-width: 750px) {
.summary {
font-size: 14px;
}
}
4.页面中导入,然后再mounted和update中调用即可
import 'github-markdown-css'
import 'highlight.js/styles/default.css'
import hljs from 'highlight.js'
const highlightCode = () => {
const preEl = document.querySelectorAll('pre')
preEl.forEach((el) => {
hljs.highlightBlock(el)
})
}
export default {
mounted() {
//高亮语法
highlightCode();
},
updated() {
//高亮语法
highlightCode();
},
}
效果
(包含了一些后期才写的效果,大家忽略)