首先我们要下载一下图标,可以到 iconfont美化界面 - 图1 下载,然后放在 project_root/static 下面,文档在这里美化界面 - 图2

全局状态

由于动态组件,退出会销毁,这很明显不是我们想要的,所以只能单独提取出来,而却最好把状态都放到全局来。

首先添加三个状态。

  1. files: [],
  2. index: 0,
  3. music: true

修改模板

修改一下 index.ejs , 因为我们等会要做 css 动画,把背景颜色做一下  兼容,并且把高度给撑开。

  1. html {
  2. background: #383a41;
  3. min-height: 100vh;
  4. }

更改 App 组件

单独提取出来就不会被销毁。Music 要是被销毁了,那就没法播放音频了。

  1. <Tip/>
  2. <svelte:component this="{$currentPage}" name="page" />
  3. <Music/>
  4. <script>
  5. export default {
  6. components: {
  7. Tip: './components/Tip.svelte',
  8. Music: './pages/Music.svelte'
  9. },
  10. };
  11. </script>

修改 Main.svelte

通过全局状态来控制菜单的显隐,同样的方式,控制 Music.svelte.

  1. <div class="wrap {$music ? 'hidden': 'show'}">
  2. <div className="music-page-btn" on:click="$set({music: true})">播放器</div>
  3. </div>
  1. .hidden {
  2. display: none;
  3. }
  4. .wrap :global(a),
  5. .wrap div {
  6. display: inline-flex;
  7. // .....
  8. }

回退修复

修改 Link.svelte 使点击 Back.svelteMusic.svelte 隐藏,所以我们每次点击都可以将这个转态置为 false,这样就保证了 Music.svelte 的隐藏。

  1. this.refs.link.addEventListener(
  2. 'click',
  3. e => {
  4. e.preventDefault()
  5. this.store.set({
  6. music: false
  7. })
  8. this.store.changePage(this.get().to)
  9. },
  10. false
  11. )

修改播放组件

首先我们需要把状态的更改都是用 this.store.set$set 进行修改,然后还需要将文件名处理成正确的显示格式。

::-webkit-scrollbar-thumb 是简单的修改了一下滚动条的颜色。

  1. <div class="music-page { $music ?'show':'hidden' } ">
  2. <Back/>
  3. <div>
  4. <ul class="main">
  5. {#each files as file, index}
  6. <li on:click="$set({index})">{handleName(file)}</li>
  7. {/each}
  8. </ul>
  9. <div class="control">
  10. <div class="title">{title}</div>
  11. <div class="flex">
  12. <button on:click="file()"><img src="plus-circle.png" width="25" height="25" alt="add"></button>
  13. <button on:click="play()"><img src="play-circle.png" width="25" height="25" alt="play"></button>
  14. <button on:click="pause()"><img src="time-out.png" width="25" height="25" alt="stop"></button>
  15. <button on:click="prev()"><img src="left-circle.png" width="25" height="25" alt="prev"></button>
  16. <button on:click="next()"><img src="right-circle.png" width="25" height="25" alt="next"></button>
  17. </div>
  18. </div>
  19. </div>
  20. </div>
  21. <script>
  22. import {
  23. ipcRenderer,
  24. remote
  25. } from "electron";
  26. const {
  27. dialog,
  28. app
  29. } = remote
  30. const {
  31. readdir
  32. } = remote.require('fs-extra')
  33. import {
  34. resolve
  35. } from 'path'
  36. function handleName(name) {
  37. return name.replace('.mp3', '').split('-')[1]
  38. }
  39. export default {
  40. data() {
  41. return {
  42. files: [],
  43. title: ''
  44. };
  45. },
  46. helpers: {
  47. handleName
  48. },
  49. components: {
  50. Back: '../components/Back.svelte'
  51. },
  52. oncreate() {
  53. this.player = new Audio()
  54. document.querySelector('#app').appendChild(this.player)
  55. const {
  56. files
  57. } = this.store.get()
  58. this.set({
  59. files
  60. })
  61. this.player.onended = this.next.bind(this) // 结束进入下一首
  62. let listener = this.store.on('state', ({
  63. changed
  64. }) => {
  65. if (changed.index || changed.files) { // 当重新选了文件,播放第一首
  66. const {
  67. files,
  68. index
  69. } = this.store.get()
  70. this.player.src = "file://" + files[index]
  71. this.set({
  72. title: handleName(this.get().files[index])
  73. })
  74. this.play()
  75. }
  76. })
  77. this.on('destroy', listener.cancel)
  78. },
  79. ondestroy() {
  80. document.querySelectorAll("audio").forEach(a => a.remove())
  81. },
  82. methods: {
  83. next() {
  84. const {
  85. index,
  86. files
  87. } = this.store.get()
  88. let i = index + 1
  89. if (i > files.length - 1) {
  90. i = files.length - 1
  91. }
  92. this.store.set({
  93. index: i
  94. })
  95. },
  96. prev() {
  97. const {
  98. index,
  99. files
  100. } = this.store.get()
  101. let i = index - 1
  102. if (i < 0) {
  103. i = 0
  104. }
  105. this.store.set({
  106. index: i
  107. })
  108. },
  109. play() {
  110. if (!this.player.currentSrc) {
  111. const {
  112. files,
  113. index
  114. } = this.store.get()
  115. this.set({
  116. title: handleName(files[index])
  117. })
  118. this.player.src = "file://" + files[index]
  119. }
  120. this.player.play()
  121. },
  122. pause() {
  123. this.player.pause()
  124. },
  125. file() {
  126. dialog.showOpenDialog({
  127. title: '选择音乐目录',
  128. defaultPath: app.getPath('home'),
  129. properties: ['openDirectory']
  130. }, async(folders) => {
  131. if (folders.length > 0) {
  132. const folder = folders[0]
  133. let files = await readdir(folder)
  134. this.set({
  135. files
  136. })
  137. const compare = (a, b) => {
  138. let t1 = a.split('-')[0];
  139. let t2 = b.split('-');
  140. return parseInt(t1) - parseInt(t2)
  141. }
  142. files = files.sort(compare).map(file => resolve(folder, file))
  143. this.store.set({
  144. files,
  145. index: 0
  146. })
  147. }
  148. })
  149. }
  150. }
  151. };
  152. </script>
  153. <style>
  154. .music-page {
  155. transition: all ease-in .1s;
  156. height: 100vh;
  157. }
  158. .hidden {
  159. transform: translate(100%, 0)
  160. }
  161. .show {
  162. transform: translate(0, 0)
  163. }
  164. .control {
  165. position: fixed;
  166. bottom: 0;
  167. left: 0;
  168. right: 0;
  169. height: 100px;
  170. background: #383A41;
  171. display: flex;
  172. flex-direction: column;
  173. }
  174. .title {
  175. color: #f8f8f8;
  176. padding: 1rem 0;
  177. text-align: center;
  178. font-size: .8rem;
  179. min-height: 54px;
  180. user-select: none;
  181. }
  182. .flex {
  183. display: flex;
  184. justify-content: space-around;
  185. align-items: center;
  186. flex-basis: 100%;
  187. }
  188. .control button {
  189. background: transparent;
  190. border: none;
  191. outline: none;
  192. cursor: pointer;
  193. }
  194. .control button:hover {
  195. background: #2f2f2f;
  196. }
  197. .main {
  198. height: calc(100vh - 160px);
  199. margin-bottom: 60px;
  200. overflow: scroll;
  201. background: #303238;
  202. }
  203. li {
  204. color: #f8f8f8;
  205. padding: 1.1rem 1rem;
  206. font-size: .9rem;
  207. cursor: pointer;
  208. }
  209. li:hover {
  210. background: #2f2f2f;
  211. }
  212. ::-webkit-scrollbar-thumb {
  213. background: #383A41;
  214. }
  215. .control button {
  216. line-height: 0;
  217. padding: .5rem 1rem;
  218. }
  219. </style>

美化界面 - 图3