mirror of
https://github.com/timeshiftsauce/CeruMusic.git
synced 2025-11-25 03:15:07 +08:00
1587 lines
171 KiB
HTML
1587 lines
171 KiB
HTML
<!doctype html>
|
||
<html>
|
||
<head>
|
||
<meta charset='UTF-8'><meta name='viewport' content='width=device-width initial-scale=1'>
|
||
|
||
<style type='text/css'>html {overflow-x: initial !important;}:root { --bg-color:#ffffff; --text-color:#333333; --select-text-bg-color:#B5D6FC; --select-text-font-color:auto; --monospace:"Lucida Console",Consolas,"Courier",monospace; --title-bar-height:20px; }
|
||
.mac-os-11 { --title-bar-height:28px; }
|
||
html { font-size: 14px; background-color: var(--bg-color); color: var(--text-color); font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; }
|
||
body { margin: 0px; padding: 0px; height: auto; inset: 0px; font-size: 1rem; line-height: 1.42857; overflow-x: hidden; background: inherit; tab-size: 4; }
|
||
iframe { margin: auto; }
|
||
a.url { word-break: break-all; }
|
||
a:active, a:hover { outline: 0px; }
|
||
.in-text-selection, ::selection { text-shadow: none; background: var(--select-text-bg-color); color: var(--select-text-font-color); }
|
||
#write { margin: 0px auto; height: auto; width: inherit; word-break: normal; overflow-wrap: break-word; position: relative; white-space: normal; overflow-x: visible; padding-top: 36px; }
|
||
#write.first-line-indent p { text-indent: 2em; }
|
||
#write.first-line-indent li p, #write.first-line-indent p * { text-indent: 0px; }
|
||
#write.first-line-indent li { margin-left: 2em; }
|
||
.for-image #write { padding-left: 8px; padding-right: 8px; }
|
||
body.typora-export { padding-left: 30px; padding-right: 30px; }
|
||
.typora-export .footnote-line, .typora-export li, .typora-export p { white-space: pre-wrap; }
|
||
.typora-export .task-list-item input { pointer-events: none; }
|
||
@media screen and (max-width: 500px) {
|
||
body.typora-export { padding-left: 0px; padding-right: 0px; }
|
||
#write { padding-left: 20px; padding-right: 20px; }
|
||
}
|
||
#write li > figure:last-child { margin-bottom: 0.5rem; }
|
||
#write ol, #write ul { position: relative; }
|
||
img { max-width: 100%; vertical-align: middle; image-orientation: from-image; }
|
||
button, input, select, textarea { color: inherit; font: inherit; }
|
||
input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }
|
||
*, ::after, ::before { box-sizing: border-box; }
|
||
#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p, #write pre { width: inherit; }
|
||
#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p { position: relative; }
|
||
p { line-height: inherit; }
|
||
h1, h2, h3, h4, h5, h6 { break-after: avoid-page; break-inside: avoid; orphans: 4; }
|
||
p { orphans: 4; }
|
||
h1 { font-size: 2rem; }
|
||
h2 { font-size: 1.8rem; }
|
||
h3 { font-size: 1.6rem; }
|
||
h4 { font-size: 1.4rem; }
|
||
h5 { font-size: 1.2rem; }
|
||
h6 { font-size: 1rem; }
|
||
.md-math-block, .md-rawblock, h1, h2, h3, h4, h5, h6, p { margin-top: 1rem; margin-bottom: 1rem; }
|
||
.hidden { display: none; }
|
||
.md-blockmeta { color: rgb(204, 204, 204); font-weight: 700; font-style: italic; }
|
||
a { cursor: pointer; }
|
||
sup.md-footnote { padding: 2px 4px; background-color: rgba(238, 238, 238, 0.7); color: rgb(85, 85, 85); border-radius: 4px; cursor: pointer; }
|
||
sup.md-footnote a, sup.md-footnote a:hover { color: inherit; text-transform: inherit; text-decoration: inherit; }
|
||
#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; }
|
||
figure { overflow-x: auto; margin: 1.2em 0px; max-width: calc(100% + 16px); padding: 0px; }
|
||
figure > table { margin: 0px; }
|
||
thead, tr { break-inside: avoid; break-after: auto; }
|
||
thead { display: table-header-group; }
|
||
table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; text-align: left; }
|
||
table.md-table td { min-width: 32px; }
|
||
.CodeMirror-gutters { border-right: 0px; background-color: inherit; }
|
||
.CodeMirror-linenumber { user-select: none; }
|
||
.CodeMirror { text-align: left; }
|
||
.CodeMirror-placeholder { opacity: 0.3; }
|
||
.CodeMirror pre { padding: 0px 4px; }
|
||
.CodeMirror-lines { padding: 0px; }
|
||
div.hr:focus { cursor: none; }
|
||
#write pre { white-space: pre-wrap; }
|
||
#write.fences-no-line-wrapping pre { white-space: pre; }
|
||
#write pre.ty-contain-cm { white-space: normal; }
|
||
.CodeMirror-gutters { margin-right: 4px; }
|
||
.md-fences { font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; overflow: visible; white-space: pre; background: inherit; position: relative !important; }
|
||
.md-fences-adv-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; }
|
||
#write .md-fences.mock-cm { white-space: pre-wrap; }
|
||
.md-fences.md-fences-with-lineno { padding-left: 0px; }
|
||
#write.fences-no-line-wrapping .md-fences.mock-cm { white-space: pre; overflow-x: auto; }
|
||
.md-fences.mock-cm.md-fences-with-lineno { padding-left: 8px; }
|
||
.CodeMirror-line, twitterwidget { break-inside: avoid; }
|
||
svg { break-inside: avoid; }
|
||
.footnotes { opacity: 0.8; font-size: 0.9rem; margin-top: 1em; margin-bottom: 1em; }
|
||
.footnotes + .footnotes { margin-top: 0px; }
|
||
.md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; background: 0px 0px; text-decoration: none; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; -webkit-tap-highlight-color: transparent; line-height: normal; font-weight: 400; text-align: left; box-sizing: content-box; direction: ltr; }
|
||
li div { padding-top: 0px; }
|
||
blockquote { margin: 1rem 0px; }
|
||
li .mathjax-block, li p { margin: 0.5rem 0px; }
|
||
li blockquote { margin: 1rem 0px; }
|
||
li { margin: 0px; position: relative; }
|
||
blockquote > :last-child { margin-bottom: 0px; }
|
||
blockquote > :first-child, li > :first-child { margin-top: 0px; }
|
||
.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; white-space: normal; }
|
||
#write .footnote-line { white-space: pre-wrap; }
|
||
@media print {
|
||
body, html { border: 1px solid transparent; height: 99%; break-after: avoid; break-before: avoid; font-variant-ligatures: no-common-ligatures; }
|
||
#write { margin-top: 0px; padding-top: 0px; border-color: transparent !important; padding-bottom: 0px !important; }
|
||
.typora-export * { -webkit-print-color-adjust: exact; }
|
||
.typora-export #write { break-after: avoid; }
|
||
.typora-export #write::after { height: 0px; }
|
||
.is-mac table { break-inside: avoid; }
|
||
.typora-export-show-outline .typora-export-sidebar { display: none; }
|
||
}
|
||
.footnote-line { margin-top: 0.714em; font-size: 0.7em; }
|
||
a img, img a { cursor: pointer; }
|
||
pre.md-meta-block { font-size: 0.8rem; min-height: 0.8rem; white-space: pre-wrap; background: rgb(204, 204, 204); display: block; overflow-x: hidden; }
|
||
p > .md-image:only-child:not(.md-img-error) img, p > img:only-child { display: block; margin: auto; }
|
||
#write.first-line-indent p > .md-image:only-child:not(.md-img-error) img { left: -2em; position: relative; }
|
||
p > .md-image:only-child { display: inline-block; width: 100%; }
|
||
#write .MathJax_Display { margin: 0.8em 0px 0px; }
|
||
.md-math-block { width: 100%; }
|
||
.md-math-block:not(:empty)::after { display: none; }
|
||
.MathJax_ref { fill: currentcolor; }
|
||
[contenteditable="true"]:active, [contenteditable="true"]:focus, [contenteditable="false"]:active, [contenteditable="false"]:focus { outline: 0px; box-shadow: none; }
|
||
.md-task-list-item { position: relative; list-style-type: none; }
|
||
.task-list-item.md-task-list-item { padding-left: 0px; }
|
||
.md-task-list-item > input { position: absolute; top: 0px; left: 0px; margin-left: -1.2em; margin-top: calc(1em - 10px); border: none; }
|
||
.math { font-size: 1rem; }
|
||
.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-radius: 10px; }
|
||
.md-toc-content { position: relative; margin-left: 0px; }
|
||
.md-toc-content::after, .md-toc::after { display: none; }
|
||
.md-toc-item { display: block; color: rgb(65, 131, 196); }
|
||
.md-toc-item a { text-decoration: none; }
|
||
.md-toc-inner:hover { text-decoration: underline; }
|
||
.md-toc-inner { display: inline-block; cursor: pointer; }
|
||
.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: 700; }
|
||
.md-toc-h2 .md-toc-inner { margin-left: 2em; }
|
||
.md-toc-h3 .md-toc-inner { margin-left: 4em; }
|
||
.md-toc-h4 .md-toc-inner { margin-left: 6em; }
|
||
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
|
||
.md-toc-h6 .md-toc-inner { margin-left: 10em; }
|
||
@media screen and (max-width: 48em) {
|
||
.md-toc-h3 .md-toc-inner { margin-left: 3.5em; }
|
||
.md-toc-h4 .md-toc-inner { margin-left: 5em; }
|
||
.md-toc-h5 .md-toc-inner { margin-left: 6.5em; }
|
||
.md-toc-h6 .md-toc-inner { margin-left: 8em; }
|
||
}
|
||
a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; }
|
||
.footnote-line a:not(.reversefootnote) { color: inherit; }
|
||
.reversefootnote { font-family: ui-monospace, sans-serif; }
|
||
.md-attr { display: none; }
|
||
.md-fn-count::after { content: "."; }
|
||
code, pre, samp, tt { font-family: var(--monospace); }
|
||
kbd { margin: 0px 0.1em; padding: 0.1em 0.6em; font-size: 0.8em; color: rgb(36, 39, 41); background: rgb(255, 255, 255); border: 1px solid rgb(173, 179, 185); border-radius: 3px; box-shadow: rgba(12, 13, 14, 0.2) 0px 1px 0px, rgb(255, 255, 255) 0px 0px 0px 2px inset; white-space: nowrap; vertical-align: middle; }
|
||
.md-comment { color: rgb(162, 127, 3); opacity: 0.6; font-family: var(--monospace); }
|
||
code { text-align: left; vertical-align: initial; }
|
||
a.md-print-anchor { white-space: pre !important; border-width: initial !important; border-style: none !important; border-color: initial !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: 0px !important; background: 0px 0px !important; text-decoration: initial !important; text-shadow: initial !important; }
|
||
.os-windows.monocolor-emoji .md-emoji { font-family: "Segoe UI Symbol", sans-serif; }
|
||
.md-diagram-panel > svg { max-width: 100%; }
|
||
[lang="flow"] svg, [lang="mermaid"] svg { max-width: 100%; height: auto; }
|
||
[lang="mermaid"] .node text { font-size: 1rem; }
|
||
table tr th { border-bottom: 0px; }
|
||
video { max-width: 100%; display: block; margin: 0px auto; }
|
||
iframe { max-width: 100%; width: 100%; border: none; }
|
||
.highlight td, .highlight tr { border: 0px; }
|
||
mark { background: rgb(255, 255, 0); color: rgb(0, 0, 0); }
|
||
.md-html-inline .md-plain, .md-html-inline strong, mark .md-inline-math, mark strong { color: inherit; }
|
||
.md-expand mark .md-meta { opacity: 0.3 !important; }
|
||
mark .md-meta { color: rgb(0, 0, 0); }
|
||
@media print {
|
||
.typora-export h1, .typora-export h2, .typora-export h3, .typora-export h4, .typora-export h5, .typora-export h6 { break-inside: avoid; }
|
||
}
|
||
.md-diagram-panel .messageText { stroke: none !important; }
|
||
.md-diagram-panel .start-state { fill: var(--node-fill); }
|
||
.md-diagram-panel .edgeLabel rect { opacity: 1 !important; }
|
||
.md-fences.md-fences-math { font-size: 1em; }
|
||
.md-fences-advanced:not(.md-focus) { padding: 0px; white-space: nowrap; border: 0px; }
|
||
.md-fences-advanced:not(.md-focus) { background: inherit; }
|
||
.typora-export-show-outline .typora-export-content { max-width: 1440px; margin: auto; display: flex; flex-direction: row; }
|
||
.typora-export-sidebar { width: 300px; font-size: 0.8rem; margin-top: 80px; margin-right: 18px; }
|
||
.typora-export-show-outline #write { --webkit-flex:2; flex: 2 1 0%; }
|
||
.typora-export-sidebar .outline-content { position: fixed; top: 0px; max-height: 100%; overflow: hidden auto; padding-bottom: 30px; padding-top: 60px; width: 300px; }
|
||
@media screen and (max-width: 1024px) {
|
||
.typora-export-sidebar, .typora-export-sidebar .outline-content { width: 240px; }
|
||
}
|
||
@media screen and (max-width: 800px) {
|
||
.typora-export-sidebar { display: none; }
|
||
}
|
||
.outline-content li, .outline-content ul { margin-left: 0px; margin-right: 0px; padding-left: 0px; padding-right: 0px; list-style: none; }
|
||
.outline-content ul { margin-top: 0px; margin-bottom: 0px; }
|
||
.outline-content strong { font-weight: 400; }
|
||
.outline-expander { width: 1rem; height: 1.42857rem; position: relative; display: table-cell; vertical-align: middle; cursor: pointer; padding-left: 4px; }
|
||
.outline-expander::before { content: ""; position: relative; font-family: Ionicons; display: inline-block; font-size: 8px; vertical-align: middle; }
|
||
.outline-item { padding-top: 3px; padding-bottom: 3px; cursor: pointer; }
|
||
.outline-expander:hover::before { content: ""; }
|
||
.outline-h1 > .outline-item { padding-left: 0px; }
|
||
.outline-h2 > .outline-item { padding-left: 1em; }
|
||
.outline-h3 > .outline-item { padding-left: 2em; }
|
||
.outline-h4 > .outline-item { padding-left: 3em; }
|
||
.outline-h5 > .outline-item { padding-left: 4em; }
|
||
.outline-h6 > .outline-item { padding-left: 5em; }
|
||
.outline-label { cursor: pointer; display: table-cell; vertical-align: middle; text-decoration: none; color: inherit; }
|
||
.outline-label:hover { text-decoration: underline; }
|
||
.outline-item:hover { border-color: rgb(245, 245, 245); background-color: var(--item-hover-bg-color); }
|
||
.outline-item:hover { margin-left: -28px; margin-right: -28px; border-left: 28px solid transparent; border-right: 28px solid transparent; }
|
||
.outline-item-single .outline-expander::before, .outline-item-single .outline-expander:hover::before { display: none; }
|
||
.outline-item-open > .outline-item > .outline-expander::before { content: ""; }
|
||
.outline-children { display: none; }
|
||
.info-panel-tab-wrapper { display: none; }
|
||
.outline-item-open > .outline-children { display: block; }
|
||
.typora-export .outline-item { padding-top: 1px; padding-bottom: 1px; }
|
||
.typora-export .outline-item:hover { margin-right: -8px; border-right: 8px solid transparent; }
|
||
.typora-export .outline-expander::before { content: "+"; font-family: inherit; top: -1px; }
|
||
.typora-export .outline-expander:hover::before, .typora-export .outline-item-open > .outline-item > .outline-expander::before { content: "−"; }
|
||
.typora-export-collapse-outline .outline-children { display: none; }
|
||
.typora-export-collapse-outline .outline-item-open > .outline-children, .typora-export-no-collapse-outline .outline-children { display: block; }
|
||
.typora-export-no-collapse-outline .outline-expander::before { content: "" !important; }
|
||
.typora-export-show-outline .outline-item-active > .outline-item .outline-label { font-weight: 700; }
|
||
.md-inline-math-container mjx-container { zoom: 0.95; }
|
||
|
||
|
||
.CodeMirror { height: auto; }
|
||
.CodeMirror.cm-s-inner { background: inherit; }
|
||
.CodeMirror-scroll { overflow: auto hidden; z-index: 3; }
|
||
.CodeMirror-gutter-filler, .CodeMirror-scrollbar-filler { background-color: rgb(255, 255, 255); }
|
||
.CodeMirror-gutters { border-right: 1px solid rgb(221, 221, 221); background: inherit; white-space: nowrap; }
|
||
.CodeMirror-linenumber { padding: 0px 3px 0px 5px; text-align: right; color: rgb(153, 153, 153); }
|
||
.cm-s-inner .cm-keyword { color: rgb(119, 0, 136); }
|
||
.cm-s-inner .cm-atom, .cm-s-inner.cm-atom { color: rgb(34, 17, 153); }
|
||
.cm-s-inner .cm-number { color: rgb(17, 102, 68); }
|
||
.cm-s-inner .cm-def { color: rgb(0, 0, 255); }
|
||
.cm-s-inner .cm-variable { color: rgb(0, 0, 0); }
|
||
.cm-s-inner .cm-variable-2 { color: rgb(0, 85, 170); }
|
||
.cm-s-inner .cm-variable-3 { color: rgb(0, 136, 85); }
|
||
.cm-s-inner .cm-string { color: rgb(170, 17, 17); }
|
||
.cm-s-inner .cm-property { color: rgb(0, 0, 0); }
|
||
.cm-s-inner .cm-operator { color: rgb(152, 26, 26); }
|
||
.cm-s-inner .cm-comment, .cm-s-inner.cm-comment { color: rgb(170, 85, 0); }
|
||
.cm-s-inner .cm-string-2 { color: rgb(255, 85, 0); }
|
||
.cm-s-inner .cm-meta { color: rgb(85, 85, 85); }
|
||
.cm-s-inner .cm-qualifier { color: rgb(85, 85, 85); }
|
||
.cm-s-inner .cm-builtin { color: rgb(51, 0, 170); }
|
||
.cm-s-inner .cm-bracket { color: rgb(153, 153, 119); }
|
||
.cm-s-inner .cm-tag { color: rgb(17, 119, 0); }
|
||
.cm-s-inner .cm-attribute { color: rgb(0, 0, 204); }
|
||
.cm-s-inner .cm-header, .cm-s-inner.cm-header { color: rgb(0, 0, 255); }
|
||
.cm-s-inner .cm-quote, .cm-s-inner.cm-quote { color: rgb(0, 153, 0); }
|
||
.cm-s-inner .cm-hr, .cm-s-inner.cm-hr { color: rgb(153, 153, 153); }
|
||
.cm-s-inner .cm-link, .cm-s-inner.cm-link { color: rgb(0, 0, 204); }
|
||
.cm-negative { color: rgb(221, 68, 68); }
|
||
.cm-positive { color: rgb(34, 153, 34); }
|
||
.cm-header, .cm-strong { font-weight: 700; }
|
||
.cm-del { text-decoration: line-through; }
|
||
.cm-em { font-style: italic; }
|
||
.cm-link { text-decoration: underline; }
|
||
.cm-error { color: red; }
|
||
.cm-invalidchar { color: red; }
|
||
.cm-constant { color: rgb(38, 139, 210); }
|
||
.cm-defined { color: rgb(181, 137, 0); }
|
||
div.CodeMirror span.CodeMirror-matchingbracket { color: rgb(0, 255, 0); }
|
||
div.CodeMirror span.CodeMirror-nonmatchingbracket { color: rgb(255, 34, 34); }
|
||
.cm-s-inner .CodeMirror-activeline-background { background: inherit; }
|
||
.CodeMirror { position: relative; overflow: hidden; }
|
||
.CodeMirror-scroll { height: 100%; outline: 0px; position: relative; box-sizing: content-box; background: inherit; }
|
||
.CodeMirror-sizer { position: relative; }
|
||
.CodeMirror-gutter-filler, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-vscrollbar { position: absolute; z-index: 6; display: none; outline: 0px; }
|
||
.CodeMirror-vscrollbar { right: 0px; top: 0px; overflow: hidden; }
|
||
.CodeMirror-hscrollbar { bottom: 0px; left: 0px; overflow: auto hidden; }
|
||
.CodeMirror-scrollbar-filler { right: 0px; bottom: 0px; }
|
||
.CodeMirror-gutter-filler { left: 0px; bottom: 0px; }
|
||
.CodeMirror-gutters { position: absolute; left: 0px; top: 0px; padding-bottom: 10px; z-index: 3; overflow-y: hidden; }
|
||
.CodeMirror-gutter { white-space: normal; height: 100%; box-sizing: content-box; padding-bottom: 30px; margin-bottom: -32px; display: inline-block; }
|
||
.CodeMirror-gutter-wrapper { position: absolute; z-index: 4; background: 0px 0px !important; border: none !important; }
|
||
.CodeMirror-gutter-background { position: absolute; top: 0px; bottom: 0px; z-index: 4; }
|
||
.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; }
|
||
.CodeMirror-lines { cursor: text; }
|
||
.CodeMirror pre { border-radius: 0px; border-width: 0px; background: 0px 0px; font-family: inherit; font-size: inherit; margin: 0px; white-space: pre; overflow-wrap: normal; color: inherit; z-index: 2; position: relative; overflow: visible; }
|
||
.CodeMirror-wrap pre { overflow-wrap: break-word; white-space: pre-wrap; word-break: normal; }
|
||
.CodeMirror-code pre { border-right: 30px solid transparent; width: fit-content; }
|
||
.CodeMirror-wrap .CodeMirror-code pre { border-right: none; width: auto; }
|
||
.CodeMirror-linebackground { position: absolute; inset: 0px; z-index: 0; }
|
||
.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; }
|
||
.CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; }
|
||
.CodeMirror-measure { position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden; }
|
||
.CodeMirror-measure pre { position: static; }
|
||
.CodeMirror div.CodeMirror-cursor { position: absolute; visibility: hidden; border-right: none; width: 0px; }
|
||
.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
|
||
.CodeMirror-focused div.CodeMirror-cursor { visibility: inherit; }
|
||
.cm-searching { background: rgba(255, 255, 0, 0.4); }
|
||
span.cm-underlined { text-decoration: underline; }
|
||
span.cm-strikethrough { text-decoration: line-through; }
|
||
.cm-tw-syntaxerror { color: rgb(255, 255, 255); background-color: rgb(153, 0, 0); }
|
||
.cm-tw-deleted { text-decoration: line-through; }
|
||
.cm-tw-header5 { font-weight: 700; }
|
||
.cm-tw-listitem:first-child { padding-left: 10px; }
|
||
.cm-tw-box { border-style: solid; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-color: inherit; border-top-width: 0px !important; }
|
||
.cm-tw-underline { text-decoration: underline; }
|
||
@media print {
|
||
.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
|
||
}
|
||
|
||
|
||
/* 待完善 */
|
||
/**
|
||
* 1. 代码非等宽字体;
|
||
* 2. kbd样式
|
||
* 3. 行内代码样式优化
|
||
*/
|
||
|
||
/* 字体引入:鸿蒙字体 */
|
||
|
||
html {
|
||
font-size: 16px;
|
||
font-family: "HarmonyOS_Sans_SC";
|
||
}
|
||
|
||
/* 打印页面设置 */
|
||
|
||
@media print {
|
||
* {
|
||
-webkit-print-color-adjust: exact;
|
||
/*确保打印颜色一致*/
|
||
print-color-adjust: exact;
|
||
}
|
||
|
||
body {
|
||
width: 21cm;
|
||
/* 设置页面宽度为A4宽度 */
|
||
height: 29.7cm;
|
||
/* 设置页面高度为A4高度 */
|
||
margin: 1cm;
|
||
/* 设置页面边距 */
|
||
}
|
||
|
||
p {
|
||
line-height: 1.5rem;
|
||
/*设置打印内容的行高*/
|
||
}
|
||
|
||
ol,
|
||
ul,
|
||
figure,
|
||
pre {
|
||
/*设置一些元素不会被分页截断对应有序列表、无序列表、图片(表格)、代码块*/
|
||
page-break-inside: avoid;
|
||
break-inside: avoid;
|
||
}
|
||
}
|
||
|
||
/* 软件内部Markdown样式 */
|
||
#write {
|
||
max-width: 950px;
|
||
margin: 0 auto;
|
||
padding: 15px;
|
||
line-height: 2.25;
|
||
color: #000;
|
||
letter-spacing: 1.1px;
|
||
word-break: break-word;
|
||
word-wrap: break-word;
|
||
text-align: left;
|
||
background-image: linear-gradient(90deg,
|
||
rgba(50, 0, 0, 0.05) calc(3% * var(--bg-grid)),
|
||
rgba(0, 0, 0, 0) calc(3% * var(--bg-grid))),
|
||
linear-gradient(360deg,
|
||
rgba(50, 0, 0, 0.05) calc(3% * var(--bg-grid)),
|
||
rgba(0, 0, 0, 0) calc(3% * var(--bg-grid)));
|
||
background-size: 20px 20px;
|
||
background-position: center center;
|
||
}
|
||
|
||
#write p {
|
||
color: #333;
|
||
margin: 10px 10px;
|
||
font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light,
|
||
"PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;
|
||
|
||
font-size: 1rem;
|
||
word-spacing: 2px;
|
||
}
|
||
|
||
#write h3:after,
|
||
h4:after,
|
||
h5:after,
|
||
h6:after {
|
||
content: "";
|
||
display: inline-block;
|
||
margin-left: 0.2em;
|
||
height: 2em;
|
||
width: 1.2em;
|
||
vertical-align: top;
|
||
}
|
||
|
||
#write h3:after {
|
||
background: var(--h3-r-graphic);
|
||
}
|
||
|
||
#write h4:after {
|
||
background: var(--h4-r-graphic);
|
||
}
|
||
|
||
#write h5:after {
|
||
background: var(--h5-r-graphic);
|
||
}
|
||
|
||
#write h6:after {
|
||
background: var(--h6-r-graphic);
|
||
}
|
||
|
||
/* 一级标题 */
|
||
#write h1:after {
|
||
font-size: 1.8rem;
|
||
text-align: center;
|
||
font-weight: bold;
|
||
color: #000;
|
||
border-bottom: none;
|
||
}
|
||
|
||
#write h1 {
|
||
text-align: center;
|
||
}
|
||
|
||
/* 二级标题 */
|
||
#write h2 {
|
||
color: var(--head-title-h2-color);
|
||
font-size: 1.4rem;
|
||
line-height: 1.6;
|
||
width: fit-content;
|
||
font-weight: bold;
|
||
margin: 20px 0;
|
||
padding: 1px 12.5px;
|
||
border-radius: 4px;
|
||
background: var(--head-title-h2-background);
|
||
background-size: 200% 100%;
|
||
background-position: 0% 0%;
|
||
transition: all ease-in-out 0.1s;
|
||
}
|
||
|
||
#write h2.md-heading a {
|
||
text-decoration: underline;
|
||
border-bottom: 0;
|
||
text-decoration-thickness: 1.2px;
|
||
text-underline-offset: 2px;
|
||
}
|
||
|
||
#write h2:hover {
|
||
background-position: -100% -100%;
|
||
transition: all ease-in-out 0.1s;
|
||
}
|
||
|
||
/* 三级标题 */
|
||
#write h3 {
|
||
width: fit-content;
|
||
margin: 20px 0;
|
||
font-size: 1.3rem;
|
||
text-align: left;
|
||
padding-left: 10px;
|
||
border-left: 5px solid var(--head-title-color);
|
||
}
|
||
|
||
/* 三级标题内容 */
|
||
#write h3 span {
|
||
border-bottom: 2px hidden var(--head-title-color);
|
||
}
|
||
|
||
/* #write h3 span:hover {
|
||
border-bottom: 2px solid var(--head-title-color);
|
||
transition: all linear 0.1s;
|
||
} */
|
||
|
||
#write h4 {
|
||
margin: 20px 0;
|
||
font-size: 1.15rem;
|
||
text-align: left;
|
||
}
|
||
|
||
#write h4::before {
|
||
content: "";
|
||
margin-right: 7px;
|
||
display: inline-block;
|
||
background-color: var(--head-title-color);
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 100%;
|
||
border: var(--head-title-color) 1px solid;
|
||
vertical-align: inherit;
|
||
}
|
||
|
||
#write h5 {
|
||
margin: 23px 0;
|
||
font-size: 1.1rem;
|
||
text-align: left;
|
||
}
|
||
|
||
#write h5::before {
|
||
content: "";
|
||
margin-right: 7px;
|
||
display: inline-block;
|
||
background-color: #ffffff;
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 100%;
|
||
border: var(--head-title-color) 2px solid;
|
||
vertical-align: inherit;
|
||
}
|
||
|
||
#write h6 {
|
||
margin: 23px 0;
|
||
font-size: 1.1rem;
|
||
text-align: left;
|
||
}
|
||
|
||
#write h6::before {
|
||
content: "-";
|
||
color: var(--head-title-color);
|
||
margin-right: 7px;
|
||
display: inline-block;
|
||
vertical-align: inherit;
|
||
}
|
||
|
||
/* 标题自动编号 */
|
||
#write {
|
||
counter-reset: h1;
|
||
}
|
||
|
||
h1 {
|
||
counter-reset: h2;
|
||
}
|
||
|
||
h2 {
|
||
counter-reset: h3;
|
||
}
|
||
|
||
h3 {
|
||
counter-reset: h4;
|
||
}
|
||
|
||
h4 {
|
||
counter-reset: h5;
|
||
}
|
||
|
||
h5 {
|
||
counter-reset: h6;
|
||
}
|
||
|
||
.sidebar-content {
|
||
counter-reset: h1
|
||
}
|
||
.outline-content {
|
||
counter-reset: h1
|
||
}
|
||
.outline-h1 {
|
||
counter-reset: h2
|
||
}
|
||
|
||
.outline-h2 {
|
||
counter-reset: h3
|
||
}
|
||
|
||
.outline-h3 {
|
||
counter-reset: h4
|
||
}
|
||
|
||
.outline-h4 {
|
||
counter-reset: h5
|
||
}
|
||
|
||
.outline-h5 {
|
||
counter-reset: h6
|
||
}
|
||
|
||
|
||
|
||
.md-toc-content {
|
||
counter-reset: h1toc
|
||
}
|
||
|
||
.md-toc-h1 {
|
||
counter-reset: h2toc
|
||
}
|
||
|
||
.md-toc-h2 {
|
||
counter-reset: h3toc
|
||
}
|
||
|
||
.md-toc-h3 {
|
||
counter-reset: h4toc
|
||
}
|
||
|
||
.md-toc-h4 {
|
||
counter-reset: h5toc
|
||
}
|
||
|
||
.md-toc-h5 {
|
||
counter-reset: h6toc
|
||
}
|
||
|
||
|
||
#write h1:before {
|
||
counter-increment: h1;
|
||
content: var(--autonum-h1);
|
||
}
|
||
#outline-content li.outline-h1>div>span.outline-label:before {
|
||
counter-increment: h1;
|
||
content: var(--autonum-h1);
|
||
}
|
||
.outline-content .outline-h1>.outline-item>.outline-label:before{
|
||
counter-increment: h1;
|
||
content: var(--autonum-h1);
|
||
}
|
||
#write span.md-toc-item.md-toc-h1>a:before {
|
||
counter-increment: h1toc;
|
||
content: var(--autonum-h1toc);
|
||
}
|
||
|
||
#write h2:before {
|
||
counter-increment: h2;
|
||
content: var(--autonum-h2);
|
||
color: var(--head-title-h2-color);
|
||
}
|
||
.outline-content .outline-h2>.outline-item>.outline-label:before {
|
||
counter-increment: h2;
|
||
content: var(--autonum-h2);
|
||
}
|
||
li.outline-h2>div>a.outline-label:before {
|
||
counter-increment: h2;
|
||
content: var(--autonum-h2);
|
||
}
|
||
|
||
#write span.md-toc-item.md-toc-h2>a:before {
|
||
counter-increment: h2toc;
|
||
content: var(--autonum-h2toc);
|
||
}
|
||
|
||
|
||
#write h3>span:first-of-type::before {
|
||
counter-increment: h3;
|
||
content: var(--autonum-h3);
|
||
color: var(--element-color);
|
||
}
|
||
#outline-content li.outline-h3>div>span.outline-label:before {
|
||
counter-increment: h3;
|
||
content: var(--autonum-h3);
|
||
}
|
||
.outline-content .outline-h3>.outline-item>.outline-label:before {
|
||
counter-increment: h3;
|
||
content: var(--autonum-h3);
|
||
}
|
||
#write span.md-toc-item.md-toc-h3>a:before {
|
||
counter-increment: h3toc;
|
||
content: var(--autonum-h3toc);
|
||
}
|
||
|
||
|
||
#write h4>span:first-of-type::before {
|
||
counter-increment: h4;
|
||
content: var(--autonum-h4);
|
||
color: var(--element-color);
|
||
}
|
||
#outline-content li.outline-h4>div>span.outline-label:before {
|
||
counter-increment: h4;
|
||
content: var(--autonum-h4);
|
||
}
|
||
.outline-content .outline-h4>.outline-item>.outline-label:before {
|
||
counter-increment: h4;
|
||
content: var(--autonum-h4);
|
||
}
|
||
#write span.md-toc-item.md-toc-h4>a:before {
|
||
counter-increment: h4toc;
|
||
content: var(--autonum-h4toc);
|
||
}
|
||
|
||
|
||
#write h5>span:first-of-type::before {
|
||
counter-increment: h5;
|
||
content: var(--autonum-h5);
|
||
color: var(--element-color);
|
||
}
|
||
#outline-content li.outline-h5>div>span.outline-label:before {
|
||
counter-increment: h5;
|
||
content: var(--autonum-h5);
|
||
}
|
||
.outline-content .outline-h5>.outline-item>.outline-label:before {
|
||
counter-increment: h5;
|
||
content: var(--autonum-h5);
|
||
}
|
||
#write span.md-toc-item.md-toc-h5>a:before {
|
||
counter-increment: h5toc;
|
||
content: var(--autonum-h5toc);
|
||
}
|
||
|
||
|
||
#write h6>span:first-of-type::before {
|
||
counter-increment: h6;
|
||
content: var(--autonum-h6);
|
||
color: var(--element-color);
|
||
}
|
||
#outline-content li.outline-h6>div>span.outline-label:before {
|
||
counter-increment: h6;
|
||
content: var(--autonum-h6);
|
||
}
|
||
.outline-content .outline-h6>.outline-item>.outline-label:before {
|
||
counter-increment: h6;
|
||
content: var(--autonum-h6);
|
||
}
|
||
#write span.md-toc-item.md-toc-h6>a:before {
|
||
counter-increment: h6toc;
|
||
content: var(--autonum-h6toc);
|
||
}
|
||
|
||
|
||
/* 列表 */
|
||
::marker {
|
||
color: var(--element-color-deep);
|
||
}
|
||
|
||
li.md-list-item {
|
||
margin: 0.4rem 0;
|
||
}
|
||
|
||
#write ul,
|
||
#write ol {
|
||
margin-top: 0px;
|
||
margin-left: 16px;
|
||
margin-bottom: 8px;
|
||
padding-left: 13px;
|
||
}
|
||
|
||
#write em {
|
||
padding: 0 3px 0 0;
|
||
}
|
||
|
||
#write ul {
|
||
list-style-type: disc;
|
||
}
|
||
|
||
#write ul ul {
|
||
list-style-type: circle;
|
||
}
|
||
|
||
#write ul ul ul {
|
||
list-style-type: square;
|
||
}
|
||
|
||
#write ol {
|
||
list-style-type: decimal;
|
||
}
|
||
|
||
#write ol ol {
|
||
list-style-type: lower-alpha;
|
||
}
|
||
|
||
#write ol ol ol {
|
||
list-style-type: lower-roman;
|
||
}
|
||
|
||
#write li section {
|
||
margin-top: 5px;
|
||
margin-bottom: 5px;
|
||
line-height: 1.7rem;
|
||
text-align: justify;
|
||
color: #000000;
|
||
font-weight: 500;
|
||
}
|
||
|
||
#write li:before {
|
||
content: "";
|
||
height: calc(100% - 50px);
|
||
top: 35px;
|
||
position: absolute;
|
||
border-left: 0.5px solid var(--element-color);
|
||
left: -14.5px;
|
||
}
|
||
|
||
/* 任务列表样式 */
|
||
|
||
.task-list-item input{
|
||
width: 1.25rem;
|
||
height: 1.25rem;
|
||
display: block;
|
||
-webkit-appearance: initial;
|
||
top: 3px;
|
||
left: 4px;
|
||
}
|
||
|
||
.task-list-item input:focus{
|
||
outline: none;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.task-list-item input:before{
|
||
border: 1px solid var(--element-color-deep);
|
||
border-radius: 1.2rem;
|
||
width: 1.2rem;
|
||
height: 1.2rem;
|
||
background: #fff;
|
||
content: ' ';
|
||
transition: background-color 200ms ease-in-out;
|
||
display: block;
|
||
}
|
||
|
||
.task-list-item input:checked:before,
|
||
.task-list-item input[checked]:before{
|
||
background: var(--element-color-soo-shallow);
|
||
border-width: 2px;
|
||
display:inline-block;
|
||
transition: background-color 200ms ease-in-out;
|
||
}
|
||
|
||
.task-list-item input:checked:after,
|
||
.task-list-item input[checked]:after {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* .task-list-item input[type="checkbox"]:checked + p span {
|
||
text-decoration: line-through;
|
||
text-decoration-color:var(--element-color)
|
||
} */
|
||
|
||
.task-list-item input[type="checkbox"] + p span {
|
||
position: relative;
|
||
display: inline-block;
|
||
}
|
||
|
||
.task-list-item input[type="checkbox"] + p span::after {
|
||
content: "";
|
||
position: absolute;
|
||
left: 0;
|
||
top: 52%;
|
||
width: calc(100%*var(--check-line));
|
||
height: 2px;
|
||
background: var(--element-color);
|
||
transform: scaleX(0);
|
||
transform-origin: left center;
|
||
transition: transform 0.2s ease-in-out;
|
||
}
|
||
|
||
.task-list-item input[type="checkbox"]:checked + p span::after {
|
||
transform: scaleX(1);
|
||
}
|
||
|
||
.task-list-item input[type="checkbox"]:not(:checked) + p span::after {
|
||
transform-origin: right center;
|
||
transition-delay: 0.1s;
|
||
}
|
||
|
||
.task-list-item input:after {
|
||
opacity: 1;
|
||
-webkit-transition: opacity 0.05s ease-in-out;
|
||
-moz-transition: opacity 0.05s ease-in-out;
|
||
transition: opacity 0.05s ease-in-out;
|
||
-webkit-transform: rotate(-45deg);
|
||
-moz-transform: rotate(-45deg);
|
||
transform: rotate(-45deg);
|
||
position: absolute;
|
||
top: 0.325rem;
|
||
left: 0.28125rem;
|
||
width: 0.6375rem;
|
||
height: 0.4rem;
|
||
border: 3px solid var(--element-color-deep);
|
||
border-top: 0;
|
||
border-right: 0;
|
||
content: ' ';
|
||
opacity: 0;
|
||
}
|
||
|
||
/* 引用 */
|
||
|
||
#write blockquote {
|
||
margin-left: 12px;
|
||
padding: 12px;
|
||
background: var(--element-color-soo-shallow);
|
||
border: 0px solid var(--element-color);
|
||
border-left-color: var(--element-color);
|
||
border-left-width: 4px;
|
||
border-radius: 4px;
|
||
line-height: 26px;
|
||
}
|
||
|
||
#write blockquote p {
|
||
color: #000;
|
||
}
|
||
|
||
/* 超链接 */
|
||
#write a {
|
||
color: #000;
|
||
}
|
||
|
||
#write a:visited {
|
||
color: var(--element-color-deep);
|
||
}
|
||
|
||
#write a:not(.md-toc-inner) {
|
||
font-weight: bolder;
|
||
text-decoration: none;
|
||
transform: all linear 0.1s;
|
||
}
|
||
|
||
#write a:hover:not(.md-toc-inner) {
|
||
font-weight: bold;
|
||
color: var(--element-color-deep);
|
||
border-bottom: 1px solid var(--element-color-deep);
|
||
transform: all linear 0.1s;
|
||
}
|
||
|
||
#write p a:not(.md-toc-inner)::before {
|
||
content: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024'%3E%3Cpath d='M477.934459 330.486594A50.844091 50.844091 0 0 1 406.752731 258.796425L512 152.532274a254.220457 254.220457 0 0 1 359.467726 359.467726L762.66137 618.772592a50.844091 50.844091 0 1 1-71.690168-71.690169l106.772591-106.772592a152.532274 152.532274 0 0 0-215.578947-215.578947z m70.164846 361.501489A50.844091 50.844091 0 1 1 619.789474 762.66137l-107.281033 107.281033A254.220457 254.220457 0 0 1 152.532274 512L259.813307 406.752731a50.844091 50.844091 0 1 1 72.19861 69.656405l-107.789474 107.281033a152.532274 152.532274 0 0 0 215.578947 215.578947z m-126.601788-16.77855a50.844091 50.844091 0 1 1-71.690168-71.690169l251.678252-251.678252a50.844091 50.844091 0 0 1 71.690169 71.690169z'/%3E%3C/svg%3E");
|
||
color: #f68800;
|
||
display: inline-block;
|
||
width: 1em;
|
||
height: 1em;
|
||
margin-right: 0.2em;
|
||
vertical-align: sub;
|
||
}
|
||
|
||
#write a.md-toc-inner:hover {
|
||
color: var(--element-color-deep);
|
||
font-weight: 700;
|
||
text-decoration: none;
|
||
}
|
||
|
||
#write sup a::before {
|
||
content: none;
|
||
}
|
||
|
||
/* 加粗 */
|
||
#write strong {
|
||
color: #000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* 斜体 */
|
||
#write em {
|
||
font-style: italic;
|
||
color: #000;
|
||
}
|
||
|
||
/* 高亮 */
|
||
#write mark {
|
||
font-weight: bolder;
|
||
color: #000;
|
||
background: var(--element-color-so-shallow);
|
||
}
|
||
|
||
/* 删除线 */
|
||
#write del {
|
||
text-decoration-color: var(--element-color-deep);
|
||
}
|
||
|
||
/* 分隔线*/
|
||
#write hr {
|
||
height: 1px;
|
||
padding: 0;
|
||
border: none;
|
||
border-top: 2px solid var(--head-title-color);
|
||
}
|
||
|
||
/* 图片*/
|
||
#write img {
|
||
border-radius: 6px;
|
||
margin: 20px auto;
|
||
object-fit: contain;
|
||
}
|
||
|
||
/* 图片描述文字 */
|
||
#write figcaption {
|
||
display: block;
|
||
font-size: 13px;
|
||
color: #595959;
|
||
}
|
||
|
||
/* Yaml */
|
||
pre.md-meta-block {
|
||
padding: 8px 15px;
|
||
border: 2px dotted var(--element-color);
|
||
background-color: var(--element-color-soo-shallow);
|
||
}
|
||
|
||
/* 行内代码 */
|
||
#write p code {
|
||
padding: 3px 3px 1px;
|
||
color: var(--element-color-linecode);
|
||
background: var(--element-color-linecode-background);
|
||
border-radius: 3px;
|
||
font-family: "CascadiaCode" monospace;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
|
||
#write li code {
|
||
color: var(--element-color-linecode);
|
||
}
|
||
|
||
/* 代码块 */
|
||
|
||
.md-fences:not([lang="mermaid"])::before {
|
||
content: attr(lang);
|
||
font-family: "CascadiaCode" monospace;
|
||
text-align: right;
|
||
padding-right: 15px;
|
||
color: #7e7e7e;
|
||
display: block;
|
||
background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iNDUwcHgiIGhlaWdodD0iMTMwcHgiPgogIDxlbGxpcHNlIGN4PSI2NSIgY3k9IjY1IiByeD0iNTAiIHJ5PSI1MiIgc3Ryb2tlPSJyZ2IoMjIwLDYwLDU0KSIgc3Ryb2tlLXdpZHRoPSIyIiBmaWxsPSJyZ2IoMjM3LDEwOCw5NikiLz4KICA8ZWxsaXBzZSBjeD0iMjI1IiBjeT0iNjUiIHJ4PSI1MCIgcnk9IjUyIiAgc3Ryb2tlPSJyZ2IoMjE4LDE1MSwzMykiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0icmdiKDI0NywxOTMsODEpIi8+CiAgPGVsbGlwc2UgY3g9IjM4NSIgY3k9IjY1IiByeD0iNTAiIHJ5PSI1MiIgIHN0cm9rZT0icmdiKDI3LDE2MSwzNykiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0icmdiKDEwMCwyMDAsODYpIi8+Cjwvc3ZnPg==);
|
||
height: 30px;
|
||
width: 100%;
|
||
background-size: 40px;
|
||
background-repeat: no-repeat;
|
||
background-color: #f8f8f8;
|
||
border-radius: 5px 5px 0 0;
|
||
background-position: 6px 10px;
|
||
}
|
||
|
||
.CodeMirror-wrap .CodeMirror-scroll {
|
||
overflow-x: auto;
|
||
}
|
||
|
||
.md-fences .cm-s-inner.CodeMirror {
|
||
margin-top: -0.5rem;
|
||
}
|
||
|
||
.cm-s-inner.CodeMirror {
|
||
padding: 1.2rem 0.8rem;
|
||
color: #4f5467;
|
||
font-family: "CascadiaCode" monospace;
|
||
border-radius: 10px;
|
||
background-color: #fa0303;
|
||
/* border: 1px solid #eef2f5;*/
|
||
line-height: 1.6rem;
|
||
}
|
||
|
||
.CodeMirror-gutters {
|
||
border-right: 1px solid #9d9d9d52;
|
||
background: inherit;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
pre.CodeMirror-line {
|
||
padding: 0 1.2rem;
|
||
}
|
||
|
||
.CodeMirror-linenumber {
|
||
padding: 0 3px 0 5px;
|
||
text-align: right;
|
||
color: #a3a3a3;
|
||
}
|
||
|
||
.cm-s-inner.CodeMirror {
|
||
background: #f8f8f8;
|
||
border-radius: 0 0 5px 5px;
|
||
padding: 20px 10px 20px 10px;
|
||
page-break-before: auto;
|
||
line-height: 1.8rem;
|
||
}
|
||
|
||
.md-rawblock .md-rawblock-tooltip {
|
||
inset: auto 0.3rem auto auto;
|
||
transform: translateY(-120%);
|
||
}
|
||
|
||
/* 代码块颜色 */
|
||
.cm-keyword {
|
||
color: #a626a4 !important;
|
||
font-weight: 700 !important;
|
||
}
|
||
|
||
.cm-variable {
|
||
color: #b92121 !important;
|
||
}
|
||
|
||
.cm-tag {
|
||
color: var(--color-cm-keyword) !important;
|
||
font-weight: 700 !important;
|
||
}
|
||
|
||
.cm-variable-3,
|
||
.cm-variable-2 {
|
||
color: #7aadad !important;
|
||
font-weight: 700 !important;
|
||
}
|
||
|
||
.cm-def {
|
||
color: #c18401 !important;
|
||
}
|
||
|
||
.cm-attribute {
|
||
color: #8f6aa8 !important;
|
||
}
|
||
|
||
.cm-comment,
|
||
.md-comment,
|
||
.md-meta {
|
||
color: #9a9a9a !important;
|
||
}
|
||
|
||
.cm-string {
|
||
color: #50a14f !important;
|
||
font-variant-ligatures: common-ligatures !important;
|
||
}
|
||
|
||
.cm-link {
|
||
color: #e46918 !important;
|
||
}
|
||
|
||
.cm-type {
|
||
color: #626161;
|
||
}
|
||
|
||
.cm-property {
|
||
color: #800a84 !important;
|
||
}
|
||
|
||
.cm-tag:not(.cm-bracket) {
|
||
font-weight: 700 !important;
|
||
}
|
||
|
||
.cm-operator {
|
||
color: #0abe00 !important;
|
||
}
|
||
|
||
.cm-number {
|
||
color: #1694b6 !important;
|
||
}
|
||
|
||
.cm-meta {
|
||
color: #4078f2 !important;
|
||
font-weight: 700 !important;
|
||
}
|
||
|
||
.cm-builtin {
|
||
color: #fa6060 !important;
|
||
}
|
||
|
||
/* KBD */
|
||
kbd {
|
||
padding: 2px 4px;
|
||
font-size: 90%;
|
||
font-weight: bolder;
|
||
color: var(--element-color-linecode);
|
||
border: var(--element-color) solid 1px;
|
||
border-radius: 3px;
|
||
transition: all 0.2s linear;
|
||
box-shadow: inset 0 -1px 0 var(--element-color-so-shallow);
|
||
}
|
||
|
||
kbd:hover {
|
||
background: var(--element-color-so-shallow);
|
||
}
|
||
|
||
/** 表格内的单元格*/
|
||
#write table tr th,
|
||
#write table tr td {
|
||
font-size: 14px;
|
||
color: #000;
|
||
}
|
||
|
||
#write .footnotes {
|
||
padding: 10px;
|
||
font-size: 14px;
|
||
border-radius: 6px;
|
||
border: 0.8px solid var(--element-color-deep);
|
||
}
|
||
|
||
#write table.md-table {
|
||
overflow: hidden;
|
||
}
|
||
|
||
#write table thead {
|
||
border-top: 1px solid #dedddd;
|
||
border-bottom: 1px solid #dedddd;
|
||
}
|
||
|
||
#write table tbody {
|
||
border-bottom: 1px solid #dedddd;
|
||
}
|
||
|
||
/* 脚注文字 */
|
||
#write .footnote-word {
|
||
font-weight: normal;
|
||
color: #595959;
|
||
}
|
||
|
||
/* 脚注上标 */
|
||
#write .footnote-ref {
|
||
font-weight: normal;
|
||
color: #595959;
|
||
}
|
||
|
||
/*脚注链接样式*/
|
||
#write .footnote-item em {
|
||
font-size: 14px;
|
||
color: #595959;
|
||
display: block;
|
||
background: none;
|
||
}
|
||
|
||
/* 目录 */
|
||
|
||
.md-toc * {
|
||
font-family: "HarmonyOS_Sans_SC";
|
||
}
|
||
|
||
.md-tooltip-hide>span {
|
||
display: none;
|
||
}
|
||
|
||
.md-toc:before {
|
||
position: relative;
|
||
display: inline-block;
|
||
width: 100%;
|
||
text-align: center;
|
||
content: "目录";
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
color: #000;
|
||
}
|
||
|
||
.md-toc {
|
||
padding: 20px 0;
|
||
margin: 0 20px;
|
||
background-color: var(--element-color-soo-shallow);
|
||
border: 2px solid var(--element-color);
|
||
border-radius: 5px;
|
||
}
|
||
|
||
.md-toc-item {
|
||
line-height: 1.8em;
|
||
display: block;
|
||
color: #333;
|
||
}
|
||
|
||
/* 程序UI */
|
||
|
||
/* 侧边栏 */
|
||
|
||
#typora-sidebar {
|
||
height: 100%;
|
||
color: var(--appui-color-text);
|
||
font-size: 0.92rem;
|
||
background-color: #fff;
|
||
}
|
||
|
||
/* 滑块 */
|
||
|
||
#outline-content::-webkit-scrollbar {
|
||
width: 5px;
|
||
}
|
||
|
||
#file-library::-webkit-scrollbar {
|
||
width: 5px;
|
||
}
|
||
|
||
::-webkit-scrollbar-track {
|
||
border-radius: 10px;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb {
|
||
border-radius: 10px;
|
||
background: rgba(179, 179, 179, 0.425);
|
||
}
|
||
|
||
::-webkit-scrollbar {
|
||
width: 5px;
|
||
}
|
||
|
||
/* 侧边栏 文件 */
|
||
|
||
.active-tab-files #info-panel-tab-file .info-panel-tab-border,
|
||
.active-tab-outline #info-panel-tab-outline .info-panel-tab-border,
|
||
.ty-show-search #info-panel-tab-search .info-panel-tab-border {
|
||
border-radius: 10px;
|
||
height: 4px;
|
||
background-color: var(--appui-color);
|
||
}
|
||
|
||
.file-node-content {
|
||
line-height: 1.2rem;
|
||
}
|
||
|
||
.file-tree-node.active>.file-node-content {
|
||
color: var(--appui-color);
|
||
}
|
||
|
||
span.file-node-title {
|
||
color: var(--appui-color-text);
|
||
}
|
||
|
||
.file-node-icon {
|
||
color: var(--appui-color-icon);
|
||
padding-right: 0.2rem;
|
||
}
|
||
|
||
.file-tree-node.active>.file-node-background {
|
||
font-weight: bolder;
|
||
border-left: 4px solid var(--appui-color);
|
||
border-color: var(--appui-color);
|
||
}
|
||
|
||
.info-panel-tab-title {
|
||
font-weight: bolder;
|
||
color: var(--appui-color-text);
|
||
}
|
||
|
||
/* 侧边栏 搜索 */
|
||
|
||
#file-library-search-panel {
|
||
background-color: #fff;
|
||
}
|
||
|
||
#file-library-search-input {
|
||
border-radius: 3px;
|
||
border-color: var(--appui-color);
|
||
}
|
||
|
||
#file-library-search-input:focus {
|
||
border-width: 2px;
|
||
}
|
||
|
||
/* 侧边栏 大纲 */
|
||
#outline-content .outline-h1>.outline-item {
|
||
font-size: larger;
|
||
font-weight: bold;
|
||
color: var(--element-color-deep);
|
||
}
|
||
|
||
#outline-content .outline-h1:not(:first-of-type)>.outline-item {
|
||
margin-top: 10px;
|
||
}
|
||
|
||
#outline-content .outline-h2>.outline-item::before {
|
||
content: "";
|
||
width: 12px;
|
||
height: 12px;
|
||
background: var(--element-color);
|
||
vertical-align: middle;
|
||
float: left;
|
||
margin-top: -2px;
|
||
margin-right: 11px;
|
||
margin-left: -24px;
|
||
border-radius: 100%;
|
||
border: 3px solid #fff;
|
||
z-index: 100;
|
||
position: relative;
|
||
top: 8px;
|
||
left: 8px;
|
||
}
|
||
|
||
#outline-content .outline-h2::after {
|
||
content: "";
|
||
height: calc(100% - 24px);
|
||
width: 1px;
|
||
background: var(--element-color);
|
||
position: absolute;
|
||
left: 3px;
|
||
top: 21px;
|
||
}
|
||
|
||
#outline-content .outline-h2>.outline-item:last-child:after {
|
||
display: none;
|
||
}
|
||
|
||
#outline-content .outline-h2>.outline-item>.outline-label {
|
||
line-height: 1.65rem;
|
||
margin: 0;
|
||
}
|
||
|
||
#outline-content .outline-h2>.outline-item {
|
||
margin-bottom: -3px;
|
||
}
|
||
|
||
#outline-content .outline-h3>.outline-item>.outline-label {
|
||
border-left: 2px solid var(--element-color);
|
||
padding-left: 8px;
|
||
}
|
||
|
||
.outline-item-active:not(.outline-item-wrapper)::after {
|
||
content: "";
|
||
position: relative;
|
||
width: 11px;
|
||
height: 8px;
|
||
background: var(--element-color-deep);
|
||
float: right;
|
||
top: -12px;
|
||
z-index: 100;
|
||
border-radius: 40% 20% 20% 40%;
|
||
}
|
||
|
||
/* 导出HTML的样式 */
|
||
body.typora-export {
|
||
padding-left: 0px;
|
||
}
|
||
|
||
.typora-export-content .outline-content::before {
|
||
content: "目录";
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
position: absolute;
|
||
top: 22px;
|
||
left: 15px;
|
||
border-radius: 5px;
|
||
box-sizing: border-box;
|
||
z-index: -1;
|
||
}
|
||
|
||
.typora-export-sidebar .outline-content {
|
||
height: 100%;
|
||
padding-left: 15px;
|
||
border-right: 1px solid #d2d2d2;
|
||
}
|
||
|
||
.typora-export-content .typora-export-content {
|
||
padding-left: 0px;
|
||
}
|
||
|
||
.typora-export-content .outline-expander {
|
||
width: 0;
|
||
}
|
||
|
||
.typora-export-content .outline-item-active>.outline-item::after {
|
||
content: "";
|
||
position: relative;
|
||
width: 11px;
|
||
height: 8px;
|
||
background: var(--element-color-deep);
|
||
float: right;
|
||
right: 5px;
|
||
top: -14px;
|
||
z-index: 100;
|
||
border-radius: 40% 20% 20% 40%;
|
||
}
|
||
|
||
.typora-export-content .outline-label {
|
||
max-width: 250px;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.outline-content .outline-h1>.outline-item {
|
||
font-size: larger;
|
||
font-weight: bold;
|
||
color: var(--element-color-deep);
|
||
}
|
||
|
||
.outline-content .outline-h1:not(:first-of-type)>.outline-item {
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.outline-content .outline-h2>.outline-item::before {
|
||
content: "";
|
||
width: 12px;
|
||
height: 12px;
|
||
background: var(--element-color-deep);
|
||
vertical-align: middle;
|
||
float: left;
|
||
margin-top: -2px;
|
||
margin-right: 11px;
|
||
margin-left: -24px;
|
||
border-radius: 100%;
|
||
border: 3px solid #fff;
|
||
z-index: 100;
|
||
position: relative;
|
||
top: 8px;
|
||
left: 8px;
|
||
}
|
||
|
||
.outline-content .outline-h2::after {
|
||
content: "";
|
||
height: calc(100% - 24px);
|
||
width: 1px;
|
||
background: var(--element-color);
|
||
position: absolute;
|
||
left: 3px;
|
||
top: 21px;
|
||
}
|
||
|
||
.outline-content .outline-h2>.outline-item:last-child:after {
|
||
display: none;
|
||
}
|
||
|
||
.outline-content .outline-h2>.outline-item>.outline-label {
|
||
line-height: 1.65rem;
|
||
margin: 0;
|
||
}
|
||
|
||
.outline-content .outline-h2>.outline-item {
|
||
margin-bottom: -3px;
|
||
}
|
||
|
||
.outline-content .outline-h3>.outline-item>.outline-label {
|
||
border-left: 2px solid var(--element-color);
|
||
padding-left: 8px;
|
||
}@import url();
|
||
|
||
:root {
|
||
/* 标题后小图标,借鉴自思源笔记主题——Savor */
|
||
--h1-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='24' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M4.8 29.714v0c-1.371 0-2.514-1.143-2.514-2.514v0c0-1.371 1.143-2.514 2.514-2.514v0c1.371 0 2.514 1.143 2.514 2.514v0c0.114 1.371-1.029 2.514-2.514 2.514z'/></svg>") no-repeat center;
|
||
--h2-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='24' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M11.429 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286z'/></svg>") no-repeat center;
|
||
--h3-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='28' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M4.571 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286z'/></svg>") no-repeat center;
|
||
--h4-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='24' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M4.571 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 22.857c1.257 0 2.286-1.029 2.286-2.286s-1.029-2.286-2.286-2.286-2.286 1.029-2.286 2.286 1.029 2.286 2.286 2.286z'/></svg>") no-repeat center;
|
||
--h5-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='24' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M4.571 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 22.857c1.257 0 2.286-1.029 2.286-2.286s-1.029-2.286-2.286-2.286-2.286 1.029-2.286 2.286 1.029 2.286 2.286 2.286zM4.571 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 11.429c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286z'/></svg>") no-repeat center;
|
||
--h6-r-graphic: url("data:image/svg+xml;utf8,<svg fill='rgba(74, 200, 141, 0.5)' height='24' viewBox='0 0 32 32' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M4.571 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM4.571 11.429c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 18.286c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 25.143c-1.257 0-2.286 1.029-2.286 2.286s1.029 2.286 2.286 2.286 2.286-1.029 2.286-2.286-1.029-2.286-2.286-2.286zM11.429 16c1.257 0 2.286-1.029 2.286-2.286s-1.029-2.286-2.286-2.286-2.286 1.029-2.286 2.286 1.029 2.286 2.286 2.286z'/></svg>") no-repeat center;
|
||
|
||
/* 是否开启网格背景?1 是;0 否 */
|
||
--bg-grid: 0;
|
||
|
||
/* 已完成的代办事项是否显示删除线?1 是;0 否 */
|
||
--check-line:1;
|
||
|
||
/* 自动编号格式设置 无需自动编号可全部注释掉或部分注释掉*/
|
||
/* --autonum-h1: counter(h1) ". ";
|
||
--autonum-h2: counter(h1) "." counter(h2) ". ";
|
||
--autonum-h3: counter(h1) "." counter(h2) "." counter(h3) ". ";
|
||
--autonum-h4: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) ". ";
|
||
--autonum-h5: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) ". ";
|
||
--autonum-h6: counter(h1) "." counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) ". "; */
|
||
|
||
/* 下面是文章内Toc目录自动编号,与上面一样即可 */
|
||
/* --autonum-h1toc: counter(h1toc) ". ";
|
||
--autonum-h2toc: counter(h1toc) "." counter(h2toc) ". ";
|
||
--autonum-h3toc: counter(h1toc) "." counter(h2toc) "." counter(h3toc) ". ";
|
||
--autonum-h4toc: counter(h1toc) "." counter(h2toc) "." counter(h3toc) "." counter(h4toc) ". ";
|
||
--autonum-h5toc: counter(h1toc) "." counter(h2toc) "." counter(h3toc) "." counter(h4toc) "." counter(h5toc) ". ";
|
||
--autonum-h6toc: counter(h1toc) "." counter(h2toc) "." counter(h3toc) "." counter(h4toc) "." counter(h5toc) "." counter(h6toc) ". "; */
|
||
|
||
|
||
/* 主题颜色 */
|
||
|
||
--head-title-color: #3db8bf;
|
||
/* 标题主色 */
|
||
--head-title-h2-color: #fff;
|
||
--head-title-h2-background: linear-gradient(to right,
|
||
#3DB8D3,
|
||
#80F7C4);
|
||
/* 二级标题主色,因为二级标题是背景色的,所以单独设置 */
|
||
|
||
--element-color: #3db8bf;
|
||
/* 元素主色 */
|
||
--element-color-deep: #089ba3;
|
||
/* 元素深色 */
|
||
--element-color-shallow: #7aeaf0;
|
||
/* 元素浅色 */
|
||
--element-color-so-shallow: #7aeaf077;
|
||
/* 元素很浅色 */
|
||
--element-color-soo-shallow: #7aeaf018;
|
||
/* 元素非常浅色 */
|
||
|
||
--element-color-linecode: #089ba3;
|
||
/* 行内代码文字色 */
|
||
--element-color-linecode-background: #7aeaf018;
|
||
/* 行内代码背景色 */
|
||
|
||
/* 程序本体UI */
|
||
--appui-color: #3db8bf;
|
||
/* 程序UI主题色 */
|
||
--appui-color-icon: #3db8bf;
|
||
/* 程序UI图标颜色 */
|
||
--appui-color-text: #333;
|
||
/* 程序UI文字色 */
|
||
--primary-color: #3db8bf;
|
||
}
|
||
|
||
|
||
</style><title>design</title>
|
||
</head>
|
||
<body class='typora-export os-windows'><div class='typora-export-content'>
|
||
<div id='write' class=''><h1 id='ceru-music-产品设计文档'><span>Ceru Music 产品设计文档</span></h1><h2 id='项目概述'><span>项目概述</span></h2><p><span>Ceru Music 是一个基于 Electron + Vue 3 的跨平台桌面音乐播放器,支持多音乐平台数据源,提供流畅的音乐播放体验。</span></p><h2 id='项目架构'><span>项目架构</span></h2><h3 id='技术栈'><span>技术栈</span></h3><ul><li><p><strong><span>前端框架</span></strong><span>: Vue 3 + TypeScript + Composition API</span></p></li><li><p><strong><span>桌面框架</span></strong><span>: Electron (v37.2.3)</span></p></li><li><p><strong><span>UI组件库</span></strong><span>: TDesign Vue Next (v1.15.2)</span></p></li><li><p><img src="D:\code\Ceru-Music\docs\assets\image-20250813180317221.png" referrerpolicy="no-referrer" alt="image-20250813180317221"></p></li><li><p><strong><span>状态管理</span></strong><span>: Pinia (v3.0.3)</span></p></li><li><p><strong><span>路由管理</span></strong><span>: Vue Router (v4.5.1)</span></p></li><li><p><strong><span>构建工具</span></strong><span>: Vite + electron-vite</span></p></li><li><p><strong><span>包管理器</span></strong><span>: PNPM</span></p></li><li><p><strong><span>Node pnpm 版本</span></strong><span>:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="bash"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">PS D:\code\Ceru-Music> <span class="cm-builtin">node</span> <span class="cm-attribute">-v</span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">v22.17.0</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">PS D:\code\Ceru-Music> pnpm <span class="cm-attribute">-v</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-number">10</span>.14.0</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 115px;"></div><div class="CodeMirror-gutters" style="display: none; height: 115px;"></div></div></div></pre></li></ul><p><span>-</span></p><h3 id='架构设计'><span>架构设计</span></h3><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="asp"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="asp"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">Ceru Music</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">├── 主进程 (Main Process)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ ├── 应用生命周期管理</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ ├── 窗口管理</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ ├── 系统集成 (托盘、快捷键)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ └── 文件系统操作</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">├── 渲染进程 (Renderer Process)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ ├── Vue 3 应用</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ ├── 用户界面</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ ├── 音乐播放控制</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ └── 数据展示</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">└── 预加载脚本 (Preload Script)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> └── 安全的 IPC 通信桥梁</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 374px;"></div><div class="CodeMirror-gutters" style="display: none; height: 374px;"></div></div></div></pre><h3 id='目录结构'><span>目录结构</span></h3><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" style="break-inside: unset;"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang=""><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">src/</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">├── main/ # 主进程代码</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ ├── index.ts # 主进程入口</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ ├── window.ts # 窗口管理</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ └── services/ # 主进程服务</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">├── preload/ # 预加载脚本</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">│ └── index.ts # IPC 通信接口</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">└── renderer/ # 渲染进程 (Vue 应用)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> ├── src/</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> │ ├── components/ # Vue 组件</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> │ ├── views/ # 页面视图</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> │ ├── stores/ # Pinia 状态管理</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> │ ├── services/ # API 服务</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> │ ├── utils/ # 工具函数</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> │ └── types/ # TypeScript 类型定义</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> └── index.html # 应用入口</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 461px;"></div><div class="CodeMirror-gutters" style="display: none; height: 461px;"></div></div></div></pre><h2 id='项目开发使用方式'><span>项目开发使用方式</span></h2><h3 id='开发环境启动'><span>开发环境启动</span></h3><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="bash"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment"># 安装依赖</span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">pnpm install</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment"># 启动开发服务器</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">pnpm dev</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment"># 代码检查</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">pnpm lint</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment"># 类型检查</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">pnpm typecheck</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 317px;"></div><div class="CodeMirror-gutters" style="display: none; height: 317px;"></div></div></div></pre><h3 id='构建打包'><span>构建打包</span></h3><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="bash"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment"># 构建当前平台</span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">pnpm build</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment"># 构建 Windows 版本</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">pnpm build:win</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment"># 构建 macOS 版本</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">pnpm build:mac</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment"># 构建 Linux 版本</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">pnpm build:linux</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 317px;"></div><div class="CodeMirror-gutters" style="display: none; height: 317px;"></div></div></div></pre><h2 id='音乐数据源接口设计'><span>音乐数据源接口设计</span></h2><h3 id='接口1-网易云音乐原生接口-主要数据源'><span>接口1: 网易云音乐原生接口 (主要数据源)</span></h3><h4 id='获取音乐信息'><span>获取音乐信息</span></h4><ul><li><strong><span>请求地址</span></strong><span>: </span><code>https://music.163.com/api/song/detail</code></li><li><strong><span>请求参数</span></strong><span>: </span><code>ids=[ID1,ID2,ID3,...]</code><span> 音乐ID列表</span></li><li><strong><span>示例</span></strong><span>: </span><code>https://music.163.com/api/song/detail?ids=[36270426]</code></li></ul><h4 id='获取音乐直链'><span>获取音乐直链</span></h4><ul><li><strong><span>请求地址</span></strong><span>: </span><code>https://music.163.com/song/media/outer/url</code></li><li><strong><span>请求参数</span></strong><span>: </span><code>id=123</code><span> 音乐ID</span></li><li><strong><span>示例</span></strong><span>: </span><code>https://music.163.com/song/media/outer/url?id=36270426.mp3</code></li></ul><h4 id='获取歌词'><span>获取歌词</span></h4><ul><li><p><strong><span>请求地址</span></strong><span>: </span><code>https://music.163.com/api/song/lyric</code></p></li><li><p><strong><span>请求参数</span></strong><span>:</span></p><ul><li><code>id=123</code><span> 音乐ID</span></li><li><code>lv=-1</code><span> 获取歌词</span></li><li><code>yv=-1</code><span> 获取逐字歌词</span></li><li><code>tv=-1</code><span> 获取歌词翻译</span></li></ul></li><li><p><strong><span>示例</span></strong><span>: </span><code>https://music.163.com/api/song/lyric?id=36270426&lv=-1&yv=-1&tv=-1</code></p></li></ul><h4 id='搜索歌曲'><span>搜索歌曲</span></h4><ul><li><p><strong><span>请求地址</span></strong><span>: </span><code>https://music.163.com/api/search/get/web</code></p></li><li><p><strong><span>请求参数</span></strong><span>:</span></p><ul><li><code>s</code><span> 歌名</span></li><li><code>type=1</code><span> 搜索类型</span></li><li><code>offset=0</code><span> 偏移量</span></li><li><code>limit=10</code><span> 搜索结果数量</span></li></ul></li><li><p><strong><span>示例</span></strong><span>: </span><code>https://music.163.com/api/search/get/web?s=来自天堂的魔鬼&type=1&offset=0&limit=10</code></p></li></ul><h3 id='接口2-meting-api-备用数据源'><span>接口2: Meting API (备用数据源)</span></h3><h4 id='参数说明'><span>参数说明</span></h4><ul><li><p><strong><span>server</span></strong><span>: 数据源</span></p><ul><li><code>netease</code><span> 网易云音乐(默认)</span></li><li><code>tencent</code><span> QQ音乐</span></li></ul></li><li><p><strong><span>type</span></strong><span>: 类型</span></p><ul><li><code>name</code><span> 歌曲名</span></li><li><code>artist</code><span> 歌手</span></li><li><code>url</code><span> 链接</span></li><li><code>pic</code><span> 封面</span></li><li><code>lrc</code><span> 歌词</span></li><li><code>song</code><span> 单曲</span></li><li><code>playlist</code><span> 歌单</span></li></ul></li><li><p><strong><span>id</span></strong><span>: 类型ID(封面ID/单曲ID/歌单ID)</span></p></li></ul><h4 id='使用示例'><span>使用示例</span></h4><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang=""><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang=""><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.198px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">https://api.qijieya.cn/meting/?type=url&id=1969519579</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">https://api.qijieya.cn/meting/?type=song&id=591321</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">https://api.qijieya.cn/meting/?type=playlist&id=2619366284</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 173px;"></div><div class="CodeMirror-gutters" style="display: none; height: 173px;"></div></div></div></pre><h3 id='接口3-备选接口'><span>接口3: 备选接口</span></h3><ul><li><strong><span>地址</span></strong><span>: </span><a href='https://doc.vkeys.cn/api-doc/' target='_blank' class='url'>https://doc.vkeys.cn/api-doc/</a></li><li><strong><span>说明</span></strong><span>: 不建议使用,延迟较高</span></li></ul><h3 id='接口4-自部署接口-备用'><span>接口4: 自部署接口 (备用)</span></h3><ul><li><strong><span>地址</span></strong><span>: </span><code>https://music.shiqianjiang.cn?id=你是我的风景&server=netease</code></li><li><strong><span>说明</span></strong><span>: 不支持分页,用于获取歌曲源、歌词源等</span></li><li><strong><span>文档</span></strong><span>: </span><a href='./api.md'><span>API文档</span></a></li></ul><h2 id='核心功能设计'><span>核心功能设计</span></h2><h3 id='通用请求函数设计'><span>通用请求函数设计</span></h3><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="typescript" style="break-inside: unset;"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="typescript"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment">// 音乐服务接口定义</span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">interface</span> <span class="cm-def">MusicService</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">search</span>({<span class="cm-property">keyword</span>: <span class="cm-def">string</span>, <span class="cm-def">page</span><span class="cm-operator">?</span>: <span class="cm-variable">number</span>, <span class="cm-variable">limit</span><span class="cm-operator">?</span>: <span class="cm-variable">number</span>}): <span class="cm-type">Promise</span><span class="cm-operator"><</span><span class="cm-type">SearchResult</span><span class="cm-operator">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">getSongDetail</span>({<span class="cm-property">id</span>: <span class="cm-def">string</span>)}: <span class="cm-type">Promise</span><span class="cm-operator"><</span><span class="cm-type">SongDetail</span><span class="cm-operator">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">getSongUrl</span>({<span class="cm-variable">id</span>: <span class="cm-variable-2">string</span>}): <span class="cm-variable">Promise</span><span class="cm-operator"><</span><span class="cm-variable">string</span><span class="cm-operator">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">getLyric</span>({<span class="cm-property">id</span>: <span class="cm-variable">string</span>}): <span class="cm-variable">Promise</span><span class="cm-operator"><</span><span class="cm-variable">LyricData</span><span class="cm-operator">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">getPlaylist</span>({<span class="cm-property">id</span>: <span class="cm-variable">string</span>}): <span class="cm-variable">Promise</span><span class="cm-operator"><</span><span class="cm-variable">PlaylistData</span><span class="cm-operator">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment">// 通用请求函数</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">async</span> <span class="cm-keyword">function</span> <span class="cm-def">request</span>(<span class="cm-def">method</span>: <span class="cm-type">string</span>, <span class="cm-meta">...</span><span class="cm-def">args</span>: <span class="cm-type">any</span>{},<span class="cm-variable">isLoading</span><span class="cm-operator">=</span><span class="cm-atom">false</span>): <span class="cm-variable">Promise</span><span class="cm-operator"><</span><span class="cm-variable">any</span><span class="cm-operator">></span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">try</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">switch</span> (<span class="cm-variable">method</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">case</span> <span class="cm-string">'search'</span>:</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">return</span> <span class="cm-keyword">await</span> <span class="cm-variable">musicService</span>.<span class="cm-property">search</span>(<span class="cm-variable">args</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">case</span> <span class="cm-string">'getSongDetail'</span>:</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">return</span> <span class="cm-keyword">await</span> <span class="cm-variable">musicService</span>.<span class="cm-property">getSongDetail</span>(<span class="cm-variable">args</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">case</span> <span class="cm-string">'getSongUrl'</span>:</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">return</span> <span class="cm-keyword">await</span> <span class="cm-variable">musicService</span>.<span class="cm-property">getSongUrl</span>(<span class="cm-variable">args</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">case</span> <span class="cm-string">'getLyric'</span>:</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">return</span> <span class="cm-keyword">await</span> <span class="cm-variable">musicService</span>.<span class="cm-property">getLyric</span>(<span class="cm-variable">args</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">default</span>:</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">throw</span> <span class="cm-keyword">new</span> <span class="cm-variable">Error</span>(<span class="cm-string-2">`未知的方法: ${</span><span class="cm-variable">method</span><span class="cm-string-2">}`</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> } <span class="cm-keyword">catch</span> (<span class="cm-def">error</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">console</span>.<span class="cm-property">error</span>(<span class="cm-string-2">`请求失败: ${</span><span class="cm-variable">method</span><span class="cm-string-2">}`</span>, <span class="cm-variable-2">error</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">throw</span> <span class="cm-variable-2">error</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment">// 使用示例</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-variable">request</span>(<span class="cm-string">'search'</span>, <span class="cm-string">'周杰伦'</span>, <span class="cm-number">1</span>, <span class="cm-number">20</span>).<span class="cm-property">then</span>((<span class="cm-def">result</span>) <span class="cm-operator">=></span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">console</span>.<span class="cm-property">log</span>(<span class="cm-string">'搜索结果:'</span>, <span class="cm-variable-2">result</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">})</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 1238px;"></div><div class="CodeMirror-gutters" style="display: none; height: 1238px;"></div></div></div></pre><h3 id='状态管理设计-pinia--localstorage'><span>状态管理设计 (Pinia + LocalStorage)</span></h3><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="typescript" style="break-inside: unset;"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="typescript"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment">// stores/music.ts</span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> { <span class="cm-def">defineStore</span> } <span class="cm-keyword">from</span> <span class="cm-string">'pinia'</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">export</span> <span class="cm-keyword">const</span> <span class="cm-def">useMusicStore</span> <span class="cm-operator">=</span> <span class="cm-variable">defineStore</span>(<span class="cm-string">'music'</span>, {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">state</span>: () <span class="cm-operator">=></span> ({</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 当前播放歌曲</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">currentSong</span>: <span class="cm-atom">null</span> <span class="cm-keyword">as</span> <span class="cm-type">Song</span> <span class="cm-operator">|</span> <span class="cm-atom">null</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 播放列表</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">playlist</span>: [] <span class="cm-keyword">as</span> <span class="cm-type">Song</span>[],</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 播放状态</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">isPlaying</span>: <span class="cm-atom">false</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 播放模式 (顺序、随机、单曲循环)</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">playMode</span>: <span class="cm-string">'order'</span> <span class="cm-keyword">as</span> <span class="cm-string">'order'</span> <span class="cm-operator">|</span> <span class="cm-string">'random'</span> <span class="cm-operator">|</span> <span class="cm-string">'repeat'</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 音量</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">volume</span>: <span class="cm-number">0.8</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 播放进度</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">currentTime</span>: <span class="cm-number">0</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">duration</span>: <span class="cm-number">0</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }),</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">actions</span>: {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 播放歌曲</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">async</span> <span class="cm-property">playSong</span>(<span class="cm-def">song</span>: <span class="cm-type">Song</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">this</span>.<span class="cm-property">currentSong</span> <span class="cm-operator">=</span> <span class="cm-variable-2">song</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">this</span>.<span class="cm-property">isPlaying</span> <span class="cm-operator">=</span> <span class="cm-atom">true</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">this</span>.<span class="cm-property">saveToStorage</span>()</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> },</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 添加到播放列表</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">addToPlaylist</span>(<span class="cm-def">songs</span>: <span class="cm-type">Song</span>[]) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">this</span>.<span class="cm-property">playlist</span>.<span class="cm-property">push</span>(<span class="cm-meta">...</span><span class="cm-variable-2">songs</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">this</span>.<span class="cm-property">saveToStorage</span>()</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> },</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 保存到本地存储</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">saveToStorage</span>() {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">localStorage</span>.<span class="cm-property">setItem</span>(</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-string">'music-state'</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">JSON</span>.<span class="cm-property">stringify</span>({</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">currentSong</span>: <span class="cm-keyword">this</span>.<span class="cm-property">currentSong</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">playlist</span>: <span class="cm-keyword">this</span>.<span class="cm-property">playlist</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">playMode</span>: <span class="cm-keyword">this</span>.<span class="cm-property">playMode</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">volume</span>: <span class="cm-keyword">this</span>.<span class="cm-property">volume</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> })</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> )</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> },</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 从本地存储恢复</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">loadFromStorage</span>() {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">const</span> <span class="cm-def">saved</span> <span class="cm-operator">=</span> <span class="cm-variable">localStorage</span>.<span class="cm-property">getItem</span>(<span class="cm-string">'music-state'</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">if</span> (<span class="cm-variable-2">saved</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">const</span> <span class="cm-def">state</span> <span class="cm-operator">=</span> <span class="cm-variable">JSON</span>.<span class="cm-property">parse</span>(<span class="cm-variable-2">saved</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">Object</span>.<span class="cm-property">assign</span>(<span class="cm-keyword">this</span>, <span class="cm-variable-2">state</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">})</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 1728px;"></div><div class="CodeMirror-gutters" style="display: none; height: 1728px;"></div></div></div></pre><h3 id='虚拟滚动列表设计'><span>虚拟滚动列表设计</span></h3><p><span>使用 TDesign 的虚拟滚动组件展示大量歌曲数据:</span></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="vue" style="break-inside: unset;"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="vue"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"><</span><span class="cm-tag">template</span><span class="cm-tag cm-bracket">></span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-virtual-scroll</span> <span class="cm-attribute">:data</span>=<span class="cm-string">"songList"</span> <span class="cm-attribute">:height</span>=<span class="cm-string">"600"</span> <span class="cm-attribute">:item-height</span>=<span class="cm-string">"60"</span> <span class="cm-attribute">:buffer</span>=<span class="cm-string">"10"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">template</span> <span class="cm-attribute">#default</span>=<span class="cm-string">"{ data: song, index }"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"song-item"</span> <span class="cm-attribute">@click</span>=<span class="cm-string">"playSong(song)"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"song-cover"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">img</span> <span class="cm-attribute">:src</span>=<span class="cm-string">"song.pic"</span> <span class="cm-attribute">:alt</span>=<span class="cm-string">"song.name"</span> <span class="cm-tag cm-bracket">/></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"song-info"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"song-name"</span><span class="cm-tag cm-bracket">></span><span class="cm-meta cm-mustache">{{ song.name }}</span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"song-artist"</span><span class="cm-tag cm-bracket">></span><span class="cm-meta cm-mustache">{{ song.artist }}</span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"song-duration"</span><span class="cm-tag cm-bracket">></span><span class="cm-meta cm-mustache">{{ formatTime(song.duration) }}</span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">template</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag cm-error">t-virtual-scroll</span><span class="cm-tag cm-bracket cm-error">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"></</span><span class="cm-tag cm-error">template</span><span class="cm-tag cm-bracket cm-error">></span></span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 662px;"></div><div class="CodeMirror-gutters" style="display: none; height: 662px;"></div></div></div></pre><h3 id='本地数据存储设计'><span>本地数据存储设计</span></h3><h4 id='播放列表存储'><span>播放列表存储</span></h4><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="typescript" style="break-inside: unset;"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="typescript"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment">// 方案1: LocalStorage (简单方案)</span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">class</span> <span class="cm-def">PlaylistStorage</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">private</span> <span class="cm-property">key</span> <span class="cm-operator">=</span> <span class="cm-string">'ceru-playlists'</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">save</span>(<span class="cm-def">playlists</span>: <span class="cm-type">Playlist</span>[]) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">localStorage</span>.<span class="cm-property">setItem</span>(<span class="cm-keyword">this</span>.<span class="cm-property">key</span>, <span class="cm-variable">JSON</span>.<span class="cm-property">stringify</span>(<span class="cm-variable-2">playlists</span>))</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">load</span>(): <span class="cm-type">Playlist</span>[] {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">const</span> <span class="cm-def">data</span> <span class="cm-operator">=</span> <span class="cm-variable">localStorage</span>.<span class="cm-property">getItem</span>(<span class="cm-keyword">this</span>.<span class="cm-property">key</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">return</span> <span class="cm-variable-2">data</span> <span class="cm-operator">?</span> <span class="cm-variable">JSON</span>.<span class="cm-property">parse</span>(<span class="cm-variable-2">data</span>) : []</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment">// 方案2: Node.js 文件存储 (最优方案,支持分享)</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">class</span> <span class="cm-def">FileStorage</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">private</span> <span class="cm-property">filePath</span> <span class="cm-operator">=</span> <span class="cm-variable">path</span>.<span class="cm-property">join</span>(<span class="cm-variable">app</span>.<span class="cm-property">getPath</span>(<span class="cm-string">'userData'</span>), <span class="cm-string">'playlists.json'</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">async</span> <span class="cm-property">save</span>(<span class="cm-def">playlists</span>: <span class="cm-type">Playlist</span>[]) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">await</span> <span class="cm-variable">fs</span>.<span class="cm-property">writeFile</span>(<span class="cm-keyword">this</span>.<span class="cm-property">filePath</span>, <span class="cm-variable">JSON</span>.<span class="cm-property">stringify</span>(<span class="cm-variable-2">playlists</span>, <span class="cm-atom">null</span>, <span class="cm-number">2</span>))</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">async</span> <span class="cm-property">load</span>(): <span class="cm-type">Promise</span><span class="cm-operator"><</span><span class="cm-type">Playlist</span>[]<span class="cm-operator">></span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">try</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">const</span> <span class="cm-def">data</span> <span class="cm-operator">=</span> <span class="cm-keyword">await</span> <span class="cm-variable">fs</span>.<span class="cm-property">readFile</span>(<span class="cm-keyword">this</span>.<span class="cm-property">filePath</span>, <span class="cm-string">'utf-8'</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">return</span> <span class="cm-variable">JSON</span>.<span class="cm-property">parse</span>(<span class="cm-variable-2">data</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> } <span class="cm-keyword">catch</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">return</span> []</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 导出播放列表</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">async</span> <span class="cm-property">export</span>(<span class="cm-def">playlist</span>: <span class="cm-type">Playlist</span>, <span class="cm-def">exportPath</span>: <span class="cm-type">string</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">await</span> <span class="cm-variable">fs</span>.<span class="cm-property">writeFile</span>(<span class="cm-variable-2">exportPath</span>, <span class="cm-variable">JSON</span>.<span class="cm-property">stringify</span>(<span class="cm-variable-2">playlist</span>, <span class="cm-atom">null</span>, <span class="cm-number">2</span>))</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 导入播放列表</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">async</span> <span class="cm-property">import</span>(<span class="cm-def">importPath</span>: <span class="cm-type">string</span>): <span class="cm-type">Promise</span><span class="cm-operator"><</span><span class="cm-type">Playlist</span><span class="cm-operator">></span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">const</span> <span class="cm-def">data</span> <span class="cm-operator">=</span> <span class="cm-keyword">await</span> <span class="cm-variable">fs</span>.<span class="cm-property">readFile</span>(<span class="cm-variable-2">importPath</span>, <span class="cm-string">'utf-8'</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">return</span> <span class="cm-variable">JSON</span>.<span class="cm-property">parse</span>(<span class="cm-variable-2">data</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 1497px;"></div><div class="CodeMirror-gutters" style="display: none; height: 1497px;"></div></div></div></pre><h2 id='用户体验设计'><span>用户体验设计</span></h2><h3 id='首次启动流程'><span>首次启动流程</span></h3><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="typescript" style="break-inside: unset;"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="typescript"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment">// stores/app.ts</span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">export</span> <span class="cm-keyword">const</span> <span class="cm-def">useAppStore</span> <span class="cm-operator">=</span> <span class="cm-variable">defineStore</span>(<span class="cm-string">'app'</span>, {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">state</span>: () <span class="cm-operator">=></span> ({</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">isFirstLaunch</span>: <span class="cm-atom">true</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">hasCompletedWelcome</span>: <span class="cm-atom">false</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">userPreferences</span>: {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">theme</span>: <span class="cm-string">'auto'</span> <span class="cm-keyword">as</span> <span class="cm-string">'light'</span> <span class="cm-operator">|</span> <span class="cm-string">'dark'</span> <span class="cm-operator">|</span> <span class="cm-string">'auto'</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">language</span>: <span class="cm-string">'zh-CN'</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">defaultMusicSource</span>: <span class="cm-string">'netease'</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">autoPlay</span>: <span class="cm-atom">false</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }),</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">actions</span>: {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">checkFirstLaunch</span>() {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">const</span> <span class="cm-def">hasLaunched</span> <span class="cm-operator">=</span> <span class="cm-variable">localStorage</span>.<span class="cm-property">getItem</span>(<span class="cm-string">'has-launched'</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">this</span>.<span class="cm-property">isFirstLaunch</span> <span class="cm-operator">=</span> <span class="cm-operator">!</span><span class="cm-variable-2">hasLaunched</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">if</span> (<span class="cm-keyword">this</span>.<span class="cm-property">isFirstLaunch</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 跳转到欢迎页面</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">router</span>.<span class="cm-property">push</span>(<span class="cm-string">'/welcome'</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> } <span class="cm-keyword">else</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 加载用户配置</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">this</span>.<span class="cm-property">loadUserPreferences</span>()</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">router</span>.<span class="cm-property">push</span>(<span class="cm-string">'/home'</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> },</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">completeWelcome</span>(<span class="cm-def">preferences</span><span class="cm-operator">?</span>: <span class="cm-type">Partial</span><span class="cm-operator"><</span><span class="cm-type">UserPreferences</span><span class="cm-operator">></span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">if</span> (<span class="cm-variable-2">preferences</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">Object</span>.<span class="cm-property">assign</span>(<span class="cm-keyword">this</span>.<span class="cm-property">userPreferences</span>, <span class="cm-variable-2">preferences</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">this</span>.<span class="cm-property">hasCompletedWelcome</span> <span class="cm-operator">=</span> <span class="cm-atom">true</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">localStorage</span>.<span class="cm-property">setItem</span>(<span class="cm-string">'has-launched'</span>, <span class="cm-string">'true'</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">localStorage</span>.<span class="cm-property">setItem</span>(<span class="cm-string">'user-preferences'</span>, <span class="cm-variable">JSON</span>.<span class="cm-property">stringify</span>(<span class="cm-keyword">this</span>.<span class="cm-property">userPreferences</span>))</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">router</span>.<span class="cm-property">push</span>(<span class="cm-string">'/home'</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">})</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 1382px;"></div><div class="CodeMirror-gutters" style="display: none; height: 1382px;"></div></div></div></pre><h3 id='欢迎页面设计'><span>欢迎页面设计</span></h3><p><img src="D:\code\Ceru-Music\docs\assets\image-20250813180856660.png" referrerpolicy="no-referrer" alt="image-20250813180856660"></p><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="vue" style="break-inside: unset;"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="vue"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"><</span><span class="cm-tag">template</span><span class="cm-tag cm-bracket">></span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"welcome-container"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-steps</span> <span class="cm-attribute">:current</span>=<span class="cm-string">"currentStep"</span> <span class="cm-attribute">class</span>=<span class="cm-string">"welcome-steps"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-step</span> <span class="cm-attribute">title</span>=<span class="cm-string">"欢迎使用"</span> <span class="cm-attribute">content</span>=<span class="cm-string">"欢迎使用 Ceru Music"</span> <span class="cm-tag cm-bracket">/></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-step</span> <span class="cm-attribute">title</span>=<span class="cm-string">"基础设置"</span> <span class="cm-attribute">content</span>=<span class="cm-string">"配置您的偏好设置"</span> <span class="cm-tag cm-bracket">/></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-step</span> <span class="cm-attribute">title</span>=<span class="cm-string">"完成设置"</span> <span class="cm-attribute">content</span>=<span class="cm-string">"开始您的音乐之旅"</span> <span class="cm-tag cm-bracket">/></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">t-steps</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">transition</span> <span class="cm-attribute">name</span>=<span class="cm-string">"slide"</span> <span class="cm-attribute">mode</span>=<span class="cm-string">"out-in"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">component</span> <span class="cm-attribute">:is</span>=<span class="cm-string">"currentStepComponent"</span> <span class="cm-attribute">@next</span>=<span class="cm-string">"nextStep"</span> <span class="cm-attribute">@skip</span>=<span class="cm-string">"skipWelcome"</span> <span class="cm-tag cm-bracket">/></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">transition</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"></</span><span class="cm-tag">template</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span> <span class="cm-attribute">setup</span> <span class="cm-attribute">lang</span>=<span class="cm-string">"ts"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> { <span class="cm-def">ref</span>, <span class="cm-def">computed</span> } <span class="cm-keyword">from</span> <span class="cm-string">'vue'</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-def">WelcomeStep1</span> <span class="cm-keyword">from</span> <span class="cm-string">'./steps/WelcomeStep1.vue'</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-def">WelcomeStep2</span> <span class="cm-keyword">from</span> <span class="cm-string">'./steps/WelcomeStep2.vue'</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">import</span> <span class="cm-def">WelcomeStep3</span> <span class="cm-keyword">from</span> <span class="cm-string">'./steps/WelcomeStep3.vue'</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">const</span> <span class="cm-def">currentStep</span> <span class="cm-operator">=</span> <span class="cm-variable">ref</span>(<span class="cm-number">0</span>)</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">const</span> <span class="cm-def">steps</span> <span class="cm-operator">=</span> [<span class="cm-variable">WelcomeStep1</span>, <span class="cm-variable">WelcomeStep2</span>, <span class="cm-variable">WelcomeStep3</span>]</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">const</span> <span class="cm-def">currentStepComponent</span> <span class="cm-operator">=</span> <span class="cm-variable">computed</span>(() <span class="cm-operator">=></span> <span class="cm-variable">steps</span>[<span class="cm-variable">currentStep</span>.<span class="cm-property">value</span>])</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">function</span> <span class="cm-def">nextStep</span>() {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">if</span> (<span class="cm-variable">currentStep</span>.<span class="cm-property">value</span> <span class="cm-operator"><</span> <span class="cm-variable">steps</span>.<span class="cm-property">length</span> <span class="cm-operator">-</span> <span class="cm-number">1</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">currentStep</span>.<span class="cm-property">value</span><span class="cm-operator">++</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> } <span class="cm-keyword">else</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">completeWelcome</span>()</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> }</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">function</span> <span class="cm-def">skipWelcome</span>() {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-variable">appStore</span>.<span class="cm-property">completeWelcome</span>()</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"><</span><span class="cm-tag">style</span> <span class="cm-attribute">scoped</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-enter-active</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-leave-active</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">transition</span>: <span class="cm-atom">all</span> <span class="cm-number">0.3s</span> <span class="cm-atom">ease</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-enter-from</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">opacity</span>: <span class="cm-number">0</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">transform</span>: <span class="cm-atom">translateX</span>(<span class="cm-number">30px</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-leave-to</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">opacity</span>: <span class="cm-number">0</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">transform</span>: <span class="cm-atom">translateX</span>(<span class="cm-number">-30px</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"></</span><span class="cm-tag">style</span><span class="cm-tag cm-bracket">></span></span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 1785px;"></div><div class="CodeMirror-gutters" style="display: none; height: 1785px;"></div></div></div></pre><h5 id='界面ui参考'><span>界面UI参考</span></h5><p><span>![.\assets\image-20250813180944752.png)</span></p><h2 id='页面动画设计'><span>页面动画设计</span></h2><h3 id='路由过渡动画'><span>路由过渡动画</span></h3><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="vue" style="break-inside: unset;"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="vue"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"><</span><span class="cm-tag">template</span><span class="cm-tag cm-bracket">></span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">router-view</span> <span class="cm-attribute">v-slot</span>=<span class="cm-string">"{ Component, route }"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">transition</span> <span class="cm-attribute">:name</span>=<span class="cm-string">"getTransitionName(route)"</span> <span class="cm-attribute">mode</span>=<span class="cm-string">"out-in"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">component</span> <span class="cm-attribute">:is</span>=<span class="cm-string">"Component"</span> <span class="cm-attribute">:key</span>=<span class="cm-string">"route.path"</span> <span class="cm-tag cm-bracket">/></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">transition</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">router-view</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"></</span><span class="cm-tag">template</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"><</span><span class="cm-tag">script</span> <span class="cm-attribute">setup</span> <span class="cm-attribute">lang</span>=<span class="cm-string">"ts"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">function</span> <span class="cm-def">getTransitionName</span>(<span class="cm-def">route</span>: <span class="cm-variable">any</span>) {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-comment">// 根据路由层级决定动画方向</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">const</span> <span class="cm-def">depth</span> <span class="cm-operator">=</span> <span class="cm-variable-2">route</span>.<span class="cm-property">path</span>.<span class="cm-property">split</span>(<span class="cm-string">'/'</span>).<span class="cm-property">length</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-keyword">return</span> <span class="cm-variable-2">depth</span> <span class="cm-operator">></span> <span class="cm-number">2</span> <span class="cm-operator">?</span> <span class="cm-string">'slide-left'</span> : <span class="cm-string">'slide-right'</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"></</span><span class="cm-tag">script</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"><</span><span class="cm-tag">style</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment">/* 滑动动画 */</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-left-enter-active</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-left-leave-active</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-right-enter-active</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-right-leave-active</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">transition</span>: <span class="cm-atom">all</span> <span class="cm-number">0.3s</span> <span class="cm-variable">cubic-bezier</span>(<span class="cm-number">0.25</span>, <span class="cm-number">0.8</span>, <span class="cm-number">0.25</span>, <span class="cm-number">1</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-left-enter-from</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">opacity</span>: <span class="cm-number">0</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">transform</span>: <span class="cm-atom">translateX</span>(<span class="cm-number">100%</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-left-leave-to</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">opacity</span>: <span class="cm-number">0</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">transform</span>: <span class="cm-atom">translateX</span>(<span class="cm-number">-100%</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-right-enter-from</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">opacity</span>: <span class="cm-number">0</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">transform</span>: <span class="cm-atom">translateX</span>(<span class="cm-number">-100%</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.slide-right-leave-to</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">opacity</span>: <span class="cm-number">0</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">transform</span>: <span class="cm-atom">translateX</span>(<span class="cm-number">100%</span>);</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment">/* 淡入淡出动画 */</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.fade-enter-active</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.fade-leave-active</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">transition</span>: <span class="cm-atom">opacity</span> <span class="cm-number">0.3s</span> <span class="cm-atom">ease</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.fade-enter-from</span>,</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-qualifier">.fade-leave-to</span> {</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-property">opacity</span>: <span class="cm-number">0</span>;</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"></</span><span class="cm-tag">style</span><span class="cm-tag cm-bracket">></span></span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 1670px;"></div><div class="CodeMirror-gutters" style="display: none; height: 1670px;"></div></div></div></pre><h2 id='核心组件设计'><span>核心组件设计</span></h2><h3 id='音乐播放器组件'><span>音乐播放器组件</span></h3><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="vue" style="break-inside: unset;"><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="vue"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"><</span><span class="cm-tag">template</span><span class="cm-tag cm-bracket">></span></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"music-player"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"player-info"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">img</span> <span class="cm-attribute">:src</span>=<span class="cm-string">"currentSong?.pic"</span> <span class="cm-attribute">class</span>=<span class="cm-string">"song-cover"</span> <span class="cm-tag cm-bracket">/></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"song-details"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"song-name"</span><span class="cm-tag cm-bracket">></span><span class="cm-meta cm-mustache">{{ currentSong?.name }}</span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"song-artist"</span><span class="cm-tag cm-bracket">></span><span class="cm-meta cm-mustache">{{ currentSong?.artist }}</span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"player-controls"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-button</span> <span class="cm-attribute">variant</span>=<span class="cm-string">"text"</span> <span class="cm-attribute">@click</span>=<span class="cm-string">"previousSong"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-icon</span> <span class="cm-attribute">name</span>=<span class="cm-string">"skip-previous"</span> <span class="cm-tag cm-bracket">/></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">t-button</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-button</span> <span class="cm-attribute">:variant</span>=<span class="cm-string">"isPlaying ? 'filled' : 'outline'"</span> <span class="cm-attribute">@click</span>=<span class="cm-string">"togglePlay"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-icon</span> <span class="cm-attribute">:name</span>=<span class="cm-string">"isPlaying ? 'pause' : 'play'"</span> <span class="cm-tag cm-bracket">/></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">t-button</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-button</span> <span class="cm-attribute">variant</span>=<span class="cm-string">"text"</span> <span class="cm-attribute">@click</span>=<span class="cm-string">"nextSong"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-icon</span> <span class="cm-attribute">name</span>=<span class="cm-string">"skip-next"</span> <span class="cm-tag cm-bracket">/></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">t-button</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text="" cm-zwsp="">
|
||
</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">div</span> <span class="cm-attribute">class</span>=<span class="cm-string">"player-progress"</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">span</span> <span class="cm-attribute">class</span>=<span class="cm-string">"time-current"</span><span class="cm-tag cm-bracket">></span><span class="cm-meta cm-mustache">{{ formatTime(currentTime) }}</span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">t-slider</span> <span class="cm-attribute">v-model</span>=<span class="cm-string">"progress"</span> <span class="cm-attribute">:max</span>=<span class="cm-string">"duration"</span> <span class="cm-attribute">@change</span>=<span class="cm-string">"seekTo"</span> <span class="cm-attribute">class</span>=<span class="cm-string">"progress-slider"</span> <span class="cm-tag cm-bracket">/></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"><</span><span class="cm-tag">span</span> <span class="cm-attribute">class</span>=<span class="cm-string">"time-duration"</span><span class="cm-tag cm-bracket">></span><span class="cm-meta cm-mustache">{{ formatTime(duration) }}</span><span class="cm-tag cm-bracket"></</span><span class="cm-tag">span</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"> <span class="cm-tag cm-bracket"></</span><span class="cm-tag">div</span><span class="cm-tag cm-bracket">></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-tag cm-bracket"></</span><span class="cm-tag">template</span><span class="cm-tag cm-bracket">></span></span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 1152px;"></div><div class="CodeMirror-gutters" style="display: none; height: 1152px;"></div></div></div></pre><h2 id='开发规范'><span>开发规范</span></h2><h3 id='代码规范'><span>代码规范</span></h3><ul><li><span>使用 TypeScript 进行类型检查</span></li><li><span>遵循 ESLint 配置的代码规范</span></li><li><span>使用 Prettier 进行代码格式化</span></li><li><span>组件命名使用 PascalCase</span></li><li><span>文件命名使用 kebab-case</span></li></ul><h3 id='git-提交规范'><span>Git 提交规范</span></h3><pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang=""><div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang=""><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 32.3958px; left: 29.1979px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">feat: 新功能</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">fix: 修复bug</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">docs: 文档更新</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">style: 代码格式调整</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">refactor: 代码重构</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">test: 测试相关</span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">chore: 构建过程或辅助工具的变动</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 202px;"></div><div class="CodeMirror-gutters" style="display: none; height: 202px;"></div></div></div></pre><h3 id='性能优化'><span>性能优化</span></h3><ul><li><span>使用虚拟滚动处理大列表</span></li><li><span>图片懒加载</span></li><li><span>组件按需加载</span></li><li><span>音频预加载和缓存</span></li><li><span>防抖和节流优化用户交互</span></li></ul><h2 id='待补充功能'><span>待补充功能</span></h2><ol start='' ><li><strong><span>歌词显示</span></strong><span>: 滚动歌词、逐字高亮</span></li><li><strong><span>音效处理</span></strong><span>: 均衡器、音效增强</span></li><li><strong><span>主题系统</span></strong><span>: 多主题切换、自定义主题</span></li><li><strong><span>快捷键</span></strong><span>: 全局快捷键支持</span></li><li><strong><span>系统集成</span></strong><span>: 媒体键支持、系统通知</span></li><li><strong><span>云同步</span></strong><span>: 播放列表云端同步</span></li><li><strong><span>插件系统</span></strong><span>: 支持第三方插件扩展</span></li><li><strong><span>音乐推荐</span></strong><span>: 基于听歌历史的智能推荐</span></li></ol><hr /><p><em><span>本设计文档将随着项目开发进度持续更新和完善。</span></em></p></div></div>
|
||
</body>
|
||
</html> |