article-detail2.vue 4.75 KB
<template>
  <Layout class="article-detail">
    <RecycleScrollReveal :size="10" ref="scroll" @scroll="onScroll" :offset="2000" :on-fetch="onFetch" :manual-init="true">
      <template v-slot:eternalTop>
        <ArticleDeatilLong v-if="articleSingleDetail.sort == 2" ref="detailLong" :data="articleSingleDetail" :scroll-top="scrollTop" :list-title="listTitle" :scroll-to="scrollTo" @on-show-more="onShowMore"></ArticleDeatilLong>
        <ArticleDeatilNote v-else :data="articleSingleDetail" :scroll-top="scrollTop" :list-title="listTitle" :scroll-to="scrollTo" @on-show-more="onShowMore"></ArticleDeatilNote>
      </template>
      <template class="article-item" #item="{ data }">
        <ArticleItem2
          type="topic"
          :index="data.index"
          :data="data.data"
          :width="colWidthForTwo"
          :share="share"
          :article-id="data.data.articleId"
          :pos-id="posId">
          <template v-if="data.data.dataType == 2">
            <ArticleResource :data="data.data"></ArticleResource>
          </template>
        </ArticleItem2>
      </template>
    </RecycleScrollReveal>

    <MoreActionSheet transfer ref="moreAction" @on-follow="onFollow" @on-delete="onDelete"></MoreActionSheet>
  </Layout>
</template>

<script>
import {get} from 'lodash';

import ArticleDeatilLong from './components/detail/article-long';
import ArticleDeatilNote from './components/detail/article-note';
import ArticleItem2 from './components/article/article-item2';
import MoreActionSheet from './components/detail/more-action-sheet';
import {createNamespacedHelpers} from 'vuex';
const {mapState, mapActions} = createNamespacedHelpers('article');

export default {
  name: 'ArticleDetailPage',
  data() {
    return {
      id: 0,
      scrollTop: 0,
      scrolling: false,
      share: false,
      listTitle: '',
      colWidthForTwo: 370,
      posId: 0
    };
  },
  activated() {
    if (+this.$route.params.id !== this.id) {
      this.id = +this.$route.params.id;
      this.init();
    }
  },
  beforeRouteUpdate(to, from, next) {
    if (+this.$route.params.id !== +to.params.id) {
      this.id = +to.params.id;
      this.init();
    }
    next();
  },
  async serverPrefetch() {
    const articleId = parseInt(this.$route.params.id, 10);

    if (articleId > 0) {
      return this.fetchArticleList({
        articleId,
        singleDetail: 'Y',
        thumb: true
      });
    }

    return;
  },
  mounted() {
    this.colWidthForTwo = Math.floor(this.$el.offsetWidth / 2);
  },
  computed: {
    ...mapState(['articleSingleDetail'])
  },
  methods: {
    ...mapActions(['fetchArticleList', 'fetchDetailRecommendAricles']),
    init() {
      this.recommendArticles = {};
      this.syncServiceArticleDetail();
    },
    onScroll({scrollTop}) {
      this.scrollTop = scrollTop;

      this.scrolling = true;
      this._scTimer && clearTimeout(this._scTimer);
      this._scTimer = setTimeout(() => {
        this.scrolling = false;
      }, 400);
    },
    syncServiceArticleDetail() {
      const articleId = parseInt(this.id, 10);

      this.fetchArticleList({
        articleId,
        singleDetail: 'Y'
      }).then(res => {
        if (this.$refs.scroll) {
          this.$refs.scroll.$el.scrollTop = 0;
          this.$refs.scroll.clear();
          this.listTitle = '';

          this.$nextTick(() => {
            this.$refs.scroll.init();
          });
        }

      });
    },
    async onFetch() {
      if (!this.id || this.fetching) {
        return [];
      }

      // 推荐文章接口一次性提供,不支持分页
      if (this.recommendArticles[this.id]) {
        return false;
      }

      this.fetching = true;

      let list = [];
      const result = await this.fetchDetailRecommendAricles({
        articleId: this.id
      });

      this.fetching = false;
      this.recommendArticles[this.id] = true;

      if (result.code === 200) {
        list = get(result, 'data', []);

        if (!list || !list.length) {
          list = false;
        } else {
          this.listTitle = '推荐阅读';
        }
      } else {
        this.$createToast && this.$createToast({
          txt: result.message || '服务器开小差了',
          type: 'warn',
          time: 1000
        }).show();
      }

      return list;
    },
    scrollTo({scrollTop}) {
      this.$refs.scroll.$el.scrollTop = scrollTop;
      this.scrollTop = scrollTop;
    },
    onShowMore() {
      this.$refs.moreAction.show(this.articleSingleDetail);
    },
    onFollow() {},
    onDelete() {}
  },
  components: {
    ArticleDeatilLong,
    ArticleDeatilNote,
    ArticleItem2,
    MoreActionSheet
  }
};
</script>

<style lang="scss" scoped>
/deep/ .scroll-reveal-list {
  padding: 6px;
  background-color: #f0f0f0;
}
/deep/ .loading {
  height: 100px;
  visibility: hidden;
}
</style>