功能实现,点击文章,可以弹出文章的详情界面
在ArticleItem.vue中,点击了文章详情,就会有一个事件响应
/*点击文章标题,跳转到文章详情*/
view(id)
{
this.$router.push({path:`/view/${id}`})
}
所以要添加对应路由:
/*文章详情*/
{
path: '/view/:id',
component: r => require.ensure([], () => r(require('@/views/articleDetail/ArticleItemDetail')), 'ArticleItemDetail')
},
文章详情组件ArticleItemDetail:
该组件通过findArticleDetailById获取文章的详情,并通过article.editor参数传递给markdown编辑器
<template>
<div class="my-view-body" v-title :data-title="title">
<el-container class="my-view-container">
<!--<el-aside class="my-area">-->
<!--<ul class="my-operation-list">-->
<!--<li class="my-operation-item">-->
<!--<el-button type="primary" icon="el-icon-edit"></el-button>-->
<!--</li>-->
<!--</ul>-->
<!--</el-aside>-->
<el-main>
<div class="my-view-card">
<!--标题-->
<h1 class="my-view-title">{{article.title}}</h1>
<div class="my-view-author">
<!--作者头像-->
<a class="">
<img class="my-view-picture" src=""></img>
</a>
<!--作者信息-->
<div class="my-view-info">
<span>{{article.author}}</span>
<div class="my-view-meta">
<span>{{article.createDate | format}}</span>
<span>阅读 {{article.viewCounts}}</span>
<span>评论 {{article.commentCounts}}</span>
</div>
</div>
<!-- <el-button-->
<!-- v-if="this.article.author.id == this.$store.state.id"-->
<!-- @click="editArticle()"-->
<!-- style="position: absolute;left: 60%;"-->
<!-- size="mini"-->
<!-- round-->
<!-- icon="el-icon-edit">编辑</el-button>-->
</div>
<!--markdown编辑器-->
<div class="my-view-content">
<markdown-editor :editor=article.editor></markdown-editor>
</div>
<div class="my-view-end">
<el-alert
title="文章End..."
type="success"
center
:closable="false">
</el-alert>
</div>
<!--文章标签-->
<div class="my-view-tag">
标签:
<!--<el-tag v-for="t in article.tags" :key="t.id" class="my-view-tag-item" size="mini" type="success">{{t.tagName}}</el-tag>-->
<el-button @click="tagOrCategory('tag', t.id)" size="mini" type="primary" v-for="t in article.tags" :key="t.id" round plain>{{t.tagName}}</el-button>
</div>
<!--文章分类-->
<div class="my-view-tag">
文章分类:
<!--<span style="font-weight: 600">{{article.category.categoryName}}</span>-->
<el-button @click="tagOrCategory('category', article.category.id)" size="mini" type="primary" round plain>{{article.category.categoryName}}</el-button>
</div>
<div class="my-view-comment">
<div class="my-view-comment-write">
<el-row :gutter="20">
<!--照片-->
<el-col :span="2">
<a class="">
<img class="my-view-picture" :src="avatar"></img>
</a>
</el-col>
<!--评论-->
<el-col :span="22">
<el-input
type="textarea"
:autosize="{ minRows: 2}"
placeholder="你的评论..."
class="my-view-comment-text"
v-model="comment.content"
resize="none">
</el-input>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="2" :offset="22">
<el-button type="text" @click="publishComment()">评论</el-button>
</el-col>
</el-row>
</div>
<div class="my-view-comment-title">
<span>{{article.commentCounts}} 条评论</span>
</div>
</div>
</div>
</el-main>
</el-container>
</div>
</template>
<script>
import {findArticleDetailById} from "@/api/article"
import MarkdownEditor from "@/components/markdown/MarkdownEditor"
export default
{
name:"ArticleItemDetail",
data()
{
return{
article: {
id: '',
title: '',
commentCounts: 0,
viewCounts: 0,
summary: '',
author: {},
tags: [],
category:{},
createDate: '',
editor: {
value: '',
toolbarsFlag: false,
subfield: false,
defaultOpen: 'preview'
}
},
comment:{},
avatar:""
}
},
computed:
{
title()
{
return `${this.article.title}文章详情`
}
},
methods:
{
findArticleById()
{
let id = this.$route.params.id;
console.log(1)
findArticleDetailById(id).then((res)=>
{
if(res.data.success)
{
Object.assign(this.article, res.data.data);
/*将文章内容传给markdown编辑器*/
this.article.editor.value = res.data.data.body.content;
}else {
this.$message.error(res.data.msg);
}
}).catch((err)=>
{
this.$message.error("系统错误")
}).finally(()=>
{
});
},
editArticle()
{
},
tagOrCategory(type,id)
{
},
publishComment()
{
}
},
components:
{
"markdown-editor":MarkdownEditor
},
created()
{
this.findArticleById();
}
}
</script>
<style>
.my-view-body
{
margin: 100px auto 140px;
}
.my-view-container
{
width: 800px;
}
.el-main
{
overflow: hidden;
}
.my-view-title
{
font-size: 34px;
font-weight: 800;
line-height: 1.3;
}
.my-view-author
{
/*margin: 30px 0;*/
margin-top: 30px;
vertical-align: middle;
}
.my-view-picture
{
width: 40px;
height: 40px;
border: 1px solid #ddd;
border-radius: 50%;
vertical-align: middle;
background-color: #5fb878;
}
.my-view-info
{
display: inline-block;
vertical-align: middle;
margin-left: 8px;
}
.my-view-meta
{
font-size: 12px;
color: #969696;
}
.my-view-end
{
margin-top: 20px;
}
.my-view-tag
{
margin-top: 20px;
padding-left: 6px;
border-left: 4px solid #c5cac3;
}
.my-view-tag-item
{
margin: 0 4px;
}
.my-view-comment
{
margin-top: 60px;
}
.my-view-comment-title
{
font-weight: 600;
border-bottom: 1px solid #f0f0f0;
padding-bottom: 20px;
}
.my-view-comment-write
{
margin-top: 20px;
}
.my-view-comment-text
{
font-size: 16px;
}
.v-show-content
{
padding: 8px 25px 15px 30px !important;
}
.v-note-wrapper .v-note-panel
{
box-shadow: none !important;
}
.v-note-wrapper .v-note-panel .v-note-show .v-show-content, .v-note-wrapper .v-note-panel .v-note-show .v-show-content-html {
background: #fff !important;
}
</style>
安装markDown编辑器插件:
依赖:
npm install mavon-editor --save
在/components/markdowm/MarkdownEditor.vue下创建markdown
<template>
<mavon-editor
class="my-editor"
ref="md"
v-model="editor.value"
@imgAdd="imgAdd"
v-bind="editor">
</mavon-editor>
</template>
<script>
import {mavonEditor} from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
import {upload} from '@/api/upload'
export default {
name: 'MarkdownEditor',
props: {
editor: Object
},
data() {
return {}
},
mounted() {
this.$set(this.editor, 'ref', this.$refs.md)
},
methods: {
imgAdd(pos, $file) {
let that = this
let formData = new FormData();
formData.append('image', $file);
upload(formData).then(data => {
// 第二步.将返回的url替换到文本原位置 -> 
if (data.success) {
that.$refs.md.$img2Url(pos, data.data);
} else {
that.$message({message: data.msg, type: 'error', showClose: true})
}
}).catch(err => {
that.$message({message: err, type: 'error', showClose: true});
})
}
},
components: {
mavonEditor
}
}
</script>
<style scoped>
.my-editor
{
z-index: 6 !important;
}
.v-note-wrapper.fullscreen
{
top: 60px !important
}
</style>
对应文章的评论数据:
评论列表:
在/components/comment/ 添加CommentItem.vue用作评论组件
<template>
<div class="my-view-body" v-title :data-title="title">
<el-container class="my-view-container">
<!--<el-aside class="my-area">-->
<!--<ul class="my-operation-list">-->
<!--<li class="my-operation-item">-->
<!--<el-button type="primary" icon="el-icon-edit"></el-button>-->
<!--</li>-->
<!--</ul>-->
<!--</el-aside>-->
<el-main>
<div class="my-view-card">
<!--标题-->
<h1 class="my-view-title">{{article.title}}</h1>
<div class="my-view-author">
<!--作者头像-->
<a class="">
<img class="my-view-picture" src=""></img>
</a>
<!--作者信息-->
<div class="my-view-info">
<span>{{article.author}}</span>
<div class="my-view-meta">
<span>{{article.createDate | format}}</span>
<span>阅读 {{article.viewCounts}}</span>
<span>评论 {{article.commentCounts}}</span>
</div>
</div>
<!-- <el-button-->
<!-- v-if="this.article.author.id == this.$store.state.id"-->
<!-- @click="editArticle()"-->
<!-- style="position: absolute;left: 60%;"-->
<!-- size="mini"-->
<!-- round-->
<!-- icon="el-icon-edit">编辑</el-button>-->
</div>
<!--markdown编辑器-->
<div class="my-view-content">
<markdown-editor :editor=article.editor></markdown-editor>
</div>
<div class="my-view-end">
<el-alert
title="文章End..."
type="success"
center
:closable="false">
</el-alert>
</div>
<!--文章标签-->
<div class="my-view-tag">
标签:
<!--<el-tag v-for="t in article.tags" :key="t.id" class="my-view-tag-item" size="mini" type="success">{{t.tagName}}</el-tag>-->
<el-button @click="tagOrCategory('tag', t.id)" size="mini" type="primary" v-for="t in article.tags" :key="t.id" round plain>{{t.tagName}}</el-button>
</div>
<!--文章分类-->
<div class="my-view-tag">
文章分类:
<!--<span style="font-weight: 600">{{article.category.categoryName}}</span>-->
<el-button @click="tagOrCategory('category', article.category.id)" size="mini" type="primary" round plain>{{article.category.categoryName}}</el-button>
</div>
<div class="my-view-comment">
<div class="my-view-comment-write">
<el-row :gutter="20">
<!--照片-->
<el-col :span="2">
<a class="">
<img class="my-view-picture" :src="avatar"></img>
</a>
</el-col>
<!--评论-->
<el-col :span="22">
<el-input
type="textarea"
:autosize="{ minRows: 2}"
placeholder="你的评论..."
class="my-view-comment-text"
v-model="comment.content"
resize="none">
</el-input>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="2" :offset="22">
<el-button type="text" @click="publishComment()">评论</el-button>
</el-col>
</el-row>
</div>
<div class="my-view-comment-title">
<span>{{article.commentCounts}} 条评论</span>
</div>
<!--评论组件,后台中的评论列表是从最新到最旧,
所以最新的应该是评论数量减去索引值0,就是该楼层-->
<commment-item
v-for="(c,index) in comments"
:comment="c"
:articleId="article.id"
:index="index"
:rootCommentCounts="comments.length"
@commentCountsIncrement="commentCountsIncrement"
:key="c.id">
</commment-item>
</div>
</div>
</el-main>
</el-container>
</div>
</template>
<script>
import {findArticleDetailById} from "@/api/article"
import {findCommentListByArticleId} from "@/api/comment"
import MarkdownEditor from "@/components/markdown/MarkdownEditor"
import CommentItem from "@/components/comment/CommentItem"
export default
{
name:"ArticleItemDetail",
data()
{
return{
article: {
id: '',
title: '',
commentCounts: 0,
viewCounts: 0,
summary: '',
author: {},
tags: [],
category:{},
createDate: '',
editor: {
value: '',
toolbarsFlag: false,
subfield: false,
defaultOpen: 'preview'
}
},
comments:[],
comment: {
article: {},
content: ''
},
avatar:""
}
},
computed:
{
title()
{
return `${this.article.title}文章详情`
}
},
methods:
{
findArticleById()
{
let id = this.$route.params.id;
findArticleDetailById(id).then((res)=>
{
if(res.data.success)
{
Object.assign(this.article, res.data.data);
/*将文章内容传给markdown编辑器*/
this.article.editor.value = res.data.data.body.content;
}else {
this.$message.error(res.data.msg);
}
}).catch((err)=>
{
this.$message.error("系统错误")
}).finally(()=>
{
});
},
findCommentList()
{
let id = this.$route.params.id;
findCommentListByArticleId(id).then((res)=>
{
if(res.data.success)
{
this.comments = res.data.data;
}else {
this.$message.error(res.data.msg);
}
}).catch((err)=>
{
this.$message.error("系统错误")
}).finally(()=>
{
});
},
editArticle()
{
},
tagOrCategory(type,id)
{
},
publishComment()
{
},
/*CommentItem.vue组件中评论成功之后,文章的评论数量自增1*/
commentCountsIncrement()
{
this.article.commentCounts += 1;
}
},
components:
{
"markdown-editor":MarkdownEditor,
"commment-item":CommentItem
},
created()
{
this.findArticleById();
this.findCommentList();
},
}
</script>
<style>
.my-view-body
{
margin: 100px auto 140px;
}
.my-view-container
{
width: 800px;
}
.el-main
{
overflow: hidden;
}
.my-view-title
{
font-size: 34px;
font-weight: 800;
line-height: 1.3;
}
.my-view-author
{
/*margin: 30px 0;*/
margin-top: 30px;
vertical-align: middle;
}
.my-view-picture
{
width: 40px;
height: 40px;
border: 1px solid #ddd;
border-radius: 50%;
vertical-align: middle;
background-color: #5fb878;
}
.my-view-info
{
display: inline-block;
vertical-align: middle;
margin-left: 8px;
}
.my-view-meta
{
font-size: 12px;
color: #969696;
}
.my-view-end
{
margin-top: 20px;
}
.my-view-tag
{
margin-top: 20px;
padding-left: 6px;
border-left: 4px solid #c5cac3;
}
.my-view-tag-item
{
margin: 0 4px;
}
.my-view-comment
{
margin-top: 60px;
}
.my-view-comment-title
{
font-weight: 600;
border-bottom: 1px solid #f0f0f0;
padding-bottom: 20px;
}
.my-view-comment-write
{
margin-top: 20px;
}
.my-view-comment-text
{
font-size: 16px;
}
.v-show-content
{
padding: 8px 25px 15px 30px !important;
}
.v-note-wrapper .v-note-panel
{
box-shadow: none !important;
}
.v-note-wrapper .v-note-panel .v-note-show .v-show-content, .v-note-wrapper .v-note-panel .v-note-show .v-show-content-html {
background: #fff !important;
}
</style>