【项目实战】基于Vue3+Vant3造一个网页版的类掘金app项目 - 创作者中心

865 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情

前言

大家好,在上一篇文章徽章墙分享中我们实现了徽章墙的展示功能。那么在个人中心首页中还有一个“创作者中心”小模块以及底部更多功能中的“创作者中心”菜单,点击后均可跳转到创作者中心详情页面,可以查看更多创作者相关的详细信息。接下来在今天的分享中我们来把创作者中心主页面功能实现一下。

布局分析

image.png 第一件事还是先来分析一下创作者中心的页面布局结构。如上图所示整个页面共分为5个模块:标题栏、个人信息、内容数据、关注者数据和创作活动。其中内容模块又分为6个小模块:总文章数、总专栏数、总沸点数、文章展现数、文章阅读数和文章收藏数。关注者数据包含:总关注者、活跃关注者和净增关注三个小块。而创作活动模块就是3个轮播图,直接使用轮播组件就可以搞定了。

另外从上图中我们还能看出内容数据、关注者数据和创作活动三个模块的整体样式基本是一样的,都是由标题和内容组成,因此我们可以定义一个公共的样式box作为这三个模块的通用样式。而内容数据中第二行中的三个模块和关注者数据中的三个模块样式也基本是一样的。因此在本次的分享有很多样式是可以共用的,这样在设计布局样式时就可以节省一些时间。

数据渲染

  • 标题栏 标题栏中不涉及数据渲染,直接拉一个van-nav-bar组件,并设置title属性为“创作者中心”,left-arrow为true并添加click-left事件实现返回功能即可。
<van-nav-bar title="创作者中心" left-arrow @click-left="toBack" />
const router = useRouter();
const toBack = () => {
  router.back();
};
  • 个人信息

个人信息模块依然使用flex布局,左侧头像和右侧个人主页链接固定宽度,中间昵称信息宽度自适应(flex:1)。数据可以直接从我们前面分析的get接口中获取,这里只需用到avatar_large、user_name和level三个属性值。

<div class="box profile-box">
    <van-image :src="userInfo.avatar_large" round class="avatar" />
    <div class="user-info">
      {{ userInfo.user_name }}
      <van-image
        src="https://lf3-cdn-tos.bytescm.com/obj/static/xitu_juejin_web/74bd93adef7feff4fee26d08c0845b4f.svg"
      />
    </div>
    <div class="home-page">
      个人主页
      <van-icon name="arrow" />
    </div>
</div>
api.getUserinfo().then((res) => {
  state.userInfo = res.data;
});
  • 内容数据

内容数据使用grid布局(display:grid),然后通过grid-template-column:repeat()和grid-gap设置小模块的高度和之间的间隙。该模块数据来自两个接口:“content_api/v1/author_center/count”接口用于返回总文章数、总专栏数和总沸点数,另一个接口“content_api/v1/author_center/data/card”是我们之前已经分析过的接口,用于返回文章展现数、阅读数、收藏数等相关信息。根据接口请求到后台数据后按照对应的字段把值渲染上去就可以了。 image.png image.png

<div class="box content-box">
    <div class="header">
      <span class="title">内容数据<van-icon name="question-o" /></span>
      <span class="more">更多内容 <van-icon name="arrow" /></span>
    </div>
    <div class="content">
      <div class="content-item">
        <div class="item-title">
          总文章数
          <van-icon name="arrow" style="margin-left: 5px" />
        </div>
        <div class="item-count">{{ centerCount.article_cnt.all_cnt }}</div>
      </div>
      <div class="content-item">
        <div class="item-title">
          总专栏数
          <van-icon name="arrow" style="margin-left: 5px" />
        </div>
        <div class="item-count">{{ centerCount.column_cnt.all_cnt }}</div>
      </div>
      <div class="content-item">
        <div class="item-title">
          总沸点数
          <van-icon name="arrow" style="margin-left: 5px" />
        </div>
        <div class="item-count">{{ centerCount.short_msg_cnt.all_cnt }}</div>
      </div>
      <div class="content-item2">
        <div class="item-title">文章展现数</div>
        <div class="item-count">
          {{ cardInfo.datas.all_article_display.cnt }}
        </div>
        <div class="item-before">
          较前日<span style="color: #1e80ff">{{
            cardInfo.datas.all_article_display.than_before
          }}</span>
        </div>
      </div>
      <div class="content-item2">
        <div class="item-title">文章阅读数</div>
        <div class="item-count">{{ cardInfo.datas.all_article_view.cnt }}</div>
        <div class="item-before">
          较前日<span style="color: #1e80ff">{{
            cardInfo.datas.all_article_view.than_before
          }}</span>
        </div>
      </div>
      <div class="content-item2">
        <div class="item-title">文章收藏数</div>
        <div class="item-count">
          {{ cardInfo.datas.all_article_collect.cnt }}
        </div>
        <div class="item-before">
          较前日<span style="color: #1e80ff">{{
            cardInfo.datas.all_article_collect.than_before
          }}</span>
        </div>
      </div>
    </div>
  </div>
 api.centerCount().then((res) => {
      state.centerCount = res.data;
    });
api
  .card([
    "all_follower",
    "all_article_display",
    "all_article_view",
    "all_article_digg",
    "all_article_comment",
    "all_article_collect",
  ])
  .then((res) => {
    state.cardInfo = res.data;
  });
  • 关注者内容

关注者内容与内容数据布局模式一样也是使用grid布局(display:grid)。该模块同样使用的是“content_api/v1/author_center/data/card”接口,只是根据传递不同的datas参数返回不同的内容,比如这里我们要请求的是关注者相关的数据,因此要传递的datas参数应该包含如下几个值:datas: ["all_follower", "incr_active_follower", "incr_do_follower", "incr_undo_follower", "incr_follower"] image.png

<div class="box content-box">
    <div class="header">
      <span class="title">关注者数据<van-icon name="question-o" /></span>
      <span class="more">更多内容 <van-icon name="arrow" /></span>
    </div>
    <div class="content">
      <div class="content-item2">
        <div class="item-title">总关注者</div>
        <div class="item-count">{{ trend.datas.all_follower.cnt }}</div>
        <div class="item-before">
          较前日<span style="color: #1e80ff">{{
            trend.datas.all_follower.than_before
          }}</span>
        </div>
      </div>
      <div class="content-item2">
        <div class="item-title">活跃关注者</div>
        <div class="item-count">{{ trend.datas.incr_active_follower.cnt }}</div>
        <div class="item-before">
          较前日<span style="color: #1e80ff">{{
            trend.datas.incr_active_follower.than_before
          }}</span>
        </div>
      </div>
      <div class="content-item2">
        <div class="item-title">净增关注</div>
        <div class="item-count">{{ trend.datas.incr_do_follower.cnt }}</div>
        <div class="item-before">
          较前日<span style="color: #1e80ff">{{
            trend.datas.incr_do_follower.than_before
          }}</span>
        </div>
      </div>
    </div>
  </div>
api
  .card([
    "all_follower",
    "incr_active_follower",
    "incr_do_follower",
    "incr_undo_follower",
    "incr_follower",
  ])
  .then((res) => {
    state.trend = res.data;
  });
  • 创作活动

最后一个模块内容就比较简单了,直接使用van-swipe轮播组件即可。该模块数据来源于:“event_api/v1/event/banner_list”即可接口,该接口返回的是包含活动封面图,活动名称及活动链接等信息,直接循环van-swipe-item将内容输出。 image.png

 <div class="box content-box" style="padding-bottom: 130px">
    <div class="header">
      <span class="title">创作活动<van-icon name="question-o" /></span>
      <span class="more">更多内容 <van-icon name="arrow" /></span>
    </div>
    <div class="banner">
      <van-swipe :autoplay="3000" indicator-color="white">
        <van-swipe-item v-for="item in bannerList" :key="item.id">
          <van-image
            :src="item.screenshot"
            style="width: 100%; height: 150px"
          />
        </van-swipe-item>
      </van-swipe>
    </div>
  </div>
 api.bannerList().then((res) => {
      state.bannerList = res.data;
      console.log(res.data);
    });

test.gif

总结

本次分享中我们对创作者中心整体页面布局进行了分析,并逐模块进行数据接口的分析及实现了数据渲染展示功能。今天的分享就到这里了!