Skip to content

Commit 60d23fc

Browse files
committed
Refactor tag dialog by pagination
1 parent fd22e61 commit 60d23fc

15 files changed

+256
-382
lines changed

_posts/opera/2022-09-25-昆曲「西厢记」四折.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ actor: 施洋 方莛玉 罗轩
77
mention: 王翼骅 李琼瑶
88
date: 2022-09-25 +0800
99
location: 杭州大剧院·可变剧场
10-
description: 同一个剧团,同一台戏,感觉上,阿逍的红娘是很小只的灵动可爱,而施洋则是另一种风格,戏曲演员中少见的纤细高挑,真的很搭一个「洋」字💃🏻。
10+
description: 同一个剧团,同一台戏,感觉上,阿逍的红娘是很小只的灵动可爱,而施洋则是另一种风格,戏曲演员中少见的纤细高挑,很搭一个「洋」字💃🏻。
1111
cover: https://apqx.oss-cn-hangzhou.aliyuncs.com/blog/opera/20220925/xixiangji/DSC03690_thumb.jpg
1212
cover-alt: 昆曲 西厢记 跳墙着棋 施洋 方莛玉 罗轩
1313
tags: 看剧 摄影 戏剧 杭州 昆曲 浙昆 西厢记 寄柬 跳墙着棋 佳期 拷红 施洋 方莛玉 罗轩 王翼骅 李琼瑶 杭州大剧院·可变剧场
@@ -25,13 +25,13 @@ tags: 看剧 摄影 戏剧 杭州 昆曲 浙昆 西厢记 寄柬 跳墙着棋
2525

2626
**拷红**`莺莺``红娘`撮合下,夜奔西厢探慰`张生`,事后被`老夫人`发觉,拷问`红娘``红娘`据实以告、以理服人,最后`老夫人`迫不得已,见木已成舟,只好将`莺莺`许配给`张生`
2727

28-
同一个剧团,同一台戏,感觉上,[阿逍的红娘]({% link _posts/opera/2022-08-21-昆曲「西厢记·跳墙着棋」折子.md %}){: target="_blank" }是很小只的灵动可爱,而施洋则是另一种风格,戏曲演员中少见的纤细高挑,真的很搭一个「洋」字💃🏻。
28+
同一个剧团,同一台戏,感觉上,[阿逍的红娘]({% link _posts/opera/2022-08-21-昆曲「西厢记·跳墙着棋」折子.md %}){: target="_blank" }是很小只的灵动可爱,而施洋则是另一种风格,戏曲演员中少见的纤细高挑,很搭一个「洋」字💃🏻。
2929

3030
![](https://apqx.oss-cn-hangzhou.aliyuncs.com/blog/opera/20220925/xixiangji/zhangtangxiao_shiyang_thumb.jpg){: loading="lazy" class="clickable clickShowOriginalImg operaCopyright" alt="红娘 张唐逍 施洋" }
3131

3232
这应该是他/她们仨第一次演完整的《西厢记》,而且是在近距离的小剧场。开始前我竖着耳朵隐约“偷听”到好像他/她们老师也来看了(小声说:其实还偷听到了另一些有趣的事🙃),就坐我前面,我不知道她会如何评价,但从一个普通的台下观众的视角,我看到的是一场精彩的演出,收获的是一个开心的周末,真不错。
3333

34-
*偷听.jpg 👀*
34+
*偷听.jpg👀*
3535

3636
![](https://apqx.oss-cn-hangzhou.aliyuncs.com/blog/opera/20220925/xixiangji/IMG_2811_thumb.jpg){: loading="lazy" class="clickable clickShowOriginalImg operaCopyright" alt="张唐逍" }
3737

api/paginate/tags/看剧&上海.txt

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
layout: paginate-posts-json
3+
sitemap: false
4+
permalink: /api/paginate/tags/看剧&上海
5+
pagination:
6+
permalink: ""
7+
enabled: true
8+
tag: "看剧,上海"
9+
extension: .json
10+
indexpage: 'page-:num'
11+
---

api/paginate/tags/看剧&南京.txt

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
layout: paginate-posts-json
3+
sitemap: false
4+
permalink: /api/paginate/tags/看剧&南京
5+
pagination:
6+
permalink: ""
7+
enabled: true
8+
tag: "看剧,南京"
9+
extension: .json
10+
indexpage: 'page-:num'
11+
---

api/paginate/tags/看剧&杭州.txt

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
layout: paginate-posts-json
3+
sitemap: false
4+
permalink: /api/paginate/tags/看剧&杭州
5+
pagination:
6+
permalink: ""
7+
enabled: true
8+
tag: "看剧,杭州"
9+
extension: .json
10+
indexpage: 'page-:num'
11+
---

npm/dist/blog-index-v2.0.0.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

npm/dist/blog-scaffold-v2.0.0.js

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

npm/src/component/dialog/SearchDialog.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export class SearchDialog extends BasicDialog<BasicDialogProps, SearchDialogStat
5858
onDialogClose(): void {
5959
super.onDialogClose()
6060
this.presenter.abortSearch()
61-
this.presenter.reduceResult()
61+
// this.presenter.reduceResult()
6262
}
6363

6464
componentDidMount(): void {

npm/src/component/dialog/TagDialog.tsx

+107-47
Original file line numberDiff line numberDiff line change
@@ -3,64 +3,57 @@ import { MDCList } from "@material/list"
33
import { MDCRipple } from "@material/ripple"
44
import { BasicDialog, BasicDialogProps, TAG_DIALOG_WRAPPER_ID, showDialog } from "./BasicDialog"
55
import { consoleDebug } from "../../util/log"
6-
import { TagDialogPresenter } from "./TagDialogPresenter"
76
import ReactDOM from "react-dom"
87
import { initListItem } from "../list"
98
import { ERROR_HINT, LoadingHint } from "../react/LoadingHint"
109
import { HeightAnimationContainer } from "../animation/HeightAnimationContainer"
10+
import { BasePostPaginateShow, BasePostPaginateShowProps, BasePostPaginateShowState, Post } from "../react/post/BasePostPaginateShow"
11+
import { IPostPaginateShowPresenter } from "../react/post/IPostPaginateShowPresenter"
12+
import { PostPaginateShowPresenter } from "../react/post/PostPaginateShowPresenter"
13+
import { getSectionTypeByPath, SECTION_TYPE_OPERA, SECTION_TYPE_ORIGINAL, SectionType } from "../../base/constant"
1114
// import "./TagEssayListDialog.scss"
1215

1316
interface DialogContentProps extends BasicDialogProps {
1417
tag: string,
1518
}
1619

1720
interface DialogContentState {
18-
loading: boolean,
19-
resultSize: number,
20-
postList: PostItemData[]
21-
loadHint: string
21+
dialogOpened: boolean,
22+
loadMoreId: number,
2223
}
2324

2425
export class TagDialog extends BasicDialog<DialogContentProps, DialogContentState> {
25-
presenter: TagDialogPresenter = null
2626
heightAnimationContainer: HeightAnimationContainer = null
2727

2828
constructor(props) {
2929
super(props)
3030
consoleDebug("TagDialogContent constructor")
31-
this.onClickLoadMore = this.onClickLoadMore.bind(this)
31+
this.onListSizeChanged = this.onListSizeChanged.bind(this)
3232
// this.scrollToTopOnDialogOpen = false
3333
this.listenScroll = true
34-
this.presenter = new TagDialogPresenter(this)
3534
this.state = {
36-
loading: true,
37-
resultSize: 0,
38-
postList: [],
39-
loadHint: null
35+
dialogOpened: false,
36+
loadMoreId: 0,
4037
}
4138
}
4239

4340
onDialogOpen() {
4441
super.onDialogOpen()
45-
// 检查是否应该触发fetch数据
46-
if (this.state.postList.length == 0) {
47-
this.presenter.findTaggedPosts(this.props.tag)
48-
}
42+
this.setState({ dialogOpened: true })
4943
}
5044

5145
onDialogClose() {
5246
super.onDialogClose()
53-
this.presenter.abortFetch()
54-
// this.presenter.reduceResult()
47+
this.setState({ dialogOpened: false })
5548
}
5649

57-
onClickLoadMore() {
58-
this.presenter.loadMore(true)
59-
}
6050

6151
scrollNearToBottom(): void {
62-
if (this.state.loadHint == ERROR_HINT) return
63-
this.presenter.loadMore(false)
52+
this.setState({ loadMoreId: this.state.loadMoreId + 1 })
53+
}
54+
55+
onListSizeChanged() {
56+
this.heightAnimationContainer.update()
6457
}
6558

6659
componentDidMount() {
@@ -69,11 +62,6 @@ export class TagDialog extends BasicDialog<DialogContentProps, DialogContentStat
6962
this.heightAnimationContainer = new HeightAnimationContainer(this.rootE.querySelector(".height-animation-container"))
7063
}
7164

72-
componentDidUpdate(prevProps: Readonly<BasicDialogProps>, prevState: Readonly<any>, snapshot?: any): void {
73-
super.componentDidUpdate(prevProps, prevState, snapshot)
74-
this.heightAnimationContainer.update()
75-
}
76-
7765
componentWillUnmount(): void {
7866
if (this.heightAnimationContainer != null) this.heightAnimationContainer.destroy()
7967
}
@@ -88,36 +76,81 @@ export class TagDialog extends BasicDialog<DialogContentProps, DialogContentStat
8876

8977
dialogContent(): JSX.Element {
9078
consoleDebug("TagDialogContent render")
79+
80+
return (
81+
<div className="height-animation-container">
82+
<ResultWrapper category={""} tag={this.props.tag} pinedPosts={[]} loadedPosts={[]}
83+
onUpdate={this.onListSizeChanged} dialogOpened={this.state.dialogOpened}
84+
loadMoreId={this.state.loadMoreId} />
85+
</div>
86+
)
87+
}
88+
}
89+
90+
interface ResultWrapperProps extends BasePostPaginateShowProps {
91+
dialogOpened: boolean
92+
loadMoreId: number
93+
}
94+
95+
class ResultWrapper extends BasePostPaginateShow<ResultWrapperProps> {
96+
97+
constructor(props: ResultWrapperProps) {
98+
super(props)
99+
this.loadFirstPageOnMount = false
100+
}
101+
102+
createPresenter(): IPostPaginateShowPresenter {
103+
return new PostPaginateShowPresenter(this, true)
104+
}
105+
106+
shouldComponentUpdate(nextProps: Readonly<ResultWrapperProps>, nextState: Readonly<BasePostPaginateShowState>, nextContext: any): boolean {
107+
if (nextProps.loadMoreId > 0 && this.props.loadMoreId != nextProps.loadMoreId &&
108+
(this.presenter.isLastPage() || this.state.loadHint == ERROR_HINT)) {
109+
// 如果是最后一页,不触发加载
110+
// 如果是异常状态,不触发加载,等待用户点击
111+
return false
112+
}
113+
return true
114+
}
115+
116+
componentDidUpdate(prevProps: Readonly<ResultWrapperProps>, prevState: Readonly<BasePostPaginateShowState>, snapshot?: any): void {
117+
super.componentDidUpdate(prevProps, prevState, snapshot)
118+
if (this.props.dialogOpened && !prevProps.dialogOpened && this.state.posts.length == 0) {
119+
this.loadFirstPage()
120+
}
121+
if (!this.props.dialogOpened && prevProps.dialogOpened) {
122+
this.presenter.abortLoad()
123+
}
124+
if (this.props.loadMoreId > 0 && this.props.loadMoreId != prevProps.loadMoreId) {
125+
this.loadMore()
126+
}
127+
}
128+
129+
render(): React.ReactNode {
91130
let count: JSX.Element
92-
if (this.state.postList.length == 0) {
131+
if (this.state.posts.length == 0) {
93132
count = <></>
94133
} else {
95-
count = <><span>{this.state.resultSize}</span></>
134+
count = <><span>{this.state.totalPostsSize}</span></>
96135
}
97136
return (
98137
<>
99-
<p className="mdc-theme--on-surface">标记 {this.props.tag}{count}篇博文
138+
<p>标记 {this.props.tag}{count}篇博文
100139
</p>
101-
102-
{/* <ProgressLinear loading={this.state.loading} /> */}
103-
<div className="height-animation-container">
104-
<div>
105-
{this.state.postList != null && this.state.postList.length != 0 &&
106-
<PostResult list={this.state.postList} />
107-
}
108-
{(this.state.loading || this.state.loadHint != null) &&
109-
<LoadingHint loading={this.state.loading} loadHint={this.state.loadHint} onClickHint={this.onClickLoadMore} />
110-
}
111-
</div>
112-
</div>
140+
{this.state.posts != null && this.state.posts.length != 0 &&
141+
<PostResult list={this.state.posts} />
142+
}
143+
{(this.state.loading || this.state.loadHint != null) &&
144+
<LoadingHint loading={this.state.loading} loadHint={this.state.loadHint} onClickHint={this.loadMoreByClick} />
145+
}
113146
</>
114147
)
115148
}
116149
}
117150

118151

119152
interface PostResultProps {
120-
list: PostItemData[]
153+
list: Post[]
121154
}
122155

123156
class PostResult extends React.Component<PostResultProps, any> {
@@ -132,15 +165,42 @@ class PostResult extends React.Component<PostResultProps, any> {
132165
new MDCList(e)
133166
}
134167

168+
getPostType(item: Post): SectionType {
169+
return getSectionTypeByPath(item.path)
170+
}
171+
172+
/**
173+
* 获取一个文章要显示的块,包括author作者、actor演员、mention提到
174+
* 显示,一共就2个block,用不同的颜色区分
175+
*/
176+
getPostBlocks(author: string, actor: Array<string>, mention: Array<string>, postType: SectionType): [string[], string[]] {
177+
if (postType.identifier === SECTION_TYPE_ORIGINAL.identifier) {
178+
// 随笔,不显示author,显示actor和mention
179+
return [actor, mention]
180+
} else if (postType.identifier === SECTION_TYPE_OPERA.identifier) {
181+
// 看剧,显示actor和mention
182+
return [actor, mention]
183+
} else {
184+
// 其它类型,显示author和mention
185+
return [[author], mention]
186+
}
187+
}
188+
135189
render() {
190+
const items = this.props.list.map((item) => {
191+
const postType = this.getPostType(item)
192+
const postBlocks = this.getPostBlocks(item.author, item.actor, item.mention, postType)
193+
// 两个chip列表
194+
return new PostItemData(item.path, item.title, item.date, postType.name, postBlocks[0], postBlocks[1])
195+
})
136196
return (
137197
<ul className="mdc-deprecated-list">
138-
{this.props.list.map((item) =>
198+
{items.map((item) =>
139199
<PostItem
140200
key={item.title + item.date}
141201
data={new PostItemData(item.url, item.title, item.date, item.type, item.block1Array, item.block2Array)}
142-
first={this.props.list.indexOf(item) === 0}
143-
last={this.props.list.indexOf(item) === (this.props.list.length - 1)}
202+
first={items.indexOf(item) === 0}
203+
last={items.indexOf(item) === (this.props.list.length - 1)}
144204
/>
145205
)}
146206
</ul>

0 commit comments

Comments
 (0)