article.vue 5.92 KB
<template>
  <div>
    <Layout class="article">
      <LayoutHeader theme="white" slot='header' :title="title" :opacity="currentAuthor.opacity">
        <template v-if="showHeader">
          <div class="avatar-wrapper" @click="toUserPage">
            <WidgetAvatar class="widget-avatar" :src="currentAuthor.authorHeadIco" :width="70" :height="70"></WidgetAvatar>
            <span class="user-name">{{currentAuthor.authorName}}</span>
          </div>
        </template>
        <template v-if="showHeader" v-slot:opts>
          <WidgetFollow :share="share" class="widget-follow" :author-uid="currentAuthor.authorUid" :follow="currentAuthor.hasAttention === 'Y'" @on-follow="follow => onFollow(currentAuthor, follow)"></WidgetFollow>
        </template>
      </LayoutHeader>
      <LayoutRecycleList :size="30" ref="scroll" @scroll="onScroll" :offset="2000" :on-fetch="onFetch">
        <template class="article-item" v-slot:item="{ data }">
          <ArticleItem
            :id="`item${data.index}`"
            :type="type"
            :data="data"
            :data-id="data.articleId"
            :share="share"
            @on-follow="follow => onFollow(data, follow)"
            @on-resize="onResize"
            @on-show-guang="onShowGuang"
            @on-show-comment="onShowComment"></ArticleItem>
          <div :id="`ph${data.index}`"></div>
        </template>
      </LayoutRecycleList>
    </Layout>
    <ArticleActionSheet v-if="showArticleDetailAction" ref="actionSheet"></ArticleActionSheet>
    <YohoActionSheet transfer v-if="showCommentAction" ref="commentAction" :full="true">
      <Comment ref="comment" :destId="articleId" :popup="true" @on-close="onClose" @on-comment="onActionComment"></Comment>
    </YohoActionSheet>
  </div>
</template>

<script>
import {debounce} from 'lodash';
import ArticleItem from './article-item';
import ArticleActionSheet from '../detail/article-action-sheet';
import {createNamespacedHelpers} from 'vuex';
const {mapMutations} = createNamespacedHelpers('article');

export default {
  name: 'Article',
  props: {
    title: {
      type: String,
      default: '逛'
    },
    share: Boolean,
    type: String,
    onFetch: Function
  },
  mounted() {
    this.scrollPreLazy = debounce(this.changeItem.bind(this), 200);
  },
  data() {
    return {
      articleId: 0,
      articleIndex: -1,
      showCommentAction: false,
      showArticleDetailAction: false,
      inx: 0,
      scrollTop: 0,
      showHeader: false,
      currentId: 0,
      currentAuthor: {
        authorUid: 0,
        authorName: '',
        authorHeadIco: '',
        hasAttention: 'N',
        opacity: 1,
        isShare: false,
        authorType: 1
      }
    };
  },
  activated() {
    if (this.scrollTop > 0) {
      this.$refs.scroll.$el.scrollTo(0, this.scrollTop);
    }
  },
  methods: {
    ...mapMutations(['CHANGE_ARTICLE_LIST_PRELAZY', 'ASYNC_ARTICLE_COMMENT']),
    toUserPage() {
      if (this.share) {
        return this.$links.toDownloadApp();
      }
      this.$router.push({
        name: 'author',
        params: {
          type: this.currentAuthor.authorType,
          id: this.currentAuthor.authorUid
        }
      });
    },
    onShowComment({articleId, index}) {
      this.articleId = articleId;
      this.articleIndex = index;
      this.showCommentAction = true;
      this.$nextTick(() => {
        this.$refs.comment.init();
        this.$refs.commentAction.show();
      });
    },
    onClose() {
      this.$refs.commentAction.hide();
    },
    changeItem(params) {
      this.CHANGE_ARTICLE_LIST_PRELAZY(params);
    },
    onActionComment() {
      this.ASYNC_ARTICLE_COMMENT({articleId: this.articleId, type: this.type});
      this.onResize(this.articleIndex);
    },
    onScroll({item, scrollTop}) {
      this.scrollTop = scrollTop;
      if (scrollTop === 0) {
        this.currentAuthor.opacity = 1;
        this.showHeader = false;
      } else if (item) {
        if (this.currentId !== item.data.articleId) {
          this.currentId = item.data.articleId;
          this.scrollPreLazy({articleId: item.data.articleId, type: this.type});
        }

        this.currentAuthor.authorUid = item.data.authorUid;
        this.currentAuthor.authorName = item.data.authorName;
        this.currentAuthor.authorHeadIco = item.data.authorHeadIco;
        this.currentAuthor.hasAttention = item.data.hasAttention;
        this.currentAuthor.authorType = item.data.authorType;

        this.showHeader = true;
        const offsetTop = scrollTop - item.top;

        if (offsetTop < 50) {
          this.currentAuthor.opacity = parseInt((offsetTop / 50) * 100, 10) / 100;
        } else if (offsetTop - item.height >= -60 && offsetTop - item.height < -10) {
          this.currentAuthor.opacity = parseInt(((Math.abs(offsetTop - item.height + 10)) / 50) * 100, 10) / 100;
        } else if (offsetTop - item.height >= -10 && offsetTop - item.height < 0) {
          this.currentAuthor.opacity = 0;
        } else {
          this.currentAuthor.opacity = 1;
        }
      }
    },
    init() {
      this.$refs.scroll.$el.scrollTop = 0;
      this.$refs.scroll.init();
    },
    onFollow(data, follow) {
      if (data.authorUid === this.currentAuthor.authorUid) {
        this.currentAuthor.hasAttention = follow ? 'Y' : 'N';
      }
    },
    onResize(index) {
      this.$refs.scroll.resize(index);
    },
    onShowGuang(params) {
      this.showArticleDetailAction = true;
      this.$nextTick(() => {
        this.$refs.actionSheet.show(params);
      });
    }
  },
  components: {
    ArticleItem,
    ArticleActionSheet
  }
};
</script>

<style lang="scss" scoped>
.article {
  background-color: #f0f0f0;
}

.avatar-wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
}

.widget-avatar {
  width: 52px;
  height: 52px;
}

.widget-follow {
  margin-right: 30px;
}

.user-name {
  margin-left: 10px;
  font-size: 24px;
  color: #000;
  max-width: 250px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
</style>