音乐网站设计

设计内容:

音乐网站网站是一款提供在线播放音乐和下载音乐功能的网站,具有音乐排行榜、歌星排行榜、音乐分类三个板块,并提供查询功能,要求如下:

① 页面布局合理,色彩和谐,链接正确,图文并茂,网页总数不少于8页。

② 网站结构合理,对网站中的文件要按文件类型建立相应的文件夹存放。

③ 要使用HTML、CSS和Javascript技术

④ 以下技术根据自己的实际掌握情况可选:

1)HTML5

2)Jquery

3)Bootstrap

  1. Vue.js(或React.js或Angular.js)

摘 要

音乐网站设计是设计开发一个音乐播发及音乐推荐平台,该平台可以根据用户的喜好推荐音乐,还可以为用户推荐当前热门歌曲和人气排行等大众喜欢的歌曲推荐给用户,满足用户的音乐需求。html、css、以及vue框架等技术实现了音乐播发及音乐推荐平台,此平台具有用户登录、歌曲搜索、热门歌曲推荐、用户喜欢歌曲推荐、歌曲排行推荐等主要功能。

关键词:音乐网站;需求分析;系统设计

1.课题描述

互联网式的音乐传播彻底改变了原有传统的音频传播途径与方式,方便的传播途径,高效的传播效率,有利于社会资源的最大化利用[5]。由于音乐平台使用方便,越来越受到大家地欢迎。但这也导致了中国的音乐网站平台数量的激增,网站为了能够有自己稳定的使用者,网站之间的竞争也空前激烈,为能在中国众多的音乐平台中起到领导地位,建立一个具有自己特色的,功能详细,实用的音乐播放及音乐推荐平台尤为重要。

音乐网站使用电脑对音乐进行管理,给用户一个良好的视觉呈现成果,通过页面元素的布局让用户直接可以进行查询搜索功能操作,进行登录操作后进行个人信息的设计以及对自己喜欢歌曲的管理。

2 应用技术

本次实训是关于音乐网站的设计,主要是进行计算机前端内容的编写,前端开发是创建WEB页面或APP等前端界面呈现给用户的过程,通过HTML,CSS及JavaScript以及衍生出来的各种技术,本文用的是VUE框架,解决方案,来实现互联网产品的用户界面交互。

2.1HTML5

HTML5 是定义 HTML 标准的最新的版本。该术语通过两个不同的概念来表现:它是一个新版本的HTML语言,具有新的元素,属性和行为,它有更大的技术集,允许构建更多样化和更强大的网站和应用程序。这个集合有时称为HTML5和它的朋友们,不过大多数时候仅缩写为一个词 HTML5。

它能够让你更恰当地描述你的内容是什么。能够让你和服务器之间通过创新的新技术方法进行通信。能够让网页在客户端本地存储数据以及更高效地离线运行。使 video 和 audio 成为了在所有 Web 中的一等公民。提供了一个更加分化范围的呈现选择。提供了非常显著的性能优化和更有效的计算机硬件使用。能够处理各种输入和输出设备及样式设计。

2.2 CSS

CSS是CascadingStyle Sheets (层叠样式表)的简称,是一组格式设置的规则和外观样式的定义M。CSS在Web应用程序界面中起到重要的作用:CSS简化了网页的代码,提高了网页的访问速度。因为外部的CSS文件会被浏览器保存在缓存中,从而加快了页面显示的速度,同时也减少了上传的代码量;CSS让网页更容易维护,其便于修改网站的样式,只需要修改CSS文件就可以改变整个网站的类型特色,避免了一个一个网页的修改,大大的减少了开发人员的工作量,而且已经定义过的css文件可以重用,即重用原来网页的样式;css使网页的功能更为强大,用户可以根据自己的需求来定义页面的显示类型等以及一些页面的特效等;同时,它将页面显示的内容与显示样式相分离,两者可以是单独的文件即.html文件和.css 文件,便于开发人员的修改和维护。

2.3 js

JavaScript是一种属于网络的脚本语言,已经被广泛应用于Web开发,常用于为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果。通常JavaScript是通过嵌入在HTML里来实现其功能。

1、是一种解释性脚本语言。

2、主要用来向HTML页面添加交互行为的语言。

3、可以直接嵌入HTML页面,但写成单独的JS文件更加的有利于代码的分离,利于后期的维护。

4、跨平台特性,能够在绝大多数浏览器的支持下,可以在多种平台下运行。

2.4 vue框架

Vue 是一款用于构建用户界面的JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。

2.5数据库MYSQL

数据库(database)就是一个存储数据的仓库。为了方便数据的管理与储存,它将数据按照特定的条件存储在磁盘上。通过数据库管理系统,可以高效的处理和管理存储在数据库中的数据。而且MySQL数据库可以说是是目前运行速度最快的SQL语言数据库。具有快捷、便捷、易用、高效、安全、大批量等优点。

3 需求分析

需求分析是经过深入细致的调研和分析,准确理解用户和项目的功能、性能、可靠性等具体要求,将用户非形式的需求表述转化为完整的需求定义,从而确定系统必须做什么的过程。本系统是一个音乐网站的设计,为了给用户提供一个听歌且为用户推荐其个人感兴趣歌曲的平台。用户注册成为系统用户后可以对系统中的歌曲进行播放,在系统的页面搜索中查询歌曲,用户可以给歌曲进行评论,平台会展示热门歌曲给用户,为用户推荐个性化的歌曲,用户在平台中管理自己的信息。

3.1功能分析

音乐播放及音乐推荐平台主要功能是让用户满足听歌并为用户推荐歌曲的作用。用户在系统中可以查询歌曲信息、对歌曲进行评价,为用户提供个性化的服务。

本系统主要模块:

1.用户登录

登录是为保障系统的安全,用户输入账号密码然后进行登录进入系统主界面。

2.主界面

主界面是系统的主要功能展示的界面,为用户提供最核心的功能以及指引用户操作。

3.歌曲搜索

可以搜索歌曲信息。

4. 热门歌曲推荐

将热门歌曲推荐给用户。

5.用户喜欢歌曲推荐

平台推荐用户可能喜欢的歌曲。

6. 歌曲排行推荐

将平台歌曲进行一个排名,给用户提供歌曲选择的信息。

7. 歌曲评论及展示

用户可以给歌曲评论及看其他用户评论。

8. 歌曲分类展示

可以将歌曲分类并展示用户查看。

3.2性能分析

每个用户自己的需要不同,考虑以后的发展和同时使用系统的情况,要求系统具备一下性能:

1)系统要满足用户注册登录功能,方便每个用户的使用。

  1. 系统要满足用户搜索功能,方便用户对音乐的选择。

4系统设计

系统设计是根据系统分析的结果,运用系统科学的思想和方法,设计出能最大限度满足所要求的目标的新系统的过程。系统设计内容,包括确定系统功能、设计方针和方法,产生理想系统并作出草案,通过收集信息对草案作出修正产生可选设计方案,将系统分解为若干子系统,进行子系统和总系统的详细设计并进行评价,对系统方案进行论证并作出性能效果预测。

4.1整体布局

页面整体布局 为头,主体和底部三部分,上中下三栏布局。头部导航栏和底部是固定的,当点击导航栏的首页,歌单,歌手,我的音乐,搜索框,登录和注册,在主体部分会显示相应内容,效果图如下图1所示。

图4.1整体布局图

5 网站与网页设计内容

内部部分主要通过下面几个模块来进行陈述,分别是注册部分,登录部分,导航栏部分,首页部分人,歌手部分,歌曲部分,我的音乐七大部分。

5.1注册部分

首先用户可以先注册账号 ,通过表单来输写个人信息,其中 用户名 密码,性别和生日为必填写内容,手机号,邮箱,地区为非必填项目。

图5.1注册图

<template>
<div class="info"><p class="title">编辑个人资料</p><hr/><div class="personal"><el-form :model="registerForm" class="demo-ruleForm" label-width="80px"><el-form-item prop="username" label="用户名"><el-input v-model="registerForm.username" placeholder="用户名"></el-input></el-form-item><el-form-item prop="password" label="密码"><el-input type="password" placeholder="密码" v-model="registerForm.password"></el-input></el-form-item><el-form-item label="性别"><el-radio-group v-model="registerForm.sex"><el-radio :label="0">女</el-radio><el-radio :label="1">男</el-radio></el-radio-group></el-form-item><el-form-item prop="phoneNum" label="手机"><el-input placeholder="手机" v-model="registerForm.phoneNum" ></el-input></el-form-item><el-form-item prop="email" label="邮箱"><el-input v-model="registerForm.email" placeholder="邮箱"></el-input></el-form-item><el-form-item prop="birth" label="生日"><el-date-picker type="date" placeholder="选择日期" v-model="registerForm.birth" style="width: 100%;"></el-date-picker></el-form-item><el-form-item prop="introduction" label="签名"><el-input type="textarea" placeholder="签名" v-model="registerForm.introduction" ></el-input></el-form-item><el-form-item prop="location" label="地区"><el-select v-model="registerForm.location" placeholder="地区" style="width:100%"><el-optionv-for="item in cities":key="item.value":label="item.label":value="item.value"></el-option></el-select></el-form-item></el-form><div class="btn"><div @click="saveMsg()">保存</div><div @click="goback">取消</div></div></div>
</div>
</template><script>
import { mapGetters } from 'vuex'
import mixin from '../mixins'
import { cities } from '../assets/data/form'
import { updateUserMsg, getUserOfId } from '../api/index'export default {
name: 'info',
mixins: [mixin],
data: function () {return {registerForm: { // 注册username: '',password: '',sex: '',phoneNum: '',email: '',birth: '',introduction: '',location: ''},cities: []}
},
computed: {...mapGetters(['userId'])
},
created () {this.cities = cities
},
mounted () {this.getMsg(this.userId)
},
methods: {getMsg (id) {getUserOfId(id).then(res => {this.registerForm.username = res[0].usernamethis.registerForm.password = res[0].passwordthis.registerForm.sex = res[0].sexthis.registerForm.phoneNum = res[0].phoneNumthis.registerForm.email = res[0].emailthis.registerForm.birth = res[0].birththis.registerForm.introduction = res[0].introductionthis.registerForm.location = res[0].locationthis.registerForm.avator = res[0].avator}).catch(err => {console.log(err)})},goback () {this.$router.go(-1)},saveMsg () {let d = new Date(this.registerForm.birth)let datetime = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate()let params = new URLSearchParams()params.append('id', this.userId)params.append('username', this.registerForm.username)params.append('password', this.registerForm.password)params.append('sex', this.registerForm.sex)params.append('phone_num', this.registerForm.phoneNum)params.append('email', this.registerForm.email)params.append('birth', datetime)params.append('introduction', this.registerForm.introduction)params.append('location', this.registerForm.location)updateUserMsg(params).then(res => {if (res.code === 1) {this.showError = falsethis.showSuccess = truethis.$store.commit('setUsername', this.registerForm.username)this.$notify.success({title: '编辑成功',showClose: true})setTimeout(function () {this.$router.go(-1)}, 2000)} else {this.showSuccess = falsethis.showError = truethis.$notify.error({title: '编辑失败',showClose: true})}}).catch(err => {console.log(err)})}
}
}
</script>

5.2登录部分

首先用户可以先注册账号 ,通过表单来输写个人信息,其中 用户名 密码,性别和生日为必填写内容,手机号,邮箱,地区为非必填项目。

图5.2登录图

<script>
export default {data() {return {uname: '',upwd: '',isSee: false,tips: ''}},methods: {showInfo() {if (this.uname === '' && this.upwd === '') {this.isSee = true;this.tips = '用户名字密码不能为空';return;} else {this.isSee = false;if (this.uname === 'admin' && this.upwd === 'zzz') {this.$router.push({path: '/index:id',name: 'A',props:true,})} else {this.isSee = true;this.tips = "用户名或者密码错误";}}},}
}</script><template><div class="main"><h2>登录页面</h2><div class="form">用户名:<input type="text" name="username" v-model="uname"><br>密&nbsp;&nbsp;&nbsp;码:<input type="password" name="password" v-model="upwd"><br><button  v-on:click="showInfo">登录</button><br></div><h2 :class="{ tip: isSee }" v-show="isSee">{{ tips }}</h2></div>
</template>
导航栏部分代码如下:
<template><div class="the-header"><!--图标--><div class="header-logo" @click="goHome"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-erji"></use></svg><span>{{musicName}}</span></div><ul class="navbar" ref="change"><li :class="{active: item.name === activeName}" v-for="item in navMsg" :key="item.path" @click="goPage(item.path, item.name)">{{item.name}}</li><li><div class="header-search"><input type="text" placeholder="搜索音乐" @keyup.enter="goSearch()" v-model="keywords"><div class="search-btn"  @click="goSearch()" ><svg class="icon" aria-hidden="true"><use xlink:href="#icon-sousuo"></use></svg></div></div></li><li v-show="!loginIn" :class="{active: item.name === activeName}" v-for="item in loginMsg" :key="item.type" @click="goPage(item.path, item.name)">{{item.name}}</li></ul><!--设置--><div class="header-right" v-show="loginIn"><div id="user"><img :src="attachImageUrl(avator)" alt=""></div><ul class="menu"><li v-for="(item, index) in menuList" :key="index" @click="goMenuList(item.path)">{{item.name}}</li></ul></div></div>
</template><script>
import { mapGetters } from 'vuex'
import mixin from '../mixins'
import { navMsg, loginMsg, menuList } from '../assets/data/header'export default {name: 'the-header',mixins: [mixin],data () {return {musicName: '个人-音乐',navMsg: [], // 左侧导航栏loginMsg: [], // 右侧导航栏menuList: [], // 用户下拉菜单项keywords: ''}
},computed: {...mapGetters(['userId','activeName','avator','username','loginIn'])
},created () {this.navMsg = navMsgthis.loginMsg = loginMsgthis.menuList = menuList
},mounted () {document.querySelector('#user').addEventListener('click', function (e) {document.querySelector('.menu').classList.add('show')e.stopPropagation()// 关键在于阻止冒泡}, false)// 点击“菜单”内部时,阻止事件冒泡。(这样点击内部时,菜单不会关闭)document.querySelector('.menu').addEventListener('click', function (e) {e.stopPropagation()}, false)document.addEventListener('click', function () {document.querySelector('.menu').classList.remove('show')}, false)
},methods: {goHome () {this.$router.push({path: '/'})},goPage (path, value) {document.querySelector('.menu').classList.remove('show')this.changeIndex(value)if (!this.loginIn && path === '/my-music') {this.notify('请先登录', 'warning')} else {this.$router.push({path: path})}},changeIndex (value) {this.$store.commit('setActiveName', value)},goMenuList (path) {if (path === 0) {this.$store.commit('setIsActive', false)}document.querySelector('.menu').classList.remove('show')if (path) {this.$router.push({path: path})} else {this.$store.commit('setLoginIn', false)this.$router.go(0)}},goSearch () {this.$store.commit('setSearchword', this.keywords)this.$router.push({path: '/search', query: {keywords: this.keywords}})}
}
}

5.3导航栏部分

导航部分是整个页面的头部部分,不会随着内容的改变而改变,采用的是tab切换,当点击导航栏部分的按钮,会在主页显示相应内容。

图5.3导航栏图

<template><div class="the-header"><!--图标--><div class="header-logo" @click="goHome"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-erji"></use></svg><span>{{musicName}}</span></div><ul class="navbar" ref="change"><li :class="{active: item.name === activeName}" v-for="item in navMsg" :key="item.path" @click="goPage(item.path, item.name)">{{item.name}}</li><li><div class="header-search"><input type="text" placeholder="搜索音乐" @keyup.enter="goSearch()" v-model="keywords"><div class="search-btn"  @click="goSearch()" ><svg class="icon" aria-hidden="true"><use xlink:href="#icon-sousuo"></use></svg></div></div></li><li v-show="!loginIn" :class="{active: item.name === activeName}" v-for="item in loginMsg" :key="item.type" @click="goPage(item.path, item.name)">{{item.name}}</li></ul><!--设置--><div class="header-right" v-show="loginIn"><div id="user"><img :src="attachImageUrl(avator)" alt=""></div><ul class="menu"><li v-for="(item, index) in menuList" :key="index" @click="goMenuList(item.path)">{{item.name}}</li></ul></div></div>
</template><script>
import { mapGetters } from 'vuex'
import mixin from '../mixins'
import { navMsg, loginMsg, menuList } from '../assets/data/header'export default {name: 'the-header',mixins: [mixin],data () {return {musicName: '个人-音乐',navMsg: [], // 左侧导航栏loginMsg: [], // 右侧导航栏menuList: [], // 用户下拉菜单项keywords: ''}
},computed: {...mapGetters(['userId','activeName','avator','username','loginIn'])
},created () {this.navMsg = navMsgthis.loginMsg = loginMsgthis.menuList = menuList
},mounted () {document.querySelector('#user').addEventListener('click', function (e) {document.querySelector('.menu').classList.add('show')e.stopPropagation()// 关键在于阻止冒泡}, false)// 点击“菜单”内部时,阻止事件冒泡。(这样点击内部时,菜单不会关闭)document.querySelector('.menu').addEventListener('click', function (e) {e.stopPropagation()}, false)document.addEventListener('click', function () {document.querySelector('.menu').classList.remove('show')}, false)
},methods: {goHome () {this.$router.push({path: '/'})},goPage (path, value) {document.querySelector('.menu').classList.remove('show')this.changeIndex(value)if (!this.loginIn && path === '/my-music') {this.notify('请先登录', 'warning')} else {this.$router.push({path: path})}},changeIndex (value) {this.$store.commit('setActiveName', value)},goMenuList (path) {if (path === 0) {this.$store.commit('setIsActive', false)}document.querySelector('.menu').classList.remove('show')if (path) {this.$router.push({path: path})} else {this.$store.commit('setLoginIn', false)this.$router.go(0)}},goSearch () {this.$store.commit('setSearchword', this.keywords)this.$router.push({path: '/search', query: {keywords: this.keywords}})}
}
}
</script>

5.4首页部分

首页页面主体分为三部分,上面部分放了一个轮播图,中间部分是歌单,当用户点歌单的时候会跳到歌单页面同时在底部会播放音乐,下半部分是歌手,当点击歌手页面的时候会跳转到歌手页面,显示歌手的信息,效果图如下图所示。

图5.4首页图

5.5歌手部分

用户通过点击首页的歌手或者在导航栏点击歌手按钮 ,会显示男歌手女歌手以及组合歌手。

图5.5歌手图

template><div class="content"><h1 class="title"><slot name="title"></slot></h1><hr><ul><li class="list-title"><div class="song-item"><span class="item-index"></span><span class="item-title">歌曲名</span><span class="item-name">艺人</span><span class="item-intro">专辑</span></div></li><li class="list-content" v-for="(item, index) in songList" :key="index"><div class="song-item" :class="{'is-play': id === item.id}"  @click="toplay(item.id, item.url, item.pic, index, item.name, item.lyric)"><span class="item-index"><span v-if="id !== item.id">{{index + 1}}</span><svg v-if="id === item.id" class="icon" aria-hidden="true"><use xlink:href="#icon-yinliang"></use></svg></span><span class="item-title">{{replaceFName(item.name)}}</span><span class="item-name">{{replaceLName(item.name)}}</span><span class="item-intro">{{item.introduction}}</span></div></li></ul></div>
</template><script>
import { mapGetters } from 'vuex'
import mixin from '../mixins'export default {name: 'album-content',mixins: [mixin],props: {songList: Array
},computed: {...mapGetters(['id' // 音乐ID])
}
}
</script>

5.6歌曲部分

用户点击歌曲的时候或者点击首页布局中的歌曲的时候,会显示歌曲分类华语粤语欧美日韩轻音乐BGM乐器。

template><div class="content"><h1 class="title"><slot name="title"></slot></h1><hr><ul><li class="list-title"><div class="song-item"><span class="item-index"></span><span class="item-title">歌曲名</span><span class="item-name">艺人</span><span class="item-intro">专辑</span></div></li><li class="list-content" v-for="(item, index) in songList" :key="index"><div class="song-item" :class="{'is-play': id === item.id}"  @click="toplay(item.id, item.url, item.pic, index, item.name, item.lyric)"><span class="item-index"><span v-if="id !== item.id">{{index + 1}}</span><svg v-if="id === item.id" class="icon" aria-hidden="true"><use xlink:href="#icon-yinliang"></use></svg></span><span class="item-title">{{replaceFName(item.name)}}</span><span class="item-name">{{replaceLName(item.name)}}</span><span class="item-intro">{{item.introduction}}</span></div></li></ul></div>
</template><script>
import { mapGetters } from 'vuex'
import mixin from '../mixins'export default {name: 'album-content',mixins: [mixin],props: {songList: Array
},computed: {...mapGetters(['id' // 音乐ID])
}
}
</script>

5.7我的音乐部分

用户下载的音乐在我的音乐里,会显示音乐名字,歌手名字和专辑名字。

<template><div class="upload"><p class="title">修改头像</p><hr/><div class="section"><el-uploaddrag:action="uploadUrl()":show-file-list="false":on-success="handleAvatarSuccess":before-upload="beforeAvatarUpload"><i class="el-icon-upload"></i><div class="el-upload__text">将文件拖到此处,或<em>修改头像</em></div><div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过10M</div></el-upload></div></div>
</template><script>
import { mapGetters } from 'vuex'
import mixin from '../mixins'export default {name: 'upload',mixins: [mixin],data () {return {imageUrl: ''}
},computed: {...mapGetters(['userId'])
},methods: {uploadUrl () {return `${this.$store.state.configure.HOST}/user/avatar/update?id=${this.userId}`},handleAvatarSuccess (res, file) {if (res.code === 1) {this.imageUrl = URL.createObjectURL(file.raw)this.$store.commit('setAvator', res.avator)this.$message({message: '修改成功',type: 'success'})} else {this.notify('修改失败', 'error')}},beforeAvatarUpload (file) {const isJPG = file.type === 'image/jpeg'const isLt2M = file.size / 1024 / 1024 < 10if (!isJPG) {this.$message.error('上传头像图片只能是 JPG 格式!')}if (!isLt2M) {this.$message.error('上传头像图片大小不能超过 10MB!')}return isJPG && isLt2M}
}
}
</script>

6网站部署和测试

6.1搜索功能

搜索部分通过歌手和歌曲名搜索,歌手和歌曲的数据来源于数据数据库,如果在搜索中不能找到相应歌手或者相应歌曲,会 弹出来此歌手或者歌曲不存在的警告。

6.1.1通过歌曲查询

如下当输入歌曲“天下”的时候会显示歌曲的详细信息艺人和专辑,效果图如下

图6.1歌曲搜索图

<template><div class="search-song-Lists"><content-list :contentList="albumDatas" path="song-list-album"></content-list></div>
</template><script>
import ContentList from '../ContentList'
import mixin from '../../mixins'
import { getSongListOfLikeTitle } from '../../api/index'export default {name: 'search-song-Lists',mixins: [mixin],components: {ContentList
},data () {return {albumDatas: []}
},mounted () {this.getSearchList()
},methods: {getSearchList () {if (!this.$route.query.keywords) returngetSongListOfLikeTitle(this.$route.query.keywords).then(res => {if (!res.length) {this.notify('暂无该歌曲内容', 'warning')} else {this.albumDatas = res}})}
}
}
</script>

6.1.2通过歌手搜索查询

在导航栏的搜索框里输入歌手的名字 ,会显示数据库中所有关于歌手的歌单,例如搜索查询歌手“张杰”,会显示他的所有歌曲,如果没有,则会判断弹出来警告,没有此歌手。

图6.2歌手搜索图

<template><div class="search-songs"><album-content :songList="listOfSongs"></album-content></div>
</template><script>
import { mapGetters } from 'vuex'
import mixin from '../../mixins'
import AlbumContent from '../AlbumContent'export default {name: 'search-songs',mixins: [mixin],components: {AlbumContent
},computed: {...mapGetters(['listOfSongs' // 存放的音乐])
},mounted () {this.getSong()
}
}
</script>

6.2播放部分

当用户点击音乐的时候,会进行音乐的播放与停止操作。

图6.3播放图

<template>
<div class="play-bar" :class="{show:!toggle}"><div @click="toggle=!toggle" class="item-up" :class="{turn: toggle}"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-jiantou-xia-cuxiantiao"></use></svg></div><div class="kongjian" ><!--上一首--><div class="item" @click="prev"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-ziyuanldpi"></use></svg></div><!--播放--><div class="item" @click="togglePlay"><svg class="icon" aria-hidden="true"><use :xlink:href="playButtonUrl"></use></svg></div><!--下一首--><div class="item" @click="next"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-ziyuanldpi1"></use></svg></div><!--歌曲图片--><div class="item-img" @click="goPlayerPage"><img :src=picUrl alt=""></div><!--播放进度--><div class="playing-speed"><!--播放开始时间--><div class="current-time">{{ nowTime }}</div><div class="progress-box"><div class="item-song-title"><div>{{this.title}}</div><div>{{this.artist}}</div></div><div ref="progress" class="progress" @mousemove="mousemove"><!--进度条--><div ref="bg" class="bg" @click="updatemove"><div ref="curProgress" class="cur-progress" :style="{width: curLength+'%'}"></div></div><!--进度条 end --><!--拖动的点点--><div ref="idot" class="idot" :style="{left: curLength+'%'}" @mousedown="mousedown" @mouseup="mouseup"></div><!--拖动的点点 end --></div></div><!--播放结束时间--><div class="left-time">{{ songTime }}</div></div><!--音量--><div class="item icon-volume" ><svg v-if="volume !== 0" class="icon" aria-hidden="true"><use xlink:href="#icon-yinliang1"></use></svg><svg v-else class="icon" aria-hidden="true"><use xlink:href="#icon-yinliangjingyinheix"></use></svg><el-slider class="volume" v-model="volume" :vertical="true"></el-slider></div><!--添加--><div class="item" @click="collection"><svg :class="{ active: isActive }" class="icon" aria-hidden="true"><use xlink:href="#icon-xihuan-shi"></use></svg></div><!--下载--><div class="item" @click="download"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-xiazai"></use></svg></div><!--歌曲列表--><div class="item" @click="changeAside"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-liebiao"></use></svg></div></div>
</div>
</template><script>
import { mapGetters } from 'vuex'
import mixin from '../mixins'
import { setCollection, download } from '../api/index'export default {
name: 'play-bar',
mixins: [mixin],
data () {return {tag: false,nowTime: '00:00',songTime: '00:00',curLength: 0, // 进度条的位置progressLength: 0, // 进度条长度mouseStartX: 0, // 拖拽开始位置toggle: true,volume: 50}
},
computed: {...mapGetters(['loginIn', // 用户登录状态'userId', // 用户 id'isPlay', // 播放状态'playButtonUrl', // 播放状态的图标'id', // 音乐id'url', // 音乐地址'title', // 歌名'artist', // 歌手名'picUrl', // 歌曲图片'curTime', // 当前音乐的播放位置'duration', // 音乐时长'listOfSongs', // 当前歌单列表'listIndex', // 当前歌曲在歌曲列表的位置'showAside', // 是否显示侧边栏'autoNext', // 用于触发自动播放下一首'isActive'])
},
watch: {// 切换播放状态的图标isPlay (val) {if (val) {this.$store.commit('setPlayButtonUrl', '#icon-zanting')} else {this.$store.commit('setPlayButtonUrl', '#icon-bofang')}},volume () {this.$store.commit('setVolume', this.volume / 100)},// 播放时间的开始和结束curTime () {this.nowTime = this.formatSeconds(this.curTime)this.songTime = this.formatSeconds(this.duration)// 移动进度条this.curLength = (this.curTime / this.duration) * 100// 处理歌词位置及颜色},// 自动播放下一首autoNext () {this.next()}
},
mounted () {this.progressLength = this.$refs.progress.getBoundingClientRect().widthdocument.querySelector('.icon-volume').addEventListener('click', function (e) {document.querySelector('.volume').classList.add('show-volume')e.stopPropagation()}, false)document.querySelector('.volume').addEventListener('click', function (e) {e.stopPropagation()}, false)document.addEventListener('click', function () {document.querySelector('.volume').classList.remove('show-volume')}, false)
},
methods: {// 下载download () {download(this.url).then(res => {let content = res.datalet eleLink = document.createElement('a')eleLink.download = `${this.artist}-${this.title}.mp3`eleLink.style.display = 'none'// 字符内容转变成blob地址let blob = new Blob([content])eleLink.href = URL.createObjectURL(blob)// 触发点击document.body.appendChild(eleLink)eleLink.click()// 然后移除document.body.removeChild(eleLink)}).catch(err => {console.log(err)})},changeAside () {let temp = !this.showAsidethis.$store.commit('setShowAside', temp)},// 控制音乐播放 / 暂停togglePlay () {if (this.isPlay) {this.$store.commit('setIsPlay', false)} else {this.$store.commit('setIsPlay', true)}},// 解析播放时间formatSeconds (value) {let theTime = parseInt(value)let theTime1 = 0let theTime2 = 0if (theTime > 60) {theTime1 = parseInt(theTime / 60) // 分theTime = parseInt(theTime % 60) // 秒// 是否超过一个小时if (theTime1 > 60) {theTime2 = parseInt(theTime1 / 60) // 小时theTime1 = 60 // 分}}// 多少秒if (parseInt(theTime) < 10) {var result = '0:0' + parseInt(theTime)} else {result = '0:' + parseInt(theTime)}// 多少分钟时if (theTime1 > 0) {if (parseInt(theTime) < 10) {result = '0' + parseInt(theTime)} else {result = parseInt(theTime)}result = parseInt(theTime1) + ':' + result}// 多少小时时if (theTime2 > 0) {if (parseInt(theTime) < 10) {result = '0' + parseInt(theTime)} else {result = parseInt(theTime)}result = parseInt(theTime2) + ':' + parseInt(theTime1) + ':' + result}return result},// 拖拽开始mousedown (e) {this.mouseStartX = e.clientXthis.tag = true},// 拖拽结束mouseup () {this.tag = false},// 拖拽中mousemove (e) {if (!this.duration) {return false}if (this.tag) {let movementX = e.clientX - this.mouseStartXlet curLength = this.$refs.curProgress.getBoundingClientRect().width// 计算出百分比this.progressLength = this.$refs.progress.getBoundingClientRect().widthlet newPercent = ((curLength + movementX) / this.progressLength) * 100if (newPercent > 100) {newPercent = 100}this.curLength = newPercentthis.mouseStartX = e.clientX// 根据百分比推出对应的播放时间this.changeTime(newPercent)}},// 更改歌曲进度changeTime (percent) {let newCurTime = this.duration * (percent * 0.01)this.$store.commit('setChangeTime', newCurTime)},updatemove (e) {if (!this.tag) {let curLength = this.$refs.bg.offsetLeftthis.progressLength = this.$refs.progress.getBoundingClientRect().widthlet newPercent = ((e.clientX - curLength) / this.progressLength) * 100if (newPercent < 0) {newPercent = 0} else if (newPercent > 100) {newPercent = 100}this.curLength = newPercentthis.changeTime(newPercent)}},// 上一首prev () {if (this.listIndex !== -1 && this.listOfSongs.length > 1) {if (this.listIndex > 0) {this.$store.commit('setListIndex', this.listIndex - 1)this.toPlay(this.listOfSongs[this.listIndex].url)} else {this.$store.commit('setListIndex', this.listOfSongs.length - 1)this.toPlay(this.listOfSongs[this.listIndex].url)}}},// 下一首next () {if (this.listIndex !== -1 && this.listOfSongs.length > 1) {if (this.listIndex < this.listOfSongs.length - 1) {this.$store.commit('setListIndex', this.listIndex + 1)this.toPlay(this.listOfSongs[this.listIndex].url)} else {this.$store.commit('setListIndex', 0)this.toPlay(this.listOfSongs[0].url)}}},// 选中播放toPlay (url) {if (url && url !== this.url) {this.$store.commit('setId', this.listOfSongs[this.listIndex].id)this.$store.commit('setUrl', this.$store.state.configure.HOST + url)this.$store.commit('setpicUrl', this.$store.state.configure.HOST + this.listOfSongs[this.listIndex].pic)this.$store.commit('setTitle', this.replaceFName(this.listOfSongs[this.listIndex].name))this.$store.commit('setArtist', this.replaceLName(this.listOfSongs[this.listIndex].name))this.$store.commit('setLyric', this.parseLyric(this.listOfSongs[this.listIndex].lyric))}},goPlayerPage () {this.$router.push({path: `/lyric/${this.id}`})},collection () {if (this.loginIn) {var params = new URLSearchParams()params.append('userId', this.userId)params.append('type', 0) // 0 代表歌曲, 1 代表歌单params.append('songId', this.id)setCollection(params).then(res => {if (res.code === 1) {this.$store.commit('setIsActive', true)this.notify('收藏成功', 'success')} else if (res.code === 2) {this.notify('已收藏', 'warning')} else {this.$notify.error({title: '收藏失败',showClose: false})}}).catch(err => {console.log(err)})} else {this.notify('请先登录', 'warning')}}
}
}
</script>

7总结

本次课设,通过自己对相关系统进行分析以及设计,使我对信息系统分析与设计这门课有了更深层次的理解以及对PD建模工具使用的更加得心应手。在课程设计过程中,首先要从需求分析出发,对系统进行深入分析。需求分析是前提,只有做好了分析,设计的系统才能符合用户的需求,对前端的内容html,css,js的初步了解通过查阅有关图书信息,以及回忆之前所学内容,运用vue框架完成了本次实训,总结了很多有价值有意义的学习经验,还能让我把以前学到的知识加以巩固并且进一步的提高对现在所学知识的理解,让我认识到了自己在以前学习方面的不足之处。以后还需要继续努力。

参考文献

[1]王昊,刘友华.信息系统分析与设计[M].江苏:南京大学出版社,2021.

[2]张俊玲.数据库原理与应用[M].北京:清华大学出版社,2010.

[3]苗雪兰,刘瑞新,宋歌.数据库系统原理[M]. 北京:机械工业出版社,2007.

[4]刘亚军,高莉莎.数据库设计及应用[M]. 北京:清华大学出版社,2007.

[5]何东健.网页设计与Web编程[M]. 西安:西安交通大学出版社,2004.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/52197.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

音乐app、音乐原型、在线音乐、云音乐、听歌、电台、本地音乐、点赞、收藏、歌单广场、动态、社区、评论、歌词、歌手、主播、视频、云村、下载、翻唱、歌曲播放、订阅、频道、引导页、登录注册、axure原型

音乐app、音乐原型、在线音乐、云音乐、听歌、电台、本地音乐、点赞、收藏、歌单广场、动态、社区、评论、歌词、歌手、主播、视频、云村、下载、翻唱、歌曲播放、订阅、频道、引导页、登录注册、axure原型、产品原型 Axure原型演示及下载地址&#xff1a;Axure Cloud - Gener…

【学习笔记】穿T恤听古典音乐

文章目录 1 走进古典音乐1.1 音乐中的自然法则1.2 音乐要素如何模仿1.3 模仿与超越 2 每一天的巴赫2.1 巴赫的故事与作品2.2 对位法2.3 数学之美 3 莫扎特&#xff1a;把日子过成歌剧3.1 《莫扎特传》序曲——唐璜3.2 历史地位与风格演变3.3 咏叹调与宣叙调3.4 《后宫诱逃》3.5…

如何找到能商用的背景纯音乐

很多时候&#xff0c;我们在网上下载的音乐都是不能商用的。如果要商用就必须向作者购买版权授权。对于一些自媒体、博主、小公司等&#xff0c;这将是一笔不菲的费用。那么&#xff0c;哪里有免费可商用的背景配乐吗&#xff1f; 有的&#xff0c;那就是版权协议为CC0的公共音…

设计师精选实用AI工具合集 | Midjourney 、GPT等...

作为一名设计师&#xff0c;我们都知道&#xff0c;在智能化技术的推动下及ChatGPT的突然爆火&#xff0c;越来越多的AI工具正在被设计师广泛应用于日常工作中。 在这里给设计师们介绍几款功能强大、易于使用的AI设计工具。 第一款&#xff0c;基于 GPT 的 Figma 配色生成插件…

比尔·盖茨退出微软董事会,回顾盖茨与微软的传奇故事

作者&#xff5c;年素清 责编&#xff5c;伍杏玲 出品&#xff5c;CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 头图&#xff5c;视觉中国 微软于周五宣布&#xff0c;公司联合创始人兼技术顾问比尔盖茨&#xff08;Bill Gates&#xff09;辞去微软董事会职务。 对于这…

后盖茨的IT世界

本文应《中华读书报》之邀所写。 图1 Joel Spolsky的新书More Joelon Software中文版,人民邮电出版社即将出版图2 The Big Switch,中文版,中信出版社 比尔盖茨今以壮岁之年隐退&#xff0c;不再掌管微软帝国的日常工作&#xff0c;标志着一个时代的结束。过渡从两年前就开始…

电子计算机比尔盖茨和微软品牌,尉迟:比尔盖茨卖安全套 牌子不能叫微软

核心提示&#xff1a;真正的土豪通常有更重要的事做&#xff0c;比方说比尔盖茨。IT男跨界转行做安全套。预计是明年2015年推出上市。但是估计不能延续以前的品牌&#xff0c;叫“微软安全套”&#xff0c;这个要改。 凤凰卫视9月27日《笑逐言开》&#xff0c;以下为文字实录&a…

比尔盖茨为什么能成为世界首富?

说到比尔盖茨的财富&#xff0c;很多人可能首先想到的是比尔盖茨精明的投资&#xff0c;因为这些年他通过跟巴菲特学投资&#xff0c;光靠投资就带来了超过700亿美元的财富&#xff0c;而微软所带来的财富只占其总财富的1/8左右。 但我想说的是&#xff0c;投资确实给比尔盖茨带…

你见过比尔盖茨38年前写的MicrosoftBasic代码吗

你见过比尔盖茨38年前写的MicrosoftBasic代码吗 2016-11-15 06:07 编辑&#xff1a; suiling 分类&#xff1a;程序人生 来源&#xff1a;w3cschoolcn 1 2830 程序员比尔盖茨 招聘信息&#xff1a; iOS开发工程师移动APP研发工程师产品经理/Product ManagerUnity开发工程师…

比尔盖茨/UNIX之父/Donald Knuth/Dijkstra等全球IT大师的编程名言

这不是一个bug,这只是一个未列出来的特性。——匿名 ​​ ​ Dennis Ritchie

比尔·盖茨1978年写的古老程序曝光:IT人膜拜

官方网站 www.itilzj.com 官方文库: wenku.itilzj.com 比尔盖茨31岁&#xff0c;就成为世界首富。很多人好奇&#xff0c;作为世界第一大PC系统的创始人&#xff0c;抛弃世界首富的头衔&#xff0c;单单从程序员角度来讨论&#xff0c;比尔盖茨的代码水平如何&#xff1f; 其实…

微软创始人 比尔·盖茨

比尔盖茨 比尔盖茨&#xff08;Bill Gates&#xff09;&#xff0c;全名威廉亨利盖茨&#xff08;William Henry Gates&#xff0c;1955年10月28日&#xff0d;&#xff09;&#xff0c;美国微软公司的董事长。他与保罗艾伦一起创建了微软公司&#xff0c;曾任微软CEO和首席软件…

有钱真的能为所欲为,微软用75亿美元解决了比尔盖茨的“心头大患”

全世界只有3.14 % 的人关注了 数据与算法之美 2018年6月4日&#xff0c;微软在官方博客上宣布&#xff1a;以75 亿美元的价格收购了全球最大的开源代码托管平台GitHub。 谁也没想到&#xff0c;微软和开源这场长达几十年的战争&#xff0c;到最后双方竟然喜结连理了。 不过&…

比尔盖茨聘请投资高手,26年亏掉4300亿美金!

作者| Mr.K 整理| Emma 来源| 技术领导力(ID&#xff1a;jishulingdaoli) 大年初五&#xff0c;聊聊挣钱的话题&#xff0c;先从比尔盖茨的故事说起&#xff1a; 2020年末&#xff0c;比尔盖茨身价1072亿美金&#xff0c;创了历史新高。其中&#xff0c;他名下微软3%的股票市…

比尔盖茨离婚,平分8000亿! 用5张图看看微软的发展史

我是Allen&#xff0c;我的公众号是【CodeAllen】&#xff0c;程序员技术交流①群&#xff1a;736386324,转载请注明出处 大早上看新闻刷到比尔盖茨离婚了&#xff0c;两人会平分8000多亿财产&#xff0c;跟很多吃瓜群众不同&#xff0c;我感觉离婚没什么&#xff0c;不管是出于…

如何使用Java开发QQ机器人 方法二

使用Java开发QQ机器人- CQ & HTTP TO CQ 警告 此方法已经无效&#xff0c;可以看simple-robot框架 2.x的帖子&#xff1a;如何用Java写QQ机器人 v2.0。 使用酷Q平台下的HTTP TO CQ插件以及simple-robot核心标准库作为依赖。 此插件与框架的 简陋 简单介绍&#xff1a;文档处…

数据分析报告

很多人在写数据分析报告的时候&#xff0c;往往更关注如何将报告做的更美观&#xff0c;例如&#xff1a;做漂亮的可视化图表&#xff0c;做很炫的PPT等。但当别人看你做的数据分析报告的时候&#xff0c;往往更关注这个报告对他是否有价值&#xff1f;价值是什么&#xff1f;值…

医学研究生常用软件介绍

作为医学图像处理专业的学生&#xff0c;时常会需要各种各样的软件处理图像&#xff0c;以及各种各种辅助撰写文章的文件&#xff0c;但是时常需要的时候找不到&#xff0c;这里做一个记录&#xff0c;持续更新中…… 用于截图 Snipaste&#xff1a; 虽然qq截图也不错&#xf…

Adversarial Attacks against Face Recognition: A Comprehensive Study论文解读

一些专有名词缩写&#xff1a;automated border control (ABC) systems. 自动控制系统、面部识别(FR).面部识别、LBP&#xff08;Local Binary Pattern&#xff0c;局部二值模式&#xff09; 面部识别(FR)已成为身份认证的主要生物识别技术&#xff0c;并广泛用于各类领域&…