小言_互联网的博客

Vue介绍以及练手案例——音乐播放器(搜索音乐、听歌、看评论、看mv等)(持续更新)

395人阅读  评论(0)

Vue概述

  1. 它是一种 javascript框架
  2. 可以简化DOM操作
  3. 进行响应式数据驱动

el: 挂载点

  1. vue实例的作用范围:vue会管理 el 选项所命中的元素及其内部的后代元素。
  2. 可以使用其他选择器,但推荐是 id 选择器
  3. 可以使用其他双标签,但不能使用 HTML 和 BODY ,一般推荐使用 div 标签
  4. 作用:设置 vue 实例挂载(管理)的元素

data: 数据对象

  1. vue 中用到的数据定义在 data 中
  2. data 中可以写复杂类型的数据,如对象、数组等
  3. 渲染复杂数据类型的数据时,遵守 js 的语法即可,数组用下标索引,对象用属性

本地应用

  • v-test:设置标签的文本值;默认写法会替换全部内容,无论内容是什么,只会解析为文本,如果进行部分替换则使用两个大括号 { { }}(差值表达式)例如:<h2>提示:{ {message + "!"}}</h2>

  • v-html:设置标签的 innerHtml;内容中有 html 结构会被自动解析为标签

  • v-on:为元素绑定事件v-on:click="方法名";事件名不需要写on;绑定事件的方法是在script标签内写上方法对象methods:{方法名:function(){ // 详细逻辑 }}

    简写形式:@click="方法名"

    v-on还可以传递自定义参数,事件修饰符,传递参数:function(p1,p2)

    事件绑定的方法写成函数调用的形式,可以传入自定义参数

    定义方法时需要定义形参来接收传入的实参

    事件后面跟上 .修饰符可以对事件进行限制

    .enter 可以限制触发的按键为回车

  • 使用 this.数据名 获取 DOM 元素

  • v-show:根据表达式的真假,切换元素的显示和隐藏,指令后面的内容最终都会被解析为布尔值,为了方便操纵,一般将这个指令定义成数据。支持表达式的书写方式。频繁切换元素用这个

    本质:修改元素的 display属性,实现显示隐藏

  • v-if:根据表达式的真假,切换元素的显示和隐藏,不频繁的切换用这个。

    本质:操纵 dom 元素的移除与添加

  • v-bind:设置元素的属性,v-bind:属性名=表达式 属性名可以省略,需要动态的增加/删除 class 属性建议使用对象的方式

  • v-for:根据数据生成列表结构;格式如:v-for="item in 数据(通常为数组名)"    //这只会生成li标签但是里面没有内容,因此要添加内容使用{ {item}},此外数组要使用数组索引号的获取方式(item, index),对象要使用对象的属性获取方式{ {item.属性名}};

    数组经常和 v-for 结合使用

    item 和 index 可以结合其他指令一起使用

    数组长度的更新会同步到页面上,是响应式的

  • v-model:便捷的获取和设置表单元素的值(双向数据绑定);绑定的数据会和表单元素的值相关联

网络应用

axios:网络请求库,它与Vue结合网络数据开发应用

axios

axios.get(地址即文档提供的接口地址).then( function(response) {}, function(err) {})

axios.get(地址?key=value&key2=value2).then( function(response) {}, function(err) {})

axios.post(地址,参数对象).then(function(response) {}, function(err) {})

axios.post(地址,{key: value,key2:value2}).then(function(response) {}, function(err) {})

注意:

  • axios必须先导入才可以使用
  • 使用 get 或 post 方法即可发送对应的请求
  • then方法中的回调函数会在请求成功或失败时触发
  • 通过回调函数的形参可以获取响应内容或错误信息
  • 在和 vue 搭配使用的时候,axios回调函数中的this已经无法改变,无法访问到 data中的数据,因此要把 this 保存起来,回调函数中直接使用保存的 this 即可

应用案例:

  1. 服务器中的数据比较复杂的时候,要注意数据的层级结构
  2. 通过对象的方式设置类名,类名生效与否取决与后面值的真假
  3. 音频中带有 play 和 pause 事件
  4. 页面结构复杂时,通过审查元素的方式可以快速定位相关元素

音乐播放器

实现界面

HTML代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>音乐播放器</title>
		<link type="text/css" href="css/music.css" rel="stylesheet" />
	</head>
	<body>
		<div class="wrap">
			<div class="play_wrap" id="player">
				<div class="search_bar">
					<div class="title">悦听</div>					
					<div class="search">
						<input v-model="music" @keyup.enter="search(music)" type="text" class="content" />
						<img class="loupe" src="img/mirror.png"  @click="search(music)"/>
					</div>
				</div>

				<div class="center_con">
					<div class="music_list">
						<ul class="music">
							<li class="music_li" v-for="item in musicList">
								<a href="javascript:;" @click="playMusic(item.id)">
									<img class="music_btn" src="img/play.png" />
								</a>
								<span class="music_name"> {
  { item.name }} </span>
								<span class="mv_btn" @click="mvPlay(item.mvid)">
									<img class="mvtable" v-if="item.mvid!=0" src="img/mv.png" />
								</span>
							</li>
						</ul>
					</div>
					<div>
						<img class="left_line" src="img/line.png" />
					</div>
					<div class="pic" :class="{playing: isPlaying}" >
						<div class="top">
							<img class="player" src="img/player_bar.png" />
						</div>
						<div class="center">
							<img class="cover" :src="picUrl" />
							<img class="disc" src="img/disc.png" />
						</div>
					</div>
					<div>
						<img class="right_line" src="img/line.png" />
					</div>
					<div class="comment_list_outer">
						<b class="comm">热门留言</b><br />
						<div class="comment_list">
							<ul class="comment">
								<li class="comment_li" v-for="item in hotComments">
									<img class="user_pic" :src="item.user.avatarUrl"/>
									<div class="comm_right">
										<b class="user_nickname">{
  { item.user.nickname }}</b><br />
										<span class="user_comm">{
  { item.content }}</span>
									</div>
								</li>
							</ul>
						</div>
					</div>

				</div>

				<div class="audio_con">
					<audio :src="musicURL" @play="play" @pause="pause" class="audio" autoplay controls loop></audio>
				</div>

				<div class="video_con"  v-show="isShow">
					<video ref="video" v-if="{hide: pause}" v-bind:src="mvUrl" v-show="isShow" autoplay controls loop></video>
					<div class="mask" @click="hide">
						<div class="map">
							<div class="city">
								<div class="dotted"></div>
								<div class="pulse1"></div>
								<div class="pulse2"></div>
								<div class="pulse3"></div>
								点外面都可以哦!
							</div>
						</div>
					</div>
				</div>
			</div>
		</div>
		<script src="js/vue.js" type="text/javascript" charset="UTF-8"></script>
		<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
		<script src="js/music.js"></script>
		
	</body>
</html>

CSS代码
* {
   
	margin: 0;
	padding: 0;
	list-style: none;
}

.wrap {
   
	width: 100vw;
	height: 100vh;
	overflow: hidden;
	background: url(../img/bg.jpg) no-repeat;
	background-size: 100% 100%;
}

.play_wrap {
   
	width: 800px;
	height: 520px;
	margin: 77px auto;
}

.search_bar {
   
	position: relative;
	z-index: 4;
	border-radius: 5px 5px 0 0;
	height: 60px;
	display: flex;
	background-color: dodgerblue;
}

.title {
   
	flex: 1;
	padding-top: 10px;
	padding-left: 15px;
	color: white;
	line-height: 40px;
	font-size: 0;
	background: url(../img/player_title.png) no-repeat;
	background-position: 20px;
}

.search {
   
	position: relative;
	flex: 1;
	line-height: 60px;
	padding-left: 240px;
}

.loupe {
   
	position: absolute;
	top: 16px;
	left: 456px;
	width: 30px;
	height: 29px;
	cursor: pointer;
}

.content {
   
	overflow: hidden;
	position: absolute;
	top: 16px;
	left: 241px;
	border: none;
	outline: none;
	width: 250px;
	height: 30px;
	padding-left: 10px;
	border-radius: 15px;
	background-color: #fcfcfc;
}

.center_con {
   
	height: 445px;
	display: flex;
	background-color: rgb(255, 255, 255, .5);
}

.music_list {
   
	flex: 6;
	overflow-y: auto;
	overflow-x: hidden;
}

.music_list::-webkit-scrollbar,
.comment_list::-webkit-scrollbar {
   
	display: none;
}

.music {
   
	padding: 5px;
}

.music_li:nth-of-type(odd) {
   
	display: flex;
	padding: 3px;
	line-height: 37px;
	font-size: 12px;
}

.music_li:nth-of-type(even) {
   
	display: flex;
	padding: 3px;
	line-height: 37px;
	font-size: 12px;
	background-color: rgba(240, 240, 240, 0.3);
}

.comment_li {
   
	display: flex;
	padding: 10px;
	line-height: 20px;
	font-size: 15px;
}

.music_btn {
   
	width: 17px;
	height: 17px;
	padding-top: 10px;
	flex: 2;
}

.music_name {
   
	flex: 5;
	margin-left: 12px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.mv_btn {
   
	flex: 2;
	cursor: pointer;
}

.mvtable {
   
	padding-top: 10px;
	margin-left: 15px;
	width: 18px;
	height: 18px;
}

.left_line,
.right_line {
   
	width: 1px;
	height: 440px;
}

.pic {
   
	flex: 12;
}

.player {
   
	position: absolute;
	top: 125px;
	left: 745px;
	z-index: 3;
	transform: rotate(-30deg);
	transform-origin: 12px 12px;
	transition: 1s;
}

.playing .player {
   
	transform: rotate(0);
}

.disc {
   
	position: absolute;
	width: 265px;
	height: 265px;
	top: 200px;
	left: 629px;
	z-index: 2;
}

.cover {
   
	position: absolute;
	width: 160px;
	height: 160px;
	top: 250px;
	left: 682px;
	z-index: 1;

}

.comment_list_outer {
   
	flex: 6;
	padding: 8px;
}

.comment_list {
   
	height: 415px;
	overflow-y: auto;
	overflow-x: hidden;
}

.user_pic {
   
	width: 40px;
	height: 40px;
	border-radius: 50%;
}

.comm_right {
   
	margin: 7px;
}

.user_comm {
   
	font-size: 12px;
	color: #666;
}

.audio_con {
   
	height: 35px;

}

.audio {
   
	outline: none;
	width: 800px;
	height: 45px;
	border-radius: 0 0 5px 5px;
	background-color: rgb(241, 243, 244);
}

.mask {
   
	position: fixed;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	z-index: 980;
	background-color: rgb(0, 0, 0, .4);
}

video {
   
	position: fixed;
	left: 368px;
	top: 96px;
	width: 800px;
	height: 531px;
	z-index: 990;
	/* border: 0; */
	outline: none;
}

@keyframes rotation {
   
	from {
   
		transform: rotateZ(0deg);
	}

	to {
   
		transform: rotateZ(360deg);
	}
}

.cover,
.disc {
   
	-webkit-transform: rotate(360deg);
	animation-name: rotation;
	animation-iteration-count: infinite;
	animation-play-state: paused;
	animation-timing-function: linear;
	animation-duration: 4s;
}

.pic.playing .disc,
.pic.playing .cover {
   
    animation-play-state: running;
}

.map {
   
	position: relative;
}

.city {
   
	position: absolute;
	top: 227px;
	right: 193px;
	color: #FFFFFF;
}

.city div[class^="pulse"] {
   
	/* 保证小波纹在父盒子里面水平和垂直居中 */
	position: absolute;
	top: 11%;
	left: 3%;
	transform: translate(-50%, -50%);
	width: 8px;
	height: 8px;
	box-shadow: 0 0 12px #009DFB;
	border-radius: 50%;
	animation: pulse 1.6s linear infinite;
}

.city div.pulse2 {
   
	animation-delay: 0.8s;
}

.city div.pulse3 {
   
	animation-delay: 1.6s;
}

@keyframes pulse {
   
	10% {
   
		width: 10px;
		height: 10px;
		opacity: 1;
	}

	40% {
   
		width: 30px;
		height: 30px;
		opacity: 0.7;
	}

	70% {
   
		width: 50px;
		height: 50px;
		opacity: 0.4;
	}

	100% {
   
		width: 70px;
		height: 70px;
		opacity: 0;
	}
}

.dotted {
   
	width: 8px;
	height: 8px;
	border-radius: 4px;
	background-color: #009dfb;
}

js代码
// 歌曲搜索
// 1.按下回车(v-on .enter)
// 2.查询数据(axios 接口 v-model)
// 3.渲染数据(v-for 数组 that)
// 请求地址:https://autumnfish.cn/search
// 请求参数:keywords

// 歌曲播放
// 1.点击播放(v-on)
// 2.歌曲地址获取(接口 歌曲id)
// 3.歌曲地址设置(v-bind)
// 请求地址:https://autumnfish.cn/song/url
// 请求参数:id(歌曲id)

// 歌曲封面
// 1.点击播放(增加逻辑)
// 2.歌曲封面获取(接口 歌曲id)
// 3.歌曲封面设置(v-bind)
// 请求地址:https:autumnfish.cn/song/detail
// 请求参数:ids

// 歌曲评论
// 1.点击播放(增加逻辑)
// 2.歌曲评论获取(接口 歌曲id)
// 3.歌曲评论渲染(v-for)
// 请求地址:https://autumnfish.cn/comment/hot?type=0
// 请求参数:id

// 播放动画
// 1.监听音乐播放(v-on play)
// 2.监听音乐暂停(v-on pause)
// 3.操纵类名(v-bind 对象 因此需要在data中添加一个boolean值)

// mv播放
// 1.图标显示(v-if)
// 2.地址获取(接口 mvid)
// 3.遮罩层(v-show v-on)
// 4.地址设置(v-bind)
// 请求地址:https://autumnfish.cn/mv/url
// 请求参数:id(mvid,为0表示没有mv)

var app = new Vue({
   
	el: "#player",
	data: {
   
		music: "",
		musicList: [],
		musicURL: "",
		picUrl: "",
		hotComments: [],
		// 动画的显示与隐藏
		isPlaying: false,
		mvId: "",
		mvUrl: "",
		// 遮罩层的显示与隐藏
		isShow: false		
	},
	methods: {
   
		// 歌曲搜索
		search:function(music) {
   
			var that = this;
			axios.get("https://autumnfish.cn/search?keywords=" + music)
			.then(function(response) {
   
				console.log(response);
				that.musicList = response.data.result.songs;
			}, function(err) {
   
				console.log(err);
			})
		},
		// 歌曲播放
		playMusic: function(musicId) {
   
			var that = this;
			axios.get("https://autumnfish.cn/song/url?id="+musicId)
			.then(function(response) {
   
				that.musicURL = response.data.data[0].url;
			}, function(err) {
   
				console.log(err);
			});
			// 歌曲封面
			axios.get("https:autumnfish.cn/song/detail?ids="+musicId)
			.then(function(response){
   
				console.log(1);
				// console.log(response);
				that.picUrl = response.data.songs[0].al.picUrl;
			},function(err){
   
				console.log(err);
			});
			// 歌曲评论
			axios.get("https://autumnfish.cn/comment/hot?type=0&id=" + musicId)
			.then(function(response) {
   
				console.log(2);
				// console.log(response);
				// console.log(response.data.hotComments);
				that.hotComments = response.data.hotComments;
			}, function(err) {
   
				console.log(err);
			})
		},
		// 播放动画
		play: function() {
   
			// console.log("play");
			this.isPlaying = true;
		},
		pause: function() {
   
			// console.log("pause");
			this.isPlaying = false;
		},
		// 播放mv
		mvPlay: function(mvId) {
   
			var that = this;
			axios.get("https://autumnfish.cn/mv/url?id=" + mvId)
			.then(function(response) {
   
				console.log(3);
				that.isShow = true;
				that.mvUrl = response.data.data.url;
			}, function(err) {
   
				console.log(err);
			})
		},
		hide: function() {
   
			this.isShow = false;
		}
		

	}
})

写在最后的话

还有部分功能暂时还未实现,比如:搜索歌曲的历史列表、歌词页、上一首、下一首等功能,后期将会持续更新,上述代码中若存在问题,欢迎交流。


转载:https://blog.csdn.net/qq_44945999/article/details/116031375
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场