22.blog前端-文章详情、评论列表

功能实现,点击文章,可以弹出文章的详情界面

在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替换到文本原位置![...](./0) -> ![...](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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值