功能需求
- 点击到文章时需要跳转到对应文章的文章内容页面
- 文章详情页面中需要有文章内容,用户信息,功能区和评论区
- 需要有点击图片预览大图的功能
- 需要在功能区完成点击关注,收藏,点赞功能
- 需要在评论区完成查看评论和点击发布评论
路由配置
- 功能技术点:在跳转路由时需要传递点击的内容的对应id,使用了路由的prop的动态传值方式,将id传递到对应的文章内容组件中
{
path: '/article/:articleId',
name: 'article',
component: () => import('@/views/article'),
props: true
}
props: {
articleId: {
type: [Number, String],
required: true
}
},
静态页面搭建
- 使用了vant组件库中的单元格组件,头部导航组件,和插槽技术来完成静态页面的搭建
<template>
<div class="article-container">
<van-nav-bar
class="page-nav-bar"
left-arrow
title="黑马头条"
></van-nav-bar>
<div class="main-wrap">
<div class="loading-wrap">
<van-loading
color="#3296fa"
vertical
>加载中</van-loading>
</div>
<div class="article-detail">
<h1 class="article-title">这是文章标题</h1>
<van-cell class="user-info" center :border="false">
<van-image
class="avatar"
slot="icon"
round
fit="cover"
src="https://img.yzcdn.cn/vant/cat.jpeg"
/>
<div slot="title" class="user-name">黑马头条号</div>
<div slot="label" class="publish-date">14小时前</div>
<van-button
class="follow-btn"
type="info"
color="#3296fa"
round
size="small"
icon="plus"
>关注</van-button>
</van-cell>
<div class="article-content">这是文章内容</div>
<van-divider>正文结束</van-divider>
</div>
<div class="error-wrap">
<van-icon name="failure" />
<p class="text">该资源不存在或已删除!</p>
</div>
<div class="error-wrap">
<van-icon name="failure" />
<p class="text">内容加载失败!</p>
<van-button class="retry-btn">点击重试</van-button>
</div>
</div>
<div class="article-bottom">
<van-button
class="comment-btn"
type="default"
round
size="small"
>写评论</van-button>
<van-icon
name="comment-o"
info="123"
color="#777"
/>
<van-icon
color="#777"
name="star-o"
/>
<van-icon
color="#777"
name="good-job-o"
/>
<van-icon name="share" color="#777777"></van-icon>
</div>
</div>
</template>
渲染文章页面并完成图片预览功能
- 调用接口获取文章详情数据,并渲染到页面上
- 这里需要使用ref属性结合$refs属性获取到图片的dom元素节点在点击图片的时候调用vant组件库中的图片预览组件就可以完成图片预览功能
- 遇到的问题:这里在获取图片dom节点时出现的值为 undefined
- 解决问题:由于异步操作的原因导致图片的dom元素还没有更新,所以使用了一个延时器来解决这个问题,也可以使用nextTick方法解决此问题
previewImg () {
const contentEl = this.$refs['article-content']
const allImg = contentEl.querySelectorAll('img')
const images = []
allImg.forEach((element, index) => {
images.push(element.src)
element.onclick = () => {
ImagePreview({
images,
startPosition: index
})
}
})
},
关注功能
- 功能技术点1:这里选择将用户点击关注和取消关注的功能封装成了组件,使用了父传子的技术将文章信息组件中获得的和关注有关的数据传给关注组件
<FollowUser
:is_followed="article.is_followed"
:user_id="article.aut_id"
@update-follow="article.is_followed = $event"
>
<!-- 点击关注 -->
</FollowUser>
- 功能技术点2:在关注组件中需要对按钮的样式做判断显示关注按钮还是以关注按钮,这里使用v-if属性来判断,给按钮添加点击事件,在点击事件中做逻辑判断,如果未关注点击就实现关注功能,如果已经关注点击就实现取消关注功能,
async follow () {
this.isFollowLoading = true
try {
const authorId = this.user_id
if (this.is_followed) {
await deleteFollow(authorId)
} else {
await addFollow(authorId)
}
this.$emit('update-follow', !this.is_followed)
} catch (err) {
console.dir(err)
if (err.response && err.response.status === 400) {
return this.$toast.fail('不能关注自己')
}
this.$toast.fail('操作失败')
}
this.isFollowLoading = false
}
文章收藏点赞功能
- 遇到的问题:接口出现400报错,是由于在传参的时候变量名写错导致
- 功能逻辑点:这两个功能的逻辑是一致的,都进行了组件的二次封装,并且在组件中通过父组件传递过来的v-model属性,使用value接受,在组件中通过value值判断是否收藏或者点赞,然后书写逻辑
- 点赞代码
async onLike () {
try {
if (this.value === 1) {
var status = -1
await deleteLike(this.articleID)
this.$toast.success('取消点赞')
} else {
await addLike(this.articleID)
status = 1
this.$toast.success('点赞成功')
}
this.$emit('input',status)
} catch (err) {
console.log(err)
this.$toast.fail('操作失败')
}
}
async onCollect () {
try {
if (this.value) {
await deleteCollect(this.articleID)
} else {
await addCollect(this.articleID)
}
this.$emit('input', !this.value)
this.$toast.success(this.value ? '取消收藏' : '收藏成功')
} catch (err) {
this.$toast('操作失败,请重试')
}
}