评论组件 artical.vue
- 功能:
- 先获取用户信息
- 获取文章 数据
- 获取评论数据
- 发表评论
- 点击回复 拿到父评论的id 并且给评论的数据对象,添加父评论的id
- 点击回复的 时候 输入框聚焦 需要使用 ref 拿到子组件的节点 然后调用子组件中的 input表单节点下 使用focus方法
- 这边引入了 评论头部组件 评论每一项item组件
<template>
<div>
<!-- 显示video -->
<div class="a_video" v-if="detail">
<video controls :src="detail.content"></video>
</div>
<!-- 可折叠 当前video信息 -->
<van-collapse v-model="activeNames">
<van-collapse-item :title="detail.name" name="1">
<div v-if="detail.category">分类: {{ detail.category.title }}</div>
<div v-if="detail.userinfo">{{ detail.date }} {{ detail.userinfo.name }}</div>
</van-collapse-item>
</van-collapse>
<!-- 收藏等 -->
<div class="collect">
<span>收藏</span>
<span>缓存</span>
<span>分享</span>
</div>
<!-- 推荐列表 -->
<div>
<artical-detail v-for="(item,index) in commomList" :key="index" :detailitem="item"></artical-detail>
</div>
<!-- 评论 -->
<comment-title @publishComment="publishComment" ref="commentIpt"></comment-title>
<comment @reviewClcik="reviewClcik" ref="commentPublish"></comment>
</div>
</template>
<script>
import Vue from "vue";
import { Collapse, CollapseItem } from "vant";
Vue.use(Collapse);
Vue.use(CollapseItem);
import ArticalDetail from "@/components/comtent/ArticalDetail";
import CommentTitle from "@/components/comtent/CommentTitle";
import Comment from "@/components/comtent/Comment";
export default {
name: "Article",
data() {
return {
detail: [],
activeNames: ["1"],
userinfo: {},
commomList: [],
publishInfo: {
comment_user: "",
comment_content: "",
comment_date: "",
parent_id: null,
comment_id: null
}
};
},
// 由于使用的同一个 组件 这个方法 只是最初的时候 触发 需要监听
created() {
this.getArticle();
this.getcommomList();
this.getUser();
},
watch: {
$route() {
this.getArticle();
this.getcommomList();
}
},
methods: {
// 获取用户信息
async getUser() {
const { data } = await this.$request.get(
"/user/" + localStorage.getItem("id")
);
this.userinfo = data[0];
},
// 获取 文章 数据
async getArticle() {
const res = await this.$request.get("/article/" + this.$route.params.id);
this.detail = res.data[0];
},
// 获取 评论列表
async getcommomList() {
const res = await this.$request.get("/commend");
this.commomList = res.data;
},
// 发表评论
async publishComment(val) {
let date = new Date();
let m = date.getMonth() + 1;
let d = date.getDate();
m = m < 10 ? "0" + m : m;
d = d < 10 ? "0" + d : d;
this.publishInfo.comment_user = this.userinfo.name;
this.publishInfo.comment_content = val;
this.publishInfo.comment_date = m + "-" + d;
this.publishInfo.comment_id = this.$route.params.id;
//把当前 发表评论写入数据库
this.$request.post(
"/comment_post/" + localStorage.getItem("id"),
this.publishInfo
);
//发表评论后 需要调用 该组件下 中的一个拿到最新的排评论的方法
this.$refs.commentPublish.getComment();
// console.log("当前", this.publishInfo);
// console.log("当前res", res);
},
// 点击回复 拿到 父id
reviewClcik(id) {
// console.log("父id", id);
this.parent_id = id;
this.$refs.commentIpt.focusIpt();
}
},
components: {
ArticalDetail,
CommentTitle,
Comment
}
};
</script>
<style lang="scss" scoped>
.a_video {
width: 100%;
height: 2rem;
video {
width: 100%;
height: 100%;
}
}
.collect {
span {
margin: 0 10px;
}
span:nth-child(1) {
margin-left: 20px;
}
}
</style>
评论头部组件 CommentTitle.vue
- 功能:
- 父组件 引用的时候 点击回复,使得当前input表单 聚焦
- 点击发表评论的时候,需要触发父组件的方法,并且传递当前的表单的内容,到父组件(自定义事件后,接受参数,操作数据)
<template>
<div>
<p>
<span>评论</span>
<span>(4080)</span>
</p>
<div>
<img :src="userinfo.user_img" alt />
<input
type="text"
placeholder="请输入评论"
ref="publishIpt"
@focus="focusInput"
v-model="commentVal"
/>
<button @click="publish">发表</button>
</div>
</div>
</template>
<script>
export default {
name: "CommentTitle",
data() {
return {
userinfo: {},
commentVal: null
};
},
created() {
if (localStorage.getItem("token")) {
this.myUserInfo();
}
},
methods: {
async myUserInfo() {
const { data } = await this.$request.get(
"/user/" + localStorage.getItem("id")
);
// console.log("res111", data[0]);
this.userinfo = data[0];
},
focusInput() {
if (
!this.userinfo &&
!localStorage.getItem("token") &&
localStorage.getItem("id")
) {
this.$msg.fail("请登录");
return;
}
},
//发表评论
publish() {
// console.log("发表", this.commentVal);
this.$emit("publishComment", this.commentVal);
this.commentVal = "";
},
// 发表评论的聚焦 在父组件的 引用子组件的时候 使用 ref的方式 拿到该子组件节点 调用该方法!
focusIpt() {
// console.log("ref", this.$refs.publishIpt);
this.$refs.publishIpt.focus();
}
},
components: {}
};
</script>
<style lang="scss" scoped>
</style>
评论组件 Comment.vue
- 功能:
- 这边写死的数据,理论需要接口的数据,若是遇到这种数据,需要递归的方式去处理
- 先获取数据,然后采用递归方式处理数据
- 点击回复的时候,触发父组件引用子组件的 回复事件
- 这边引入了 二级评论的组件
<!-- -->
<template>
<div class="comment" v-if="commentChildList">
<div class="comment_item" v-for="(item,idx) in commentChildList" :key="idx">
<div class="comment_title">
<div class="comment_img">
<img v-if="item.userinfo" :src="item.userinfo.user_img" alt />
<img v-else src="../../assets/default_img.jpg" alt />
</div>
</div>
<div class="comment_info">
<div class="comment_user">
<span v-if="item.userinfo.name">{{ item.userinfo.name }}</span>
<span v-else>匿名</span>
<span>{{ item.comment_date }}</span>
</div>
<div class="comment_con">
{{ item.comment_content }}
<span style="color:red" @click="reviewClcik(item.comment_id)">回复</span>
</div>
<!-- 二级评论等 把二级评论 传递进去 渲染 -->
<comment-child :commentChild="item.child"></comment-child>
</div>
</div>
</div>
</template>
<script>
import CommentChild from "../comtent/CommentChild";
export default {
name: "Comment",
data() {
return {
commentChildList: null,
list: [
{
comment_id: 76,
user_id: 42,
comment_date: "05-14",
comment_content: "你好",
parent_id: null,
userinfo: {
gender: "1",
id: 42,
name: "黄民泽",
user_desc: "Mr.Huang",
user_img:
"http://112.74.99.5:3000/upload/fad74f638b1cbc452378fb4e3496faed"
}
},
{
comment_id: 78,
user_id: 42,
comment_date: "05-14",
comment_content: "你也好",
parent_id: "76",
userinfo: {
gender: "0",
id: 43,
name: "小红帽",
user_desc: "888",
user_img:
"http://112.74.99.5:3000/upload/d7747f9ee313f4eee2a105f5ad166889"
}
},
{
comment_id: 79,
user_id: 42,
comment_date: "05-14",
comment_content: "你也是",
parent_id: "78",
userinfo: {
gender: "0",
id: 43,
name: "小红帽",
user_desc: "888",
user_img:
"http://112.74.99.5:3000/upload/d7747f9ee313f4eee2a105f5ad166889"
}
},
{
comment_id: 80,
user_id: 42,
comment_date: "05-14",
comment_content: "你也一样",
parent_id: "79",
userinfo: {
gender: "0",
id: 43,
name: "小红帽",
user_desc: "888",
user_img:
"http://112.74.99.5:3000/upload/d7747f9ee313f4eee2a105f5ad166889"
}
},
{
comment_id: 81,
user_id: 42,
comment_date: "05-14",
comment_content: "大家都好",
parent_id: "80",
userinfo: {
gender: "0",
id: 43,
name: "小红帽",
user_desc: "888",
user_img:
"http://112.74.99.5:3000/upload/d7747f9ee313f4eee2a105f5ad166889"
}
},
{
comment_id: 82,
user_id: 391,
comment_date: "05-14",
comment_content: "大家都一样",
parent_id: "81",
userinfo: {
gender: "0",
id: 43,
name: "小红帽",
user_desc: "888",
user_img:
"http://112.74.99.5:3000/upload/d7747f9ee313f4eee2a105f5ad166889"
}
},
{
comment_id: 83,
user_id: 42,
comment_date: "05-14",
comment_content: "",
parent_id: null,
userinfo: {
gender: "0",
id: 43,
name: "小红帽",
user_desc: "888",
user_img:
"http://112.74.99.5:3000/upload/d7747f9ee313f4eee2a105f5ad166889"
}
}
]
};
},
created() {
this.getComment();
},
methods: {
async getComment() {
//需要发起请求 拿到评论的数据
// const { data } = await this.$request.get(
// "/comment/" + this.$route.params.id
// );
// console.log("评论", data);
// this.commentChildList = this.getCommentChild(data);
//使用的是 死数据 进行渲染的
this.commentChildList = await this.getCommentChild(this.list);
console.log("plun", this.commentChildList);
},
async getCommentChild(data) {
function fun(temp) {
let arr1 = [];
for (let i = 0; i < data.length; i++) {
//遍历 假如数据中 parent_id 为null 那么就是代表为 一级评论
if (data[i].parent_id == temp) {
arr1.push(data[i]);
data[i].child = fun(data[i].comment_id);
}
}
return arr1;
}
return fun(null);
},
reviewClcik(id) {
// console.log("id", id);
this.$emit("reviewClcik", id);
}
},
components: {
CommentChild
}
};
</script>
<style lang="scss" scoped>
.comment_item {
display: flex;
margin-bottom: 10px;
.comment_title {
display: flex;
align-items: center;
height: 0.4rem;
padding: 0 10px;
.comment_img {
width: 0.35rem;
height: 0.35rem;
img {
width: 100%;
height: 100%;
}
}
}
.comment_user {
height: 0.35rem;
margin-left: 10px;
}
.comment_info {
display: flex;
flex-direction: column;
}
.comment_con {
width: 100%;
display: flex;
justify-content: space-between;
margin-top: 10px;
}
.comment_child {
margin-left: 40px;
}
}
</style>
二级评论组件 ComemntChild.vue
- 功能:
- 接受父组件 传递来的二级评论数据等 然后渲染数据
- 还有实现组件的递归 假如有三级评论等 就传入数据,继续递归下去
<!-- -->
<template>
<div class="comment-child">
<div class="comment-box" v-for="(item,idx) in commentChild" :key="idx">
<div class="comment_title">
<div class="comment_img">
<img v-if="item.userinfo" :src="item.userinfo.user_img" alt />
<img v-else src="../../assets/default_img.jpg" alt />
</div>
</div>
<div class="comment_info">
<div class="comment_user">
<span v-if="item.userinfo.name">{{ item.userinfo.name }}</span>
<span v-else>匿名</span>
<span>{{ item.comment_date }}</span>
</div>
<div
class="comment_con"
v-if="temp"
@click="commentClild(item.comment_id)"
>回复 XXX {{ item.comment_content }}</div>
<div class="comment_con" v-else @click="commentClild(item.comment_id)">
回复 某某
<!-- <span style="color:#333">{{ item.parent_user_info.name }}</span> -->
{{ item.comment_content }}
</div>
</div>
<!-- 组件的递归 -->
<div style="padding-left:30">
<comment-child :commentChild="item.child" :temp="true"></comment-child>
</div>
</div>
</div>
</template>
<script>
export default {
name: "CommentChild",
props: ["commentChild", "temp"],
data() {
return {};
},
methods: {
commentClild(id) {
console.log("二级", id);
}
},
components: {}
};
</script>
<style lang="scss" scoped>
.comment-box {
display: flex;
flex-direction: column;
}
.comment-child {
margin-top: 10px;
}
.comment_item {
display: flex;
margin-bottom: 10px;
.comment_title {
display: flex;
align-items: center;
height: 0.4rem;
padding: 0 10px;
.comment_img {
width: 0.35rem;
height: 0.35rem;
img {
width: 100%;
height: 100%;
}
}
}
.comment_user {
height: 0.35rem;
margin-left: 10px;
}
.comment_info {
display: flex;
flex-direction: column;
}
.comment_con {
margin-top: 5px;
}
.comment_child {
margin-left: 0px;
}
}
</style>