前言:
本篇主要讲一下vue的基本语法,!
这里可以直接看他的语雀笔记
Vue核心 Vue简介 初识 · 语雀 (yuque.com)
啊啊啊他写的太好了, 建议直接看他的, 如果愿意多看一下我的话, 就都看吧。
vue简介及环境搭建:
如果建议别用管理员cmd
引入vue的包或者下载:
//开发版本:
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
//生产版本:
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
//通过相对路径引入:
<script src="./js/vue.js"></script>
vue基本介绍:
想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象
root 容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法
root 容器里的代码被称为Vue模板
Vue 实例与容器是一一对应的
真实开发中只有一个Vue实例,并且会配合着组件一起使用
{
{xxx}}中的 xxx 要写 js 表达式,且 xxx 可以自动读取到data中的所有属性一旦data中的数据发生变化,那么模板中用到该数据的地方也会自动更新
注意区分:js 表达式 和 js代码(语句)
js表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
a a+b demo(1) x === y ? 'a' : 'b'
js代码(语句)
if(){} for(){}
第一个简单的vue程序:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>初识Vue</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="demo">
<h1>Hello,{{ name.toUpperCase() }},{{ address }}</h1>
</div>
<script type="text/javascript" >
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
// 创建Vue实例
new Vue({
el: '#demo', // el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串
data: { // data中用于存储数据,数据供el所指定的容器去使用,值暂时先写成一个对象
name: 'cess',
address: '成都'
}
})
</script>
</body>
</html>
常用指令:
v-test和v-html:
当我们网速很慢或者javascript出错时,会显示{undefined{xxx}};Vue提供的v-text、v-html可以解决这个问题;
v-test
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>v-text指令</title>
</head>
<body>
<div id="app">
<!--字符串的拼接依旧是加号-->
<h2 v-text="message+'!'">成都</h2>
<h2 v-text="info+'!'">成都</h2><!--v-text一定会替换掉内部的默认值-->
<h2>{{ message +'!'}}--成都</h2><!--这里深圳没被替换, 因为这里用了两个大括号, 只是具备替换-->
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
message:"兴趣使然的小小!!!",
info:"计算机学院"
}
})
</script>
</body>
</html>
v-html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>v-html指令</title>
</head>
<body>
<div id="app">
<!--html结构-->
<p v-text="content"></p>
<p v-html="content"></p>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
content:"兴趣使然的小小",
content:"<a href='https://ladfeng.top'>兴趣使然的小小</a>"
}
})
</script>
</body>
</html>
(事件监听)v-on:
v-on 就是监听事件,可以用v-on指令监听DOM事件来触发一些javascript代码;
@
为
v-on
的缩写!
@click
为
v-on:click
@dblclick
为
v-on:dblclick
一些按键事件
@keydown和@keyup
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>键盘事件</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>欢迎打开{{name}}笔记</h2>
<input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo"><br/>
<input type="text" placeholder="按下tab提示输入" @keydown.tab="showInfo"><br/>
<input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo"><br/>
</div>
<script type="text/javascript">
Vue.config.productionTip = false // 阻止 vue 在启动时生成生产提示。
Vue.config.keyCodes.huiche = 13 // 定义了一个别名按键
new Vue({
el: '#root',
data: {
name: 'cess'
},
methods: {
showInfo(e) {
// console.log(e.key,e.keyCode)
console.log(e.target.value)
}
},
})
</script>
</body>
</html>
使用v-on:xxx或@xxx绑定事件,其中 xxx 是事件名
事件的回调需要配置在methods对象中,最终会在vm上
methods中配置的函数,不要用箭头函数,否则 this 就不是vm了
methods中配置的函数,都是被 Vue所管理的函数,this 的指向是vm或组件实例对象
@click=”demo”和@click=”demo($event)”效果一致,但后者可以传参
demo2
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>事件的基本使用</title>
<!-- 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="root">
<h2>欢迎来看{{name}}的笔记</h2>
<!-- <button v-on:click="showInfo">点我提示信息</button> -->
<button @click="showInfo1">点我提示信息1(不传参)</button>
<button @click="showInfo2($event,66)">点我提示信息2(传参)</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
const vm = new Vue({
el: '#root',
data: {
name: '小小',
},
methods: {
showInfo1(event) {
console.log(event.target.innerText)
// console.log(this) // 此处的this是vm
alert('同学你好!')
},
showInfo2(event, number) {
console.log(event, number)
console.log(event.target.innerText)
// console.log(this) // 此处的this是vm
alert('同学你好!!'+number)
}
}
})
</script>
</body>
</html>
更多的事件处理
Vue核心 事件处理 · 语雀 (yuque.com)
demo3
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>事件修饰符</title>
<!-- 引入Vue -->
<script type="text/javascript" src="../js/vue.js"></script>
<style>
* {margin-top: 20px;}
.demo1 {height: 50px;background-color: skyblue;}
.box1 {padding: 5px;background-color: skyblue;}
.box2 {padding: 5px;background-color: white;}
.list {width: 200px;height: 200px;background-color: skyblue;overflow: auto;}
li {height: 100px;}
</style>
</head>
<body>
<div id="root">
<h2>欢迎来到{{ name }}学习</h2>
<!-- 阻止默认事件(常用) -->
<a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a>
<!-- 阻止事件冒泡(常用) -->
<div class="demo1" @click="showInfo">
<button @click.stop="showInfo">点我提示信息</button>
<!-- 修饰符可以连续写 -->
<!-- <a href="http://www.qq.com" @click.prevent.stop="showInfo">点我提示</a> -->
</div>
<!-- 事件只触发一次(常用) -->
<button @click.once="showInfo">点我提示信息</button>
<!-- 使用事件的捕获模式 -->
<div class="box1" @click.capture="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
</div>
</div>
<!-- 只有event.target是当前操作的元素时才触发事件; -->
<div class="demo1" @click.self="showInfo">
<button @click="showInfo">点我提示信息</button>
</div>
<!-- 事件的默认行为立即执行,无需等待事件回调执行完毕; -->
<!-- scroll是滚动条滚动,passsive没有影响 -->
<!-- wheel是鼠标滚轮滚动,passive有影响 -->
<ul @wheel.passive="demo" class="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
name: '尚硅谷'
},
methods: {
showInfo(e) {
alert('同学你好!')
// console.log(e.target)
},
showMsg(msg) {
console.log(msg)
},
demo() {
for (let i = 0; i < 100000; i++) {
console.log('#')
}
console.log('累坏了')
}
}
})
</script>
</body>
</html>
(数据绑定)v-model:
Vue中有两种
数据绑定
的方式:
-
单向绑定
v-bind
数据只能从data流向页面 -
双向绑定
v-model
数据不仅能从data流向页面, 还可以从页面流向data
获取和设置表单元素的值(双向数据绑定)
demo1:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>数据绑定</title>
<!-- 引入Vue -->
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="root">
<!-- 普通写法 -->
<!-- 单向数据绑定:<input type="text" v-bind:value="name"><br/> -->
<!-- 双向数据绑定:<input type="text" v-model:value="name"><br/> -->
<!-- 简写 -->
单向数据绑定:<input type="text" :value="name"><br/>
双向数据绑定:<input type="text" v-model="name"><br/>
<!-- 如下代码是错误的,因为 v-model 只能应用在表单类元素(输入类元素)上 -->
<!-- <h2 v-model:x="name">你好啊</h2> -->
</div>
<script type="text/javascript">
Vue.config.productionTip = false // 阻止 vue 在启动时生成生产提示。
new Vue({
el: '#root',
data: {
name: 'cess'
}
})
</script>
</body>
</html>
demo2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>v-model指令</title>
</head>
<body>
<div id="app">
<input type="button" value="重置message" @click="setM">
<!--当敲击的键盘起来的,就触发事件getM-->
<input type="text" v-model="message" @keyup.enter="getM">
<h2>{{ message }}</h2>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
message:"兴趣使然的小小"
},
methods: {
getM:function(){
alert("浏览器已经收到了message: "+this.message);
},
setM:function(){
this.message ="兴趣使然的小小";
}
},
})
</script>
</body>
</html>
(数据绑定和样式绑定)v-bind:
v-bind
: 用来绑定标签的属性从而通过vue动态修改标签的属性
v-bind:属性名
简化之后
:属性名
demo1:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>模板语法</title>
<!-- 引入Vue -->
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="root">
<h2>插值语法</h2>
<h4>你好,{{ name }}</h4>
<hr />
<h2>指令语法</h2>
<a v-bind:href="tencent.url.toUpperCase()" x="hello">点我去看{{ tencent.name }}1</a>
<a :href="tencent.url" x="hello">点我去看{{ tencent.name }}2</a>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el: '#root',
data: {
name: '小小',
tencent: {
name: '开端',
url: 'https://v.qq.com/x/cover/mzc00200mp8vo9b/n0041aa087e.html',
}
}
})
</script>
</html>
demo02
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>v-bind指令</title>
<style>
.active{
border: 5px solid red;
}
</style>
</head>
<body>
<div id="app">
<!--原始的写法-->
<img v-bind:src="imgSrc" alt="">
<br>
点击下面的一张图片!<br>
<!--缩写冒号就行!-->
<!-- <img v-bind:src="imgSrc" alt="这里是没有图片的时候显示的文本!" v-bind:title="imgTitle+'的图片!!!'" v-bind:class="isActive?'active':''" v-on:click="toggleActive"><!–这里有用到三元运算符!–>-->
<img
:src="imgSrc"
alt="这里是没有图片的时候显示的文本!"
:title="imgTitle+'的图片!!!'"
:class="isActive?'active':''"
@click="toggleActive"
><!--这里有用到三元运算符!-->
<br>
<img
:src="imgSrc"
alt=""
:title="imgTitle+'!!!'"
:class="{active:isActive}"
@click="toggleActive"
><!--用对象的形式!推荐使用! -->
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
imgSrc:"https://qiniu.ladidol.top/img/image-20220421111816375.png",
imgTitle:"小小",
isActive:false
},
methods: {
toggleActive:function(){
this.isActive = !this.isActive;
}
},
})
</script>
</body>
</html>
Vue核心 计算属性 侦听属性 · 语雀 (yuque.com)
特别提一下
computed
计算属性
定义:要用的属性不存在,需要通过已有属性计算得来
原理:底层借助了Objcet.defineproperty()方法提供的getter和setter
get函数什么时候执行?
a初次读取时会执行一次
b当依赖的数据发生改变时会被再次调用优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便
备注
a计算属性最终会出现在vm上,直接读取使用即可
b如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变
c如果计算属性确定不考虑修改,可以使用计算属性的简写形式
使用
computed
计算属性之前
<title>姓名案例_methods实现</title>
<script type="text/javascript" src="../js/vue.js"></script>
<div id="root">
姓:<input type="text" v-model="firstName"><br/>
名:<input type="text" v-model="lastName"><br/>
全名:<span>{{ fullName() }}</span>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三'
},
methods: {
fullName() {
return this.firstName + '-' + this.lastName
}
},
})
</script>
之后
<title>姓名案例_计算属性实现</title>
<script type="text/javascript" src="../js/vue.js"></script>
<div id="root">
姓:<input type="text" v-model="firstName"> <br/>
名:<input type="text" v-model="lastName"> <br/>
测试:<input type="text" v-model="x"> <br/> // 这里修改 不会调 fullName的get方法
全名:<span>{{fullName}}</span> <br/>
<!-- 全名:<span>{{fullName}}</span> <br/> -->
<!-- 全名:<span>{{fullName}}</span> <br/> -->
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
firstName:'张',
lastName:'三',
x:'你好'
},
computed: {
//完整写法
// fullName: {
// get() {
// console.log('get被调用了')
// return this.firstName + '-' + this.lastName
// },
// set(value) {
// console.log('set', value)
// const arr = value.split('-')
// this.firstName = arr[0]
// this.lastName = arr[1]
// }
// }
// 简写
fullName() {
console.log('get被调用了')
return this.firstName + '-' + this.lastName
}
}
})
</script>
这里还可以提到
watch
属性
绑定样式
Vue核心 绑定样式 条件渲染 · 语雀 (yuque.com)
<style>
.basic {width: 300px;height: 50px;border: 1px solid black;}
.happy {border: 3px solid red;background-color: rgba(255, 255, 0, 0.644);
background: linear-gradient(30deg, yellow, pink, orange, yellow);}
.sad {border: 4px dashed rgb(2, 197, 2);background-color: skyblue;}
.normal {background-color: #bfa;}
.atguigu1 {background-color: yellowgreen;}
.atguigu2 {font-size: 20px;text-shadow: 2px 2px 10px red;}
.atguigu3 {border-radius: 20px;}
</style>
<div id="root">
<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
<div class="basic" :class="mood" @click="changeMood">{{name}}</div><br/><br/>
<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
<div class="basic" :class="classArr">{{name}}</div><br/><br/>
<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
<div class="basic" :class="classObj">{{name}}</div><br/><br/>
<!-- 绑定style样式--对象写法 -->
<div class="basic" :style="styleObj">{{name}}</div><br/><br/>
<!-- 绑定style样式--数组写法 -->
<div class="basic" :style="styleArr">{{name}}</div>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el: '#root',
data: {
name: '尚硅谷',
mood: 'normal',
classArr: ['atguigu1', 'atguigu2', 'atguigu3'],
classObj: {
atguigu1: false,
atguigu2: false,
},
styleObj: {
fontSize: '40px',
color: 'red',
},
styleObj2: {
backgroundColor: 'orange'
},
styleArr: [
{
fontSize: '40px',
color: 'blue',
},
{
backgroundColor: 'gray'
}
]
},
methods: {
changeMood() {
const arr = ['happy', 'sad', 'normal']
const index = Math.floor(Math.random() * 3)
this.mood = arr[index]
}
},
})
</script>
v-if和v-show:
简单的判断语法, 其实功能有点类似
v-show
v-show
:用来控制页面中某个标签元素是否展示 底层使用控制是 display 属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>v-show指令</title>
</head>
<body>
<div id="app">
<input type="button" value="切换显示状态" @click="changeIsShow">
<input type="button" value="累加年龄" @click="addAge">
<span>{{age}}</span>
<img v-show="isShow" src="https://qiniu.ladidol.top/img/image-20220421111715822.png" alt="">
<img v-show="age>=18" src="https://qiniu.ladidol.top/img/image-20220421111816375.png" alt="">
</div>
<!-- 1.开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
isShow:false,
age:10
},
methods: {
changeIsShow:function(){
this.isShow = !this.isShow;
},
addAge:function(){
this.age++;
}
},
})
</script>
</body>
</html>
v-if
v-if
: 用来控制页面元素是否展示 底层控制是DOM元素 操作DOM
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>v-if指令</title>
</head>
<body>
<div id="app">
<input type="button" value="切换显示" @click="toggleIsShow">
<p v-if="isShow">兴趣使然的小小</p>
<p v-show="isShow">ladidol的 v-show修饰</p><br>
<span>现在的温度: {{temperature}}℃</span>
<h2 v-if="temperature>=35">这个温度我要热死啦</h2>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
isShow:false,
temperature:40
},
methods: {
toggleIsShow:function(){
this.isShow = !this.isShow;
}
},
})
</script>
</body>
</html>
条件渲染
配合
template
标签
使用 保留页面加载时隐藏的内容。通常使用 JavaScript 来显示
<title>条件渲染</title>
<script type="text/javascript" src="../js/vue.js"></script>
<div id="root">
<h2>当前的n值是:{{ n }}</h2>
<button @click="n++">点我n+1</button>
<!-- 使用v-show做条件渲染 -->
<!-- <h2 v-show="false">欢迎来到{{name}}</h2> -->
<!-- <h2 v-show="1 === 1">欢迎来到{{name}}</h2> -->
<!-- 使用v-if做条件渲染 -->
<!-- <h2 v-if="false">欢迎来到{{name}}</h2> -->
<!-- <h2 v-if="1 === 1">欢迎来到{{name}}</h2> -->
<!-- v-else和v-else-if -->
<!-- <div v-show="n === 1">Angular</div> -->
<!-- <div v-show="n === 2">React</div> -->
<!-- <div v-show="n === 3">Vue</div> -->
<!-- <div v-if="n === 1">Angular</div> -->
<!-- <div v-else-if="n === 2">React</div> -->
<!-- <div v-else-if="n === 3">Vue</div> -->
<!-- <div v-else>哈哈</div> -->
<!-- v-if与template的配合使用 -->
<template v-if="n === 1">
<h3>你好</h3>
<h3>尚硅谷</h3>
<h3>北京</h3>
</template>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷',
n:0
}
})
</script>
v-for:
v-for指令是循环渲染一组data中的数组,需要以
item in items
或者
(item,index) in items
形式,items是源数据数组并且item是数组元素迭代的别名。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>v-for指令</title>
</head>
<body>
<div id="app">
<input type="button" value="添加数据" @click="add">
<input type="button" value="移除数据" @click="remove">
<ul>
<!--index和value-->
<li v-for="(it,index) in school">
{{ index+1 }}学校:{{ it }}
</li>
</ul>
<!--这里只遍历了, value-->
<h2 v-for="item in vegetables" v-bind:title="item.name">
{{ item.name }}
</h2>
</div>
<!-- 1.开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:"#app",
data:{
school:["丰禾镇中心小学","四川省邻水实验学校","成都信息工程大学"],
vegetables:[
{name:"西兰花炒蛋"},
{name:"蛋炒西蓝花"},
{name:"鱼香肉丝"},
{name:"麻婆豆腐"}
]
},
methods: {
add:function(){
this.vegetables.push({ name:"锅巴土豆!" });
},
remove:function(){
//删除第一个元素
// this.vegetables.shift();
//删除最后一个!
this.vegetables.pop();
}
},
})
</script>
</body>
</html>
v-bind:key
是为了在v-for循环中给 Vue 一个提示
内置命令
Vue核心 内置指令 自定义指令 · 语雀 (yuque.com)
v-cloak
<title>v-cloak指令</title>
<meta charset="UTF-8">
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<style>
[v-cloak] {
display:none;
}
</style>
<div id="root">
<h2 v-cloak>{{ name }}</h2>
<h2>{{ name }}</h2>
</div>
<!--// 够延迟5秒收到vue.js-->
<script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script>
<script type="text/javascript">
console.log(1)
Vue.config.productionTip = false
new Vue({
el:'#root',
data:{name:'小小'}
})
</script>
到此可以简单了解一下axios和vue的结合:
后端理解ajax和axios_兴趣使然的小小的博客-CSDN博客
数组的常用方法:
Vue生命周期
Vue核心 Vue生命周期 · 语雀 (yuque.com)
基础语法案例汇总:
计数器:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
#app {
width: 480px;
height: 100px;
margin: 200px auto;
}
.input-num {
margin-top: 20px;
height: 100%;
display: flex;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 0 4px black;
}
.input-num button {
width: 150px;
height: 100%;
font-size: 40px;
color: gray;
cursor: pointer;
border: none;
outline: none;
}
.input-num span {
height: 100%;
font-size: 40px;
flex: 1;
text-align: center;
line-height: 100px;
}
</style>
</head>
<body>
<div id="app">
<!-- <img src="" alt="" />-->
<!-- 计数器 -->
<div class="input-num">
<button @click="sub">-</button>
<span>{{num}}</span>
<button @click="add">+</button>
</div>
</div>
</body>
</html>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 编码 -->
<script>
// 创建Vue实例
var app = new Vue({
el: "#app",
data: {
num: 1,
max: 10,
min: 0
},
methods: {
add: function() {
if(this.num<this.max){//注意这里要带上this这个关键字
this.num++;
}else{
alert("别点了,最大了");
}
},
sub: function() {
if(this.num>this.min){
this.num--;
}else{
alert("别点了,最小了");
}
}
}
});
</script>
图片切换案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body,
#mask {
width: 100%;
height: 100%;
}
#mask {
background-color: #c9c9c9;
position: relative;
}
#mask .center {
position: absolute;
background-color: #fff;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 10px;
}
#mask .center .title {
position: absolute;
display: flex;
align-items: center;
height: 56px;
top: -61px;
left: 0;
padding: 5px;
padding-left: 10px;
padding-bottom: 0;
color: rgba(175, 47, 47, 0.8);
font-size: 26px;
font-weight: normal;
background-color: white;
padding-right: 50px;
z-index: 2;
}
#mask .center .title img {
height: 40px;
margin-right: 10px;
}
#mask .center .title::before {
content: "";
position: absolute;
width: 0;
height: 0;
border: 65px solid;
border-color: transparent transparent white;
top: -65px;
right: -65px;
z-index: 1;
}
#mask .center > img {
display: block;
width: 700px;
height: 458px;
}
#mask .center a {
text-decoration: none;
width: 45px;
height: 100px;
position: absolute;
top: 179px;
vertical-align: middle;
opacity: 0.5;
}
#mask .center a :hover {
opacity: 0.8;
}
#mask .center .left {
left: 15px;
text-align: left;
padding-right: 10px;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
#mask .center .right {
right: 15px;
text-align: right;
padding-left: 10px;
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
</style>
</head>
<body>
<div id="mask">
<div class="center">
<h2 class="title">
<img src="https://qiniu.ladidol.top/img/image-20220421114425049.png"
alt=""> 小小的博客乐园!
</h2>
<!--用数组来存图片,通过改变index来改变展示的图片!-->
<img :src="imgList[index]" alt="" />
<a
href="javascript:void(0)"
@click="prev"
class="left"
v-show="index>0"
>
<img src="https://qiniu.ladidol.top/img/image-20220421114038121.png" alt="" />
</a>
<!--如果超过范围, 就不显示按钮!-->
<a
href="javascript:void(0)"
@click="next"
class="right"
v-show="index<imgList.length-1"
>
<img src="https://qiniu.ladidol.top/img/image-20220421114013041.png" alt="" />
</a>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: "#mask",
data: {
imgList: [
"https://qiniu.ladidol.top/img/image-20220421114859124.png",
"https://qiniu.ladidol.top/img/image-20220421114839120.png",
"https://qiniu.ladidol.top/img/image-20220421114817142.png",
],
index: 0
},
methods: {
// 上一张
prev() {
this.index--;
},
// 下一张
next() {
this.index++;
}
}
});
</script>
</body>
</html>
天知道:
Vue网络应用-axios的基本使用
axios.get(地址?key=value&key2=values).then(function(response){},function(err){})
axios.post(地址,{key:value,key2:value2}).then(function(response){},function(err){})
emm依旧一些不理解, 为啥还原不了那个动态刷新
后端理解ajax和axios_兴趣使然的小小的博客-CSDN博客
reset.css
body,ul,h1,h2,h3,h4,h5,h6{
margin: 0;
padding: 0;
}
h1,h2,h3,h4,h5,h6{
font-size:100%;
font-weight:normal;
}
a{
text-decoration:none;
}
ul{
list-style:none;
}
img{
border:0px;
}
/* 清除浮动,解决margin-top塌陷 */
.clearfix:before,.clearfix:after{
content:'';
display:table;
}
.clearfix:after{
clear:both;
}
.clearfix{
zoom:1;
}
.fl{
float:left;
}
.fr{
float:right;
}
index.css
body{
font-family:'Microsoft YaHei';
}
.wrap{
position: fixed;
left:0;
top:0;
width:100%;
height:100%;
/* background: radial-gradient(#f3fbfe, #e4f5fd, #8fd5f4); */
/* background:#8fd5f4; */
/* background: linear-gradient(#6bc6ee, #fff); */
background:#fff;
}
.search_form{
width:640px;
margin:100px auto 0;
}
.logo img{
display:block;
margin:0 auto;
}
.form_group{
width:640px;
height:40px;
margin-top:45px;
}
.input_txt{
width:538px;
height:38px;
padding:0px;
float:left;
border:1px solid #41a1cb;
outline:none;
text-indent:10px;
}
.input_sub{
width:100px;
height:40px;
border:0px;
float: left;
background-color: #41a1cb;
color:#fff;
font-size:16px;
outline:none;
cursor: pointer;
position: relative;
}
.input_sub.loading::before{
content:'';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: url('../img/loading.gif');
}
.hotkey{
margin:3px 0 0 2px;
}
.hotkey a{
font-size:14px;
color:#666;
padding-right:15px;
}
.weather_list{
height:200px;
text-align:center;
margin-top:50px;
font-size:0px;
}
.weather_list li{
display:inline-block;
width:140px;
height:200px;
padding:0 10px;
overflow: hidden;
position: relative;
background:url('../img/line.png') right center no-repeat;
background-size: 1px 130px;
}
.weather_list li:last-child{
background:none;
}
/* .weather_list .col02{
background-color: rgba(65, 165, 158, 0.8);
}
.weather_list .col03{
background-color: rgba(94, 194, 237, 0.8);
}
.weather_list .col04{
background-color: rgba(69, 137, 176, 0.8);
}
.weather_list .col05{
background-color: rgba(118, 113, 223, 0.8);
} */
.info_date{
width:100%;
height:40px;
line-height:40px;
color:#999;
font-size:14px;
left:0px;
bottom:0px;
margin-top: 15px;
}
.info_date b{
float: left;
margin-left:15px;
}
.info_type span{
color:#fda252;
font-size:30px;
line-height:80px;
}
.info_temp{
font-size:14px;
color:#fda252;
}
.info_temp b{
font-size:13px;
}
.tem .iconfont {
font-size: 50px;
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>天知道</title>
<link rel="stylesheet" href="css/reset.css" />
<link rel="stylesheet" href="css/index.css" />
</head>
<body>
<div class="wrap" id="app">
<div class="search_form">
<div class="logo"><img src="img/logo.png" alt="logo" /></div>
<div class="form_group">
<!--搜索框-->
<input type="text" v-model="city" @keyup.enter="searchWeather" class="input_txt" placeholder="请输入查询的天气"/>
<button class="input_sub" @click="searchWeather">
搜 索
</button>
</div>
<div class="hotkey">
<!-- <a href="javascript:;">北京</a>-->
<!-- <a href="javascript:;">上海</a>-->
<!-- <a href="javascript:;">广州</a>-->
<!-- <a href="javascript:;">深圳</a>-->
<!--对于上面的像列表一样的东西, 可以用v-for来代替-->
<!--这里href-->
<a href="javascript:;" v-for="city in hotCitys" @click="clickCity(city)">{{city}}</a>
<!-- <a href="#" v-for="city in hotCitys" @click="clickCity(city)">{{city}}</a>-->
</div>
</div>
<ul class="weather_list">
<!--这里是展示, 查询到的天气结果-->
<!--为了是每一次搜索同一个城市的时候都有刷新一下的效果, 这里用v-bind绑定一下数据-->
<li v-for="(item,index) in weatherList" :key="item.date" :style="{transitionDelay:index*100+'ms'}">
<div class="info_type">
<span class="iconfont">{{ item.type }}</span>
</div>
<div class="info_temp">
<b>{{ item.low }}</b>
~
<b>{{ item.high }}</b>
</div>
<div class="info_date">
<span>{{ item.date }}</span>
</div>
</li>
</ul>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- 自己的js -->
<!-- <script src="./js/main.js"></script>-->
<script>
var app = new Vue({
el: "#app",
data: {
city: '',
weatherList: [],
hotCitys: ["北京", "重庆", "广安", "成都"]
},
methods: {
searchWeather: function () {
// console.log('天气查询');
// console.log(this.city);
// 调用接口
// 保存this
var that = this;
this.weatherList = [];//这个重置一下,数组中的数据,会有个一闪一闪的动画
axios.get('http://wthrcdn.etouch.cn/weather_mini?city=' + this.city)
// .then(res => {//这里是匿名函数!
// console.log(res);
// this.weatherList = res.data.data.forecast;
// })
.then(function (response) {
// console.log(response);
console.log(response.data.data.forecast);
that.weatherList = response.data.data.forecast;
})
.catch(function (err) {
})
.finally(() => { });
},
clickCity(city){
this.city = city;
this.searchWeather();
}
},
})
</script>
</body>
</html>
记事本:
主要功能:
主要数据类型:
data: {
list: ["写代码", "吃饭饭", "睡觉觉"],
inputValue: "好好学习,天天向上"
},
全部源码:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>小黑记事本</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="googlebot" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
html,
body {
margin: 0;
padding: 0;
}
body {
background: #fff;
}
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font: 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #f5f5f5;
color: #4d4d4d;
min-width: 230px;
max-width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 300;
}
:focus {
outline: 0;
}
.hidden {
display: none;
}
#todoapp {
background: #fff;
margin: 180px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
#todoapp input::-webkit-input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp input::-moz-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp input::input-placeholder {
font-style: italic;
font-weight: 300;
color: gray;
}
#todoapp h1 {
position: absolute;
top: -160px;
width: 100%;
font-size: 60px;
font-weight: 100;
text-align: center;
color: rgba(175, 47, 47, .8);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
.new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.new-todo {
padding: 16px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
}
.main {
position: relative;
z-index: 2;
border-top: 1px solid #e6e6e6;
}
.toggle-all {
width: 1px;
height: 1px;
border: none; /* Mobile Safari */
opacity: 0;
position: absolute;
right: 100%;
bottom: 100%;
}
.toggle-all + label {
width: 60px;
height: 34px;
font-size: 0;
position: absolute;
top: -52px;
left: -13px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.toggle-all + label:before {
content: "❯";
font-size: 22px;
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
.toggle-all:checked + label:before {
color: #737373;
}
.todo-list {
margin: 0;
padding: 0;
list-style: none;
max-height: 420px;
overflow: auto;
}
.todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
height: 60px;
box-sizing: border-box;
}
.todo-list li:last-child {
border-bottom: none;
}
.todo-list .view .index {
position: absolute;
color: gray;
left: 10px;
top: 20px;
font-size: 16px;
}
.todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none; /* Mobile Safari */
-webkit-appearance: none;
appearance: none;
}
.todo-list li .toggle {
opacity: 0;
}
.todo-list li .toggle + label {
/*
Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
*/
background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center left;
}
.todo-list li .toggle:checked + label {
background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E");
}
.todo-list li label {
word-break: break-all;
padding: 15px 15px 15px 60px;
display: block;
line-height: 1.2;
transition: color 0.4s;
}
.todo-list li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}
.todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
transition: color 0.2s ease-out;
}
.todo-list li .destroy:hover {
color: #af5b5e;
}
.todo-list li .destroy:after {
content: "×";
}
.todo-list li:hover .destroy {
display: block;
}
.todo-list li .edit {
display: none;
}
.todo-list li.editing:last-child {
margin-bottom: -1px;
}
.footer {
color: #777;
padding: 10px 15px;
height: 20px;
text-align: center;
border-top: 1px solid #e6e6e6;
}
.footer:before {
content: "";
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 50px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
.todo-count {
float: left;
text-align: left;
}
.todo-count strong {
font-weight: 300;
}
.filters {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
right: 0;
left: 0;
}
.filters li {
display: inline;
}
.filters li a {
color: inherit;
margin: 3px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
.filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
.clear-completed,
html .clear-completed:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
cursor: pointer;
}
.clear-completed:hover {
text-decoration: underline;
}
.info {
margin: 50px auto 0;
color: #bfbfbf;
font-size: 15px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center;
}
.info p {
line-height: 1;
}
.info a {
color: inherit;
text-decoration: none;
font-weight: 400;
}
.info a:hover {
text-decoration: underline;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio: 0) {
.toggle-all,
.todo-list li .toggle {
background: none;
}
.todo-list li .toggle {
height: 40px;
}
}
@media (max-width: 430px) {
.footer {
height: 50px;
}
.filters {
bottom: 10px;
}
}
</style>
<!-- <link rel="stylesheet" type="text/css" href="./css/index.css" />-->
</head>
<body>
<!-- 主体区域 -->
<section id="todoapp">
<!-- 输入框 -->
<header class="header">
<h1>小小记事本</h1>
<input v-model="inputValue" @keyup.enter="add" autofocus="autofocus" autocomplete="off" placeholder="请输入任务"
class="new-todo" />
</header>
<!-- 列表区域 -->
<section class="main">
<ul class="todo-list">
<!--list就是-->
<li class="todo" v-for="(item,index) in list">
<div class="view">
<span class="index">{{ index+1 }}.</span>
<label>{{ item }}</label>
<button class="destroy" @click="remove(index)"></button>
</div>
</li>
</ul>
</section>
<!-- 统计和清空 -->
<footer class="footer" v-show="list.length>0">
<span class="todo-count" >
<strong>{{list.length}}</strong> items left
</span>
<button class="clear-completed" @click="clear">
Clear
</button>
</footer>
</section>
<!-- 底部 -->
<footer class="info">
<p>
<a href="https://ladfeng.top/"><img src="https://qiniu.ladidol.top/img/image-20220421114425049.png" alt="" /></a>
</p>
</footer>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: "#todoapp",
data: {
list: ["写代码", "吃饭饭", "睡觉觉"],
inputValue: "好好学习,天天向上"
},
methods: {
add: function () {
/*add就push一个元素到最后*/
this.list.push(this.inputValue);
},
remove:function(index){
console.log("删除");
console.log(index);
/*remove就把数组的第index个开始,裁剪一个*/
this.list.splice(index,1);
},
clear:function () {
this.list = [];
}
},
})
</script>
</body>
</html>
音乐播放器:
服务器返回的数据比较复杂时,获取的时候需要注意层级结构
通过审查元素快速定位到需要操纵的元素, 比如这里的
#player
注意你要对页面上的东西进行什么操作!
index.css
body,
ul,
dl,
dd {
margin: 0px;
padding: 0px;
}
.wrap {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: url("../images/bg.jpg") no-repeat;
background-size: 100% 100%;
}
.play_wrap {
width: 800px;
height: 544px;
position: fixed;
left: 50%;
top: 50%;
margin-left: -400px;
margin-top: -272px;
/* background-color: #f9f9f9; */
}
.search_bar {
height: 60px;
background-color: #1eacda;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
z-index: 11;
}
.search_bar img {
margin-left: 23px;
}
.search_bar input {
margin-right: 23px;
width: 296px;
height: 34px;
border-radius: 17px;
border: 0px;
background: url("../images/zoom.png") 265px center no-repeat
rgba(255, 255, 255, 0.45);
text-indent: 15px;
outline: none;
}
.center_con {
height: 435px;
background-color: rgba(255, 255, 255, 0.5);
display: flex;
position: relative;
}
.song_wrapper {
width: 200px;
height: 435px;
box-sizing: border-box;
padding: 10px;
list-style: none;
position: absolute;
left: 0px;
top: 0px;
z-index: 1;
}
.song_stretch {
width: 600px;
}
.song_list {
width: 100%;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
}
.song_list::-webkit-scrollbar {
display: none;
}
.song_list li {
font-size: 12px;
color: #333;
height: 40px;
display: flex;
flex-wrap: wrap;
align-items: center;
width: 580px;
padding-left: 10px;
}
.song_list li:nth-child(odd) {
background-color: rgba(240, 240, 240, 0.3);
}
.song_list li a {
display: block;
width: 17px;
height: 17px;
background-image: url("../images/play.png");
background-size: 100%;
margin-right: 5px;
box-sizing: border-box;
}
.song_list li b {
font-weight: normal;
width: 122px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.song_stretch .song_list li b {
width: 200px;
}
.song_stretch .song_list li em {
width: 150px;
}
.song_list li span {
width: 23px;
height: 17px;
margin-right: 50px;
}
.song_list li span i {
display: block;
width: 100%;
height: 100%;
cursor: pointer;
background: url("../images/table.png") left -48px no-repeat;
}
.song_list li em,
.song_list li i {
font-style: normal;
width: 100px;
}
.player_con {
width: 400px;
height: 435px;
position: absolute;
left: 200px;
top: 0px;
}
.player_con2 {
width: 400px;
height: 435px;
position: absolute;
left: 200px;
top: 0px;
}
.player_con2 video {
position: absolute;
left: 20px;
top: 30px;
width: 355px;
height: 265px;
}
.disc {
position: absolute;
left: 73px;
top: 60px;
z-index: 9;
}
.cover {
position: absolute;
left: 125px;
top: 112px;
width: 150px;
height: 150px;
border-radius: 75px;
z-index: 8;
}
.comment_wrapper {
width: 180px;
height: 435px;
list-style: none;
position: absolute;
left: 600px;
top: 0px;
padding: 25px 10px;
}
.comment_wrapper .title {
position: absolute;
top: 0;
margin-top: 10px;
}
.comment_wrapper .comment_list {
overflow: auto;
height: 410px;
}
.comment_wrapper .comment_list::-webkit-scrollbar {
display: none;
}
.comment_wrapper dl {
padding-top: 10px;
padding-left: 55px;
position: relative;
margin-bottom: 20px;
}
.comment_wrapper dt {
position: absolute;
left: 4px;
top: 10px;
}
.comment_wrapper dt img {
width: 40px;
height: 40px;
border-radius: 20px;
}
.comment_wrapper dd {
font-size: 12px;
}
.comment_wrapper .name {
font-weight: bold;
color: #333;
padding-top: 5px;
}
.comment_wrapper .detail {
color: #666;
margin-top: 5px;
line-height: 18px;
}
.audio_con {
height: 50px;
background-color: #f1f3f4;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.myaudio {
width: 800px;
height: 40px;
margin-top: 5px;
outline: none;
background-color: #f1f3f4;
}
/* 旋转的动画 */
@keyframes Rotate {
from {
transform: rotateZ(0);
}
to {
transform: rotateZ(360deg);
}
}
/* 旋转的类名 */
.autoRotate {
animation-name: Rotate;
animation-iteration-count: infinite;
animation-play-state: paused;
animation-timing-function: linear;
animation-duration: 5s;
}
/* 是否正在播放 */
.player_con.playing .disc,
.player_con.playing .cover {
animation-play-state: running;
}
.play_bar {
position: absolute;
left: 200px;
top: -10px;
z-index: 10;
transform: rotate(-25deg);
transform-origin: 12px 12px;
transition: 1s;
}
/* 播放杆 转回去 */
.player_con.playing .play_bar {
transform: rotate(0);
}
/* 搜索历史列表 */
.search_history {
position: absolute;
width: 296px;
overflow: hidden;
background-color: rgba(255, 255, 255, 0.3);
list-style: none;
right: 23px;
top: 50px;
box-sizing: border-box;
padding: 10px 20px;
border-radius: 17px;
}
.search_history li {
line-height: 24px;
font-size: 12px;
cursor: pointer;
}
.switch_btn {
position: absolute;
right: 0;
top: 0;
cursor: pointer;
}
.right_line {
position: absolute;
left: 0;
top: 0;
}
.video_con video {
position: fixed;
width: 800px;
height: 546px;
left: 50%;
top: 50%;
margin-top: -273px;
transform: translateX(-50%);
z-index: 990;
}
.video_con .mask {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: 980;
background-color: rgba(0, 0, 0, 0.8);
}
.video_con .shutoff {
position: fixed;
width: 40px;
height: 40px;
background: url("../images/shutoff.png") no-repeat;
left: 50%;
margin-left: 400px;
margin-top: -273px;
top: 50%;
z-index: 995;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>悦听player</title>
<!-- 样式 -->
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<div class="wrap">
<!-- 播放器主体区域 -->
<div class="play_wrap" id="player">
<div class="search_bar">
<img src="images/player_title.png" alt="" />
<!-- 搜索歌曲 -->
<input type="text" autocomplete="off" v-model="query" @keyup.enter="searchMusic" />
</div>
<div class="center_con">
<!-- 搜索歌曲列表 -->
<div class='song_wrapper'>
<ul class="song_list">
<li v-for="item in musicList"><!--对歌曲进行循环展示-->
<a href="javascript:;" @click="playMusic(item.id)"></a> <!--播放按钮-->
<b>{{ item.name }} -{{ item.artists[0].name }}</b><!--歌曲名和歌手名-->
<span v-if="item.mvid!=0" @click="playMV(item.mvid)"><i></i></span><!--如果有mv的话,就显示mv标识-->
</li>
</ul>
<img src="images/line.png" class="switch_btn" alt="">
</div>
<!-- 歌曲信息容器 -->
<div class="player_con" :class="{playing:isPlaying}">
<img src="images/player_bar.png" class="play_bar" />
<!-- 黑胶碟片 -->
<img src="images/disc.png" class="disc autoRotate" />
<img :src="musicCover" class="cover autoRotate" />
</div>
<!-- 评论容器 -->
<div class="comment_wrapper">
<h5 class='title'>热门留言</h5>
<div class='comment_list'>
<dl v-for="item in hotComments">
<dt><img :src="item.user.avatarUrl" alt=""></dt>
<dd class="name">{{ item.nickname}}</dd>
<dd class="detail">
{{ item.content }}
</dd>
</dl>
</div>
<img src="images/line.png" class="right_line">
</div>
</div>
<div class="audio_con">
<audio ref='audio' @play="play" @pause="pause" :src="musicUrl" controls autoplay loop class="myaudio"></audio>
</div>
<div class="video_con" v-show="isShow" style="display: none;">
<video :src="mvUrl" controls="controls"></video>
<div class="mask" @click="hide"></div>
</div>
</div>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- <script src="./js/main.js"></script>-->
<script>
/*
1:歌曲搜索接口
请求地址:https://autumnfish.cn/search
请求方法:get
请求参数:keywords(查询关键字)
响应内容:歌曲搜索结果
2:歌曲url获取接口
请求地址:https://autumnfish.cn/song/url
请求方法:get
请求参数:id(歌曲id)
响应内容:歌曲url地址
3.歌曲详情获取
请求地址:https://autumnfish.cn/song/detail
请求方法:get
请求参数:ids(歌曲id)
响应内容:歌曲详情(包括封面信息)
4.热门评论获取
请求地址:https://autumnfish.cn/comment/hot?type=0
请求方法:get
请求参数:id(歌曲id,地址中的type固定为0)
响应内容:歌曲的热门评论
5.mv地址获取
请求地址:https://autumnfish.cn/mv/url
请求方法:get
请求参数:id(mvid,为0表示没有mv)
响应内容:mv的地址
*/
var app = new Vue({
el: "#player",
data: {
// 查询关键字
query: "",
// 歌曲数组
musicList: [],
// 歌曲地址
musicUrl: "",
// 歌曲封面
musicCover: "",
// 歌曲评论
hotComments: [],
// 动画播放状态
isPlaying: false,
// 遮罩层的显示状态
isShow: false,
// mv地址
mvUrl: ""
},
methods: {
// 歌曲搜索
searchMusic: function() {
var that = this;
axios.get("https://autumnfish.cn/search?keywords=" + this.query)
.then(
function(response) {
//先通过console看一下response的数据结构!
// console.log(response);
that.musicList = response.data.result.songs;
console.log(response.data.result.songs);
},
function(err) {}
);
},
// 歌曲播放
//播放歌曲的本质就是设置了歌曲的audio的src, 本请求主要是为了得到歌曲的url
playMusic: function(musicId) {
// console.log(musicId);
var that = this;
// 获取歌曲地址
axios.get("https://autumnfish.cn/song/url?id=" + musicId).then(
function(response) {
// console.log(response);
// console.log(response.data.data[0].url);
that.musicUrl = response.data.data[0].url;
},
function(err) {}
);
// 歌曲详情获取
axios.get("https://autumnfish.cn/song/detail?ids=" + musicId).then(
function(response) {
// console.log(response);
// console.log(response.data.songs[0].al.picUrl);
that.musicCover = response.data.songs[0].al.picUrl;
},
function(err) {}
);
// 歌曲评论获取
axios.get("https://autumnfish.cn/comment/hot?type=0&id=" + musicId).then(
function(response) {
// console.log(response);
// console.log(response.data.hotComments);
that.hotComments = response.data.hotComments;
},
function(err) {}
);
},
// 歌曲播放
play: function() {
// console.log("play");
this.isPlaying = true;
},
// 歌曲暂停
pause: function() {
// console.log("pause");
this.isPlaying = false;
},
// 播放mv
playMV: function(mvid) {
var that = this;
axios.get("https://autumnfish.cn/mv/url?id=" + mvid).then(
function(response) {
// console.log(response);
console.log(response.data.data.url);
that.isShow = true;
that.mvUrl = response.data.data.url;
},
function(err) {}
);
},
// 隐藏
hide: function() {
this.isShow = false;
}
}
});
</script>
</body>
</html>
href=”#”和href=”javascript:”的区别 – 妮小朱 – 博客园 (cnblogs.com)
javascript:表示这是一个空连接。点击之后没任何反应。 类似的是#,但是一个#点击之后页面很长的情况下会会滚到顶部;而javascript:是没有这种问题的。经过测试他还是在当前位置。 当然###这样的效果就跟javascript:一样了
END
本文于2022年5月6日23:20:01更新了一下