14 changed files with 1148 additions and 791 deletions
@ -0,0 +1,115 @@
@@ -0,0 +1,115 @@
|
||||
<template> |
||||
<div class="marquee" :class="name+'-marquee'" ref="marquee"> |
||||
<span class="text" ref="marqueeText"> |
||||
{{ text }}<span class="space"></span> |
||||
{{ text }}<span class="space"></span> |
||||
{{ text }}<span class="space"></span> |
||||
</span> |
||||
</div> |
||||
</template> |
||||
<script> |
||||
import Dom from "../utils/dom"; |
||||
import {nextTick} from "vue"; |
||||
|
||||
export default { |
||||
name: "BaseMarquee", |
||||
props: { |
||||
text: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
name: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
//用于第一条数据,自动播放,如果都用事件去触发播放,有延迟 |
||||
isPlay: { |
||||
type: Boolean, |
||||
default: () => { |
||||
return true |
||||
} |
||||
}, |
||||
}, |
||||
data() { |
||||
return { |
||||
timer: null, |
||||
contentWidth: 0, |
||||
transformX: 0, |
||||
$marqueeContent: null, |
||||
} |
||||
}, |
||||
methods: { |
||||
pause() { |
||||
// console.log('pause') |
||||
cancelAnimationFrame(this.timer) |
||||
}, |
||||
stop() { |
||||
// console.log('stop') |
||||
cancelAnimationFrame(this.timer) |
||||
this.transformX = 0 |
||||
this.marqueeText.css('transform', `translate3d(0,0,0)`) |
||||
}, |
||||
start() { |
||||
// console.log('start') |
||||
if (this.contentWidth <= 0) { // 没有内容搞什么动画 |
||||
return; |
||||
} |
||||
let fn = () => { |
||||
if (this.transformX > (-this.contentWidth / 3)) { |
||||
this.transformX -= 1 |
||||
this.marqueeText.css('transform', `translate3d(${this.transformX}px,0,0)`) |
||||
} else { |
||||
this.transformX = 0 |
||||
} |
||||
this.timer = requestAnimationFrame(fn) |
||||
} |
||||
fn() |
||||
} |
||||
}, |
||||
mounted() { |
||||
nextTick(() => { |
||||
//直接document.querySelectorAll,找不到dom,必须用$refs的方式 |
||||
this.marqueeText = new Dom(this.$refs.marqueeText) |
||||
//必须在nextTick在调用,不然后新生成dom,获取不到width |
||||
this.contentWidth = this.marqueeText.getWidth() |
||||
|
||||
// console.log(this.name, this.isPlay, this.marqueeText) |
||||
// console.log(this.name, this.isPlay, this.contentWidth) |
||||
|
||||
new Dom(this.$refs.marquee).on('pause', this.pause) |
||||
new Dom(this.$refs.marquee).on('start', this.start) |
||||
new Dom(this.$refs.marquee).on('stop', this.stop) |
||||
if (this.isPlay) { |
||||
this.start() |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped lang="less"> |
||||
.marquee { |
||||
width: 100%; |
||||
display: block; |
||||
margin: 0 auto; |
||||
overflow: hidden; |
||||
white-space: nowrap; |
||||
text-overflow: clip; |
||||
position: relative; |
||||
|
||||
.text { |
||||
color: white; |
||||
display: inline-block; |
||||
position: relative; |
||||
white-space: nowrap; |
||||
|
||||
.space { |
||||
display: inline-block; |
||||
width: 5rem; |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
</style> |
@ -0,0 +1,163 @@
@@ -0,0 +1,163 @@
|
||||
<template> |
||||
<div class="music-wrapper" :class="name+'-music'" ref="musicWrapper"> |
||||
<template v-if="!isStop"> |
||||
<img class="music1" src="../assets/img/icon/home/music1.png" alt=""> |
||||
<img class="music2" src="../assets/img/icon/home/music2.png" alt=""> |
||||
</template> |
||||
<div class="music-bg" ref="musicBg"> |
||||
<img class="music" :src="cover"> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
<script> |
||||
import Dom from "../utils/dom"; |
||||
import {nextTick} from "vue"; |
||||
import BaseButton from "./BaseButton"; |
||||
|
||||
export default { |
||||
name: "BaseMusic", |
||||
components: { |
||||
BaseButton |
||||
}, |
||||
props: { |
||||
cover: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
name: { |
||||
type: String, |
||||
default: '' |
||||
}, |
||||
//用于第一条数据,自动播放,如果都用事件去触发播放,有延迟 |
||||
isPlay: { |
||||
type: Boolean, |
||||
default: () => { |
||||
return true |
||||
} |
||||
}, |
||||
}, |
||||
data() { |
||||
return { |
||||
isStop: false, |
||||
musicBg: null, |
||||
} |
||||
}, |
||||
methods: { |
||||
// triggerPause() { |
||||
// new Dom('.music-wrapper').trigger('pause') |
||||
// }, |
||||
// triggerStart() { |
||||
// new Dom('.music-wrapper').trigger('start') |
||||
// }, |
||||
pause() { |
||||
this.isStop = true |
||||
this.musicBg.css('webkitAnimationPlayState', 'paused') |
||||
}, |
||||
stop() { |
||||
this.isStop = true |
||||
this.musicBg.css('webkitAnimationPlayState', 'paused') |
||||
}, |
||||
start() { |
||||
this.isStop = false |
||||
this.musicBg.css('webkitAnimationPlayState', 'running') |
||||
} |
||||
}, |
||||
mounted() { |
||||
nextTick(() => { |
||||
//直接document.querySelectorAll,找不到dom,必须用$refs的方式 |
||||
this.musicBg = new Dom(this.$refs.musicBg) |
||||
|
||||
new Dom(this.$refs.musicWrapper).on('pause', this.pause) |
||||
new Dom(this.$refs.musicWrapper).on('start', this.start) |
||||
new Dom(this.$refs.musicWrapper).on('stop', this.stop) |
||||
if (this.isPlay) { |
||||
this.start() |
||||
} else { |
||||
this.stop() |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="less"> |
||||
.music-wrapper { |
||||
position: relative; |
||||
|
||||
.music-bg { |
||||
background-image: linear-gradient(black, #424242, black); |
||||
border-radius: 50%; |
||||
width: 50px; |
||||
height: 50px; |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
animation: animations 5s linear forwards infinite; |
||||
|
||||
//animation-play-state:paused; |
||||
//display: none; |
||||
|
||||
.music { |
||||
//display: none; |
||||
width: 25px; |
||||
height: 25px; |
||||
border-radius: 50%; |
||||
} |
||||
} |
||||
|
||||
|
||||
.music1, .music2 { |
||||
//display: none; |
||||
position: absolute; |
||||
width: 18px; |
||||
height: 18px; |
||||
top: 10px; |
||||
} |
||||
|
||||
.music1 { |
||||
animation: anim-music1 2s linear forwards infinite; |
||||
} |
||||
|
||||
.music2 { |
||||
animation: anim-music1 2s linear forwards infinite; |
||||
animation-delay: 1s; |
||||
} |
||||
|
||||
|
||||
@keyframes animations { |
||||
0% { |
||||
transform: rotate(0deg);; |
||||
} |
||||
100% { |
||||
transform: rotate(360deg); |
||||
} |
||||
} |
||||
@keyframes anim-music1 { |
||||
0% { |
||||
transform: translate3d(0, 0, 0); |
||||
opacity: 0; |
||||
} |
||||
20% { |
||||
transform: translate3d(-8px, 0px, 0) rotate(30deg); |
||||
opacity: .3; |
||||
} |
||||
40% { |
||||
transform: translate3d(-16px, -5px, 0) rotate(15deg); |
||||
opacity: .5; |
||||
} |
||||
60% { |
||||
transform: translate3d(-24px, -15px, 0) rotate(0deg); |
||||
opacity: 1; |
||||
} |
||||
80% { |
||||
transform: translate3d(-32px, -30px, 0) rotate(-15deg); |
||||
opacity: 1; |
||||
} |
||||
100% { |
||||
transform: translate3d(-32px, -50px, 0) rotate(-30deg); |
||||
opacity: 0; |
||||
} |
||||
} |
||||
} |
||||
|
||||
</style> |
@ -1,193 +0,0 @@
@@ -1,193 +0,0 @@
|
||||
<template> |
||||
<div class='Music'> |
||||
<header class="pl15p pr15p pt20p"> |
||||
<div class="top pb20p d-flex justify-content-between"> |
||||
<img src="../../assets/img/icon/next.svg" alt="" @click="back()"> |
||||
<img src="../../assets/img/icon/share.svg" alt=""> |
||||
</div> |
||||
<div class="bottom"> |
||||
<img class="logo" src="../../assets/img/poster/src1-bg.png" alt=""> |
||||
<div class="info"> |
||||
<div class="name">MT创作的原声</div> |
||||
<div class="user">NT ></div> |
||||
<div class="peoples">1人使用</div> |
||||
<div class="collection"> |
||||
<img src="../../assets/img/icon/collect-white.svg" alt=""> |
||||
<span>收藏</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</header> |
||||
<div class="content"> |
||||
<div class="tabs"> |
||||
<div class="tab active" @click="toggleTab($event,0)">热门</div> |
||||
<div class="tab" @click="toggleTab($event,1)">最新</div> |
||||
</div> |
||||
<div class="video-container" v-for="(item,index) of videos" v-bind:style="{'height':width/3*1.2+'px'}"> |
||||
<video src="../../assets/video/1.mp4" poster="../../assets/img/poster/src1-bg.png"></video> |
||||
<div class="no" v-if="index===1||index===2"> |
||||
NO. <span>{{index+1}}</span> |
||||
</div> |
||||
<span v-if="index===0" class="first">首发</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
<script> |
||||
|
||||
export default { |
||||
name: "Music", |
||||
components: {}, |
||||
data() { |
||||
return { |
||||
videos: [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}], |
||||
} |
||||
}, |
||||
created() { |
||||
}, |
||||
computed: {}, |
||||
methods: { |
||||
toggleTab(e, index) { |
||||
if (!e.target.classList.contains('active')) { |
||||
e.target.classList.toggle('active') |
||||
} |
||||
|
||||
if (index === 1) { |
||||
let pre = e.target.previousElementSibling |
||||
pre.classList.remove('active') |
||||
} else { |
||||
let pre = e.target.nextElementSibling |
||||
pre.classList.remove('active') |
||||
} |
||||
|
||||
}, |
||||
back() { |
||||
window.history.back() |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped lang="less"> |
||||
.Music { |
||||
header { |
||||
background: #454b66; |
||||
padding-bottom: 30px; |
||||
|
||||
.top { |
||||
img { |
||||
width: 20px; |
||||
height: 20px; |
||||
|
||||
&:nth-child(1) { |
||||
transform: rotate(180deg); |
||||
} |
||||
} |
||||
} |
||||
|
||||
.bottom { |
||||
display: flex; |
||||
height: 120px; |
||||
|
||||
.logo { |
||||
width: 120px; |
||||
height: 100%; |
||||
border-radius: 4px; |
||||
} |
||||
|
||||
.info { |
||||
margin-left: 15px; |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: space-between; |
||||
|
||||
.name { |
||||
font-size: 18px; |
||||
color: #fff; |
||||
font-weight: bold; |
||||
margin-bottom: 10px; |
||||
} |
||||
|
||||
.user, .peoples { |
||||
margin-bottom: 5px; |
||||
color: #999999; |
||||
} |
||||
|
||||
.collection { |
||||
display: flex; |
||||
justify-content: center; |
||||
height: 25px; |
||||
width: 80px; |
||||
align-items: center; |
||||
color: #ffffff; |
||||
background: #999; |
||||
border-radius: 2px; |
||||
|
||||
img { |
||||
margin-right: 10px; |
||||
width: 15px; |
||||
height: 15px; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.content { |
||||
.tabs { |
||||
height: 40px; |
||||
display: flex; |
||||
align-items: center; |
||||
color: #fff; |
||||
|
||||
.tab { |
||||
height: 90%; |
||||
width: 50%; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
margin: 10px; |
||||
|
||||
&.active { |
||||
border-bottom: 3px solid yellow; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.video-container { |
||||
width: 33%; |
||||
float: left; |
||||
position: relative; |
||||
overflow: hidden; |
||||
border: .5px solid black; |
||||
|
||||
video { |
||||
width: 100%; |
||||
} |
||||
|
||||
.first { |
||||
padding: 0 5px; |
||||
border-radius: 4px; |
||||
position: absolute; |
||||
top: 10px; |
||||
left: 10px; |
||||
background: yellow; |
||||
} |
||||
|
||||
.no { |
||||
position: absolute; |
||||
color: #bdbdbd; |
||||
bottom: 10px; |
||||
right: 10px; |
||||
font-style: italic; |
||||
|
||||
span { |
||||
color: #ffffff; |
||||
font-size: 20px; |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,66 @@
@@ -0,0 +1,66 @@
|
||||
<template> |
||||
<div class="Test"> |
||||
<div class="content1"> |
||||
<BaseMarquee :is-play="true" :text="text" style="width: 150px;"/> |
||||
<BaseButton @click="triggerPause">pause</BaseButton> |
||||
<BaseButton @click="triggerStart">start</BaseButton> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
<script> |
||||
|
||||
import BaseButton from "../components/BaseButton"; |
||||
import BaseMarquee from "../components/BaseMarquee"; |
||||
import Dom from "../utils/dom"; |
||||
|
||||
export default { |
||||
name: "Test4", |
||||
components: {BaseButton, BaseMarquee}, |
||||
props: { |
||||
text: { |
||||
type: String, |
||||
default: '@喵嗷污说电影创作的原声' |
||||
} |
||||
}, |
||||
data() { |
||||
return { |
||||
timer: null, |
||||
contentWidth: 0, |
||||
transformX: 0, |
||||
$marqueeContent: null, |
||||
} |
||||
}, |
||||
methods: { |
||||
triggerPause() { |
||||
new Dom('.text').trigger('pause') |
||||
}, |
||||
triggerStart() { |
||||
new Dom('.text').trigger('start') |
||||
}, |
||||
}, |
||||
mounted() { |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped lang="less"> |
||||
@import "../assets/scss/index"; |
||||
|
||||
.Test { |
||||
position: fixed; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
top: 0; |
||||
overflow: auto; |
||||
font-size: 1.4rem; |
||||
color: white; |
||||
|
||||
.content1 { |
||||
padding-top: 6rem; |
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
</style> |
@ -0,0 +1,199 @@
@@ -0,0 +1,199 @@
|
||||
<template> |
||||
<div class="Music"> |
||||
<BaseHeader> |
||||
<template v-slot:center> |
||||
<span class="f16">申报学校信息</span> |
||||
</template> |
||||
<template v-slot:right> |
||||
<img src="../../assets/img/icon/share.svg" alt=""> |
||||
</template> |
||||
</BaseHeader> |
||||
<div class="content"> |
||||
<div class="bottom"> |
||||
<img class="logo" src="../../assets/img/poster/src1-bg.png" alt=""> |
||||
<div class="info"> |
||||
<div class="name">MT创作的原声</div> |
||||
<div class="user">NT ></div> |
||||
<div class="peoples">1人使用</div> |
||||
<div class="collection"> |
||||
<img src="../../assets/img/icon/collect-white.svg" alt=""> |
||||
<span>收藏</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="tabs"> |
||||
<div class="tab active" @click="toggleTab($event,0)">热门</div> |
||||
<div class="tab" @click="toggleTab($event,1)">最新</div> |
||||
</div> |
||||
<div class="video-container" v-for="(item,index) of videos" v-bind:style="{'height':width/3*1.2+'px'}"> |
||||
<video src="../../assets/video/1.mp4" poster="../../assets/img/poster/src1-bg.png"></video> |
||||
<div class="no" v-if="index===1||index===2"> |
||||
NO. <span>{{ index + 1 }}</span> |
||||
</div> |
||||
<span v-if="index===0" class="first">首发</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
<script> |
||||
|
||||
export default { |
||||
name: "Music", |
||||
components: {}, |
||||
data() { |
||||
return { |
||||
videos: [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}], |
||||
} |
||||
}, |
||||
created() { |
||||
}, |
||||
computed: {}, |
||||
methods: { |
||||
toggleTab(e, index) { |
||||
if (!e.target.classList.contains('active')) { |
||||
e.target.classList.toggle('active') |
||||
} |
||||
|
||||
if (index === 1) { |
||||
let pre = e.target.previousElementSibling |
||||
pre.classList.remove('active') |
||||
} else { |
||||
let pre = e.target.nextElementSibling |
||||
pre.classList.remove('active') |
||||
} |
||||
|
||||
}, |
||||
back() { |
||||
window.history.back() |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped lang="less"> |
||||
|
||||
@import "../../assets/scss/index"; |
||||
|
||||
.Music { |
||||
position: fixed; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
top: 0; |
||||
overflow: auto; |
||||
color: white; |
||||
font-size: 1.4rem; |
||||
|
||||
img { |
||||
width: 2rem; |
||||
height: 2rem; |
||||
} |
||||
|
||||
.content { |
||||
padding-top: 6rem; |
||||
|
||||
.bottom { |
||||
display: flex; |
||||
height: 120px; |
||||
|
||||
.logo { |
||||
width: 120px; |
||||
height: 100%; |
||||
border-radius: 4px; |
||||
} |
||||
|
||||
.info { |
||||
margin-left: 15px; |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: space-between; |
||||
|
||||
.name { |
||||
font-size: 18px; |
||||
color: #fff; |
||||
font-weight: bold; |
||||
margin-bottom: 10px; |
||||
} |
||||
|
||||
.user, .peoples { |
||||
margin-bottom: 5px; |
||||
color: #999999; |
||||
} |
||||
|
||||
.collection { |
||||
display: flex; |
||||
justify-content: center; |
||||
height: 25px; |
||||
width: 80px; |
||||
align-items: center; |
||||
color: #ffffff; |
||||
background: #999; |
||||
border-radius: 2px; |
||||
|
||||
img { |
||||
margin-right: 10px; |
||||
width: 15px; |
||||
height: 15px; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.tabs { |
||||
height: 40px; |
||||
display: flex; |
||||
align-items: center; |
||||
color: #fff; |
||||
|
||||
.tab { |
||||
height: 90%; |
||||
width: 50%; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
margin: 10px; |
||||
|
||||
&.active { |
||||
border-bottom: 3px solid yellow; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.video-container { |
||||
width: 33%; |
||||
float: left; |
||||
position: relative; |
||||
overflow: hidden; |
||||
border: .5px solid black; |
||||
|
||||
video { |
||||
width: 100%; |
||||
} |
||||
|
||||
.first { |
||||
padding: 0 5px; |
||||
border-radius: 4px; |
||||
position: absolute; |
||||
top: 10px; |
||||
left: 10px; |
||||
background: yellow; |
||||
} |
||||
|
||||
.no { |
||||
position: absolute; |
||||
color: #bdbdbd; |
||||
bottom: 10px; |
||||
right: 10px; |
||||
font-style: italic; |
||||
|
||||
span { |
||||
color: #ffffff; |
||||
font-size: 20px; |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
</style> |
Loading…
Reference in new issue