Skip to content

Commit

Permalink
feat: music player
Browse files Browse the repository at this point in the history
  • Loading branch information
lizmlzhou committed Oct 27, 2019
1 parent f7ebb9f commit 1e90c98
Show file tree
Hide file tree
Showing 16 changed files with 727 additions and 0 deletions.
49 changes: 49 additions & 0 deletions music-player/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<template>
<div id="app">
<transition>
<router-view />
</transition>
</div>
</template>

<style>
@import url('https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.css');
* {
margin: 0;
padding: 0;
}
a {
text-decoration: inherit;
}
ul,
ol {
list-style: none;
}
h1,
h2,
h3,
h4 {
font: inherit;
}
input,
select,
button {
font: inherit;
}
html,
body {
height: 100%;
-webkit-user-select: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
#app {
height: 100%;
overflow: hidden;
}
</style>
14 changes: 14 additions & 0 deletions music-player/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# music-player

### Compiles and hot-reloads for development
```
npm run serve
```

### Compiles and minifies for production
```
npm run build
```

### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
Binary file added music-player/assets/cover.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added music-player/assets/cover2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added music-player/assets/cover3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added music-player/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
120 changes: 120 additions & 0 deletions music-player/components/Control.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<template>
<div class="control" :class="{ control__playing: isPlaying }">
<div class="control_btn control_btn__side" @click="handlePrev">
<i class="fa fa-backward" />
</div>
<div class="control_btn" @click="handlePlay">
<span class="play-btn" />
</div>
<div class="control_btn control_btn__side" @click="handleNext">
<i class="fa fa-forward" />
</div>
</div>
</template>

<script>
import { mapState } from 'vuex'
import { player } from '../player'
export default {
computed: {
...mapState(['isPlaying'])
},
methods: {
handlePlay () {
if (!player.isEmpty) {
if (!this.isPlaying) {
player.play()
} else {
player.pause()
}
}
},
handlePrev () {
if (this.isPlaying) {
player.prev()
}
},
handleNext () {
if (this.isPlaying) {
player.next()
}
}
}
}
</script>

<style lang="scss">
.control {
display: flex;
height: 100%;
}
.control_btn {
display: flex;
margin: 2px;
align-items: center;
justify-content: center;
flex: 1;
border-radius: 4px;
color: #ccc;
font-size: 16px;
transition: background-color 0.6s ease;
}
.control_btn:hover {
background-color: #ddd;
color: white;
}
.control_btn__side {
font-size: 14px;
}
.play-btn {
position: relative;
width: 20px;
height: 20px;
}
.play-btn::before {
content: '';
position: absolute;
left: 11px;
top: 50%;
margin-left: -4px;
margin-top: -10px;
width: 0;
height: 0;
border: 12px solid transparent;
border-left-color: #ccc;
border-top-width: 10px;
border-bottom-width: 10px;
transition: all 0.2s ease;
}
.play-btn::after {
content: '';
position: absolute;
right: 5px;
top: 50%;
margin-right: -4px;
margin-top: -10px;
width: 0;
height: 20px;
border: 0 solid transparent;
border-width: 0 0 0 6px;
border-left-color: #ccc;
opacity: 0;
transform: scale(0);
transition: all 0.2s ease;
}
.control__playing .play-btn::before {
border-width: 0 0 0 6px;
height: 20px;
left: 5px;
}
.control__playing .play-btn::after {
opacity: 1;
transform: scale(1);
}
.control_btn:hover .play-btn::before {
border-left-color: white;
}
.control_btn:hover .play-btn::after {
border-color: white;
}
</style>
143 changes: 143 additions & 0 deletions music-player/components/Disk.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<template>
<div class="disk" :class="{ disk__playing: isPlaying }">
<label
class="disk_cover"
ref="cover"
for="file"
:style="{
transform: stopMatrix,
backgroundImage: coverUrl ? `url(${coverUrl})` : ''
}"
/>
<input
id="file"
ref="file"
type="file"
accept=".mp3"
multiple
@change="handleChange"
/>
</div>
</template>

<script>
import { mapState, mapMutations } from 'vuex'
import { player } from '../player'
export default {
data () {
return {
stopMatrix: ''
}
},
computed: {
...mapState(['isPlaying', 'coverUrl'])
},
watch: {
isPlaying (val) {
if (!val) {
this.stopMatrix = window.getComputedStyle(this.$refs.cover).transform
} else {
const matrix = this.stopMatrix
this.stopMatrix = ''
const match = matrix.match(/^matrix\(([^,]+),([^,]+)/)
const [, sin, cos] = match || [0, 0, 0]
const deg = ((Math.atan2(cos, sin) / 2 / Math.PI) * 360) % 360
const styles = [...document.styleSheets]
styles.forEach(style => {
const rules = [...style.cssRules]
rules.forEach(rule => {
if (rule.type === rule.KEYFRAMES_RULE && rule.name === 'rotate') {
rule.cssRules[0].style.transform = `rotate(${deg}deg)`
rule.cssRules[1].style.transform = `rotate(${deg + 360}deg)`
}
})
})
}
}
},
methods: {
...mapMutations(['togglePlay', 'changeCover']),
async handleChange () {
const target = this.$refs.file
const files = target.files ? target.files : []
if (files.length) {
for (let i = 0; i < files.length; i++) {
await player.append(files[i])
}
}
target.value = ''
}
},
mounted () {
player.onReady.listen(() => {
this.changeCover()
})
player.onChange.listen(() => {
this.changeCover()
})
player.onPlay.listen(() => {
this.togglePlay(true)
})
player.onPause.listen(() => {
this.togglePlay(false)
})
}
}
</script>

<style lang="scss">
.disk {
position: relative;
padding-top: 100%;
border-radius: 100%;
overflow: hidden;
transform: translateY(-50%) scale(0.88);
transform-origin: center bottom;
transition: all 0.6s ease;
}
.disk input {
display: none;
}
.disk_cover {
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background-image: radial-gradient(circle, #444 0%, #333 100%);
background-size: cover;
background-position: center;
}
.disk_cover::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
margin-left: -8px;
margin-top: -8px;
width: 16px;
height: 16px;
border-radius: 100%;
background-image: linear-gradient(45deg, white, #dabad1);
box-shadow: 0 1px 1px 1px rgba(0, 0, 0, 0.2);
}
.disk__playing {
transform: translateY(-50%);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1),
0 20px 20px -10px rgba(108, 29, 171, 0.3);
}
.disk__playing .disk_cover {
animation: rotate infinite 6s linear;
}
@keyframes rotate {
from {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
</style>
58 changes: 58 additions & 0 deletions music-player/components/Player.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<template>
<div class="player">
<div class="player_disk">
<disk />
</div>
<div class="player_control">
<control />
</div>
<div class="player_progress">
<progress-bar />
</div>
</div>
</template>

<script>
import Disk from './Disk.vue'
import Control from './Control.vue'
import ProgressBar from './ProgressBar.vue'
export default {
components: {
Disk,
Control,
ProgressBar
}
}
</script>

<style lang="scss">
.player {
position: relative;
display: flex;
max-width: 300px;
max-height: 75px;
width: 300px;
height: 75px;
border-radius: 8px;
background-color: white;
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.12),
0 20px 20px rgba(95, 23, 101, 0.2);
}
.player_disk {
flex: 1.2;
padding: 12px;
}
.player_control {
flex: 2;
padding: 12px 0;
padding-right: 12px;
}
.player_progress {
position: absolute;
left: 9px;
right: 9px;
top: 0;
bottom: 25px;
z-index: -1;
}
</style>
Loading

0 comments on commit 1e90c98

Please sign in to comment.