Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
AI_BOOK_TOOL
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
template admin
AI_BOOK_TOOL
Commits
c0996581
Commit
c0996581
authored
Jun 19, 2025
by
15011343103
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 字幕逐字高亮
parent
243286c8
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
116 additions
and
1 deletion
+116
-1
index.css
play/index.css
+39
-0
index.html
play/index.html
+19
-1
index.js
play/index.js
+58
-0
No files found.
play/index.css
View file @
c0996581
...
...
@@ -193,6 +193,26 @@ body::-webkit-scrollbar, html::-webkit-scrollbar {
line-height
:
1.5
;
}
.subtitle-text
span
{
display
:
inline-block
;
margin
:
0
8px
;
transition
:
all
0.2s
ease
;
}
.subtitle-text
.highlighted-word
{
color
:
#ffeb3b
;
text-shadow
:
0
0
10px
rgba
(
255
,
235
,
59
,
0.8
);
transform
:
scale
(
1.05
);
font-weight
:
900
;
animation
:
wordPulse
0.5s
ease-in-out
;
}
@keyframes
wordPulse
{
0
%
{
transform
:
scale
(
1
);
}
50
%
{
transform
:
scale
(
1.1
);
}
100
%
{
transform
:
scale
(
1.05
);
}
}
.controls
{
display
:
flex
;
justify-content
:
center
;
...
...
@@ -219,3 +239,22 @@ body::-webkit-scrollbar, html::-webkit-scrollbar {
max-width
:
300px
;
}
}
/* 调试面板样式 */
.debug-panel
{
position
:
fixed
;
top
:
20px
;
right
:
20px
;
background
:
rgba
(
0
,
0
,
0
,
0.8
);
color
:
#fff
;
padding
:
15px
;
border-radius
:
8px
;
font-size
:
14px
;
z-index
:
100
;
min-width
:
200px
;
}
.debug-info
div
{
margin-bottom
:
5px
;
font-family
:
monospace
;
}
\ No newline at end of file
play/index.html
View file @
c0996581
...
...
@@ -27,7 +27,25 @@
</transition>
</div>
<div
class=
"subtitle-bar"
v-if=
"currentAudioText"
>
<div
class=
"subtitle-text"
>
{{ currentAudioText }}
</div>
<div
class=
"subtitle-text"
>
<span
v-for=
"(word, index) in currentWords"
:key=
"index"
:class=
"{ 'highlighted-word': highlightedWordIndexes.includes(index) }"
>
{{ word.word }}
</span>
</div>
</div>
<!-- 调试面板 -->
<div
class=
"debug-panel"
v-if=
"isPlaying"
>
<div
class=
"debug-info"
>
<div>
时间: {{ debugInfo.currentTime.toFixed(2) }}s
</div>
<div>
单词数: {{ debugInfo.totalWords }}
</div>
<div>
高亮索引: {{ debugInfo.highlightedIndexes.join(', ') }}
</div>
<div>
当前单词: {{ debugInfo.currentWord }}
</div>
</div>
</div>
<div
class=
"fixed-btn-group"
>
<el-button
...
...
play/index.js
View file @
c0996581
...
...
@@ -38,6 +38,9 @@ function initializeApp(data) {
isRectVisible
:
false
,
pageTransition
:
'
slide-left
'
,
needJumpToPageStartOnPlay
:
false
,
// 逐字高亮相关
currentWords
:
[],
highlightedWordIndexes
:
[],
},
computed
:
{
currentGroups
()
{
...
...
@@ -73,6 +76,17 @@ function initializeApp(data) {
width
:
(
r
.
width
*
this
.
imageSize
.
width
)
+
'
px
'
,
height
:
(
r
.
height
*
this
.
imageSize
.
height
)
+
'
px
'
,
};
},
// 调试信息
debugInfo
()
{
if
(
this
.
currentWords
.
length
===
0
)
return
'
无单词数据
'
;
const
currentWord
=
this
.
highlightedWordIndexes
.
length
>
0
?
this
.
currentWords
[
this
.
highlightedWordIndexes
[
0
]]
:
null
;
return
{
currentTime
:
this
.
audio
?
this
.
audio
.
currentTime
:
0
,
totalWords
:
this
.
currentWords
.
length
,
highlightedIndexes
:
this
.
highlightedWordIndexes
,
currentWord
:
currentWord
?
`
${
currentWord
.
word
}
(
${
currentWord
.
start
}
-
${
currentWord
.
end
}
)`
:
'
无
'
};
}
},
watch
:
{
...
...
@@ -173,14 +187,54 @@ function initializeApp(data) {
// 字幕严格跟随 audio_points.points
let
subtitle
=
''
;
let
currentPointIndex
=
-
1
;
let
currentWords
=
[];
let
highlightedWordIndexes
=
[];
for
(
let
i
=
0
;
i
<
this
.
audioPoints
.
length
;
i
++
)
{
const
p
=
this
.
audioPoints
[
i
];
if
(
currentTime
>=
p
.
start
&&
currentTime
<=
p
.
end
)
{
subtitle
=
p
.
text
;
currentPointIndex
=
i
;
currentWords
=
p
.
words
||
[];
// 改进的单词高亮逻辑
if
(
currentWords
.
length
>
0
)
{
// 找到所有时间匹配的单词(允许多个单词同时高亮)
for
(
let
j
=
0
;
j
<
currentWords
.
length
;
j
++
)
{
const
word
=
currentWords
[
j
];
if
(
currentTime
>=
word
.
start
&&
currentTime
<=
word
.
end
)
{
highlightedWordIndexes
.
push
(
j
);
}
}
// 如果没有精确匹配,尝试找到所有在合理时间范围内的单词
if
(
highlightedWordIndexes
.
length
===
0
)
{
for
(
let
j
=
0
;
j
<
currentWords
.
length
;
j
++
)
{
const
word
=
currentWords
[
j
];
const
distanceToStart
=
Math
.
abs
(
currentTime
-
word
.
start
);
const
distanceToEnd
=
Math
.
abs
(
currentTime
-
word
.
end
);
const
minWordDistance
=
Math
.
min
(
distanceToStart
,
distanceToEnd
);
// 如果距离在合理范围内(比如0.3秒内),就高亮这个单词
if
(
minWordDistance
<=
0.3
)
{
highlightedWordIndexes
.
push
(
j
);
}
}
}
// 调试信息
const
highlightedWords
=
highlightedWordIndexes
.
map
(
idx
=>
currentWords
[
idx
]?.
word
).
join
(
'
,
'
);
console
.
log
(
'
当前时间:
'
,
currentTime
,
'
高亮单词索引:
'
,
highlightedWordIndexes
,
'
单词:
'
,
highlightedWords
);
}
break
;
}
}
this
.
currentAudioText
=
subtitle
;
this
.
currentAudioPointIndex
=
currentPointIndex
;
this
.
currentWords
=
currentWords
;
this
.
highlightedWordIndexes
=
highlightedWordIndexes
;
},
handleAudioEnded
()
{
this
.
isPlaying
=
false
;
...
...
@@ -188,6 +242,10 @@ function initializeApp(data) {
this
.
isRectVisible
=
false
;
this
.
activeGroupIndexes
=
[];
this
.
currentPage
=
0
;
// 播放结束后回到第一页
// 重置逐字高亮状态
this
.
currentWords
=
[];
this
.
highlightedWordIndexes
=
[];
this
.
currentAudioPointIndex
=
-
1
;
},
togglePlay
()
{
if
(
this
.
isPlaying
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment