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
31508526c79f77a9ccc3e268f3ec25e226c2fe8b
1 parent
ca6ce969
long detail context
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
296 additions
and
70 deletions
apps/pages/article/article-detail2.vue
apps/pages/article/components/detail/article-footer.vue
apps/pages/article/components/detail/article-intro.vue
apps/pages/article/components/detail/article-long.vue
apps/pages/article/components/detail/article-note.vue
apps/pages/article/components/detail/comment-list.vue
apps/store/article/actions.js
config/api-map.js
apps/pages/article/article-detail2.vue
View file @
3150852
...
...
@@ -2,8 +2,8 @@
<Layout class="article-detail">
<RecycleScrollReveal :size="5" ref="scroll" @scroll="onScroll" :offset="800" :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> -->
<!-- <ArticleDeatilNote :data="article" :scroll-top="scrollTop" :list-title="listTitle"></ArticleDeatilNote> -->
<ArticleDeatilLong ref="detailLong" :data="article" :scroll-top="scrollTop" :list-title="listTitle"></ArticleDeatilLong>
</template>
<template class="article-item" #item="{ data }">
<ArticleItem2
...
...
@@ -78,7 +78,7 @@ export default {
articleId,
page: 1,
limit: 1,
columnType: 1002
singleDetail: 'Y'
}).then(res => {
this.article = get(res, 'data.detailList[0]', {});
});
...
...
apps/pages/article/components/detail/article-footer.vue
View file @
3150852
...
...
@@ -54,7 +54,7 @@ export default {
.article-footer-wrapper {
display: flex;
height: 100px;
border-top: 1px solid #
e0e0e
0;
border-top: 1px solid #
f0f0f
0;
background-color: white;
}
...
...
apps/pages/article/components/detail/article-intro.vue
0 → 100644
View file @
3150852
<template>
<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>
<span ref="expand" class="expand" v-if="showExpandTxt">…<b>继续阅读</b></span>
</div>
<div class="collapse" v-if="showCollapseTxt">收起</div>
</div>
</template>
<script>
import {get, trim, forEach} from 'lodash';
const MAX_LINES = 6;
export default {
name: 'ArticleIntro',
props: {
data: {
type: Object,
default() {
return {};
}
},
share: Boolean,
thumb: Boolean
},
data() {
return {
introHeight: 0,
introCollapseHeight: 0,
isIntroEllipsis: true,
isIntroExpand: false,
isIntroAnimateing: false,
canRetract: false,
}
},
watch: {
'data.intro': function() {
this.introHeight = 0;
this.updateHeight();
}
},
computed: {
maxLines() {
return (this.data.maxLines || MAX_LINES) - 1;
},
trimIntro() {
return trim(this.data.intro);
},
showIntro() {
let line = 0;
let textArr = [];
forEach(this.trimIntro, (val, index) => {
let isEnter = /(\r\n)|(\n)/.test(val);
textArr[line] = textArr[line] || '';
textArr[line] += val;
if (textArr[line].length >= 24 || isEnter) {
line++;
}
if (line > this.maxLines) {
textArr[this.maxLines] = textArr[this.maxLines].substring(0, Math.min(21, textArr[this.maxLines].length));
return false;
}
});
this.isIntroEllipsis = line > this.maxLines;
return trim(textArr.join(''));
},
intro() {
if (this.isIntroExpand || !this.isIntroEllipsis) {
return this.trimIntro;
} else {
return this.showIntro;
}
},
introClass() {
return {
'intro-expand': this.isIntroExpand,
'no-more': !this.isIntroEllipsis,
'intro-will-change': this.isIntroAnimateing
};
},
introStyle() {
let introHeight;
if (this.isIntroExpand) {
introHeight = this.introHeight;
} else {
introHeight = this.introCollapseHeight;
}
return {
height: introHeight ? `${introHeight}px` : void 0
};
},
showExpandTxt() {
return this.isIntroEllipsis && !this.isIntroExpand && !this.isIntroAnimateing;
},
showCollapseTxt() {
return this.isIntroEllipsis && this.isIntroExpand && !this.isIntroAnimateing && this.canRetract;
}
},
mounted() {
this.updateHeight();
this.$refs.intro && this.$refs.intro.addEventListener('transitionend', this.onExpand.bind(this));
},
destroyed() {
this.$refs.intro && this.$refs.intro.removeEventListener('transitionend', this.onExpand.bind(this));
},
methods: {
updateHeight() {
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() {
if (!this.isIntroEllipsis || (this.isIntroExpand && !this.canRetract)) {
return;
}
if (!this.canRetract) {
this.canRetract = this.introHeight - 21 > get(this.$refs, 'expand.offsetHeight', 0) * (this.maxLines + 4);
}
this.isIntroExpand = !this.isIntroExpand;
this.isIntroAnimateing = true;
},
onExpand() {
this.isIntroAnimateing = false;
this.$nextTick(() => {
this.$emit('on-expand');
});
},
},
};
</script>
<style lang="scss" scoped>
.intro-wrap {
padding: 0 30px;
margin-top: 20px;
overflow: hidden;
transition: height 250ms cubic-bezier(0.165, 0.84, 0.44, 1);
.intro-content {
line-height: 48px;
font-size: 28px;
color: #4a4a4a;
letter-spacing: 0.06PX;
box-sizing: content-box;
position: relative;
}
.pre-wrap {
white-space: pre-wrap;
word-wrap: break-word;
display: inline;
}
&.intro-will-change {
will-change: height;
}
&.intro-expand {
-webkit-line-clamp: initial;
text-overflow: initial;
}
&.no-more {
height: auto;
}
}
.intro-pool {
position: absolute;
width: 100%;
top: -1000px;
visibility: hidden;
}
.collapse {
width: 100%;
text-align: right;
font-size: 28px;
color: #000;
font-weight: bold;
}
.expand {
font-size: 28px;
color: #000;
line-height: 20px;
&.collapse {
position: absolute;
right: 14px;
bottom: 0;
height: 28px;
}
> b {
font-weight: bold;
}
}
</style>
...
...
apps/pages/article/components/detail/article-long.vue
View file @
3150852
...
...
@@ -9,21 +9,27 @@
</div>
</ArticleDetailHeader>
<div ref="coverFigure" class="cover-figure">
<img class="cover-img" :src="coverImage.src" :style="`transform: translate3d(0, ${coverTranslateY}px, 0)`"
>
<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">
<ArticleItemHeader :share="share" :data="authorData" :lazy="lazy" :more="showMoreOpt" @on-follow="onFollow"></ArticleItemHeader>
</div>
<div class="main-detail">
<div class="article-context" style="height: 1000px;background: #ccc;">
<div class="article-context">
<div class="context-title">{{data.articleTitle}}</div>
<div 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" model="2"></ProductGroup>
</div>
<ArticleItemTopics class="topics-wrap" :data="data" :share="share"></ArticleItemTopics>
<LayoutTitle class="rec-goods-title">推荐商品</LayoutTitle>
<ProductGroup :data="recomendProduct" model="2"></ProductGroup>
<LayoutTitle class="rec-article-title">{{listTitle}}</LayoutTitle>
</div>
<ArticleDetailFooter class="detail-fixed-footer" @on-comment-click="onComment">
<ArticleDetailFooter class="detail-fixed-footer"
v-bind="footerData"
@on-comment-click="onComment">
<template v-slot:after>
<div class="article-goods">文中商品</div>
</template>
...
...
@@ -58,57 +64,7 @@ export default {
downgrade: false,
showMoreOpt: false,
authorBlock: {},
recomendProduct: [{
"id": 230,
"marketPrice": 390,
"orderBy": 0,
"productId": 142427,
"productImage": "http://img10.static.yhbimg.com/goodsimg/2019/01/16/16/0123e8e8c7243ca83e37e6a11d4a431777.png?imageView2/{mode}/w/{width}/h/{height}",
"productName": "Timberland 插肩印花短袖T恤",
"productSkn": 51085719,
"productType": 1,
"salesPrice": 11
}, {
"id": 232,
"marketPrice": 1290,
"orderBy": 1,
"productId": 142447,
"productImage": "http://img13.static.yhbimg.com/goodsimg/2015/02/13/08/024becd3478789516c2749d5bc0e4e48cc.jpg?imageView2/{mode}/w/{width}/h/{height}",
"productName": "Timberland 女士经典无里衬帆船鞋",
"productSkn": 51085694,
"productType": 1,
"salesPrice": 11
}, {
"id": 234,
"marketPrice": 444,
"orderBy": 2,
"productId": 508376,
"productImage": "http://img13.static.yhbimg.com/goodsimg/2017/03/31/17/021204a24a95b6a5c258e7469e7bbbd22f.jpg?imageView2/{mode}/w/{width}/h/{height}",
"productName": "bigrabbit男手套",
"productSkn": 512587700,
"productType": 1,
"salesPrice": 444
}, {
"id": 236,
"marketPrice": 790,
"orderBy": 3,
"productId": 142413,
"productImage": "http://img10.static.yhbimg.com/goodsimg/2019/01/17/10/01d10b02308ecbfb42176cbf965478181a.jpg?imageView2/{mode}/w/{width}/h/{height}",
"productName": "Timberland 男士休闲短裤116",
"productSkn": 51085737,
"productType": 1,
"salesPrice": 11
}, {
"id": 238,
"marketPrice": 429,
"orderBy": 4,
"productId": 69792,
"productImage": "http://img13.static.yhbimg.com/goodsimg/2014/05/14/03/02e5b2050d3fd73584dd786cadc4eaf68d.jpg?imageView2/{mode}/w/{width}/h/{height}",
"productName": "izzue 碎花拼接T恤",
"productSkn": 51041119,
"productType": 1,
"salesPrice": 11
}],
recomendProduct: [],
};
},
mounted() {
...
...
@@ -134,8 +90,12 @@ export default {
}
});
let width = Math.min(+this.data.imageWidth, 1000);
return {
src: '//flv01.static.yhbimg.com/grassImg/2019/05/07/12/03a620a29bb8b3a4f508dc8f86f6974a7a.jpg'
src: this.data.coverImage,
width,
height: width * this.data.imageHeight / this.data.imageWidth
};
},
coverTranslateY() {
...
...
@@ -198,6 +158,16 @@ export default {
isAuthor: this.data.isAuthor
};
},
footerData() {
return {
favoriteCount: this.data.favoriteCount,
praiseCount: this.data.praiseCount,
commentCount: this.data.commentCount,
hasFavor: this.data.hasFavor,
hasPraise: this.data.hasPraise,
articleId: this.data.articleId
};
},
lazy() {
return this.data.lazy;
}
...
...
@@ -268,12 +238,30 @@ export default {
.main-detail {
position: relative;
z-index: 1;
background-color: #fff;
}
.article-context {
padding: 30px;
}
.context-title {
font-size: 34px;
color: #444;
line-height: 52px;
margin-bottom: 10px;
}
.context-rich-text /deep/ {
img {
max-width: 100%!important;
}
p {
font-size: 24px!important;
}
}
.topics-wrap {
padding-left: 30px;
margin-bottom: 36px;
...
...
apps/pages/article/components/detail/article-note.vue
View file @
3150852
...
...
@@ -13,13 +13,14 @@
<div class="article-context">
<ArticleItemSlide :thumb="thumb" :share="share" :data="slideData" :slide-index="slideIndex" :lazy="lazy" @on-praise="onPraise" @change="onChangeSlide"></ArticleItemSlide>
<ProductGroup :article-id="data.articleId" :pos-id="0" :index="0" :thumb="thumb" v-if="productListData.length" :share="share" :data="productListData" :lazy="lazy"></ProductGroup>
<ArticleDetailIntro :data="introData"></ArticleDetailIntro>
<ArticleItemTopics class="topics-wrap" :data="topicsData" :share="share"></ArticleItemTopics>
<p class="publish-time">{{publishTime}}</p>
<ArticleDetailCommentList
:dest-id="140838
" :article-id="data.articleId" :comment-count="data.commentCount"></ArticleDetailCommentList>
<ArticleDetailCommentList
v-if="data.commentCount
" :article-id="data.articleId" :comment-count="data.commentCount"></ArticleDetailCommentList>
<LayoutTitle class="rec-article-title">{{listTitle}}</LayoutTitle>
</div>
<ArticleDetailFooter class="detail-fixed-footer" @on-comment-click="onComment">
<ArticleDetailFooter class="detail-fixed-footer" v-bind="footerData" @on-comment-click="onComment">
<template v-slot:before>
<div class="footer-comment">
<CommentPlaceholder
...
...
@@ -51,6 +52,7 @@ import ArticleItemHeader from '../article/article-item-header';
import ArticleItemSlide from '../article/article-item-slide';
import ArticleItemTopics from '../article/article-item-topics';
import ArticleDetailFooter from './article-footer';
import ArticleDetailIntro from './article-intro';
import dayjs from 'utils/day';
export default {
...
...
@@ -107,12 +109,30 @@ export default {
productListData() {
return this.data.productList || [];
},
introData() {
let blockList = get(this.data, 'blockList', []);
return {
intro: get(blockList.filter(block => block.templateKey === 'text'), '[0].contentData', ''),
maxLines: 10
};
},
topicsData() {
return {
topicList: this.data.topicList,
articleType: this.data.articleType
};
},
footerData() {
return {
favoriteCount: this.data.favoriteCount,
praiseCount: this.data.praiseCount,
commentCount: this.data.commentCount,
hasFavor: this.data.hasFavor,
hasPraise: this.data.hasPraise,
articleId: this.data.articleId
};
},
publishTime() {
return dayjs(this.data.publishTime).fromNow();
},
...
...
@@ -141,6 +161,7 @@ export default {
ArticleItemHeader,
ArticleItemSlide,
ArticleItemTopics,
ArticleDetailIntro,
ArticleDetailCommentList,
ArticleDetailFooter
}
...
...
apps/pages/article/components/detail/comment-list.vue
View file @
3150852
...
...
@@ -34,7 +34,6 @@ const {mapActions} = createNamespacedHelpers('comment');
export default {
name: 'ArticleDetailCommentList',
props: {
destId: [Number, String],
commentCount: [Number, String],
articleId: [Number, String],
columnType: {
...
...
@@ -71,7 +70,7 @@ export default {
this.onFetching = true;
const result = await this.fetchCommentList({
destId: this.
dest
Id,
destId: this.
article
Id,
columnType: this.columnType,
page: this.page,
limit: 10
...
...
apps/store/article/actions.js
View file @
3150852
...
...
@@ -4,7 +4,7 @@ import * as guangProcess from './guangProcess';
import
*
as
sleep
from
'../../utils/sleep'
;
export
default
{
async
fetchArticleList
({
commit
},
{
articleId
,
authorUid
,
authorType
,
limit
=
5
,
page
=
1
,
thumb
=
false
,
columnType
=
1001
})
{
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
result
=
await
this
.
$api
.
get
(
'/api/grass/columnArticleDetail'
,
{
articleId
,
...
...
@@ -12,7 +12,8 @@ export default {
page
,
authorUid
,
authorType
,
columnType
columnType
,
singleDetail
});
if
(
result
&&
result
.
code
===
200
)
{
...
...
config/api-map.js
View file @
3150852
...
...
@@ -33,7 +33,8 @@ module.exports = {
page
:
{
type
:
Number
,
require
:
false
},
limit
:
{
type
:
Number
,
require
:
false
},
articleId
:
{
type
:
Number
},
columnType
:
{
type
:
Number
}
columnType
:
{
type
:
Number
},
singleDetail
:
{
type
:
String
}
}
},
'/api/grass/updateAttention'
:
{
...
...
Please
register
or
login
to post a comment