Toggle navigation
Toggle navigation
This project
Loading...
Sign in
fe
/
yoho-community-web
·
Commits
Go to a project
GitLab
Go to group
Project
Activity
Files
Commits
Pipelines
0
Builds
0
Graphs
Milestones
Issues
1
Merge Requests
0
Members
Labels
Wiki
Forks
Network
Create a new issue
Download as
Email Patches
Plain Diff
Browse Files
Authored by
yyq
6 years ago
Commit
5bfe8d22f93cbefcc80a3040bbe3018ede0ef69f
1 parent
31508526
detail
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
244 additions
and
55 deletions
apps/components/layouts/recycle-scroll-reveal.vue
apps/pages/article/article-detail2.vue
apps/pages/article/components/article/article-item2.vue
apps/pages/article/components/detail/article-intro.vue
apps/pages/article/components/detail/article-long.vue
apps/pages/article/index.js
apps/pages/userpage/components/author-article-item.vue
apps/store/article/actions.js
apps/store/article/index.js
apps/store/article/mutations.js
apps/store/article/types.js
apps/utils/image-handler.js
config/api-map.js
apps/components/layouts/recycle-scroll-reveal.vue
View file @
5bfe8d2
...
...
@@ -102,7 +102,9 @@ export default {
let list = newList.slice(oldList.length, newList.length);
if (list.length) {
this.revealCalcing = true;
this.loadItems(list, oldList.length).then(() => {
this.revealCalcing = false;
if (oldList.length < 2) {
this._updateList();
}
...
...
@@ -141,14 +143,16 @@ export default {
this.load(true);
},
clear() {
this.clearTimestamp = new Date().getTime();
this.noMore = false;
this.items = [];
for (let i = 0; i < this.cols; i++) {
this.visibleItems[i].length = 0;
this.colsHeight[i] = 0;
this.startIndexs[i] = 0;
}
this.items = [];
},
load(reload) {
if (reload) {
...
...
@@ -182,6 +186,7 @@ export default {
}
let startCol = this.getMinHeightCol();
const timestamp = this.clearTimestamp;
for (let i = 0; i < list.length; i++) {
await this.loadItem({
...
...
@@ -190,7 +195,7 @@ export default {
width: this.itemWidth,
isThumb: true,
placeholder: false
}, i < lastIndex ? (startCol + i) % this.cols : -1);
}, i < lastIndex ? (startCol + i) % this.cols : -1
, timestamp
);
}
this.$nextTick(() => {
...
...
@@ -228,8 +233,12 @@ export default {
return true;
});
},
loadItem(item, index) {
loadItem(item, index
, timestamp
) {
return new Promise(r => {
if (timestamp !== this.clearTimestamp) {
return r();
}
if (index < 0) {
index = this.getMinHeightCol();
}
...
...
@@ -298,7 +307,7 @@ export default {
const heights = this.$refs.scroll.offsetHeight;
// trigger load
if (scrollTop + this.$el.offsetHeight > heights - this.offset) {
if (scrollTop + this.$el.offsetHeight > heights - this.offset
&& !this.revealCalcing
) {
this.load();
}
...
...
apps/pages/article/article-detail2.vue
View file @
5bfe8d2
<template>
<Layout class="article-detail">
<RecycleScrollReveal :size="
5" ref="scroll" @scroll="onScroll" :offset="8
00" :on-fetch="onFetch" :manual-init="true">
<RecycleScrollReveal :size="
10" ref="scroll" @scroll="onScroll" :offset="20
00" :on-fetch="onFetch" :manual-init="true">
<template v-slot:eternalTop>
<!-- <ArticleDeatilNote :data="article" :scroll-top="scrollTop" :list-title="listTitle"></ArticleDeatilNote> -->
<ArticleDeatilLong ref="detailLong" :data="article" :scroll-top="scrollTop" :list-title="listTitle"></ArticleDeatilLong>
<ArticleDeatilLong v-if="article.sort == 2" ref="detailLong" :data="article" :scroll-top="scrollTop" :list-title="listTitle"></ArticleDeatilLong>
<ArticleDeatilNote v-else :data="article" :scroll-top="scrollTop" :list-title="listTitle"></ArticleDeatilNote>
</template>
<template class="article-item" #item="{ data }">
<ArticleItem2
...
...
@@ -52,14 +52,22 @@ export default {
this.init();
}
},
beforeRouteUpdate(to, from, next) {
if (+this.$route.params.id !== +to.params.id) {
this.id = +to.params.id;
this.init();
}
next();
},
mounted() {
this.colWidthForTwo = Math.floor(this.$el.offsetWidth / 2);
},
computed: {
},
methods: {
...mapActions(['fetchArticleList']),
...mapActions(['fetchArticleList'
, 'fetchDetailRecommendAricles'
]),
init() {
this.recommendArticles = {};
this.syncServiceArticleDetail();
},
onScroll({scrollTop}) {
...
...
@@ -76,15 +84,57 @@ export default {
this.fetchArticleList({
articleId,
page: 1,
limit: 1,
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();
this.$nextTick(() => {
this.$refs.scroll.init();
});
}
});
},
onFetch() {
return Promise.resolve([this.article]);
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;
if (result.code === 200) {
list = get(result, 'data', []);
if (!list || !list.length) {
list = false;
} else {
this.recommendArticles[this.id] = true;
}
} else {
this.$createToast && this.$createToast({
txt: result.message || '服务器开小差了',
type: 'warn',
time: 1000
}).show();
}
return list;
}
},
components: {
...
...
@@ -100,4 +150,8 @@ export default {
padding: 6px;
background-color: #f0f0f0;
}
/deep/ .loading {
height: 100px;
visibility: hidden;
}
</style>
...
...
apps/pages/article/components/article/article-item2.vue
View file @
5bfe8d2
...
...
@@ -2,8 +2,9 @@
<div class="article-item">
<slot>
<div class="article-item-main">
<a v-if="actionUrl" class="action-article" :href="actionUrl" target="_blank"></a>
<div class="layer-image" :style="`height: ${Math.floor(width * coverImage.scale)}px`" @click="toArticlePage">
<ImageFormat :mode="1" :src="coverImage.contentData" :width="
imgWidth" :height="Math.floor(coverImage.scale * imgWidth)" :style="imageStyle
"></ImageFormat>
<ImageFormat :mode="1" :src="coverImage.contentData" :width="
coverImage.width" :height="coverImage.height
"></ImageFormat>
</div>
<div v-if="intro" class="description" @click="toArticlePage">{{intro}}</div>
<div class="attribution">
...
...
@@ -23,6 +24,7 @@
<script>
import {get, round} from 'lodash';
import YAS from 'utils/yas-constants';
import {getArticleImageSize} from 'utils/image-handler';
import {createNamespacedHelpers} from 'vuex';
const {mapState} = createNamespacedHelpers('article');
...
...
@@ -55,23 +57,31 @@ export default {
return this.articleStates[this.data.articleId] || this.data;
},
coverImage() {
let img = get(this.data, 'blockList', []).filter(block => block.templateKey === 'image')[0] || {};
let img = get(this.data, 'blockList', []).filter(block => block.templateKey === 'image')[0] || {
contentData: this.data.coverImage,
width: this.data.imageWidth,
height: this.data.imageHeight
};
Object.assign(img, getArticleImageSize({
width: img.width,
height: img.height,
maxWidth: 500
}));
img.scale = img.height / img.width;
return img;
},
imageStyle() {
let width = 370;
let height = Math.floor(this.coverImage.scale * width);
return {
width: `${round(width / 40, 2)}rem`,
height: `${round(height / 40, 2)}rem`,
};
},
intro() {
return get(get(this.data, 'blockList', []).filter(block => block.templateKey === 'text'), '[0].contentData', '')
return get(get(this.data, 'blockList', []).filter(block => block.templateKey === 'text'), '[0].contentData', this.data.content)
},
actionUrl() {
if (this.data.sort === 3) {
return this.data.actionUrl;
}
return '';
},
favOption() {
return {
...
...
@@ -110,12 +120,10 @@ export default {
}
this.$router.push({
name: 'article',
name: 'article
.detail
',
params: {
id: this.data.articleId
},
query: {
columnType: 1002
id: this.data.articleId,
type: this.data.sort
}
});
this.reportClickArticle();
...
...
@@ -155,9 +163,24 @@ export default {
.article-item-main {
background-color: #fff;
border-radius: 2PX;
position: relative;
overflow: hidden;
}
.action-article {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1;
}
.layer-image img {
width: 100%;
height: 100%;
}
.description {
margin: 14px 20px;
font-size: 24px;
...
...
apps/pages/article/components/detail/article-intro.vue
View file @
5bfe8d2
...
...
@@ -2,7 +2,7 @@
<div ref="intro" class="intro-wrap" :class="introClass" :style="introStyle" @click="onExpanding">
<div v-if="trimIntro" class="intro-content">
<p class="pre-wrap">{{intro}}</p>
<div ref="introPool" class="intro-pool pre-wrap">{{trimIntro}}</div>
<div ref="introPool" class="intro-pool pre-wrap"
v-if="!introHeight"
>{{trimIntro}}</div>
<span ref="expand" class="expand" v-if="showExpandTxt">…<b>继续阅读</b></span>
</div>
<div class="collapse" v-if="showCollapseTxt">收起</div>
...
...
@@ -47,6 +47,8 @@ export default {
return (this.data.maxLines || MAX_LINES) - 1;
},
trimIntro() {
this.introHeight = 0;
this.introCollapseHeight = 0;
return trim(this.data.intro);
},
showIntro() {
...
...
@@ -120,8 +122,6 @@ export default {
this.$nextTick(() => {
this.introHeight = get(this.$refs, 'introPool.scrollHeight', 0) + 20;
this.introCollapseHeight = get(this.$refs, 'intro.offsetHeight', 0);
console.log(this.introHeight, this.introCollapseHeight);
});
},
onExpanding() {
...
...
apps/pages/article/components/detail/article-long.vue
View file @
5bfe8d2
...
...
@@ -8,7 +8,7 @@
</div>
</div>
</ArticleDetailHeader>
<div ref="coverFigure" class="cover-figure">
<div ref="coverFigure" class="cover-figure"
:style="coverStyle"
>
<ImageFormat class="cover-img" :src="coverImage.src" :width="coverImage.width" :height="coverImage.height" :style="`transform: translate3d(0, ${coverTranslateY}px, 0)`"></ImageFormat>
</div>
<div ref="authorBlock" class="author-block">
...
...
@@ -34,11 +34,22 @@
<div class="article-goods">文中商品</div>
</template>
</ArticleDetailFooter>
<YohoActionSheet transfer v-if="showCommentAction" ref="commentAction" :full="true">
<Comment ref="comment"
:destId="data.articleId"
:popup="true"
:article-id="data.articleId"
:commentCount="data.commentCount"
:pos-id="posId"
@on-close="onCloseComment"
@on-comment="onActionComment"></Comment>
</YohoActionSheet>
</div>
</template>
<script>
import {get} from 'lodash';
import {get
, floor
} from 'lodash';
import ArticleItemHeader from '../article/article-item-header';
import ArticleItemTopics from '../article/article-item-topics';
import ArticleDetailFooter from './article-footer';
...
...
@@ -65,6 +76,8 @@ export default {
showMoreOpt: false,
authorBlock: {},
recomendProduct: [],
showCommentAction: false,
showCommentActioning: false
};
},
mounted() {
...
...
@@ -76,6 +89,11 @@ export default {
},
computed: {
...mapState(['yoho']),
coverStyle() {
return {
height: `${floor(this.data.imageHeight / this.data.imageHeight * 750 / 40, 2)}rem`
};
},
coverImage() {
this.$nextTick(() => {
if (this.$refs.coverFigure) {
...
...
@@ -125,7 +143,7 @@ export default {
if (this.$refs && this.$refs.header) {
scrollTop += this.$refs.header.$el.offsetHeight;
}
console.log(scrollTop, top, height)
if (top && height) {
if (scrollTop >= top + height) {
return 100;
...
...
@@ -182,8 +200,24 @@ export default {
this.$emit('on-follow', 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() {
},
},
components: {
ArticleDetailHeader,
...
...
apps/pages/article/index.js
View file @
5bfe8d2
...
...
@@ -15,17 +15,25 @@ export default [{
keepAlive
:
true
}
},
{
path
:
'/article/detail/:id'
,
name
:
'article.detail'
,
alias
:
'/article/detail/:id'
,
path
:
'/article/detail2/:id'
,
name
:
'article.detail2'
,
alias
:
'/article/detail2/:id'
,
component
:
()
=>
import
(
/* webpackChunkName: "article" */
'./article-detail'
),
meta
:
{
keepAlive
:
true
}
},
{
path
:
'/article/detail2/:id'
,
name
:
'article.detail2'
,
alias
:
'/article/detail2/:id'
,
path
:
'/article/:type/:id'
,
name
:
'article.detail'
,
alias
:
'/article/:type/:id'
,
component
:
()
=>
import
(
/* webpackChunkName: "article-detail" */
'./article-detail2'
),
meta
:
{
keepAlive
:
true
}
},
{
path
:
'/article/detail/:id'
,
name
:
'article.detail'
,
alias
:
'/article/detail/:id'
,
component
:
()
=>
import
(
/* webpackChunkName: "article-detail" */
'./article-detail2'
),
meta
:
{
keepAlive
:
true
...
...
apps/pages/userpage/components/author-article-item.vue
View file @
5bfe8d2
...
...
@@ -2,6 +2,7 @@
<div class="wf-item" :class="temporary ? 'wf-temp' : ''">
<div v-if="temporary"></div>
<div v-else class="wf-item-mid">
<a v-if="actionUrl" class="action-article" :href="actionUrl" target="_blank"></a>
<div class="layer-image" @click="onClick" :style="`height: ${data.blockWidth * data.scale}px`">
<ImageFormat :mode="1" :src="data.coverImage" :width="imgWidth" :height="Math.floor(data.scale * imgWidth)"></ImageFormat>
</div>
...
...
@@ -57,6 +58,13 @@ export default {
iconFontSize: 30,
textAlign: 'normal'
};
},
actionUrl() {
if (this.data.sort === 3) {
return this.data.actionUrl;
}
return '';
}
},
methods: {
...
...
@@ -91,9 +99,19 @@ export default {
.wf-item-mid {
border-radius: 2PX;
overflow: hidden;
position: relative;
background-color: #fff;
}
.action-article {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1;
}
.layer-image {
background-color: #f4f4f4;
min-height: 100px;
...
...
apps/store/article/actions.js
View file @
5bfe8d2
...
...
@@ -280,5 +280,21 @@ export default {
}
return
result
;
},
async
fetchDetailRecommendAricles
({
commit
},
{
articleId
})
{
commit
(
Types
.
FETCH_DETAIL_RECOMMEND_REQUEST
);
const
result
=
await
this
.
$api
.
post
(
'/api/grass/detailRecommendArticles'
,
{
articleId
});
if
(
result
&&
result
.
code
===
200
)
{
commit
(
Types
.
FETCH_DETAIL_RECOMMEND_SUCCESS
,
{
data
:
result
.
data
||
[]
});
}
else
{
commit
(
Types
.
FETCH_DETAIL_RECOMMEND_FAILD
);
}
return
result
;
}
};
...
...
apps/store/article/index.js
View file @
5bfe8d2
...
...
@@ -20,7 +20,9 @@ export default function() {
articleStates
:
{},
fetchTopicInfo
:
false
,
topicInfo
:
{},
fetchTopicArticles
:
false
fetchTopicArticles
:
false
,
articleDetailList
:
[],
fetchDetailRecommendArticles
:
false
},
actions
,
mutations
...
...
apps/store/article/mutations.js
View file @
5bfe8d2
...
...
@@ -63,14 +63,17 @@ function setArticleList(state, data, type, thumb) {
let
{
width
,
height
}
=
getArticleImageSize
({
width
:
img
.
width
,
height
:
img
.
height
,
MIN_SCALE
:
inx
===
0
?
(
3
/
4
)
:
0
minScale
:
inx
===
0
?
(
3
/
4
)
:
0
});
img
.
width
=
parseInt
(
width
,
10
);
img
.
height
=
parseInt
(
height
,
10
);
});
});
state
[
articlefield
(
type
,
thumb
)]
=
state
[
articlefield
(
type
,
thumb
)].
concat
(
data
);
if
(
articlefield
(
type
,
thumb
))
{
state
[
articlefield
(
type
,
thumb
)]
=
state
[
articlefield
(
type
,
thumb
)].
concat
(
data
);
}
}
export
default
{
...
...
@@ -227,4 +230,14 @@ export default {
state
.
topicInfo
.
hasAttention
=
follow
;
}
},
[
Types
.
FETCH_DETAIL_RECOMMEND_REQUEST
](
state
,
topicId
)
{
state
.
fetchDetailRecommendArticles
=
true
;
},
[
Types
.
FETCH_DETAIL_RECOMMEND_SUCCESS
](
state
,
{
data
})
{
state
.
fetchDetailRecommendArticles
=
false
;
setArticleList
(
state
,
data
,
'detail'
);
},
[
Types
.
FETCH_DETAIL_RECOMMEND_FAILD
](
state
)
{
state
.
fetchDetailRecommendArticles
=
false
;
},
};
...
...
apps/store/article/types.js
View file @
5bfe8d2
...
...
@@ -33,3 +33,7 @@ export const FETCH_TOPIC_INFO_REQUEST = 'FETCH_TOPIC_INFO_REQUEST';
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_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'
;
...
...
apps/utils/image-handler.js
View file @
5bfe8d2
const
MAX_WIDTH
=
1000
;
export
function
getArticleImageSize
({
width
,
height
,
MIN_SCALE
=
0.75
})
{
export
function
getArticleImageSize
({
width
,
height
,
minScale
=
0.75
,
maxWidth
=
MAX_WIDTH
})
{
width
=
+
width
;
height
=
+
height
;
if
(
width
>
MAX_WIDTH
)
{
height
=
height
/
(
width
/
MAX_WIDTH
);
width
=
MAX_WIDTH
;
if
(
width
>
maxWidth
)
{
height
=
height
/
(
width
/
maxWidth
);
width
=
maxWidth
;
}
if
(
MIN_SCALE
&&
width
/
height
<
MIN_SCALE
)
{
height
=
width
/
MIN_SCALE
;
if
(
minScale
&&
width
/
height
<
minScale
)
{
height
=
width
/
minScale
;
}
if
(
width
===
1
)
{
width
=
MAX_WIDTH
/
2
;
width
=
maxWidth
/
2
;
}
if
(
height
===
1
)
{
height
=
MAX_WIDTH
/
2
;
height
=
maxWidth
/
2
;
}
return
{
width
,
height
};
return
{
width
,
height
:
Math
.
round
(
height
)
};
}
...
...
config/api-map.js
View file @
5bfe8d2
...
...
@@ -37,6 +37,14 @@ module.exports = {
singleDetail
:
{
type
:
String
}
}
},
'/api/grass/detailRecommendArticles'
:
{
api
:
'app.grass.otherArticle'
,
cache
:
true
,
auth
:
true
,
params
:
{
articleId
:
{
type
:
Number
,
require
:
false
}
}
},
'/api/grass/updateAttention'
:
{
api
:
'app.grass.updateAttention'
,
auth
:
true
,
...
...
Please
register
or
login
to post a comment