新闻头条类移动端项目文章详情功能

243 阅读2分钟

功能需求

  1. 点击到文章时需要跳转到对应文章的文章内容页面
  2. 文章详情页面中需要有文章内容,用户信息,功能区和评论区
  3. 需要有点击图片预览大图的功能
  4. 需要在功能区完成点击关注,收藏,点赞功能
  5. 需要在评论区完成查看评论和点击发布评论

路由配置

  • 功能技术点:在跳转路由时需要传递点击的内容的对应id,使用了路由的prop的动态传值方式,将id传递到对应的文章内容组件中
 //路由信息
 {
    path: '/article/:articleId',
    name: 'article',
    component: () => import('@/views/article'),
    // 将路由动态参数映射到组件的 props 中,更推荐这种做法
    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-button
            class="follow-btn"
            round
            size="small"
          >已关注</van-button> -->
        </van-cell>
        <!-- /用户信息 -->

        <!-- 文章内容 -->
        <div class="article-content">这是文章内容</div>
        <van-divider>正文结束</van-divider>
      </div>
      <!-- /加载完成-文章详情 -->

      <!-- 加载失败:404 -->
      <div class="error-wrap">
        <van-icon name="failure" />
        <p class="text">该资源不存在或已删除!</p>
      </div>
      <!-- /加载失败:404 -->

      <!-- 加载失败:其它未知错误(例如网络原因或服务端异常) -->
      <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>

渲染文章页面并完成图片预览功能

  1. 调用接口获取文章详情数据,并渲染到页面上
  2. 这里需要使用ref属性结合$refs属性获取到图片的dom元素节点在点击图片的时候调用vant组件库中的图片预览组件就可以完成图片预览功能
  • 遇到的问题:这里在获取图片dom节点时出现的值为 undefined
  • 解决问题:由于异步操作的原因导致图片的dom元素还没有更新,所以使用了一个延时器来解决这个问题,也可以使用nextTick方法解决此问题
   // 获得图片dom节点并操作
    previewImg () {
        // 得到所有节点
    const contentEl = this.$refs['article-content']
    const allImg = contentEl.querySelectorAll('img')
    // 获取所有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('操作失败')
      }

      // 关闭按钮的 loading 状态
      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) {
            // 父组件 传递articleId
            await deleteCollect(this.articleID)
        } else {
            await addCollect(this.articleID)
        }
        // 更新视图
        this.$emit('input', !this.value)
        this.$toast.success(this.value ? '取消收藏' : '收藏成功')
    } catch (err) {
        this.$toast('操作失败,请重试')
    }
}