⼀、
VUE
简介
1.1
使⽤
jQuery
的复杂性问题
使⽤
jQuery
进⾏前后端分离开发,既可以实现前后端交互(
ajax
)
,
⼜可以完成数据渲
染;
存在的问题:
jQuery
需要通过
HTML
标签拼接、
DOM
节点操作完成数据的显示,开发效
率低且容易出错,渲染效率较低
vue
是继
jQuery
之后的⼜⼀优秀的前端框架:专注于前端数据的渲染
——
语法简单、渲
染效率⾼
1.2 VUE
简介
1.2.1
前端框架
前端三要素:
HTML
、
CSS
、
JavaScript
HTML
决定⽹⻚结构
CSS
决定显示效率
JavaScript
决定⽹⻚功能(交互、数据显示)
UI
框架:
Bootstrap
amazeUI
Layui
JS
框架:
jQuery
(
jQuery UI
)
React
angular
nodejs----
后端开发
vue
集各种前端框架的优势发展⽽来
1.2.2 MVVM
项⽬结构经历的三个阶段:
后端
MVC
我们就可以理解为单体架构,流程控制是由后端控制器来完成
前端
MVC
前后端分离开发,后端只负责接收响应请求
MVVM
前端请求后端接⼝,后端返回数据,前端接收数据,并将接收的数据设置
“VM”,HTML
从
vm
取值
M model
数据模型
指的是后端接⼝返回的数据
V view
视图
MVC
MVVM
VM ViewModel
视图模型
数据模型与视图之间的桥梁,后端返回的
model
转换前端所需
的
vm
,视图层可以直接从
vm
中提取数据
⼆、
vue
的⼊⻔使⽤
Vue
被设计为可以⾃底向上逐层应⽤。
Vue
的核⼼库只关注视图层,不仅易于上⼿,还
便于与第三⽅库或既有项⽬整合
.
2.1 vue
的引⼊
离线引⽤:下载
vue
的
js
⽂件,添加到前端项⽬,在⽹⻚中通过
script
标签引⽤
vue.js
⽂件
CDN
引⽤:
2.2
⼊⻔案例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="container">
从vm中获取的数据为:{{str}}
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
str:"从前有座⼭"
}
});
</script>
</body>
</html>
三、 vue的语法
3.1
基本类型数据和字符串
{{code}}
{{str}}
-------------------------
data:{
code:10,
str:"test"
}
3.2
对象类型数据
⽀持
ognl
语法
{{stu.stuNum}}
{{stu.stuName}}
-----------------------------
data{
stu:{
stuNum:"100001",
stuName:"张三",
stuGender:"M",
stuAge:20
}
}
3.3 条件 v-if
<label v-if="stu.stuGender=='M'">男</label><br/>
-------------------------------------------------------
data:{
stu:{
stuNum:"100001",
stuName:"张三",
stuGender:"M",
stuAge:20
}
}
3.4
循环
v-for
<table border="1" cellspacing="0" width="400">
<tr>
<th>序号</th>
<th>学号</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
</tr>
<tr v-for="s,index in stus">
<td>{{index+1}}</td>
<td>{{s.stuNum}}</td>
<td>{{s.stuName}}</td>
<td>
<label v-if="s.stuGender == 'M'">男</label>
<label v-if="s.stuGender == 'F'">⼥</label>
</td>
<td>{{s.stuAge}}</td>
</tr>
</table>
---------------------------------------------------------------------
data:{
stus:[
{
stuNum:"100001",
stuName:"张⼤三",
stuGender:"M",
stuAge:23
},
{
stuNum:"100002",
stuName:"张中三",
stuGender:"M",
stuAge:22
},
{
stuNum:"100003",
stuName:"张⼩三",
stuGender:"F",
stuAge:20
}
]
}
3.5 v-bind绑定标签属性
<input type="text" v-bind:value="str"/>
<img :src="stu.stuImg"/>
------------------------------------
data{
str:"从前有座⼭",
stu:{
stuImg:"img/01.jpg"
}
}
v-bind:
可简写为
:
3.6
表单标签的双向绑定
v-model
只能使⽤在表单输⼊标签
v-model:value
可以简写为
v-model
<input type="text" v-model:value="str"/>
<input type="text" v-model="str"/>
------------------------------------
data{
str:"从前有座⼭"
}
四、vue实例
每个使⽤
vue
进⾏数据渲染的⽹⻚⽂档都需要创建⼀个
Vue
实例
—— ViewModel
4.1 Vue
实例的⽣命周期
vue
实例⽣命周期
——vue
实例从创建到销毁的过程
创建
vue
实例(初始化
data
、加载
el
)
数据挂载(将
vue
实例
data
中的数据渲染到⽹⻚
HTML
标签)
重新渲染(当
vue
的
data
数据发⽣变化,会重新渲染到
HTML
标签)
销毁实例
4.2
钩⼦函数
为了便于开发者在
vue
实例⽣命周期的不同阶段进⾏特定的操作,
vue
在⽣命周期四个阶
段的前后分别提供了⼀个函数,这个函数⽆需开发者调⽤,当
vue
实例到达⽣命周期的指
定阶段会⾃动调⽤对应的函数。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="js/vue.js" ></script>
</head>
<body>
<div id="container">
<label v-once>{{str}}</label><br/>
<label>{{str}}</label><br/>
<input type="text" v-model="str"/>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{},
beforeCreate:function(){
//1.data初始化之前执⾏,不能操作data
},
created:function(){
//2.data初始化之后执⾏,模板加载之前,可以修改/获取data中的值
console.log(this.str);
//this.str = "⼭⾥有座庙";
},
beforeMount:function(){
//3.模板加载之后,数据初始渲染(挂载)之前,可以修改/获取data中的值
//this.str = "庙⾥有⼝井";
},
mounted:function(){
//4.数据初始渲染(挂载)之后,可以对data中的变量进⾏修改,但是不会影响
v-once的渲染
//this.str = "井⾥有只蛙";
},
beforeUpdate:function(){
//5.数据渲染之后,当data中的数据发⽣变化触发重新渲染,渲染之前执⾏此函
数
// data数据被修改之后,重新渲染到⻚⾯之前
console.log("-----"+this.str);
this.str = "从前有座⼭2";
},
updated:function(){
//6.data数据被修改之后,重新渲染到⻚⾯之后
//this.str = "从前有座⼭3";
},
beforeDestroy:function(){
//7.实例销毁之前
},
destroyed:function(){
//8.实例销毁之后
}
});
</script>
</body>
</html>
五、计算属性和侦听器
5.1
计算属性
data
中的属性可以通过声明获得,也可以通过在
computed
通过计算获得
特性:计算属性所依赖的属性值发⽣变化会影响计算属性的值同时发⽣变化
示例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="js/vue.js" ></script>
</head>
<body>
<div id="container">
<input type="text" v-model="str1"/><br/>
<input type="text" v-model="str2"/><br/>
{{str3}}
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
str1:"千",
str2:"武"
},
computed:{
str3:function(){
return this.str1+this.str2;
}
}
});
</script>
</body>
</html>
5.2 侦听器
侦听器,就是
data
中属性的监听器,当
data
中的属性值发⽣变化就会触发侦听器函数的
执⾏
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="js/vue.js" ></script>
</head>
<body>
<div id="container">
<input type="text" v-model="str1"/><br/>
<input type="text" v-model="str2"/><br/>
{{str3}}
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
str1:"千",
str2:"武",
str3:"千武"
},
watch:{
str1:function(){
this.str3 = this.str1 +this.str2;
},
str2:function(){
this.str3 = this.str1 +this.str2;
}
}
});
</script>
</body>
</html>
六、class与style绑定
我们可以使⽤
mustache
语法将
vue
中
data
的数据绑定到
HTML
标签及标签的属性,如何
将
data
中的值绑定到标签的
class
及
style
属性呢?
6.1 class
绑定
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
.mystyle1{
width: 200px;
height: 100px;
background: orange;
}
.mystyle3{
width: 200px;
height: 100px;
background: black;
}
.my-style2{
border-radius: 10px;
}
</style>
<script type="text/javascript" src="js/vue.js" ></script>
</head>
<body>
<div id="container">
<!--如果b1为true就加载 mystyle1;如果b2为true,则加载my-style2-->
<div :class="{mystyle1:b1,'my-style2':b2}"></div>
<!--为class属性加载多个样式名 -->
<div :class="[chooseStyle1,chooseStyle2]"></div>
<!--如果b3为true,则class='mystyle3'; 否则class='mystyle1'
如果在三⽬运算中使⽤样式名则需加单引号,不加单引号则表示从data变量中获取样式
名-->
<div :class="[b3 ? 'mystyle3' : 'mystyle1']"></div>
<div :class="[b3 ? chooseStyle3 : chooseStyle1]"></div>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
b1:true,
b2:true,
b3:false,
chooseStyle1:"mystyle1",
chooseStyle2:"my-style2",
chooseStyle3:"mystyle3"
}
});
</script>
</body>
</html>
6.2 style绑定
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="js/vue.js" ></script>
</head>
<body>
<div id="container">
<!--当使⽤v-bind绑定内联样式时:
1. 使⽤{}定义style样式,才能获取data中的值,{}要遵循JSON格式
2. {}中不在使⽤style样式属性名“font-size”,⽽要使⽤对应的js属性名
border-style-width --- borderStyleWidth
-->
<div v-bind:style="{color: colorname,fontSize: fontsize+'px'
}">WH2010</div>
<!--我们可以直接为style属性绑定⼀个data中定义好的内联样式的字符串-->
<div v-bind:style="mystyle1">Java-WH2010</div>
<!--我们可以直接为style属性绑定⼀个data中定义好的内联样式的对象-->
<div v-bind:style="mystyle2">千锋Java-WH2010</div>
<!--可以在同⼀个style上通过数组引⽤多个内联样式的对象-->
<div v-bind:style="[mystyle2,mystyle3]">Java-WH2010</div>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
colorname:"green",
fontsize:30,
mystyle1:"color:orange;font-size:45px",
mystyle2:{
color:"blue",
fontSize:"40px"
},
mystyle3:{
textShadow:"orange 3px 3px 5px"
}
}
});
</script>
</body>
</html>
七、条件与列表渲染
7.1
条件渲染
7.1.1 v-if
在
html
标签可以添加
v-if
指令指定⼀个条件,如果条件成⽴则显示此
HTML
标签,如果不
成⽴则不显示当前标签;
条件可以是⼀个表达式也可以是⼀个具体的
bool
类型值
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="js/vue.js" ></script>
</head>
<body>
<div id="container">
<h3 v-if="b">从前有座⼭</h3>
<h3 v-if="code == 1">从前有座⼭</h3>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
code:2,
b:false
}
});
</script>
</body>
</html>
7.1.2 v-else
<div id="container">
<!--v-else标签需要紧跟在v-if的标签之后,中间不能有其他标签-->
<h3 v-if="code == 1">从前有座⼭</h3>
<h3 v-else>⼭⾥有座庙</h3>
</div> <script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
code:1
}
});
</script>
7.1.3 v-else-if
<div id="container">
<h3 v-if="code >= 90">优秀</h3>
<h3 v-else-if="code >= 80">良好</h3>
<h3 v-else-if="code >= 70">中等</h3>
<h3 v-else-if="code >= 60">及格</h3>
<h3 v-else>不想理你</h3>
</div> <script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
code:85
}
});
</script>
7.1.4 v-show
从功能上将
v-show
和
v-if
作⽤是相同的,渲染过程有区别
v-if
是
“
真正
”
的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和⼦组件适当
地被销毁和重建。
v-if
也是
惰性的
:如果在初始渲染时条件为假,则什么也不做
——
直到条件第⼀次变为真
时,才会开始渲染条件块。
相⽐之下,
v-show
就简单得多
——
不管初始条件是什么,元素总是会被渲染,并且只是简单
地基于
CSS
进⾏切换。
⼀般来说,
v-if
有更⾼的切换开销,⽽
v-show
有更⾼的初始渲染开销。因此,如果需要⾮
常频繁地切换,则使⽤
v-show
较好;如果在运⾏时条件很少改变,则使⽤
v-if
较好。
7.2
列表渲染
将集合数据以表格、列表的形式显示
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="css/bootstrap.css" />
<script type="text/javascript" src="js/jquery-3.4.1.min.js" >
</script>
<script type="text/javascript" src="js/bootstrap.js" ></script>
<script type="text/javascript" src="js/vue.js" ></script>
</head>
<body>
<div id="container">
<ul>
<li v-for="c in categories">
<a :href="'query?cid='+c.cid">{{c.cname}}</a>
</li>
</ul>
<table class="table table-bordered">
<tr>
<th>学号</th>
<th>照⽚</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>操作</th>
</tr>
<template v-for="s,index in stus">
<tr :id="'tr'+s.stuNum">
<td>{{s.stuNum}}</td>
<td>
<img height="30" :src="s.stuImg"/>
</td>
<td>{{s.stuName}}</td>
<td>
<!--{{s.stuGender=='M'?'男':'⼥'}}-->
<img v-if="s.stuGender=='M'" src="img/m.bmp">
<img v-else src="img/f.bmp">
</td>
<td>{{s.stuAge}}</td>
<td>
<a class="btn btn-danger btn-xs" :href="'stu/delete?
cid='+s.stuNum">删除</a>
<a class="btn btn-success btn-xs" :href="'stu/update?
cid='+s.stuNum">修改</a>
</td>
</tr>
</template>
</table>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
categories:[
{
cid:1,
cname:"华为"
},
{
cid:2,
cname:"⼩⽶"
},
{
cid:3,
cname:"OPPO"
},
{
cid:4,
cname:"VIVO"
}
],
stus:[
{
stuNum:"10010",
stuImg:"img/01.jpg",
stuName:"Tom",
stuGender:"M",
stuAge:20
},
{
stuNum:"10011",
stuImg:"img/02.jpg",
stuName:"LiLei",
stuGender:"M",
stuAge:20
},
{
stuNum:"10012",
stuImg:"img/03.jpg",
stuName:"Lucy",
stuGender:"F",
stuAge:20
},
{
stuNum:"10013",
stuImg:"img/04.jpg",
stuName:"Polly",
stuGender:"F",
stuAge:20
}
]
}
});
</script>
</body>
</html>
⼋、事件处理
在使⽤
vue
进⾏数据渲染时,如果使⽤原⽣
js
事件绑定
(
例如
onclick)
,如果需要获取
vue
实例中的数据并传参则需要通过拼接来完成
vue
提供了
v-on
指令⽤于绑定各种事件(
v-on:click
),简化了从
vue
取值的过程,但
是触发的⽅法需要定义在
vue
实例的
methods
中
<button type="button" von:click="doDelete(s.stuNum,s.stuName)">删除</button> <script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{},
methods:{
doDelete:function(snum,sname){
console.log("----delete:"+snum+" "+sname)
}
}
});
</script>
v-on:clicl
可以缩写为
@click
8.1
使⽤
JS
函数传值
<button type="button" class="btn btn-danger btn-xs" von:click="doDelete(s.stuNum,s.stuName)">删除</button> <script>
var vm = new Vue({
el:"#container",
data:{};
methods:{
doDelete:function(snum,sname){
console.log("----delete:"+snum+" "+sname)
}
}
});
</script>
8.2
使⽤
dataset
对象传值
<button type="button" class="btn btn-success btn-xs" @click="doUpdate"
:data-snum="s.stuNum"
:data-sname="s.stuName" :data-simg="s.stuImg">修 改</button> <script>
var vm = new Vue({
el:"#container",
data:{};
methods:{
doUpdate:function(event){
//如果v-on绑定的js函数没有参数,调⽤的时候可以省略(),同时可以给
js函数⼀个event参数(事件对象)
// 1. event 表示触发当前函数的事件
// 2. event.srcElement 表示发⽣事件的元素---修改按钮
// 3. event.srcElement.dataset 表示按钮上绑定的数据集
(data-开头的属性)
console.log("-----update")
var stu = event.srcElement.dataset;
}
}
});
</script>
8.3 混合使⽤
$event
<button type="button" class="btn btn-danger btn-xs" von:click="doDelete(s.stuNum,s.stuName,$event)":data-simg="s.stuImg">删 除</button> <script>
var vm = new Vue({
el:"#container",
data:{};
methods:{
doDelete:function(snum,sname,event){
console.log("----delete:"+snum+" "+sname)
console.log(event.srcElement.dataset);
}
}
});
</script>
8.4
事件修饰符
当使⽤
v-on
进⾏事件绑定的时候,可以添加特定后缀,设置事件触发的特性
8.4.1
事件修饰符使⽤示例
<button type="submit" @click.prevent="事件函数">测试</button>
8.4.2
事件修饰符
.prevent
消除元素的默认事件
<div id="container">
<form action="https://www.baidu.com">
<button type="submit" class="btn btn-success btn-xs"
@click.prevent="test">测试</button>
</form>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
},
methods:{
test:function(){
console.log("---test");
}
}
});
</script>
.stop 阻⽌事件冒泡(阻⽌⼦标签向上冒泡)
.self
设置只能⾃⼰触发事件(⼦标签不能触发)
<div id="container">
<div style="width: 200px; height: 200px; background: red;"
@click.self="method1">
<div style="width: 150px; height: 150px; background: green;"
@click="method2">
<button type="button" @click.stop="method3">测试</button>
</div>
</div>
</div> <script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
},
methods:{
method1:function(){
alert("1");
},
method2:function(){
alert("2");
},
method3:function(){
alert("3");
}
}
});
</script>
.once 限定事件只触发⼀次
8.4.3
按键修饰符
按键修饰符就是针对键盘事件的修饰符,限定哪个按键会触发事件
.enter
.tab
.delete
(
捕获
“
删除
”
和
“
退格
”
键
)
.esc
.space
.up
.down
.left
.right
除了以上
vue
提供按钮的别名之外,我们还可以根据键盘为按键⾃定义别名
键盘码
示例
:
<div id="container">
<!--2.使⽤⾃定义的按键别名aaa作为修饰符-->
<input type="text" @keyup.aaa="method4"/>
</div>
<script type="text/javascript">
//1.为按键J定于别名为 aaa
Vue.config.keyCodes.aaa =74;
var vm = new Vue({
el:"#container",
data:{},
methods:{
method4:function(){
alert("4");
}
}
});
</script>
8.4.3 系统修饰符
组合键
示例
ctrl+j
触发事件
<div id="container">
<input type="text" @keyup.ctrl.j="method4"/>
</div>
<script type="text/javascript">
Vue.config.keyCodes.j =74;
var vm = new Vue({
el:"#container",
data:{},
methods:{
method4:function(){
alert("4");
}
}
});
</script>
.ctrl
.alt
.shift
.meta
windows
键
九、表单输⼊绑定
表单输⼊绑定,即双向绑定:就是能够将
vue
实例的
data
数据渲染到表单输⼊视图
(
input\textarea\select
),也能够将输⼊视图的数据同步更新到
vue
实例的
data
中
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="css/bootstrap.css" />
<script type="text/javascript" src="js/jquery-3.4.1.min.js" >
</script>
<script type="text/javascript" src="js/bootstrap.js" ></script>
<script type="text/javascript" src="js/vue.js" ></script>
</head>
<body>
<div id="container">
<!--⽂本输⼊框、密码输⼊框-->
<input type="text" v-model="text"/><br/>
<input type="password" v-model="pwd"/><br/>
<!--单选按钮-->
<input type="radio" v-model="opt1" value="A"/>A 3
<input type="radio" v-model="opt1" value="B"/>B 4
<input type="radio" v-model="opt1" value="C"/>C 5
<input type="radio" v-model="opt1" value="D"/>D 6 <br/>
<!--复选框,绑定的是⼀个数组-->
<input type="checkbox" v-model="opt2" value="篮球"/>篮球 <br/>
<input type="checkbox" v-model="opt2" value="⾜球"/>⾜球 <br/>
<input type="checkbox" v-model="opt2" value="⽻⽑球"/>⽻⽑球 <br/>
<input type="checkbox" v-model="opt2" value="乒乓球"/>乒乓球<br/>
<!--下拉菜单select:绑定⼀个字符串-->
<select v-model="city">
<option value="BJ">北京</option>
<option value="SH">上海</option>
<option value="GZ">⼴州</option>
<option value="SZ">深圳</option>
</select>
<br/>
<!--下拉菜单select:如果有multiple表示可多选,需要绑定⼀个数组-->
<select v-model="cities" multiple>
<option value="BJ">北京</option>
<option value="SH">上海</option>
<option value="GZ">⼴州</option>
<option value="SZ">深圳</option>
</select>
<br/>
<button type="button" @click="doSearch">测试</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
text:"aaa",
pwd:"111111",
opt1:"C",
opt2:["篮球","⽻⽑球"],
city:"SZ",
cities:["BJ","SZ"]
},
methods:{
doSearch:function(){
alert(vm.cities);
}
}
});
</script>
</body>
</html>
⼗、vue使⽤案例
10.1
接⼝说明
接⼝名称
| |
功能描述
| 根据关键字搜索⾳乐信息 |
请求
URL
|
http://47.96.11.185:9999/music/search
|
请求⽅式
|
GET | POST
|
请求参数
|
s string [
必须
]
搜索关键字
limit int [
可选
]
返回的搜索结果的条数,默认为
10
type int [
可选
]
搜索类型
(1
单曲
10
歌单
)
,默认为
1
offset int [
可选
]
搜索结果的偏移
|
返回结果
|
10.2
如何部署
jar
⽂件
10.3
案例⽬标
请⼤家根据以上接⼝实现搜索和列表显示功能
10.4
案例实现
java -jar music-1.0.0.jar
10.4.1
⾳乐搜索
10.4.2
⾳乐播放
在
music.html
中定义⾳频播放器
(
定义在
vue
的容器之外
)
<audio controls style="width:100%" src="" id="player"></audio>
给播放按钮绑定点击事件触发的函数
doPlay
<button type="button" class="btn btn-success btn-xs" @click="doPlay"
:data-mid="song.id">播放</button>
在
doPlay
中执⾏播放
<script type="text/javascript">
var player = document.getElementById("player");
var vm = new Vue({
el:"#container",
data:{
keyword:"张韶涵",
songs:[],
currentid:0
},
methods:{
doSearch:function(){
console.log(vm.keyword);
$.get("http://localhost:9999/music/search", {s:vm.keyword,limit:15,offset:0},function(res){
console.log(res);
if(res.code==200){
//获取此关键词搜索的总记录数
var count = res.result.songCount;
//获取⾳乐集合
var arr = res.result.songs;
vm.songs = arr;
}else{
vm.songs = data;
}
},"json");
},
doPlay:function(event){
vm.currentid = event.srcElement.dataset.mid;
//⽹易云⾳乐播放地址:
http://music.163.com/song/media/outer/url?id=songId
player.src =
"http://music.163.com/song/media/outer/url?id="+vm.currentid;
player.play();
}
}
});
</script>
10.4.3 播放暂停切换
⼗⼀、组件
11.1
组件介绍及示例
组件,就是将通⽤的
HTML
模块进⾏封装
——
可复⽤
11.1.1
组件注册
将通⽤的
HTML
模块封装注册到
vue
中
Vue.component("header-bar",{
});
11.1.2
组件引⽤
定义组件需要依赖
vue.js
,在引⽤⾃定义组件的
js
⽂件之前要先引⽤
vue.js
组件的引⽤必须在
vue
实例
el
指定的容器中
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="container">
<header-bar></header-bar>
</div>
<script type="text/javascript" src="js/vue.js" ></script>
<script type="text/javascript" src="js/my-components.js" ></script>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
});
</script>
</body>
</html>
11.2 组件注册
11.2.1
⾃定义组件的结构
data
定义组件的模板渲染的数据
template
组件的
HTML
模块(
HTML
标签
\css
样式)
methods
定义组件中的标签事件绑定的
JS
函数
Vue.component("header-bar",{
data:function(){
//组件中的data是通过函数返回的对象
return {
title:"Java电商平台"
};
},
template:`<div style="width: 100%; height: 80px; background:
lightyellow;">
<table width="100%">
<tr>
<td width="200" align="right" valign="middle">
<img src="img/logo.png" height="80">
</td>
<td>
<label style="color: deepskyblue;font-size:32px; fontfamily: 华⽂⾏楷; margin-left: 30px;">
{{title}}
</label>
</td>
<td>
<button @click="test">组件中的按钮</button>
</td>
</tr>
</table>
</div>`,
methods:{
test:function(){
alert("组件中定义的函数");
}
}
});
11.2.2
组件的封装
将模版中的
css
样式提出取来,单独定义到
css
⽂件存储在
css
⽬录
将模版中的图⽚存在在
img
⽬录
将定义组件的
js
⽂件和
vue
的⽂件存放到
js
⽬录
vue组件封装的⽬录结构
11.2.3
组件的复⽤
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" href="css/my-components.css" />
</head>
<body>
<div id="container">
<header-bar></header-bar>
</div>
<script type="text/javascript" src="js/vue.js" ></script>
<script type="text/javascript" src="js/my-components.js" ></script>
<script type="text/javascript">
var vm = new Vue({
el:"#container"
});
</script>
</body>
</html>
11.3
组件通信
vue
实例本身就是⼀个组件(模板就是
el
指定容器
,data
就是组件数据
,methods
就是组件
的事件函数)
在
vue
实例指定的
el
容器中引⽤的组件称为⼦组件
,
当前
vue
实例就是⽗组件
11.3.1
⽗传⼦
vue
实例引⽤组件的时候,传递数据到引⽤的组件中
示意图
11.3.2
⼦传⽗
通过⼦组件的按钮
“
调⽤
”
⽗组件的函数,通过函数传值
调⽤流程示意图
11.4
组件插槽
当我们⾃定义
vue
组件时,允许组件中的部分内容在调⽤组件时进⾏定义
——
插槽
11.4.1
插槽的使⽤
在⾃定义组件时通过
slot
标签在组件的模版中定义插槽
Vue.component("header-bar",{
data:function(){
//组件中的data是通过函数返回的对象
return {
str2:"⼦组件中的数据"
};
},
template:`<div class="divStyle">
<table class="tableStyle">
<tr>
<td width="200" align="right" valign="middle">
<img src="img/logo.png" class="logoImg">
</td>
<td>
<label class="titleStyle">
{{title}}
</label>
</td>
<td>
<slot></slot>
</td>
<td>
<button @click="childMethod">⼦组件中的按钮</button>
</td>
</tr>
</table>
</div>`,
props:["title"],
methods:{
childMethod:function(){
this.$emit("my-event",this.str2);
}
}
});
在⽗组件中调⽤此组件时,指定插槽填充的模版
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="css/bootstrap.css" />
<link rel="stylesheet" href="css/my-components.css" />
<script type="text/javascript" src="js/jquery-3.4.1.min.js" >
</script>
<script type="text/javascript" src="js/bootstrap.js" ></script>
<script type="text/javascript" src="js/vue.js" ></script>
</head>
<body>
<div id="container">
<header-bar :title="sss">
<!--组件标签包含的HTML默认为填充到插槽的模版-->
<input/><button>搜索</button>
</header-bar>
</div>
<script type="text/javascript" src="js/my-components.js" >
</script>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
sss:"⾃定义标题"
}
});
</script>
</body>
</html>
11.4.2 具名插槽
当组件中的插槽数量
>1
时,需要给组件中的
slot
标签添加
name
属性指定插槽的名字
定义组件:
Vue.component("page-frame",{
template:`<div>
<div id="header" style="width:100%;
height:100px;background:pink">
<slot name="s1"></slot>
</div>
<div style="width:100%; height:580px">
<slot name="s2"></slot>
</div>
<div id="footer" style="width:100%;
height:40px;background:lightgray">{{cr}}</div>
</div>`,
props:["title","cr"]
});
引⽤组件
template
<div id="container">
<page-frame title="标题" cr="千锋武汉">
<!--定义⼀个模版,填充到组件的name=s1的 插槽-->
<template slot="s1">
<input type="text" placeholder="歌曲名、歌⼿" />
<button type="button" @click="doSearch">搜索</button>
</template>
<!--定义⼀个模版,填充到组件的name=s2的 插槽-->
<template slot="s2">
<table class="table table-bordered table-condensed">
<tr>
<th>序号</th>
<th>歌曲ID</th>
<th>歌曲名</th>
<th>歌⼿</th>
<th>专辑</th>
<th>时⻓</th>
<th>操作</th>
</tr>
</table>
</template>
</page-frame>
</div>
11.4.3 插槽作⽤域
定义组件时,将组件中的数据绑定到
slot
标签
Vue.component("page-frame",{
template:`<div>
<div id="header" style="width:100%;
height:100px;background:pink">
<slot name="s1"></slot>
</div>
<div style="width:100%; height:580px">
<slot name="s2" v-bind:musics="songs"></slot>
</div>
<div id="footer" style="width:100%;
height:40px;background:lightgray">{{cr}}</div>
</div>`,
props:["title","cr"],
data:function(){
return {
songs:[
{},{}
]
};
}
});
引⽤组件时,在填充插槽的模版上使⽤ slot-scopt 属性获取插槽绑定的值
<page-frame title="标题" cr="千锋武汉">
<template slot="s1">
<input type="text" placeholder="歌曲名、歌⼿" />
<button type="button" @click="doSearch">搜索</button>
</template>
<!--在使⽤模版填充组件插槽时,可以使⽤slot-scope属性获取组件插槽绑定的数据的
集合 -->
<template slot="s2" slot-scope="res">
<table class="table table-bordered table-condensed">
<tr>
<th>序号</th>
<th>歌曲ID</th>
<th>歌曲名</th>
<th>歌⼿</th>
<th>专辑</th>
<th>时⻓</th>
<th>操作</th>
</tr>
<tr v-for="song,index in res.musics">
<td>{{index+1}}</td>
<td>{{song.id}}</td>
<td>
{{song.name}}
</td>
<td>
<span v-for="artist in song.artists">
{{artist.name}}
</span>
</td>
<td>{{song.album.name}}</td>
<td width="8%">
{{ Math.floor( Math.round(song.duration/1000)/60)
< 10 ? '0'+Math.floor( Math.round(song.duration/1000)/60) : Math.floor(
Math.round(song.duration/1000)/60) }}
{{ Math.round(song.duration/1000)%60 <10 ? '0'+(
Math.round(song.duration/1000)%60 ) : Math.round(song.duration/1000)%60
}}
</td>
<td width="10%">
<button type="button" class="btn btn-primary btnxs">播放</button>
</td>
</tr>
</table>
</template>
</page-frame>
⼗⼆、axios
12.1 axios
介绍
vue
可以实现数据的渲染,但是如何获取数据呢?
vue
本身不具备通信能⼒,通常结合
axios—
⼀个专注于异步通信的
js
框架来使⽤
axios
数据通信
vue
数据渲染
12.2 axios
⼊⻔使⽤
原⽣
ajax ---
实现步骤复杂
jQuery
笨重
axios
简洁、⾼效,对
RESTful
⽀持良好
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="js/vue.js" ></script>
<script type="text/javascript" src="js/axios.min.js" ></script>
</head>
<body>
<div id="container">
<button type="button" @click="test1">测试1</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#container",
methods:{
test1:function(){
//发送异步请求
// axios.get(url).then(fn);
// axios.get(url,{}).then(fn)
axios.get("http://localhost:9999/music/detail",{
params:{
id:"25640392"
}
})
.then(function(res){
console.log(res);
});
}
}
});
</script>
</body>
</html>
12.3 axios异步请求⽅法
axios
提供了多种异步请求⽅法,实现对
RESTful
⻛格的⽀持
12.3.1 get
请求
axios.get(url).then(fn);
axios.get(url,{}).then(fn)
//使⽤axios的get请求传递参数,需要将参数设置在params下
axios.get("http://localhost:9999/music/detail",{
params:{
id:"25640392"
}
})
.then(function(res){
console.log(res);
});
12.3.2 post请求
axios.post(url,{}).then(fn)
axios.post("http://localhost:9999/music/search",{s:"阿刁"})
.then(function(res){
console.log(res);
});
12.3.3
⾃定义请求
⾃定义请求:⾃定义请求⽅式、请求参数、请求头、请求体(
post
)
axios({
url:"http://localhost:9999/music/search",
method:"post",
params:{
//设置请求⾏传值
s:"成都",
limit:15
},
headers:{
//设置请求头
},
data:{
//设置请求体(post/put)
}
}).then(function(res){
console.log(res)
})
12.3.4
其他
delete
put
option
12.4
并发请求
<div id="container">
<button type="button" @click="test1">测试1</button>
</div> <script type="text/javascript">
var vm = new Vue({
el:"#container",
methods:{
test1:function(){
//发送异步请求
axios.all([listMusics(),getMusicDetail()]).then(axios.spread(function
(r1, r2) {
// 两个请求现在都执⾏完成
console.log(r1);
console.log(r2);
}));
}
}
});
function listMusics() {
return axios.get('http://localhost:9999/music/search?s=成都');
}
function getMusicDetail() {
return axios.get('http://localhost:9999/music/detail?
id=25640392');
}
</script>
12.5 箭头函数
12.5.1 axios
回调函数的参数
res
res
并不是接⼝返回的数据,⽽是表示⼀个响应对象;
res.data
才表示接⼝响应的数据
12.5.2
箭头函数
<script type="text/javascript">
var vm = new Vue({
el:"#container",
data:{
song:{
}
},
methods:{
test1:function(){
//发送异步请求
axios.get("http://localhost:9999/music/detail?
id=25640392").then( (res)=>{
// res并不是接⼝返回的数据,⽽是表示⼀个响应对象;res.data
才表示接⼝响应的数据
if(res.data.code == 200){
this.song = res.data.songs[0];
}
});
}
}
});
</script>
⼗三、路由
router
router
是由
vue
官⽅提供的⽤于实现组件跳转的插件
13.1 路由插件的引⽤
13.3.1
离线
<script type="text/javascript" src="js/vue.js" ></script> <script type="text/javascript" src="js/vue-router.js"></script>
13.3.2
在线
CDN
<script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
13.2
路由使⽤案例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
body{padding: 0px;margin: 0px;}
ul{list-style: none;}
ul li{display: inline; float: left; margin-left: 15px; marginbottom: 15px;}
ul li a{text-decoration: none; color: white; font-size: 18px;
font-weight: bold;}
ul li a:hover{color: yellow;}
</style>
<script type="text/javascript" src="js/vue.js" ></script>
<script type="text/javascript" src="js/vue-router.js"></script>
</head>
<body>
<div id="container">
<div style="width: 100%; height: 70px; background: #00BFFF;">
<table>
<tr>
<td><img src="img/logo.png" height="70" style="marginleft:100px;"/></td>
<td>
<ul>
<li><router-link to="/a">⾸⻚</router-link></li>
<li><router-link to="/b">Java</router-link></li>
<li><router-link to="/c">HTML5</router-link></li>
<li><router-link to="/d">Python</router-link></li>
</ul>
</td>
</tr>
</table>
</div>
<div style="width: 100%; height: 680px; background:
lemonchiffon;">
<router-view></router-view>
</div>
</div>
<script type="text/javascript">
// vue的路由旨在为单⻚⾯应⽤开发提供便捷
//1.定义链接跳转的模板(组件)
const t1 = {template:`<p>index</p>`};
const t2 = {template:`<p>Java</p>`};
const t3 = {template:`<p>HTML5</p>`};
const t4 = {template:`<p>PYTHON</p>`};
const myrouter = new VueRouter({
routes:[
{path:"/a",component:t1},
{path:"/b",component:t2},
{path:"/c",component:t3},
{path:"/d",component:t4}
]
});
var vm = new Vue({
el:"#container",
router:myrouter
});
</script>
</body>
</html>
13.3 动态路由匹配
13.3.1
通配符
*
可以匹配任意路径
例如:
/user-*
匹配所有以
user-
开头的任意路径
/*
匹配所有路径
const myrouter = new VueRouter({
routes:[
{path:"/user-*",component:...},
{path:"/*",component:...}
]
});
注意
如果使⽤通配符定义路径,需要注意路由声明的顺序
13.3.2
路由参数
/a/:id
可以匹配
/a/
开头的路径
<div id="container">
<li><router-link to="/a/101">⾸⻚</router-link></li>
<router-view></router-view>
</div>
<script type="text/javascript">
const t1 = {template:`<p>index:{{$route.params.id}}</p>`};
const myrouter = new VueRouter({
routes:[
{path:"/a/:id",component:t1}
]
});
var vm = new Vue({
el:"#container",
router:myrouter
});
</script>
13.3.3 优先级
如果⼀个路径匹配了多个路由,则按照路由的配置顺序:路由定义的越早优先级就越⾼。
13.4
嵌套路由
在⼀级路由的组件中显示⼆级路由
<div id="container">
<router-link to="/a">⾸⻚</router-link>
<router-link to="/a/c1">⾸⻚-c1</router-link>
<router-link to="/a/c2">⾸⻚-c2</router-link>
<router-view></router-view>
</div>
<script type="text/javascript">
const t1 = {
template:"<div style='width:400px; height:200px; border:blue
1px solid'>index<hr/><router-view></router-view></div>"
};
const t2 = {template:`<div>t2</div>`};
const t3 = {template:`<div>t3</div>`};
const myrouter = new VueRouter({
routes:[
{
path:"/a",
component:t1,
children:[
{
path:"c1",
component:t2
},
{
path:"c2",
component:t3
}
]
}
]
});
var vm = new Vue({
el:"#container",
router:myrouter
});
</script>
13.5 编程式导航
13.5.1 push()
<div id="container">
<button type="button" @click="test">按钮</button>
<router-view></router-view>
</div> <script type="text/javascript">
const t1 = {
template:"<div style='width:400px; height:200px; border:blue
1px solid'>index</div>"
};
const myrouter = new VueRouter({
routes:[
{
path:"/a",
component:t1
}
]
});
var vm = new Vue({
el:"#container",
router:myrouter,
methods:{
test:function(){
//js代码实现路由跳转:编程式导航
myrouter.push("/a");
}
}
});
</script>
13.5.2 push()参数
//1.字符串
myrouter.push("/a");
//2.对象
myrouter.push({path:"/a"});
//3.命名的路由 name参数指的是定义路由时指定的名字
myrouter.push({name:"r1",params:{id:101}});
//4.URL传值,相当于/a?id=101
myrouter.push({path:"/a",query:{id:101}});
13.5.3 replace()
功能与
push
⼀致,区别在于
replace()
不会向
history
添加新的浏览记录
13.5.4 go()
参数为⼀个整数,表示在浏览器历史记录中前后
/
后退多少步
相当于
window.history.go(-1)
的作⽤
13.6
命名路由
命名路由:在定义路由的时候可以给路由指定
name
,我们在进⾏路由导航时可以通过路
由的名字导航
<div id="container">
<input type="text" v-model="rname"/>
<router-link :to="{name:rname}">t1</router-link>
<button type="button" @click="test">按钮1</button>
<router-view></router-view>
</div> <script type="text/javascript">
const t1 = {
template:"<div style='width:400px; height:200px; border:blue
1px solid'>t1</div>"
};
const t2 = {
template:"<div style='width:400px; height:200px; border:red 1px
solid'>t2</div>"
};
const myrouter = new VueRouter({
routes:[
{
path:"/a",
name:"r1",
component:t1
},
{
path:"/b",
name:"r2",
component:t2
}
]
});
var vm = new Vue({
el:"#container",
data:{
rname:"r1"
},
router:myrouter,
methods:{
test:function(){
myrouter.push({name:vm.rname});
}
}
});
</script>
13.7 命名路由视图
<div id="container">
<router-link to="/a">t1</router-link>
<router-link to="/b">t2</router-link>
<!--路由视图-->
<!--如果在HTML中有⼀个以上的路由视图router-view,需要给router-view指定
name,在路由中使⽤components映射多个组件根据name设置组件与router-view绑定关系-->
<router-view name="v1"></router-view>
<router-view name="v2"></router-view>
</div> <script type="text/javascript">
const t11 = {
template:"<div style='width:400px; height:200px; border:blue
1px solid'>t11</div>"
};
const t12 = {
template:"<div style='width:400px; height:200px;
background:pink'>t12</div>"
};
const t21 = {
template:"<div style='width:400px; height:200px; border:red 1px
solid'>t21</div>"
};
const t22 = {
template:"<div style='width:400px; height:200px;
background:yellow'>t22</div>"
};
const myrouter = new VueRouter({
routes:[
{
path:"/a",
components:{
v1:t11,
v2:t12
}
},
{
path:"/b",
components:{
v1:t21,
v2:t22
}
}
]
});
var vm = new Vue({
el:"#container",
router:myrouter
});
</script>
13.8 重定向和别名
13.8.1
重定向
访问
/b
,重定向到
/a
<div id="container">
<router-link to="/a">路径A</router-link>
<router-link to="/b">路径B</router-link>
<router-view></router-view>
</div> <script type="text/javascript">
const t1 = {
template:"<div style='width:400px; height:200px; border:blue
1px solid'>index</div>"
};
const myrouter = new VueRouter({
routes:[
{
path:"/a",
component:t1
},
{
path:"/b",
redirect:"/a"
}
]
});
var vm = new Vue({
el:"#container",
router:myrouter
});
</script>
根据路由命名重定向
const myrouter = new VueRouter({
routes:[
{
path:"/a",
name:"r1",
component:t1
},
{
path:"/b",
//redirect:"/a" //根据路由路径重定向
redirect:{name:"r1"} //根据路由命名重定向
}
]
});
13.8.2
路由别名
<div id="container">
<router-link to="/a">路径A</router-link>
<router-link to="/wahaha">路径wahaha(别名)</router-link>
<router-view></router-view>
</div> <script type="text/javascript">
const t1 = {
template:"<div style='width:400px; height:200px; border:blue
1px solid'>index</div>"
};
const myrouter = new VueRouter({
routes:[
{
path:"/a",
alias:"/wahaha",
component:t1
}
]
});
var vm = new Vue({
el:"#container",
router:myrouter
});
</script>
13.9 路由组件传参
可以通过
/url/:attr
⽅式实现通过路由传值给组件
<div id="container">
<router-link to="/a/101">路径A</router-link> <router-view></router-view>
</div> <script type="text/javascript">
const t1 = {
template:`<div style='width:400px; height:200px; border:blue
1px solid'>
index:{{$route.params.id}}
</div>`
};
const myrouter = new VueRouter({
routes:[
{
path:"/a/:id",
component:t1
}
]
});
var vm = new Vue({
el:"#container",
router:myrouter
});
</script>
通过
props
传参
<div id="container">
<router-link to="/a/102">路径A</router-link>
<router-view></router-view>
</div> <script type="text/javascript">
const t1 = {
props:["id"],
template:`<div style='width:400px; height:200px; border:blue
1px solid'>
index:{{id}}
</div>`
};
const myrouter = new VueRouter({
routes:[
{
path:"/a/:id",
props:true,
component:t1
}
]
});
var vm = new Vue({
el:"#container",
router:myrouter
});
</script>