Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
pic-reader
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
龙菲
pic-reader
Commits
892f9f9d
提交
892f9f9d
authored
6月 25, 2025
作者:
搞事情
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
1、增加拖动翻页功能
上级
651caf63
显示空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
334 行增加
和
41 行删除
+334
-41
turn.js
src/assets/js/turn.js
+327
-40
index.vue
src/components/BookReader/index.vue
+7
-1
没有找到文件。
src/assets/js/turn.js
浏览文件 @
892f9f9d
import
$
from
'jquery'
;
// turn.js - 翻页库
(
function
(
$
)
{
'use strict'
;
var
has3d
,
var
has3d
,
vendor
=
''
,
vendor
=
''
,
...
@@ -70,7 +72,7 @@ var has3d,
...
@@ -70,7 +72,7 @@ var has3d,
// Size of the active zone of each corner
// Size of the active zone of each corner
cornerSize
:
20
0
,
cornerSize
:
5
0
,
// Enables gradients
// Enables gradients
...
@@ -82,7 +84,19 @@ var has3d,
...
@@ -82,7 +84,19 @@ var has3d,
// Enables hardware acceleration
// Enables hardware acceleration
acceleration
:
true
acceleration
:
true
,
// Enables non-corner area flipping
enableNonCorner
:
true
,
// Maximum folding distance ratio for non-corner flipping (0.1 - 1.0)
maxFoldingDistance
:
0.8
,
// Minimum drag distance to trigger non-corner flip
minDragDistance
:
30
},
},
// Number of pages in the DOM, minimum value: 6
// Number of pages in the DOM, minimum value: 6
...
@@ -1229,6 +1243,128 @@ var has3d,
...
@@ -1229,6 +1243,128 @@ var has3d,
},
},
// 检测非corner区域翻页
_nonCornerActivated
:
function
(
e
)
{
if
(
e
.
originalEvent
===
undefined
)
{
return
false
;
}
var
data
=
this
.
data
().
f
;
// 检查是否启用非corner翻页
if
(
!
data
.
opts
.
enableNonCorner
)
{
return
false
;
}
e
=
(
isTouch
)
?
e
.
originalEvent
.
touches
:
[
e
];
var
pos
=
data
.
parent
.
offset
(),
width
=
this
.
width
(),
height
=
this
.
height
(),
point
=
{
x
:
Math
.
max
(
0
,
e
[
0
].
pageX
-
pos
.
left
),
y
:
Math
.
max
(
0
,
e
[
0
].
pageY
-
pos
.
top
)
},
csz
=
data
.
opts
.
cornerSize
||
50
,
allowedCorners
=
flipMethods
.
_cAllowed
.
call
(
this
),
turnData
=
data
.
opts
.
turn
?
data
.
opts
.
turn
.
data
()
:
null
;
if
(
point
.
x
<=
0
||
point
.
y
<=
0
||
point
.
x
>=
width
||
point
.
y
>=
height
)
return
false
;
// 检查是否在corner区域(如果在corner区域,则不处理)
var
inCorner
=
false
;
if
(
point
.
y
<
csz
)
inCorner
=
true
;
else
if
(
point
.
y
>=
height
-
csz
)
inCorner
=
true
;
if
(
inCorner
&&
(
point
.
x
<=
csz
||
point
.
x
>=
width
-
csz
))
return
false
;
// 非corner区域翻页逻辑
var
virtualCorner
=
flipMethods
.
_calculateVirtualCorner
.
call
(
this
,
point
,
allowedCorners
,
turnData
);
return
virtualCorner
;
},
// 改进的虚拟corner计算逻辑
_calculateVirtualCorner
:
function
(
point
,
allowedCorners
,
turnData
)
{
var
width
=
this
.
width
(),
height
=
this
.
height
(),
data
=
this
.
data
().
f
,
virtualCorner
=
null
;
// 双页模式的改进逻辑
if
(
turnData
&&
turnData
.
display
===
'double'
)
{
// 获取当前页面在双页视图中的位置
var
currentView
=
turnData
.
view
||
[
data
.
opts
.
page
];
var
isLeftPage
=
data
.
opts
.
page
%
2
===
0
;
// 改进的双页拖动检测:支持跨页拖动
var
dragThreshold
=
width
*
0.3
;
// 30%的区域作为拖动触发区
if
(
isLeftPage
)
{
// 左页:右侧30%区域可以向右翻页,左侧30%区域可以向左翻页
if
(
point
.
x
>
width
-
dragThreshold
)
{
// 右侧拖动区域,向右翻页
virtualCorner
=
(
point
.
y
<
height
/
2
)
?
'tr'
:
'br'
;
}
else
if
(
point
.
x
<
dragThreshold
)
{
// 左侧拖动区域,向左翻页
virtualCorner
=
(
point
.
y
<
height
/
2
)
?
'tl'
:
'bl'
;
}
}
else
{
// 右页:左侧30%区域可以向左翻页,右侧30%区域可以向右翻页
if
(
point
.
x
<
dragThreshold
)
{
// 左侧拖动区域,向左翻页
virtualCorner
=
(
point
.
y
<
height
/
2
)
?
'tl'
:
'bl'
;
}
else
if
(
point
.
x
>
width
-
dragThreshold
)
{
// 右侧拖动区域,向右翻页
virtualCorner
=
(
point
.
y
<
height
/
2
)
?
'tr'
:
'br'
;
}
}
}
else
{
// 单页模式:保持原有逻辑
var
centerX
=
width
/
2
;
var
centerY
=
height
/
2
;
if
(
point
.
x
<
centerX
)
{
// 左侧点击,向左翻页
virtualCorner
=
(
point
.
y
<
centerY
)
?
'tl'
:
'bl'
;
}
else
{
// 右侧点击,向右翻页
virtualCorner
=
(
point
.
y
<
centerY
)
?
'tr'
:
'br'
;
}
}
// 检查计算出的corner是否被允许
if
(
virtualCorner
&&
$
.
inArray
(
virtualCorner
,
allowedCorners
)
!==
-
1
)
{
return
{
x
:
point
.
x
,
y
:
point
.
y
,
corner
:
virtualCorner
,
originalPoint
:
{
x
:
point
.
x
,
y
:
point
.
y
},
isVirtual
:
true
,
// 添加拖动起始信息,用于改进拖动体验
dragStartX
:
point
.
x
,
dragStartY
:
point
.
y
};
}
return
false
;
},
// 改进的虚拟corner映射
_mapVirtualToRealCorner
:
function
(
virtualPoint
)
{
if
(
!
virtualPoint
.
isVirtual
)
return
virtualPoint
;
// 获取真实corner的位置
var
realCorner
=
flipMethods
.
_c
.
call
(
this
,
virtualPoint
.
corner
);
return
{
corner
:
virtualPoint
.
corner
,
x
:
virtualPoint
.
x
,
y
:
virtualPoint
.
y
,
isVirtual
:
true
,
originalPoint
:
virtualPoint
.
originalPoint
,
realCorner
:
realCorner
,
dragStartX
:
virtualPoint
.
dragStartX
,
dragStartY
:
virtualPoint
.
dragStartY
};
},
_cornerActivated
:
function
(
e
)
{
_cornerActivated
:
function
(
e
)
{
if
(
e
.
originalEvent
===
undefined
)
{
if
(
e
.
originalEvent
===
undefined
)
{
return
false
;
return
false
;
...
@@ -1258,27 +1394,21 @@ var has3d,
...
@@ -1258,27 +1394,21 @@ var has3d,
},
},
_c
:
function
(
corner
,
opts
)
{
// 统一的区域激活检测函数
_areaActivated
:
function
(
e
)
{
opts
=
opts
||
0
;
// 首先检测corner区域
return
({
var
cornerResult
=
flipMethods
.
_cornerActivated
.
call
(
this
,
e
);
tl
:
point2D
(
opts
,
opts
),
if
(
cornerResult
)
{
tr
:
point2D
(
this
.
width
()
-
opts
,
opts
),
return
cornerResult
;
bl
:
point2D
(
opts
,
this
.
height
()
-
opts
),
}
br
:
point2D
(
this
.
width
()
-
opts
,
this
.
height
()
-
opts
)
})[
corner
];
},
_c2
:
function
(
corner
)
{
return
{
// 如果不在corner区域,检测非corner区域
tl
:
point2D
(
this
.
width
()
*
2
,
0
),
var
nonCornerResult
=
flipMethods
.
_nonCornerActivated
.
call
(
this
,
e
);
tr
:
point2D
(
-
this
.
width
(),
0
),
if
(
nonCornerResult
)
{
bl
:
point2D
(
this
.
width
()
*
2
,
this
.
height
()),
return
flipMethods
.
_mapVirtualToRealCorner
.
call
(
this
,
nonCornerResult
);
br
:
point2D
(
-
this
.
width
(),
this
.
height
())
}
}[
corner
];
return
false
;
},
},
_foldingPage
:
function
(
corner
)
{
_foldingPage
:
function
(
corner
)
{
...
@@ -1502,7 +1632,6 @@ var has3d,
...
@@ -1502,7 +1632,6 @@ var has3d,
gradientOpacity
=
(
far
<
width
)
?
far
/
width
:
1
;
gradientOpacity
=
(
far
<
width
)
?
far
/
width
:
1
;
if
(
data
.
opts
.
frontGradient
)
{
if
(
data
.
opts
.
frontGradient
)
{
gradientStartV
=
gradientSize
>
100
?
(
gradientSize
-
100
)
/
gradientSize
:
0
;
gradientStartV
=
gradientSize
>
100
?
(
gradientSize
-
100
)
/
gradientSize
:
0
;
...
@@ -1783,7 +1912,7 @@ var has3d,
...
@@ -1783,7 +1912,7 @@ var has3d,
var
data
=
this
.
data
().
f
;
var
data
=
this
.
data
().
f
;
if
(
!
data
.
disabled
&&
!
this
.
flip
(
'isTurning'
))
{
if
(
!
data
.
disabled
&&
!
this
.
flip
(
'isTurning'
))
{
data
.
corner
=
flipMethods
.
_corner
Activated
.
call
(
this
,
e
);
data
.
corner
=
flipMethods
.
_area
Activated
.
call
(
this
,
e
);
if
(
data
.
corner
&&
flipMethods
.
_foldingPage
.
call
(
this
,
data
.
corner
))
{
if
(
data
.
corner
&&
flipMethods
.
_foldingPage
.
call
(
this
,
data
.
corner
))
{
flipMethods
.
_moveFoldingPage
.
call
(
this
,
true
);
flipMethods
.
_moveFoldingPage
.
call
(
this
,
true
);
this
.
trigger
(
'pressed'
,
[
data
.
point
]);
this
.
trigger
(
'pressed'
,
[
data
.
point
]);
...
@@ -1802,14 +1931,42 @@ var has3d,
...
@@ -1802,14 +1931,42 @@ var has3d,
if
(
data
.
corner
)
{
if
(
data
.
corner
)
{
var
pos
=
data
.
parent
.
offset
();
var
pos
=
data
.
parent
.
offset
();
var
currentMouseX
=
e
[
0
].
pageX
-
pos
.
left
;
var
currentMouseY
=
e
[
0
].
pageY
-
pos
.
top
;
// 检查是否是虚拟corner(非corner区域拖拽)
if
(
data
.
corner
.
isVirtual
)
{
// 计算拖动距离
var
dragDistance
=
Math
.
sqrt
(
Math
.
pow
(
currentMouseX
-
data
.
corner
.
dragStartX
,
2
)
+
Math
.
pow
(
currentMouseY
-
data
.
corner
.
dragStartY
,
2
)
);
// 最小拖动距离阈值
var
minDragDistance
=
data
.
opts
.
minDragDistance
||
30
;
if
(
dragDistance
<
minDragDistance
)
{
// 拖动距离太小,不执行翻页效果
return
;
}
data
.
corner
.
x
=
e
[
0
].
pageX
-
pos
.
left
;
// 根据拖动轨迹计算真实的折叠点
data
.
corner
.
y
=
e
[
0
].
pageY
-
pos
.
top
;
var
foldPoint
=
flipMethods
.
_calculateNonCornerFoldPoint
.
call
(
this
,
data
.
corner
.
corner
,
currentMouseX
-
data
.
corner
.
dragStartX
,
currentMouseY
-
data
.
corner
.
dragStartY
,
dragDistance
,
data
.
corner
.
realCorner
);
data
.
corner
.
x
=
foldPoint
.
x
;
data
.
corner
.
y
=
foldPoint
.
y
;
}
else
{
// 传统corner拖拽,直接使用鼠标位置
data
.
corner
.
x
=
currentMouseX
;
data
.
corner
.
y
=
currentMouseY
;
}
flipMethods
.
_showFoldedPage
.
call
(
this
,
data
.
corner
);
flipMethods
.
_showFoldedPage
.
call
(
this
,
data
.
corner
);
}
else
if
(
!
this
.
data
().
effect
&&
this
.
is
(
':visible'
))
{
// roll over
}
else
if
(
!
this
.
data
().
effect
&&
this
.
is
(
':visible'
))
{
// roll over
var
corner
=
flipMethods
.
_corner
Activated
.
call
(
this
,
e
[
0
]);
var
corner
=
flipMethods
.
_area
Activated
.
call
(
this
,
e
[
0
]);
if
(
corner
)
{
if
(
corner
)
{
var
origin
=
flipMethods
.
_c
.
call
(
this
,
corner
.
corner
,
data
.
opts
.
cornerSize
/
2
);
var
origin
=
flipMethods
.
_c
.
call
(
this
,
corner
.
corner
,
data
.
opts
.
cornerSize
/
2
);
corner
.
x
=
origin
.
x
;
corner
.
x
=
origin
.
x
;
...
@@ -1822,6 +1979,144 @@ var has3d,
...
@@ -1822,6 +1979,144 @@ var has3d,
}
}
},
},
// 新增:根据拖动轨迹计算真实的折叠点
_calculateNonCornerFoldPoint
:
function
(
corner
,
dragDeltaX
,
dragDeltaY
,
dragDistance
,
realCorner
)
{
var
data
=
this
.
data
().
f
;
var
width
=
this
.
width
();
var
height
=
this
.
height
();
var
maxFoldingDistance
=
data
.
opts
.
maxFoldingDistance
||
0.6
;
// 获取起点(拖动开始点)和终点(当前鼠标位置)
var
startX
=
data
.
corner
.
dragStartX
;
var
startY
=
data
.
corner
.
dragStartY
;
var
endX
=
startX
+
dragDeltaX
;
var
endY
=
startY
+
dragDeltaY
;
// 获取参考corner的位置
var
referenceCorner
=
flipMethods
.
_c
.
call
(
this
,
corner
);
// 计算拖动向量
var
dragVectorX
=
endX
-
startX
;
var
dragVectorY
=
endY
-
startY
;
// 如果拖动距离太小,返回参考corner
if
(
Math
.
abs
(
dragVectorX
)
<
5
&&
Math
.
abs
(
dragVectorY
)
<
5
)
{
return
{
x
:
referenceCorner
.
x
,
y
:
referenceCorner
.
y
};
}
// 计算拖动线段的中点
var
midX
=
(
startX
+
endX
)
/
2
;
var
midY
=
(
startY
+
endY
)
/
2
;
// 计算从中点到参考corner的垂直向量
// 如果拖动向量是(dx, dy),那么垂直向量是(-dy, dx)或(dy, -dx)
var
perpX
=
-
dragVectorY
;
var
perpY
=
dragVectorX
;
// 归一化垂直向量
var
perpLength
=
Math
.
sqrt
(
perpX
*
perpX
+
perpY
*
perpY
);
if
(
perpLength
>
0
)
{
perpX
=
perpX
/
perpLength
;
perpY
=
perpY
/
perpLength
;
}
// 计算从中点到参考corner的向量
var
toCornerX
=
referenceCorner
.
x
-
midX
;
var
toCornerY
=
referenceCorner
.
y
-
midY
;
// 计算参考corner在垂直线上的投影点(折叠轴上的点)
var
projectionOnPerp
=
toCornerX
*
perpX
+
toCornerY
*
perpY
;
var
axisPointX
=
midX
+
projectionOnPerp
*
perpX
;
var
axisPointY
=
midY
+
projectionOnPerp
*
perpY
;
// 计算参考corner关于折叠轴的对称点
var
symmetricX
=
2
*
axisPointX
-
referenceCorner
.
x
;
var
symmetricY
=
2
*
axisPointY
-
referenceCorner
.
y
;
// 计算折叠强度(基于拖动距离)
var
foldIntensity
=
Math
.
min
(
dragDistance
/
(
Math
.
min
(
width
,
height
)
*
0.4
),
1
);
// 应用最大折叠距离限制
var
maxDistance
=
Math
.
min
(
width
,
height
)
*
maxFoldingDistance
;
var
symmetricDistance
=
Math
.
sqrt
(
Math
.
pow
(
symmetricX
-
referenceCorner
.
x
,
2
)
+
Math
.
pow
(
symmetricY
-
referenceCorner
.
y
,
2
)
);
var
foldX
,
foldY
;
if
(
symmetricDistance
>
maxDistance
&&
symmetricDistance
>
0
)
{
// 限制折叠距离
var
scale
=
maxDistance
/
symmetricDistance
;
foldX
=
referenceCorner
.
x
+
(
symmetricX
-
referenceCorner
.
x
)
*
scale
*
foldIntensity
;
foldY
=
referenceCorner
.
y
+
(
symmetricY
-
referenceCorner
.
y
)
*
scale
*
foldIntensity
;
}
else
{
// 应用折叠强度
foldX
=
referenceCorner
.
x
+
(
symmetricX
-
referenceCorner
.
x
)
*
foldIntensity
;
foldY
=
referenceCorner
.
y
+
(
symmetricY
-
referenceCorner
.
y
)
*
foldIntensity
;
}
// 根据corner类型应用边界限制(这很重要,确保_fold函数能正常工作)
switch
(
corner
)
{
case
'tl'
:
foldX
=
Math
.
max
(
foldX
,
1
);
foldY
=
Math
.
max
(
foldY
,
1
);
break
;
case
'tr'
:
foldX
=
Math
.
min
(
foldX
,
width
-
1
);
foldY
=
Math
.
max
(
foldY
,
1
);
break
;
case
'bl'
:
foldX
=
Math
.
max
(
foldX
,
1
);
foldY
=
Math
.
min
(
foldY
,
height
-
1
);
break
;
case
'br'
:
foldX
=
Math
.
min
(
foldX
,
width
-
1
);
foldY
=
Math
.
min
(
foldY
,
height
-
1
);
break
;
}
// 最终边界检查
foldX
=
Math
.
max
(
0
,
Math
.
min
(
width
,
foldX
));
foldY
=
Math
.
max
(
0
,
Math
.
min
(
height
,
foldY
));
return
{
x
:
foldX
,
y
:
foldY
};
},
disable
:
function
(
disable
)
{
flipMethods
.
setData
.
call
(
this
,
{
'disabled'
:
disable
});
return
this
;
},
_c
:
function
(
corner
,
opts
)
{
opts
=
opts
||
0
;
return
({
tl
:
point2D
(
opts
,
opts
),
tr
:
point2D
(
this
.
width
()
-
opts
,
opts
),
bl
:
point2D
(
opts
,
this
.
height
()
-
opts
),
br
:
point2D
(
this
.
width
()
-
opts
,
this
.
height
()
-
opts
)
})[
corner
];
},
_c2
:
function
(
corner
)
{
return
{
tl
:
point2D
(
this
.
width
()
*
2
,
0
),
tr
:
point2D
(
-
this
.
width
(),
0
),
bl
:
point2D
(
this
.
width
()
*
2
,
this
.
height
()),
br
:
point2D
(
-
this
.
width
(),
this
.
height
())
}[
corner
];
},
_eventEnd
:
function
()
{
_eventEnd
:
function
()
{
var
data
=
this
.
data
().
f
;
var
data
=
this
.
data
().
f
;
...
@@ -1835,13 +2130,6 @@ var has3d,
...
@@ -1835,13 +2130,6 @@ var has3d,
data
.
corner
=
null
;
data
.
corner
=
null
;
},
disable
:
function
(
disable
)
{
flipMethods
.
setData
.
call
(
this
,
{
'disabled'
:
disable
});
return
this
;
}
}
},
},
...
@@ -1855,7 +2143,7 @@ var has3d,
...
@@ -1855,7 +2143,7 @@ var has3d,
throw
args
[
0
]
+
' is an invalid value'
;
throw
args
[
0
]
+
' is an invalid value'
;
};
};
$
.
extend
(
$
.
fn
,
{
$
.
extend
(
$
.
fn
,
{
flip
:
function
(
req
,
opts
)
{
flip
:
function
(
req
,
opts
)
{
return
cla
(
this
,
flipMethods
,
arguments
);
return
cla
(
this
,
flipMethods
,
arguments
);
...
@@ -1925,10 +2213,9 @@ $.extend($.fn, {
...
@@ -1925,10 +2213,9 @@ $.extend($.fn, {
delete
data
[
'effect'
];
delete
data
[
'effect'
];
}
}
}
}
});
});
$
.
isTouch
=
isTouch
;
$
.
isTouch
=
isTouch
;
export
default
$
;
})(
jQuery
)
;
src/components/BookReader/index.vue
浏览文件 @
892f9f9d
...
@@ -154,7 +154,7 @@
...
@@ -154,7 +154,7 @@
<
script
setup
>
<
script
setup
>
import
$
from
"jquery"
;
import
$
from
"jquery"
;
import
turn
from
"@/assets/js/turn.js"
;
import
"@/assets/js/turn.js"
;
// 直接导入执行,扩展 jQuery 对象
import
{
ref
,
onMounted
,
onUnmounted
,
watch
,
nextTick
,
computed
}
from
"vue"
;
import
{
ref
,
onMounted
,
onUnmounted
,
watch
,
nextTick
,
computed
}
from
"vue"
;
import
VueEasyLightbox
from
"vue-easy-lightbox"
;
import
VueEasyLightbox
from
"vue-easy-lightbox"
;
import
GuideMobile
from
"../GuideMobile/index.vue"
;
import
GuideMobile
from
"../GuideMobile/index.vue"
;
...
@@ -395,6 +395,12 @@ const initBook = async () => {
...
@@ -395,6 +395,12 @@ const initBook = async () => {
height
:
pageHeight
,
height
:
pageHeight
,
display
:
isMobile
.
value
?
"single"
:
"double"
,
display
:
isMobile
.
value
?
"single"
:
"double"
,
acceleration
:
true
,
acceleration
:
true
,
// 启用非corner区域翻页
enableNonCorner
:
true
,
// 最大折叠距离比例 (0.1 - 1.0)
maxFoldingDistance
:
0.6
,
// 最小拖拽距离触发翻页
minDragDistance
:
30
,
gradients
:
true
,
gradients
:
true
,
elevation
:
80
,
elevation
:
80
,
duration
:
isMobile
.
value
?
200
:
600
,
duration
:
isMobile
.
value
?
200
:
600
,
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论