黑马头条项目练习(day07)

编程入门 行业动态 更新时间:2024-10-28 07:24:36

黑马<a href=https://www.elefans.com/category/jswz/34/1765373.html style=头条项目练习(day07)"/>

黑马头条项目练习(day07)

今天说到了文章评论列表,文章评论列表的话还是用到了我们熟悉的vant里的list组件

但是用到了新的技术,比如说,使用了v-model进行了父子组件的数据通信

首先是更新后了的article/index.vue代码

<template><div class="article-container"><!-- 导航栏 --><van-nav-barclass="page-nav-bar"left-arrowtitle="黑马头条"@click-left="$router.back()"></van-nav-bar><!-- /导航栏 --><div class="main-wrap"><!-- 加载中 --><div class="loading-wrap" v-if="loading"><van-loading color="#3296fa" vertical>加载中</van-loading></div><!-- /加载中 --><!-- 加载完成-文章详情 --><div class="article-detail" v-else-if="article.title"><!-- 文章标题 --><h1 class="article-title">{{ article.title }}</h1><!-- /文章标题 --><!-- 用户信息 --><van-cell class="user-info" center :border="false"><van-imageclass="avatar"slot="icon"roundfit="cover":src="article.aut_photo"/><div slot="title" class="user-name">{{ article.aut_name }}</div><div slot="label" class="publish-date">{{ article.pubdate | relativeTime }}</div><!-- <van-button@click="onFollow"v-if="article.is_followed"class="follow-btn"roundsize="small":loading="followLoading">已关注</van-button><van-button@click="onFollow"v-elseclass="follow-btn"type="info"color="#3296fa"roundsize="small"icon="plus":loading="followLoading">关注</van-button> --><!-- $event是用来接收子组件传过来的值 --><!-- 在使用组件的同一个变量既要传递数据又要修改数据传递props::is-followed="article.is_followed"修改:自定义事件@updataFollow="article.is_followed = $event"--><!-- 可以使用简化形式 v-model --><!-- 传递props::value="article.is_followed"修改:内置封装 input@input="article.is_followed = $event"--><!-- <FollowUser:isFollowed="article.is_followed":followUserId="article.aut_id"@updataFollow="article.is_followed = $event"></FollowUser> --><FollowUser:followUserId="article.aut_id"v-model="article.is_followed"></FollowUser></van-cell><!-- /用户信息 --><!-- 文章内容 --><divclass="article-content markdown-body"v-html="article.content"ref="article-content"></div><van-divider>正文结束</van-divider><!-- 评论列表开始 --><CommentList:articleId="article.art_id"@commentCounts="totalCommentCount = $event"></CommentList><!-- 评论列表结束 --><!-- 底部区域 --><div class="article-bottom"><van-button class="comment-btn" type="default" round size="small">写评论</van-button><van-icon name="comment-o" :info="totalCommentCount" color="#777" /><!-- <van-icon color="#777" name="star-o" /> --><collectArticlev-model="article.is_collected":articleId="article.art_id"></collectArticle><!-- 点赞区域开始 --><!-- <van-icon color="#777" name="good-job-o" /> --><LikeArticleclass="btn-item"v-model="article.attitude":article-id="article.art_id"></LikeArticle><!-- 点赞区域结束 --><van-icon name="share" color="#777777"></van-icon></div><!-- /底部区域 --></div><!-- /加载完成-文章详情 --><!-- 加载失败:404 --><div class="error-wrap" v-else-if="errStatus === 404"><van-icon name="failure" /><p class="text">该资源不存在或已删除!</p></div><!-- /加载失败:404 --><!-- 加载失败:其它未知错误(例如网络原因或服务端异常) --><div class="error-wrap" v-else><van-icon name="failure" /><p class="text">内容加载失败!</p><van-button class="retry-btn" @click="loadArticleDetail">点击重试</van-button></div><!-- /加载失败:其它未知错误(例如网络原因或服务端异常) --></div></div>
</template><script>
import LikeArticle from "@/components/like-article";
import CommentList from "./components/comment-list";
import collectArticle from "@/components/collect-article";
import FollowUser from "@/components/follow-user";
// import { addFollowAPI, deleteFollowAPI } from "@/api";
import { getArticleByIdAPI } from "@/api";
import { ImagePreview } from "vant";
// vant的ImagePreview配置代码
// ImagePreview({
//   images: [
//     ".jpg",
//     ".jpg",
//   ],
//   startPosition: 1,
//   closeable: true,
//   onClose() {
//     this.$toast("关闭");
//   },
// });
export default {name: "ArticleIndex",components: {FollowUser,collectArticle,CommentList,LikeArticle,},props: {// 使用props获取动态路由的数据articleId: {type: [Number, String],required: true,},},data() {return {article: {},loading: true, // 加载中的状态errStatus: 0, // 存储错误的状态码followLoading: false, // 控制加载中的状态totalCommentCount: 0, // 存储评论总数};},computed: {},watch: {},created() {this.loadArticle();},mounted() {},methods: {// 3. 定义获取数据请求方法async loadArticle() {// 开启加载中的状态this.loading = true;try {// 手动抛出错误,测试功能// if (Math.random() > 0.6) {//   throw new Error("错误");// }// 3.1 发送请求const { data } = await getArticleByIdAPI(this.articleId);// 3.3 成功赋值this.article = data.data; // vue的dom更新是异步的setTimeout(() => {// 在数据更新之后,调用图片预览功能this.previewImage();}, 0);console.log(this.article); // 控制台查看数据输出} catch (err) {// 3.2 失败处理if (err.response && err.response.status === 404) {this.errStatus = 404;this.$toast("访问的文章资源不存在");} else {this.$toast("获取文章详情失败");console.log(err);}}// 关闭加载中的状态this.loading = false;},loadArticleDetail() {this.loadArticle();},previewImage() {// 得到所有的 img 节点const articleContent = this.$refs["article-content"]; // 获取到了容器节点const imgs = articleContent.querySelectorAll("img");// 存储文章内容中的所有图片地址const images = [];// 遍历所有的图片,拿到每个图片的地址imgs.forEach((img, index) => {// 把图片地址push进images数组里images.push(img.src);// 给每个图片添加一个点击事件,调用ImagePreview图片预览功能img.onclick = () => {ImagePreview({images: images,// 指定预览图片的起始位置startPosition: index,});};});},// 关注用户,和取消关注// async onFollow() {//   this.followLoading = true;//   // 判断用户是否登录,如果没有请先登录才能操作//   if (!this.$store.state.user) return this.$toast("请先登录");//   // 发送请求实现登录(添加关注,和取消关注)//   try {//     const AutId = this.article.aut_id;//     // 判断是否已经关注了//     if (this.article.is_followed) {//       await deleteFollowAPI(AutId);//     } else {//       await addFollowAPI(AutId);//     }//     // 更新视图//     this.article.is_followed = !this.article.is_followed;//   } catch (err) {//     if (err && err.response.status === 400) {//       this.$toast("用户不能关注自己");//     } else {//       this.$toast("请求失败");//     }//   }//   this.followLoading = false;// },},
};
</script><style scoped lang="less">
@import "./github-markdown.css";
.article-container {.main-wrap {position: fixed;left: 0;right: 0;top: 92px;bottom: 88px;overflow-y: scroll;background-color: #fff;}.article-detail {.article-title {font-size: 40px;padding: 50px 32px;margin: 0;color: #3a3a3a;}.user-info {padding: 0 32px;.avatar {width: 70px;height: 70px;margin-right: 17px;}.van-cell__label {margin-top: 0;}.user-name {font-size: 24px;color: #3a3a3a;}.publish-date {font-size: 23px;color: #b7b7b7;}.follow-btn {width: 170px;height: 58px;}}.article-content {padding: 55px 32px;/deep/ p {text-align: justify;}}}.loading-wrap {padding: 200px 32px;display: flex;align-items: center;justify-content: center;background-color: #fff;}.error-wrap {padding: 200px 32px;display: flex;flex-direction: column;align-items: center;justify-content: center;background-color: #fff;.van-icon {font-size: 122px;color: #b4b4b4;}.text {font-size: 30px;color: #666666;margin: 33px 0 46px;}.retry-btn {width: 280px;height: 70px;line-height: 70px;border: 1px solid #c3c3c3;font-size: 30px;color: #666666;}}.article-bottom {position: fixed;left: 0;right: 0;bottom: 0;display: flex;justify-content: space-around;align-items: center;box-sizing: border-box;height: 88px;border-top: 1px solid #d8d8d8;background-color: #fff;ment-btn {width: 282px;height: 46px;border: 2px solid #eeeeee;font-size: 30px;line-height: 46px;color: #a7a7a7;}.van-icon {font-size: 40px;.van-info {font-size: 16px;background-color: #e22829;}}}
}
</style>

article/commponents/comment-item.vue

<template><van-cell class="comment-item"><van-imageslot="icon"class="avatar"roundfit="cover":src="comment.aut_photo"/><div slot="title" class="title-wrap"><div class="user-name">{{ comment.aut_name }}</div><van-buttonclass="like-btn":icon="comment.is_liking ? 'good-job' : 'good-job-o'">{{ comment.like_count > 0 ? comment.like_count : "赞" }}</van-button></div><div slot="label"><p class="comment-content">{{ comment.content }}</p><div class="bottom-info"><span class="comment-pubdate">{{comment.pubdate | relativeTime}}</span><van-button class="reply-btn" round>回复 {{ comment.reply_count }}</van-button></div></div></van-cell>
</template><script>
export default {name: "CommentItem",props: {//每行的评论信息comment: {type: Object,required: true,},},methods: {},
};
</script><style scoped lang="less">
ment-item {.avatar {width: 72px;height: 72px;margin-right: 25px;}.title-wrap {display: flex;justify-content: space-between;align-items: center;.user-name {color: #406599;font-size: 26px;}}ment-content {font-size: 32px;color: #222222;word-break: break-all;text-align: justify;}ment-pubdate {font-size: 19px;color: #222;margin-right: 25px;}.bottom-info {display: flex;align-items: center;}.reply-btn {width: 135px;height: 48px;line-height: 48px;font-size: 21px;color: #222;}.like-btn {height: 30px;padding: 0;border: none;font-size: 19px;line-height: 30px;margin-right: 7px;.van-icon {font-size: 30px;}}.liked {background-color: orange;}
}
</style>

配置好收藏功能代码api/article.js补充代码 

/*** 收藏文章*/
export const addCollect = (target) => {return request({method: "POST",url: "/v1_0/article/collections",data: {target,},});
};/*** 取消收藏文章*/
export const deleteCollect = (target) => {return request({method: "DELETE",url: `/v1_0/article/collections/${target}`,});
};

article/commponents/comment-list.vue

<template><van-listv-model="loading":finished="finished"finished-text="没有更多了"@load="onLoad"><!-- <van-cellv-for="comment in list":key="comment_id":title="comment.content"></van-cell> --><CommentItemv-for="comment in list":key="comment_id":title="comment.content":comment="comment"></CommentItem></van-list>
</template>
<script>
import CommentItem from "./comment-item";
import { getCommentsAPI } from "@/api";
export default {name: "CommentList",components: {CommentItem,},props: {articleId: {type: [String, Number],required: true,},},created() {//   页面刚开始触发函数,加载评论数this.onLoad();},data() {return {list: [], // 评论列表loading: false, // 上拉加载更多的 loadingfinished: false, // 是否加载结束offset: null,limit: 20, // 每一页的个数type: "a", // 'a | c'};},methods: {async onLoad() {// 1. 获取数据try {const { data } = await getCommentsAPI({type: this.type, //  评论类型,a-对文章(article)的评论,c-对评论(comment)的回复source: this.articleId, // 源id,文章id或评论idoffset: this.offset, // 获取评论的偏移量limit: this.limit, // 每一页的个数});console.log(data);const { results } = data.data;// 2. 更新数据,将获取到的数据追加到数组中this.list = [...this.list, ...results];this.$emit("commentCounts", data.data.total_count);// 3. 将loading设置为falsethis.loading = false;// 4. 判断数据是否加载完毕if (results.length) {// 4.1 如果还有数据,进行翻页this.offset = data.data.last_id;} else {// 4.2 如果没有数据将finished设置为falsethis.finished = true;}} catch (error) {this.loading = false;this.$toast("请求评论失败");}},},
};
</script>

然后就是src/components/collect-article/index.vue

<template><van-button:loading="CollectLoading"@click="onCollect":icon="value ? 'star' : 'star-o'":class="{ collected: value }"></van-button>
</template>
<script>
import { addCollectAPI, deleteCollectAPI } from "@/api";
export default {name: "CollectArticle",props: {value: {type: Boolean,required: true,},articleId: {type: [String, Number],required: true,},},data() {return {CollectLoading: false,};},methods: {async onCollect() {this.CollectLoading = true;try {//   判断用户是否登录,如果没有,让用户先登录在操作if (!this.$store.state.user) return this.$toast("请先登录");// 判断是否已经收藏if (this.value) {// 已经收藏,取消收藏await deleteCollectAPI(this.articleId);this.$toast("取消收藏成功");} else {// 收藏文章await addCollectAPI(this.articleId);this.$toast("收藏成功");}// 同步视图this.$emit("input", !this.value);} catch (error) {this.$toast("收藏失败");}this.CollectLoading = false;},},created() {},
};
</script>
<style scoped lang="less">
.collected {.van-icon {color: #ffa500;}
}
</style>

over!

更多推荐

黑马头条项目练习(day07)

本文发布于:2024-02-16 19:08:13,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1691144.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:头条   黑马   项目

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!