Skip to content

Commit 39cfbfd

Browse files
committed
style: 🚨 修复循环依赖
1 parent 100ca82 commit 39cfbfd

24 files changed

Lines changed: 488 additions & 462 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { type State, store } from '../store';
2+
import { withOptionalState } from './helper';
3+
import { isBottom, isTop } from './memo';
4+
5+
export type Dir = 'next' | 'prev';
6+
7+
/** 处理尽头翻页。返回当前是否已抵达尽头 */
8+
export const handleEndTurnPage = withOptionalState(
9+
(dir: Dir, state: State): boolean => {
10+
if (dir === 'prev') {
11+
switch (state.show.endPage) {
12+
case 'start':
13+
if (state.scrollLock || store.option.scroolEnd !== 'auto')
14+
return true;
15+
state.prop.onPrev?.();
16+
return true;
17+
case 'end':
18+
state.show.endPage = undefined;
19+
return true;
20+
21+
default:
22+
// 弹出卷首结束页
23+
if (isTop()) {
24+
if (state.scrollLock) return true;
25+
if (
26+
!state.prop.onExit ||
27+
!state.prop.onPrev ||
28+
store.option.scroolEnd !== 'auto'
29+
)
30+
return true;
31+
32+
state.show.endPage = 'start';
33+
return true;
34+
}
35+
}
36+
} else {
37+
switch (state.show.endPage) {
38+
case 'end':
39+
if (state.scrollLock || store.option.scroolEnd === 'none')
40+
return true;
41+
if (store.option.scroolEnd === 'auto' && state.prop.onNext)
42+
state.prop.onNext();
43+
else state.prop.onExit?.(true);
44+
return true;
45+
case 'start':
46+
state.show.endPage = undefined;
47+
return true;
48+
49+
default:
50+
// 弹出卷尾结束页
51+
if (isBottom()) {
52+
if (state.scrollLock) return true;
53+
if (!state.prop.onExit) return true;
54+
55+
state.show.endPage = 'end';
56+
return true;
57+
}
58+
}
59+
}
60+
61+
return false;
62+
},
63+
);
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
import { approx } from 'helper';
2+
3+
import { setState, store } from '../store';
4+
import { handleEndTurnPage } from './endPage';
5+
import { getImg, setOption } from './helper';
6+
import { reloadImg } from './imageLoad';
7+
import {
8+
abreastScrollFill,
9+
findTopPage,
10+
getPageTop,
11+
isAbreastMode,
12+
isScrollMode,
13+
pageHeightList,
14+
scrollLength,
15+
scrollTop,
16+
setAbreastScrollFill,
17+
} from './memo';
18+
import { showImgList } from './renderPage';
19+
import { constantScroll, scrollBy, scrollTo } from './scroll';
20+
import {
21+
switchAutoScroll,
22+
switchDir,
23+
switchFillEffect,
24+
switchFullscreen,
25+
switchGridMode,
26+
switchOnePageMode,
27+
switchScrollMode,
28+
} from './switch';
29+
import { translateAll, translateCurrent, translateToEnd } from './translation';
30+
import { turnPage } from './turnPage';
31+
32+
/** 卷轴模式下滚动至指定页数 */
33+
const scrollIntoView = (index: number, position: 'start' | 'end' = 'start') =>
34+
scrollTo(
35+
position === 'start'
36+
? getPageTop(index)
37+
: getPageTop(index + 1) - store.rootSize.height,
38+
true,
39+
);
40+
41+
/** 判断指定页能否被完全显示出来 */
42+
const isFullView = (i: number) => pageHeightList()[i] < store.rootSize.height;
43+
44+
/** 在卷轴模式下,智能滚动至图片的头尾 */
45+
const scrollViewTurnPage = (offset: number) => {
46+
if (!store.option.scrollMode.enabled) return;
47+
48+
const dir = offset > 0 ? 'next' : 'prev';
49+
if (handleEndTurnPage(dir)) return;
50+
51+
if (!store.option.scrollMode.alignEdge) return scrollBy(offset, true);
52+
53+
const viewBottom = scrollTop() + store.rootSize.height;
54+
let viewBottomPage = findTopPage(viewBottom);
55+
// 如果底页只露出了一点点,就当它没显示出来,避免小数滚动的误差
56+
if (approx(getPageTop(viewBottomPage), viewBottom)) viewBottomPage -= 1;
57+
58+
const viewTop = scrollTop();
59+
let viewTopPage = findTopPage(viewTop);
60+
// 如果顶页只露出了一点点,就当它没显示出来,避免小数滚动的误差
61+
if (approx(getPageTop(viewTopPage + 1), viewTop)) viewTopPage += 1;
62+
63+
if (dir === 'next') {
64+
const pageBottom = getPageTop(viewBottomPage + 1);
65+
66+
// 如果底页没显示出结尾,就跳转显示底页
67+
if (!approx(viewBottom, pageBottom)) {
68+
// 如果当前显示的图片占满了屏幕
69+
if (viewBottomPage === viewTopPage) {
70+
// 并且在滚动了指定距离后显示的还是这个图片,就直接滚动完事
71+
if (viewBottom + offset <= pageBottom) return scrollBy(offset, true);
72+
// 否则跳至底页结尾
73+
return scrollIntoView(viewBottomPage, 'end');
74+
}
75+
76+
return scrollIntoView(
77+
viewBottomPage,
78+
isFullView(viewBottomPage) ? 'end' : 'start',
79+
);
80+
}
81+
// 否则下一页
82+
const nextPage = viewBottomPage + 1;
83+
scrollIntoView(nextPage, isFullView(nextPage) ? 'end' : 'start');
84+
} else {
85+
const pageTop = getPageTop(viewTopPage);
86+
87+
// 如果顶页没显示出开头,就跳转显示顶页
88+
if (!approx(viewTop, pageTop)) {
89+
// 如果当前显示的图片占满了屏幕
90+
if (viewBottomPage === viewTopPage) {
91+
// 并且在滚动了指定距离后显示的还是这个图片,就直接滚动完事
92+
if (viewTop + offset >= pageTop) return scrollBy(offset, true);
93+
// 否则跳至顶页开头
94+
return scrollIntoView(viewTopPage, 'start');
95+
}
96+
97+
return scrollIntoView(
98+
viewTopPage,
99+
isFullView(viewTopPage) ? 'start' : 'end',
100+
);
101+
}
102+
// 否则上一页
103+
const prevPage = viewTopPage - 1;
104+
scrollIntoView(prevPage, isFullView(prevPage) ? 'start' : 'end');
105+
}
106+
};
107+
108+
/** 根据是否开启了 左右翻页键交换 来切换翻页方向 */
109+
const handleSwapPageTurnKey = (nextPage: boolean) => {
110+
const next = store.option.swapPageTurnKey ? !nextPage : nextPage;
111+
return next ? 'next' : 'prev';
112+
};
113+
114+
export const handleHotkey = (hotkey: string, e?: KeyboardEvent) => {
115+
// 并排卷轴模式下的快捷键
116+
if (isAbreastMode()) {
117+
switch (hotkey) {
118+
case 'scroll_up':
119+
return setAbreastScrollFill(abreastScrollFill() - 40);
120+
case 'scroll_down':
121+
return setAbreastScrollFill(abreastScrollFill() + 40);
122+
123+
case 'scroll_left':
124+
if (e?.repeat)
125+
return constantScroll.start(store.option.dir === 'rtl' ? -1 : 1);
126+
return scrollBy(store.option.dir === 'rtl' ? -40 : 40);
127+
case 'scroll_right':
128+
if (e?.repeat)
129+
return constantScroll.start(store.option.dir === 'rtl' ? 1 : -1);
130+
return scrollBy(store.option.dir === 'rtl' ? 40 : -40);
131+
132+
case 'page_up':
133+
return scrollBy(-store.rootSize.width * 0.8);
134+
case 'page_down':
135+
return scrollBy(store.rootSize.width * 0.8);
136+
137+
case 'jump_to_home':
138+
return scrollTo(0);
139+
case 'jump_to_end':
140+
return scrollTo(scrollLength());
141+
}
142+
}
143+
144+
// 普通卷轴模式下的快捷键
145+
if (isScrollMode()) {
146+
switch (hotkey) {
147+
case 'page_up':
148+
return scrollViewTurnPage(-store.rootSize.height * 0.8);
149+
case 'page_down':
150+
return scrollViewTurnPage(store.rootSize.height * 0.8);
151+
152+
case 'scroll_up':
153+
if (e?.repeat) return constantScroll.start(-1);
154+
return scrollBy(-40, true);
155+
case 'scroll_down':
156+
if (e?.repeat) return constantScroll.start(1);
157+
return scrollBy(40, true);
158+
}
159+
}
160+
161+
switch (hotkey) {
162+
case 'page_up':
163+
case 'scroll_up':
164+
return turnPage('prev');
165+
166+
case 'page_down':
167+
case 'scroll_down':
168+
return turnPage('next');
169+
170+
case 'scroll_left':
171+
return turnPage(handleSwapPageTurnKey(store.option.dir === 'rtl'));
172+
case 'scroll_right':
173+
return turnPage(handleSwapPageTurnKey(store.option.dir !== 'rtl'));
174+
175+
case 'jump_to_home':
176+
return setState('activePageIndex', 0);
177+
case 'jump_to_end':
178+
return setState(
179+
'activePageIndex',
180+
Math.max(0, store.pageList.length - 1),
181+
);
182+
183+
case 'switch_page_fill':
184+
return switchFillEffect();
185+
case 'switch_scroll_mode':
186+
return switchScrollMode();
187+
case 'switch_single_double_page_mode':
188+
return switchOnePageMode();
189+
case 'switch_dir':
190+
return switchDir();
191+
case 'switch_grid_mode':
192+
return switchGridMode();
193+
194+
case 'translate_current_page':
195+
return translateCurrent();
196+
case 'translate_all':
197+
return translateAll();
198+
case 'translate_to_end':
199+
return translateToEnd();
200+
201+
case 'auto_scroll':
202+
return switchAutoScroll();
203+
case 'fullscreen':
204+
return switchFullscreen();
205+
206+
case 'jump_next':
207+
return store.prop.onNext?.();
208+
case 'jump_prev':
209+
return store.prop.onPrev?.();
210+
211+
case 'switch_auto_enlarge':
212+
return setOption((draftOption) => {
213+
draftOption.disableZoom = !draftOption.disableZoom;
214+
});
215+
216+
case 'reload_current_error_img':
217+
for (const i of showImgList()) reloadImg(getImg(i).src);
218+
return;
219+
220+
case 'exit':
221+
return store.prop.onExit?.();
222+
223+
// 阅读模式以外的快捷键转发到网页上去处理
224+
default:
225+
document.body.dispatchEvent(new KeyboardEvent('keydown', e));
226+
document.body.dispatchEvent(new KeyboardEvent('keyup', e));
227+
}
228+
};

src/components/Manga/actions/image.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { createEffectOn, isEqual, throttle } from 'helper';
33
import { handleComicData } from '../handleComicData';
44
import { type State, setState } from '../store';
55
import { type PageList } from '../store/image';
6-
import { activeImgIndex, isOnePageMode, pageNum } from './memo';
6+
import { activeImgIndex } from './memo/img';
7+
import { isOnePageMode, pageNum } from './memo/options';
78

89
/** 重新计算图片排列 */
910
export const updatePageData = (state: State) => {

src/components/Manga/actions/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
export * from '../handleComicData';
2+
export * from './endPage';
23
export * from './helper';
4+
export * from './hotkeyAction';
35
export * from './hotkeys';
46
export * from './image';
57
export * from './imageLoad';

src/components/Manga/actions/memo/abreastScroll.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { clamp, createRootMemo, createThrottleMemo } from 'helper';
22
import { createSignal } from 'solid-js';
33

4-
import { placeholderSize } from '.';
54
import { store } from '../../store';
65
import { getImg } from '../helper';
6+
import { placeholderSize } from './img';
77
import { isAbreastMode } from './options';
88

99
/** 并排卷轴模式下的全局滚动填充 */

0 commit comments

Comments
 (0)