Authored by yyq

server prefetch && share

... ... @@ -2,8 +2,8 @@
<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="article.sort == 2" ref="detailLong" :data="article" :scroll-top="scrollTop" :list-title="listTitle" :scroll-to="scrollTo" @on-show-more="onShowMore"></ArticleDeatilLong>
<ArticleDeatilNote v-else :data="article" :scroll-top="scrollTop" :list-title="listTitle" :scroll-to="scrollTo" @on-show-more="onShowMore"></ArticleDeatilNote>
<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
... ... @@ -42,7 +42,6 @@ export default {
id: 0,
scrollTop: 0,
scrolling: false,
article: {},
share: false,
listTitle: '',
colWidthForTwo: 370,
... ... @@ -62,10 +61,24 @@ export default {
}
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']),
... ... @@ -89,8 +102,6 @@ export default {
articleId,
singleDetail: 'Y'
}).then(res => {
this.article = get(res, 'data.detailList[0]', {});
if (this.$refs.scroll) {
this.$refs.scroll.$el.scrollTop = 0;
this.$refs.scroll.clear();
... ... @@ -146,7 +157,7 @@ export default {
this.scrollTop = scrollTop;
},
onShowMore() {
this.$refs.moreAction.show(this.article);
this.$refs.moreAction.show(this.articleSingleDetail);
},
onFollow() {},
onDelete() {}
... ...
... ... @@ -2,7 +2,7 @@
<div class="article-footer-wrapper">
<slot name="before"></slot>
<div class="tool-bar">
<WidgetIconBtn class="item" type="fav" :pos-id="sceneId" :text="praiseCount" :articleId="articleId" :option="optionPraise"></WidgetIconBtn>
<WidgetIconBtn ref="favIcon" class="item" type="fav" :pos-id="sceneId" :text="praiseCount" :articleId="articleId" :option="optionPraise"></WidgetIconBtn>
<WidgetIconBtn class="item" type="star" :pos-id="sceneId" :text="favoriteCount" :articleId="articleId" :option="optionFav" ></WidgetIconBtn>
<WidgetIconBtn class="item" type="msg" :text="commentCount" :option="optionComment" @click="onComment"></WidgetIconBtn>
</div>
... ... @@ -21,12 +21,6 @@ export default {
props: ['favoriteCount', 'praiseCount', 'commentCount', 'hasFavor', 'hasPraise', 'articleId'],
data() {
return {
optionPraise: {
selected: this.hasPraise === 'Y'
},
optionFav: {
selected: this.hasFavor === 'Y'
},
optionComment: {
emitName: 'click',
canSelect: false
... ... @@ -35,8 +29,16 @@ export default {
};
},
computed: {
optionPraise() {
return {
selected: this.hasPraise === 'Y'
};
},
mounted() {
optionFav() {
return {
selected: this.hasFavor === 'Y'
}
}
},
methods: {
onComment() {
... ... @@ -44,8 +46,13 @@ export default {
},
onClose() {
this.$emit('on-close');
},
onPraise() {
if (this.hasPraise !== 'Y') {
this.$refs.favIcon.onClick();
}
},
},
};
</script>
... ...
... ... @@ -14,8 +14,9 @@
</template>
<script>
import {get} from 'lodash';
import ArticleItemHeader from '../article/article-item-header';
import {getDetailShareData} from 'utils/share-handler';
export default {
name: 'ArticleDetailHeader',
data() {
... ... @@ -59,17 +60,9 @@ export default {
return '-' + parseInt(`0${this.titleStep}`, 10) + '%';
}
},
watch: {
},
methods: {
onShare() {
this.$yoho.share({
title: this.data.topicName,
imgUrl: this.data.topicImageUrl,
link: `${location.origin}/grass/topic/share/${this.data.topicId}`,
desc: '我在有货的社区发现一个热门话题。' + this.data.topicDesc,
hideType: ['7', '8', '9']
});
this.$yoho.share(getDetailShareData(this.data));
},
onFollow() {
return parseInt(this.step, 10) / 100;
... ...
<template>
<div class="article-detail-long">
<ArticleDetailHeader ref="header" :step="headerAnimateStep" :title-step="headerTitleAnimateStep">
<ArticleDetailHeader ref="header" :data="data" :step="headerAnimateStep" :title-step="headerTitleAnimateStep">
<div class="title-main">
<div class="title-info" :style="`transform: translate3d(0, ${titleTranslateY}, 0)`">
<ArticleItemHeader class="title-info-author" :share="share" :data="authorData" :lazy="lazy" :more="showMoreOpt" @on-follow="onFollow"></ArticleItemHeader>
... ... @@ -54,7 +54,8 @@ import ArticleItemHeader from '../article/article-item-header';
import ArticleItemTopics from '../article/article-item-topics';
import ArticleDetailFooter from './article-footer';
import ArticleDetailHeader from './article-header';
import {mapState, mapMutations} from 'vuex';
import {mapState, mapMutations, createNamespacedHelpers} from 'vuex';
const {mapState: mapArticleState} = createNamespacedHelpers('article');
export default {
name: 'ArticleDetailLong',
... ... @@ -89,6 +90,10 @@ export default {
},
computed: {
...mapState(['yoho']),
...mapArticleState(['articleStates']),
articleState() {
return this.articleStates[this.data.articleId] || this.data;
},
coverStyle() {
return {
height: `${floor(this.data.imageHeight / this.data.imageHeight * 750 / 40, 2)}rem`
... ... @@ -186,8 +191,8 @@ export default {
favoriteCount: this.data.favoriteCount,
praiseCount: this.data.praiseCount,
commentCount: this.data.commentCount,
hasFavor: this.data.hasFavor,
hasPraise: this.data.hasPraise,
hasFavor: this.articleState.hasFavor,
hasPraise: this.articleState.hasPraise,
articleId: this.data.articleId
};
},
... ...
<template>
<div class="article-detail-notes">
<ArticleDetailHeader ref="header" :step="100" :title-step="100">
<ArticleDetailHeader ref="header" :data="data" :step="100" :title-step="100">
<div class="title-main">
<div class="title-info" :style="`transform: translate3d(0, ${titleTranslateY}, 0)`">
<ArticleItemHeader class="title-info-author" :share="share" :data="authorData" :lazy="lazy" :more="false" @on-follow="onFollow"></ArticleItemHeader>
<ArticleItemHeader class="title-info-author" :share="share" :data="authorData" :lazy="lazy" :more="false"></ArticleItemHeader>
<div class="title-info-rec">{{listTitle}}</div>
</div>
</div>
... ... @@ -28,7 +28,7 @@
<LayoutTitle>{{listTitle}}</LayoutTitle>
</div>
</div>
<ArticleDetailFooter class="detail-fixed-footer" v-bind="footerData" @on-comment-click="toCommentList">
<ArticleDetailFooter ref="footer" class="detail-fixed-footer" v-bind="footerData" @on-comment-click="toCommentList">
<template v-slot:before>
<div class="footer-comment">
<CommentPlaceholder
... ... @@ -63,6 +63,8 @@ import ArticleItemTopics from '../article/article-item-topics';
import ArticleDetailFooter from './article-footer';
import ArticleDetailIntro from './article-intro';
import dayjs from 'utils/day';
import {createNamespacedHelpers} from 'vuex';
const {mapState} = createNamespacedHelpers('article');
export default {
name: 'ArticleDetailNote',
... ... @@ -89,6 +91,10 @@ export default {
}
},
computed: {
...mapState(['articleStates']),
articleState() {
return this.articleStates[this.data.articleId] || this.data;
},
titleTranslateY() {
let scrollTop = this.scrollTop;
... ... @@ -137,23 +143,21 @@ export default {
favoriteCount: this.data.favoriteCount,
praiseCount: this.data.praiseCount,
commentCount: this.data.commentCount,
hasFavor: this.data.hasFavor,
hasPraise: this.data.hasPraise,
hasFavor: this.articleState.hasFavor,
hasPraise: this.articleState.hasPraise,
articleId: this.data.articleId
};
},
publishTime() {
return dayjs(this.data.publishTime).fromNow();
return this.data.publishTime ? dayjs(this.data.publishTime).fromNow() : '';
},
lazy() {
return this.data.lazy;
}
},
methods: {
onFollow() {
},
onPraise() {
this.$refs.footer.onPraise();
},
onChangeSlide({index}) {
this.slideIndex = index;
... ...
... ... @@ -5,7 +5,10 @@ import * as sleep from '../../utils/sleep';
export default {
async fetchArticleList({ commit }, { articleId, authorUid, authorType, limit = 5, page = 1, thumb = false, columnType = 1001, singleDetail = 'N'}) {
commit(Types.FETCH_ARTICLE_LIST_REQUEST, { refresh: page === 1 });
const commitType = singleDetail === 'Y' ? 'ARTICLE_SINGLE_DETAIL' : 'ARTICLE_LIST';
commit(Types[`FETCH_${commitType}_REQUEST`], { refresh: page === 1 });
const result = await this.$api.get('/api/grass/columnArticleDetail', {
articleId,
limit,
... ... @@ -20,12 +23,13 @@ export default {
if (!result.data.detailList) {
result.data.detailList = [];
}
commit(Types.FETCH_ARTICLE_LIST_SUCCESS, {
commit(Types[`FETCH_${commitType}_SUCCESS`], {
data: result.data.detailList,
thumb
});
} else {
commit(Types.FETCH_ARTICLE_LIST_FAILD);
commit(Types[`FETCH_${commitType}_FAILD`]);
}
return result;
},
... ...
... ... @@ -21,7 +21,8 @@ export default function() {
fetchTopicInfo: false,
topicInfo: {},
fetchTopicArticles: false,
articleDetailList: [],
articleSingleDetail: {},
fetchArticleSingleDetail: false,
fetchDetailRecommendArticles: false
},
actions,
... ...
... ... @@ -230,6 +230,31 @@ export default {
state.topicInfo.hasAttention = follow;
}
},
[Types.FETCH_ARTICLE_SINGLE_DETAIL_REQUEST](state, topicId) {
state.fetchArticleSingleDetail = true;
},
[Types.FETCH_ARTICLE_SINGLE_DETAIL_SUCCESS](state, {data, thumb}) {
state.fetchArticleSingleDetail = false;
let item = data[0] || {};
if (thumb) {
item.comments = [];
item.hasAttention = '';
item.hasFavor = '';
item.hasPraise = '';
item.commentCount = 0;
item.favoriteCount = 0;
item.praiseCount = 0;
} else {
setArticleList(state, data, 'detail');
}
state.articleSingleDetail = item;
},
[Types.FETCH_ARTICLE_SINGLE_DETAIL_FAILD](state) {
state.fetchArticleSingleDetail = false;
},
[Types.FETCH_DETAIL_RECOMMEND_REQUEST](state, topicId) {
state.fetchDetailRecommendArticles = true;
},
... ...
... ... @@ -34,6 +34,10 @@ export const FETCH_TOPIC_INFO_FAILD = 'FETCH_TOPIC_INFO_FAILD';
export const FETCH_TOPIC_INFO_SUCCESS = 'FETCH_TOPIC_INFO_SUCCESS';
export const CHANGE_TOPIC_FOLLOW = 'CHANGE_TOPIC_FOLLOW';
export const FETCH_ARTICLE_SINGLE_DETAIL_REQUEST = 'FETCH_ARTICLE_SINGLE_DETAIL_REQUEST';
export const FETCH_ARTICLE_SINGLE_DETAIL_FAILD = 'FETCH_ARTICLE_SINGLE_DETAIL_FAILD';
export const FETCH_ARTICLE_SINGLE_DETAIL_SUCCESS = 'FETCH_ARTICLE_SINGLE_DETAIL_SUCCESS';
export const FETCH_DETAIL_RECOMMEND_REQUEST = 'FETCH_DETAIL_RECOMMEND_REQUEST';
export const FETCH_DETAIL_RECOMMEND_FAILD = 'FETCH_DETAIL_RECOMMEND_FAILD';
export const FETCH_DETAIL_RECOMMEND_SUCCESS = 'FETCH_DETAIL_RECOMMEND_SUCCESS';
... ...
import {get, first} from 'lodash';
const getDetailShareData = (article) => {
let shareImage = '';
let desc = '';
if (article.sort === 2) {
shareImage = article.coverImage;
desc = article.articleTitle;
} else {
let blockList = get(article, 'blockList', []);
shareImage = get(first(blockList.filter(block => block.templateKey === 'image')), 'contentData', '');
desc = get(blockList.filter(block => block.templateKey === 'text'), '[0].contentData', '');
}
return {
title: `@${article.authorName} 在有货社区上发了一篇笔记,快点开看看!`,
imgUrl: shareImage.replace('{mode}', 2).replace('{width}', 200).replace('{height}', 200),
link: `${window ? window.location.origin : ''}/grass/article/share/${article.articleId}`,
desc,
hideType: ['7', '8', '9']
};
}
export {
getDetailShareData
};
... ...