article-long.vue 8.17 KB
<template>
  <div class="article-detail-long">
    <div class="header-cover"></div>
    <ArticleItemSlideImage ref="coverFigure" class="cover-figure" :data="coverImage" :thumb-size="coverSize" :style="`transform: translate3d(0, ${coverTranslateY}px, 0)`">
    </ArticleItemSlideImage>
    <div ref="authorBlock" class="author-block">
      <ArticleItemHeader :share="share" :data="authorData" :lazy="lazy" :more="showMoreOpt" @on-follow="onFollowAuthor"></ArticleItemHeader>
    </div>
    <div class="main-detail">
      <div class="article-context">
        <div class="context-title">{{data.articleTitle}}</div>
        <div ref="richText" class="context-rich-text" v-html="data.richText"></div>
      </div>

      <ArticleItemTopics v-if="data.topicList && data.topicList.length" class="topics-wrap" :data="data" :share="share"></ArticleItemTopics>

      <div v-if="recomendProduct.length">
        <LayoutTitle class="rec-goods-title">推荐商品</LayoutTitle>
        <ProductGroup :data="recomendProduct" :share="share" model="2"></ProductGroup>
      </div>

      <LayoutTitle v-if="listTitle" class="rec-article-title">{{listTitle}}</LayoutTitle>
    </div>

    <YohoActionSheet transfer v-if="showCommentAction" ref="commentAction" :full="true">
      <Comment ref="comment"
        :destId="data.articleId"
        :popup="true"
        :article-id="data.articleId"
        :commentCount="articleState.commentCount"
        :share="share"
        :pos-id="posId"
        @on-close="onCloseComment"
        @on-comment="onActionComment"></Comment>
    </YohoActionSheet>
  </div>
</template>

<script>
import {floor, round} from 'lodash';
import ArticleItemHeader from '../article/article-item-header';
import ArticleItemTopics from '../article/article-item-topics';
import ArticleDetailFooter from './article-footer';
import ArticleItemSlideImage from '../article/article-item-slide-image';
import ArticleDetailHeader from './article-header';
import {mapState, mapMutations, createNamespacedHelpers} from 'vuex';
const {mapState: mapArticleState} = createNamespacedHelpers('article');

export default {
  name: 'ArticleDetailLong',
  props: {
    data: {
      type: Object,
      default() {
        return {};
      }
    },
    listTitle: String,
    scrollTop: Number,
    scrollTo: Function,
    share: Boolean,
    posId: Number,
  },
  data() {
    return {
      coverHeight: 0,
      downgrade: false,
      showMoreOpt: false,
      authorBlock: {},
      recomendProduct: [],
      showCommentAction: false,
      showCommentActioning: false,
    };
  },
  mounted() {
    if (!this.$yoho.isiOS) {
      this.downgrade = true;
    }

    this.handleRechText();
  },
  computed: {
    ...mapState(['yoho']),
    ...mapArticleState(['articleStates', 'authorStates']),
    articleState() {
      const articleState = this.articleStates[this.data.articleId] || this.data;
      const authorState = this.authorStates[`${this.data.authorUid}-${this.data.authorType}`] || this.data;

      return Object.assign({...articleState}, {hasAttention: authorState.hasAttention});
    },
    coverSize() {
      return {
        width: round(750 / 40, 2),
        height: floor(this.data.imageHeight / this.data.imageWidth * 750 / 40, 2)
      };
    },
    coverImage() {
      this.$nextTick(() => {
        if (this.$refs.coverFigure) {
          this.coverHeight = this.$refs.coverFigure.$el.offsetHeight;
        }

        if (this.$refs.authorBlock) {
          this.authorBlock = {
            height: this.$refs.authorBlock.offsetHeight,
            top: this.$refs.authorBlock.offsetTop
          };
        }
      });

      return {
        contentData: this.data.coverImage,
        bigImage: this.data.bigImage,
        width: this.data.imageWidth,
        height: this.data.imageHeight
      };
    },
    coverTranslateY() {
      let top = this.scrollTop > 0 ? this.scrollTop : 0;

      if (top && !this.downgrade && this.coverHeight && top < this.coverHeight) {
        return top / 2;
      } else {
        return 0;
      }
    },
    authorData() {
      return {
        authorName: this.data.authorName,
        authorUid: this.data.authorUid,
        authorType: this.data.authorType,
        authorHeadIco: this.data.authorHeadIco,
        authGroupId: this.data.authGroupId,
        hasAttention: this.articleState.hasAttention,
        isAuthor: this.data.isAuthor
      };
    },
    lazy() {
      return this.data.lazy;
    }
  },
  watch: {
    'data.richText': function() {
      this.handleRechText();
    }
  },
  methods: {
    ...mapMutations(['SET_STATUS_BAR_COLOR']),
    onFollowAuthor(follow) {
      this.$emit('on-follow', this.data, follow);
    },
    onComment() {
      this.showCommentAction = true;
      this.$nextTick(() => {
        if (this.showCommentActioning) {
          return;
        }
        this.showCommentActioning = true;
        this.$refs.comment.init();
        this.$refs.commentAction.show();
        setTimeout(() => {
          this.showCommentActioning = false;
        }, 300);
      });
    },
    onCloseComment() {
      this.$refs.commentAction.hide();
    },
    onActionComment() {
    },
    handleRechText() {
      this.$nextTick(() => {
        this.$refs.richText && this.$refs.richText.querySelectorAll('a').forEach(ele => {
          if (ele.querySelector('img')) {
            ele.classList.add('yoho-img-link');
          }
        });
      });
    }
  },
  components: {
    ArticleDetailHeader,
    ArticleItemHeader,
    ArticleItemTopics,
    ArticleDetailFooter,
    ArticleItemSlideImage
  }
};
</script>

<style lang="scss" scoped>
.header-cover {
  width: 100%;
  height: 400px;
  position: absolute;
  top: 0;
  overflow: hidden;

  &:before {
    content: "";
    height: 1px;
    position: absolute;
    top: -1px;
    left: 0;
    right: 0;
    z-index: 1;
    box-shadow: 0 0 160px 10px #000;
  }
}

.cover-figure {
  opacity: 1!important;
}

.cover-img {
  width: 100%;
  display: block;
  position: relative;
  z-index: 0;
}

.author-block,
.main-detail {
  position: relative;
  z-index: 2;
  background-color: #fff;
  border-bottom: 1px solid #f6f6f6;
}

.article-context {
  padding: 30px;
}

.context-title {
  font-size: 40px;
  color: #222;
  line-height: 1.7;
  margin-bottom: 30px;
  font-weight: 700;
}

.context-rich-text /deep/ {
  font-size: 32px!important;
  line-height: 1.8!important;

  * {
    font-family: "PingFang SC", "HiraginoSansGB-W3", "SanFranciscoText-Regular", Helvetica, Roboto, "Heiti SC", "黑体", Arial!important;
  }

  h1,
  h2,
  h3 {
    font-weight: 700!important;
  }

  h1 {
    font-size: 38px!important;
  }

  h2 {
    font-size: 36px!important;
  }

  h3 {
    font-size: 34px!important;
  }

  img {
    max-width: 100%!important;
    height: auto;
  }

  p {
    font-size: 32px!important;

    * {
      font-size: 32px!important;
      letter-spacing: normal!important;
    }
  }

  b,
  strong {
    font-weight: 500;
  }

  blockquote {
    border-left: 12px solid #b4b4b4;
    background-color: #f7f7f7;
    padding: 30px;
  }

  ol,
  ul {
    padding-inline-start: 38px;

    li {
      list-style: inherit;
    }
  }

  a {
    color: #468ee5;
    position: relative;
    display: inline-block;

    &:before {
      content: "";
      display: inline-block;
      width: 36px;
      height: 36px;
      margin-right: 8px;
      background-image: url('~statics/image/article/link-text-icon.png');
      background-size: contain;
      background-repeat: no-repeat;
      vertical-align: sub;
      position: relative;
      top: -1px;
      z-index: -1;
    }

    &.yoho-img-link:after {
      content: "";
      width: 36px;
      height: 36px;
      background-image: url('~statics/image/article/link-img-icon.png');
      background-size: contain;
      background-repeat: no-repeat;
      position: absolute;
      right: 8px;
      bottom: 8px;
      z-index: 1;
    }

    &.yoho-img-link:before {
      visibility: hidden;
    }

    > img {
      margin-top: -50px;
      display: block;
    }
  }
}

.topics-wrap {
  padding-left: 30px;
  margin-bottom: 36px;
}

.rec-goods-title {
  margin-bottom: -32px;
}

/deep/ .product-item:first-child {
  margin-left: 30px;
}

/deep/ .product-item:last-child {
  margin-right: 30px;
}

.rec-article-title {
  margin-top: -6px;
}
</style>