黑马 Vue 快速入门 笔记
- 0 VUE相关了解
- 0.1 概述
- 0.2 MVVM
- 0.3 JavaScript框架
- 0.4 七大属性
- 0.5 el:挂载点
- 1 VUE基础
- 1.0 第一个vue代码:Hello,vue
- 1.1 v-bind 设置元素的属性 简写 :
- 1.2 v-if , v-else , v-else-if
- v-if , v-else
- v-else-if
- v-for结合v-if
- 1.3 v-for 根据数据生成列表结构
- 1.4 v-on 监听事件 简写@
- 1.5 v-text 标签文本值
- 1.6 v-html
- 1.7 v-show 元素的显示与隐藏
- 1.8 v-model 获取&设置 表单元素的数值,双向绑定
- 案例:计数器
- 案例:图片切换
- 案例:小黑记事本
- 知识点:绑定class属性
- 2 表单双向绑定,组件
- 2.1 什么是双向数据绑定
- 2.2 在表单中使用双向数据绑定
- 单行文本
- 多行文本
- 单复选框
- 多复选框
- 单选按钮
- 下拉框
- 知识点 v-bind 和 v-model 区分
- 3 Axios
- 介绍
- 3.1 第一个Axios应用程序
- 案例: axios + vue
- 案例:网络应用[天知道]
- 黑马代码(接口已报废)
- 我的代码(接口可用)
- 案例:音乐播放器
0 VUE相关了解
0.1 概述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eoZjRpqU-1677055291257)(…/…/images/image-20220716152842582.png)]
-
只关心视图层,自底向上.遵守SOC关注点分离原则(术有专攻,只关注一点)
-
HTML + CSS + JS : 视图 :
给用户看,刷新后台给的数据
-
MVVM,是Model-View-ViewModel的简写,是M-V-VM三部分组成。它本质上就是MVC 的改进版。采用双向数据绑定,MVVM 就是将其中的View 的状态和行为抽象化,其中ViewModel将视图 UI 和业务逻辑分开,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。
0.2 MVVM
MVVM是什么?
MVVM(Model-View-ViewModel)是一种软件设计模式,由微软WPF(用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight(类似于Java Applet,简单点说就是在浏览器上运行WPF)的架构师Ken Cooper和Ted Peters开发,是一种简化用户界面的事件驱动编程方式。由John Gossman(同样也是WPF和Sliverlight的架构师)与2005年在他的博客上发表。
MVVM源自于经典的MVC(Model-View-Controller)模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用。其作用如下:
- 该层向上与视图层进行双向数据绑定
- 向下与Model层通过接口请求进行数据交互
MVVM已经相当成熟了,主要运用但不仅仅在网络应用程序开发中。当下流行的MVVM框架有Vue.js
,Anfular JS
-
Model 层: 对应数据层的域模型,它主要做域模型的同步。通过 Ajax/fetch 等 API 完成客户端和服务端业务 Model 的同 步。在层间关系⾥,它主要⽤于抽象出 ViewModel 中视图的 Model 。
-
View 层: 作为视图模板存在,在 MVVM ⾥,整个 View 是⼀个动态模板。除了定义结构、布局外,它展示的是 ViewModel 层的数据和状态。 View 层不负责处理状态, View 层做的是 数据绑定的声明、 指令的声明、 事件绑定的声明。
-
ViewModel 层: 把 View 需要的层数据暴露,并对 View 层的 数据绑定声明、 指令声明、 事件绑定声明 负责,也就是处理 View 层的具体业务逻辑。 ViewModel 底层会做好绑定属性的监听。当 ViewModel 中数据变化, View 层会得到更 新;⽽当 View 中声明了数据的双向绑定(通常是表单元素),框架也会监听 View 层(表单)值的变化。⼀旦值变 化,View 层绑定的 ViewModel 中的数据也会得到⾃动更新。
MVVM 的优缺点 ?
优点:
- 分离视图(View)和模型( Model ) , 降低代码耦合,提⾼视图或者逻辑的重⽤性 : ⽐如视图(View)可以独⽴于 Model变化和修改,⼀个 ViewModel 可以绑定不同的 “View” 上,当 View 变化的时候 Model 不可以不变,当 Model 变化 的时候View 也可以不变。你可以把⼀些视图逻辑放在⼀个 ViewModel ⾥⾯,让很多 view 重⽤这段视图逻辑。
- 提⾼可测试性 : ViewModel 的存在可以帮助开发者更好地编写测试代码。
- ⾃动更新 dom: 利⽤双向绑定 , 数据更新后视图⾃动更新 , 让开发者从繁琐的⼿动 dom 中解放。
缺点:
- Bug 很难被调试 : 因为使⽤双向绑定的模式,当你看到界⾯异常了,有可能是你 View 的代码有 Bug ,也可能是 Model 的代码有问题。数据绑定使得⼀个位置的Bug 被快速传递到别的位置,要定位原始出问题的地⽅就变得不那么容易 了。另外,数据绑定的声明是指令式地写在View 的模版当中的,这些内容是没办法去打断点 debug 的。
- ⼀个⼤的模块中 model 也会很⼤,虽然使⽤⽅便了也很容易保证了数据的⼀致性,当时⻓期持有,不释放内存就造 成了花费更多的内存。
- 对于⼤型的图形应⽤程序,视图状态较多, ViewModel 的构建和维护的成本都会⽐较⾼。
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处
- 低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
- 可复用:你可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。
- 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewMode),设计人员可以专注于页面设计。
- 可测试:界面素来是比较难以测试的,而现在测试可以针对ViewModel来写。
(1)View
View是视图层, 也就是用户界面。前端主要由HTH L和csS来构建, 为了更方便地展现vi eu to del或者Hodel层的数据, 已经产生了各种各样的前后端模板语言, 比如FreeMarker,Thyme leaf等等, 各大MV VM框架如Vue.js.Angular JS, EJS等也都有自己用来构建用户界面的内置模板语言。
(2)Model
Model是指数据模型, 泛指后端进行的各种业务逻辑处理和数据操控, 主要围绕数据库系统展开。这里的难点主要在于需要和前端约定统一的接口规则
(3)ViewModel
ViewModel是由前端开发人员组织生成和维护的视图数据层。在这一层, 前端开发者对从后端获取的Model数据进行转换处理, 做二次封装, 以生成符合View层使用预期的视图数据模型。
需要注意的是View Model所封装出来的数据模型包括视图的状态和行为两部分, 而Model层的数据模型是只包含状态的
0.3 JavaScript框架
- JQuery:大家熟知的JavaScript库,优点就是简化了DOM操作,缺点就是DOM操作太频繁,影响前端性能;在前端眼里使用它仅仅是为了兼容IE6,7,8;
- Angular:Google收购的前端框架,由一群Java程序员开发,其特点是将后台的MVC模式搬到了前端并增加了模块化开发的理念,与微软合作,采用了TypeScript语法开发;对后台程序员友好,对前端程序员不太友好;最大的缺点是版本迭代不合理(如1代–>2 代,除了名字,基本就是两个东西;截止发表博客时已推出了Angular6)
- React:Facebook 出品,一款高性能的JS前端框架;特点是提出了新概念 【虚拟DOM】用于减少真实 DOM 操作,在内存中模拟 DOM操作,有效的提升了前端渲染效率;缺点是使用复杂,因为需要额外学习一门【JSX】语言;
- Vue:一款渐进式 JavaScript 框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了 Angular(模块化)和React(虚拟 DOM) 的优点;
- Axios:前端通信框架;因为 Vue 的边界很明确,就是为了处理 DOM,所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互;当然也可以直接选择使用jQuery 提供的AJAX 通信功能;
0.4 七大属性
- el属性
- 用来指示Vue编译器从什么地方开始解析Vue的语法,可以说是一个占位符。
- data属性
- 用来组织从view中抽象出来的属性,可以说将视图的数据抽象出来存放在data中。
- methods属性
- 放置页面中的业务逻辑,js方法一般都放置在methods中
- template属性
- 用来设置模板,会替换页面元素,包括占位符。
- render属性
- 创建真正的virtual Dom 用js来渲染组件
- computed属性
- 用来计算
- watch属性
- watch:funtion(new,old){}
- 监听data中的数据的变化
- 两个参数,一个返回新值,一个返回旧值
0.5 el:挂载点
- el挂载点的范围:命中元素及其子元素
- 可以id选择器"#“,可以类选择器”."
- 只能使用于双标签之上,不可以用于body,html标签。
1 VUE基础
1.0 第一个vue代码:Hello,vue
使用方法
1. 导入Vue.js 依赖
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
2. new 一个Vue对象
3. 绑定一个元素, id对应# class对应..........
4. data属性存放数据
5. 从模板里取出数据
第一个代码实例(菜鸟教育):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<!--引入VUE-->
<script src="https://cdn.staticfile.org/vue/2.7.0/vue.min.js"></script>
</head>
<body>
<div id="app"> // 绑定元素,
<p>{{ message }}</p>
</div>
<script>
new Vue({
el: '#app', // 这里对应上面绑定的元素
data: { // 里面存放数据
message: 'Hello Vue.js!'
}
})
</script>
</body>
</html>
第一个代码实例(狂神)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层,模板-->
<div id="app">
{{message}}
{{message1}}
</div>
<!-- 1. 导入Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<!-- 2. 创建VUE实例 -->
<script type="text/javascript">
var vm = new Vue({
// 绑定元素的ID,el=Element
el: "#app",
/*Model:数据*/
data: {
message: "hello,vue!",
message1:"123"
}
});
</script>
</body>
</html>
- 获取元素时候在控制台vm.message=123即可。因为data是个方法,取值赋值时候不需要
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3oSo9thg-1677055291259)(…/…/images/image-20220721161623011.png)]
- 只需要在绑定的元素中使用双花括号将Vue创建的名为message属性包裹起来, 即可实现数据绑定功能, 也就实现了View Model层所需的效果, 是不是和EL表达式非常像?
1.1 v-bind 设置元素的属性 简写 :
你看到的v-bind等被称为指令。指令带有前缀v以表示它们是Vue提供的特殊特性。
该指令的意思是:“将这个元素节点的title特性和Vue实例的message属性保持一致”。
如果你再次打开浏览器的JavaScript控制台, 输入app.message=‘新消息’,就会再一次看到这个绑定了title特性的HTML已经进行了更新。
简写:符号
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
.class1 {
border: 3px solid red;
width: 10%;
height:10%
}
</style>
<body>
<!--view层,模板-->
<div id="app">
<!--vue绑定-->
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
<br />
<span title="1111111111">
测试span标签,效果是悬停时候会提示title属性的内容55q
</span>
<br />
<span :title="message+'------'">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
<br /> <br /> <br />
<p>v-bind img</p>
<img :src="imgUrl" width="10%" height="10%">
<p>class 属性修改 img {{num}}</p>
使用两种方法修改class属性
1. 直接三元运算符
2. 使用兑现方式实现
<img :src="imgUrl" alt="" @click="fun1" :class="num?'class1':'' " width="10%" height="10%">
<img :src="imgUrl" alt="" @click="fun1" :class="{class1:num}" width="10%" height="10%">
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.staticfile.org/vue/2.7.0/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
/*Model:数据*/
data: {
message: '页面加载于 ' + new Date().toLocaleString(),
imgUrl: './1.jpg',
num: false
},
methods: {
fun1: function () {
this.num = !this.num;
}
}
});
</script>
</body>
</html>
1.2 v-if , v-else , v-else-if
v-if , v-else
根据表达式真假切换元素显示状态
本质是操作dom元素
true使得元素存在于元素树,反之从dom树中移除
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层,模板,开始数据绑定,v-if标签绑定data1-->
<div id="div1">
<button @click="fun1">点击按钮切换judge属性</button>
<h1 v-if="judge">Yes</h1>
<h1 v-else>No</h1>
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.staticfile.org/vue/2.7.0/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#div1",
/*Model:数据*/
data: {
judge: true
},
methods: {
fun1:function(){
this.judge=!this.judge;
}
},
});
</script>
</body>
</html>
v-else-if
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层,模板-->
<div id="app">
<h2 v-if="type==='A'">AAA</h2>
<h2 v-else-if="type==='B'">BBB</h2>
<h2 v-else-if="type==='C'">CCC</h2>
<h2 v-else>DDD</h2>
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
/*Model:数据*/
data: {
//这里的type代表通用的意思,不是DOM的ID绑定
type: 'A'
}
});
</script>
</body>
</html>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aGreIkED-1677055291260)(…/…/images/image-20220721164028775.png)]
v-for结合v-if
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层,模板-->
<div id="app">
<li v-for="(item,index) in items">
{{item.message}}---{{index}}
<h5 v-if="index==0">11111</h5>
<h5 v-else-if="item.message==='狂神说运维'">这是第三项内容</h5>
<h5 v-else>这啥也不是</h5>
</li>
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
/*Model:数据*/
data: {
items: [
{message: '狂神说Java'},
{message: '狂神说前端'},
{message: '狂神说运维'}
]
}
});
</script>
</body>
</html>
1.3 v-for 根据数据生成列表结构
格式:
<div id="app">
<!--从index里面便利(item,index)-->
<li v-for="(item,index) in items">
{{item.message}}---{{index}}
</li>
</div>
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层,模板-->
<div id="app">
<li v-for="(item,index) in items">
{{item.message}}---{{index}}
index是角标,从0开始,item才是每一项内容
</li>
----------------------
<p @click="fun1">添加</p>
<p @click="fun2">移除</p>
<li v-for="obj in arr">
某一项{{obj}} - 全部{{arr}}
</li>
-----------------------
<li v-for="obj1 in list">
{{obj1}} - {{obj1.name}} - {{obj1.age}}
</li>
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
/*Model:数据*/
data: {
items: [{
message: '狂神说Java'
},
{
message: '狂神说前端'
},
{
message: '狂神说运维'
}
],
arr: ["java", "linux", "sql", "vue"],
list: [{
name: "name1",
age: "age1"
}, {
name: "name2",
age: "age2"
}]
},
methods:{
//添加方法
fun1:function(){
this.arr.push("111");
this.arr.push("222");
},
//移除方法
fun2:function(){
this.arr.shift(this.arr[0]);
}
}
});
</script>
</body>
</html>
测试:在控制台输入
vm.items.push({message:'狂神说运维'})
,尝试追加一条数据,你会发现浏览器中显示的内容会增加一条狂神说运维
.
1.4 v-on 监听事件 简写@
v-on
监听事件,事件有Vue的事件、和前端页面本身的一些事件!我们这里的click
是vue的事件,可以绑定到Vue中的methods
中的方法事件!
点击事件: v-on:click="方法名"
右键事件: v-on:monseenter="方法名"
双击事件: v-on:dblclick="方法名"
@dblclick="方法名"
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button v-on:click="sayHi">点我</button>
</div>
-------------------
<div id="name1">
<button v-on:dblclick="fun1">点我1</button>
<button @dblclick="fun1">点我2</button>
<button @click="fun2">改变msg1</button>
<p>{{msg1}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
message: 'Hello World'
},
//所有vue方法必须放在methods里面
methods: {
//方法名是sayHi,参数event不添加也可以。
sayHi: function (event) {
//'this'在方法里面指向当前Vue实例
alert(this.message);
}
}
});
var vm1=new Vue({
el: "#name1",
data: {
msg1: "this is msg1"
},
methods: {
fun1: function(event){
alert("this.msg1");
},
fun2: function(){
this.msg1="我不是黄蓉"
}
}
})
</script>
</body>
</html>
事件绑定方法写成函数调用的方式,需要传入自定义的参数
定义方法想要接受参数必须传入实参
事件修饰符可以对事件进行限制,比如限制输入的按键。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层,模板-->
<div id="app">
<input type="button" value="无参数" @click="fun1">
<input type="button" value="有参数" @click="fun2(111,222)">
<br/>
<input type="text" value="对照组">
<input type="text" value="什么都会触发" @keyup="fun1">
<input type="text" value="仅回车键触发" @keyup.enter="fun1">
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
/*Model:数据*/
data: {
},
methods:{
fun1:function(){
console.log("方法已触发");
},
//定义形式参数
fun2:function(num1,num2){
console.log(num1,num2);
},
fun3:function(num1,num2){
console.log();
},
}
});
</script>
</body>
</html>
1.5 v-text 标签文本值
- 单引号与双引号都可用
- v-text是整体替换,{{}}是局部替换
- 标签优先级比局部替换{{}}要高,以标签优先。
- 里面可以用表达式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<!--引入VUE-->
<script src="https://cdn.staticfile.org/vue/2.7.0/vue.js"></script>
</head>
<body>
<!-- 绑定元素 -->
<div id="name1">
<p v-text="msg1"></p>
<p v-text="msg1 + '1' "></p>
--------------------
<p>{{ msg1 }}</p>
--------------------
<p>{{ msg1 + '1' }}</p>
--------------------
<p>{{ msg1 + "1" }}</p>
</div>
<script>
var app = new Vue({
el: '#name1', // 这里对应上面绑定的元素
data: { // 里面存放数据+
msg1: ' 111 '
}
})
</script>
</body>
</html>
1.6 v-html
v-text标签只会解析成文本
v-html会被解析为标签
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<!--引入VUE-->
<script src="https://cdn.staticfile.org/vue/2.7.0/vue.js"></script>
</head>
<body>
<!-- 绑定元素 -->
<div id="name1">
<p v-text="msg2"></p>
<p v-html="msg2"></p>
</div>
<script>
var app = new Vue({
el: '#name1', // 这里对应上面绑定的元素
data: { // 里面存放数据+
msg1: ' 111 ',
msg2: '<a href="https://www.baidu.com" >百度</a>'
}
})
</script>
</body>
</html>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wLG8pYBE-1677055291261)(…/…/images/image-20230215155418190.png)]
1.7 v-show 元素的显示与隐藏
根据指令内容,修改display属性来实现效果
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="div1">
<button @click="fun1"> 切换文字效果1 </button>
<button @click="fun2"> 切换文字效果2 </button>
<button @click="fun3"> 点击按钮更换v-show条件 </button>
<p v-show="judge">{{str1}}</p>
<p v-show="num%2==1">{{str1}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script type="text/javascript">
var vue = new Vue({
el: "#div1",
data: {
judge: true,
str1: "我是文字",
num: 1
},
methods: {
fun1: function () {
this.judge = !this.judge;
},
fun2: function () {
if (this.str1 == '我是文字') {
this.str1 = '我不是';
} else {
this.str1 = '我是文字';
}
},
fun3: function () {
this.num++;
}
}
})
</script>
</body>
</html>
1.8 v-model 获取&设置 表单元素的数值,双向绑定
双向绑定,页面改变数据也会改变。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层,模板-->
<div id="app">
<input type="text" v-model="msg1"> msg1的数值: {{msg1}}
<p @click="fun1">点我可修改msg1的数值</p>
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
/*Model:数据*/
data: {
msg1:0,
},
methods:{
fun1:function(){
this.msg1="我是皮卡丘"
}
}
});
</script>
</body>
</html>
案例:计数器
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="div1">
<button @click="fun1"> + </button>
<p>{{num}}</p>
<button @click="fun2"> - </button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script type="text/javascript">
var vue = new Vue({
el: "#div1",
data: {
num: 0
},
methods: {
fun1: function () {
if(this.num<10)
this.num++;
},
fun2: function () {
if(this.num>0)
this.num--;
}
}
})
</script>
</body>
</html>
案例:图片切换
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
.class1 {
border: 3px solid red;
width: 20px;
height: 20px;
}
</style>
<body>
<!--view层,模板-->
<div id="app">
<p>{{index}}</p>
<p @click="fun1" v-show="index!=0">上一张</p>
<img :src="imgArr[index]" :class=" 'class1' ">
或者 <img :src="imgArr[index]" :class="{class1:true}">
<p @click="fun2" v-show="index!=2">下一张</p>
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.staticfile.org/vue/2.7.0/vue.js"></script>
<script type="text/javascript">
var myVue = new Vue({
el: "#app",
data: {
//定义图片数组
imgArr: ["1.jpg", "2.jpg", "3.jpg"],
//数组角标
index: 0
},
methods: {
fun1: function () {
if (this.index > 0) {
this.index--;
}
},
fun2: function () {
if (this.index < 2) {
this.index++;
}
}
}
})
</script>
</body>
</html>
案例:小黑记事本
v-for 实现数据展示
input type=’text‘ 实现输入
v-model 实现数据双向绑定
arr数组用来存储数据
v-show / v-if实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
.class1{
border: red solid 6px ;
width: 500px;
}
</style>
<body>
<!--view层,模板-->
<div id="app">
<h3>小黑记事本</h3>
<br/>
<div class="class1">
<input type="text" v-model="msg" width="490px" background="blue" @keyup.enter="fun1">
<li v-for="(item,index) in arr" >
{{index}} || {{item}} || <img src="./1.jpg" width="60px" height="60px" v-on:click="fun2(index)">
</li>
<br/>
数据总数:{{arr.length}}
<br/>
<input type="button" value="删除全部点我" @click="fun3">
<p v-show="arr.length!=0">当没有数据时候,此行文字会隐藏</p>
<p v-if="arr.length!=0">当没有数据时候,此行文字会隐藏</p>
</div>
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
//记事本数据
data: {
arr:["7:00早起"],
msg:""
},
methods:{
//添加方法
fun1:function(){
this.arr.push(this.msg);
console.log("已添加msg");
},
//删除方法
fun2:function(index){
console.log("要删除的是:"+index)
this.arr.splice(index,1);
},
//全部删除方法
fun3:function(){
console.log("要删除的是:"+this.deleteName)
this.arr=[];
}
}
});
</script>
</body>
</html>
知识点:绑定class属性
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<style>
.class1 {
border: 3px solid red;
width: 20px;
height: 20px;
}
</style>
<body>
<!--view层,模板-->
<div id="app">
1. :class标签内容 clas1需要单引号包起来
<img :src="imgArr[index]" :class=" 'class1' ">
2. 使用对象方式
<img :src="imgArr[index]" :class="{class1:true}">
3. 使用三元运算符
<img :src="imgArr[index]" class="布尔值?'class1':'class2' ">
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.staticfile.org/vue/2.7.0/vue.js"></script>
<script type="text/javascript">
var myVue = new Vue({
el: "#app"
}
})
</script>
</body>
</html>
2 表单双向绑定,组件
2.1 什么是双向数据绑定
Vue.js是一个MVVM框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是Vue.js的精髓之处了。
值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突。
(1)为什么要实现数据的双向绑定
在Vue.js
中,如果使用vuex
, 实际上数据还是单向的, 之所以说是数据双向绑定,这是用的UI控件来说, 对于我们处理表单, Vue.js
的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。
2.2 在表单中使用双向数据绑定
你可以用v-model 指令在表单<input>
,<textarea>
及<select>
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇, 但v-model
本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
注意:v-model
会忽略所有表单元素的value
、checked
、selected
特性的初始值而总是将Vue
实例的数据作为数据来源。你应该通过JavaScript
在组件的data
选项中声明初始值!
单行文本
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
输入的文本:<input type="text" v-model="message" value="hello">{{message}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
message: ""
}
});
</script>
</body>
</html>
多行文本
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
输入的文本:<input type="text" v-model="message1" value="hello">{{message1}}
<br/>
多行文本:<textarea v-model="message2"></textarea>多行文本是:{{message2}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
message1: "1",
message2: "2"
}
});
</script>
</body>
</html>
单复选框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
单复选框:
<input type="checkbox" id="checkbox" v-model="checked">
<br />
<label for="checkbox">{{checked}}</label>
<!--
<label> 标签为 input 元素定义标签(label)。
label 元素不会向用户呈现任何特殊的样式。不过,它为鼠标用户改善了可用性,因为如果用户点击 label 元素内的文本,则会切换到控件本身。
<label> 标签的 for 属性应该等于相关元素的 id 元素,以便将它们捆绑起来。
-->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
checked: false
}
});
</script>
</body>
</html>
多复选框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
多复选框:
<br>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<br>
<input type="checkbox" id="join" value="Join" v-model="checkedNames">
<label for="join">Join</label>
<br>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>选中的值:{{checkedNames}}</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
checkedNames: []
}
});
</script>
</body>
</html>
单选按钮
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
单选框:
<br>
<input type="radio" name="sex" value="男" v-model="data1" >男
<br/>
<input type="radio" name="sex" value="女" v-model="data1" >女
<br/>
<p>打印选中的数据:{{data1}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
data1: ''
}
});
</script>
</body>
</html>
下拉框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
下拉框:
<select v-model="pan">
<option value="" disabled>---请选择---</option>
<option disabled value="">A</option>
<option value="bbbbb">B</option>
<option>C</option>
<option>D</option>
</select>
<span>value:{{pan}}</span>
## disabled表示禁用字段
## 当option属性有value值的时候,vue获取到的数值是对应选项的value值
## 没有value值的时候才会是默认的变迁内部的数据
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
pan:"A"
}
});
</script>
</body>
</html>
注意:v-model
表达式的初始值未能匹配任何选项,元系将被渲染为“未选中”状态。 在iOS中, 这会使用户无法选择第一个选项,因为这样的情况下,iOS不会触发change
事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
知识点 v-bind 和 v-model 区分
(1)v-bind是单项数据绑定,映射关系是Model->View,我们通过Model操作就可以实现视图的联动更新。
- 格式:v-bind:(props)=“(message)”
- props就是组件component的元素
- message就是vm中Data对象的数据
- 绑定一个属性
<img v-bind:src="imagesrc"/>
(2)v-model是双向数据绑定,映射关系是 View接受的数据,传给model,model的数据再传给view ,用于表单控件
3 Axios
介绍
Axios是一个开源的可以用在浏览器端和Node.js
的异步通信框架
, 她的主要作用就是实现AJAX异步通信
,其功能特点如下:
- 从浏览器中创建
XMLHttpRequests
- 从node.js创建http请求
- 支持Promise API[JS中链式编程]
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防御XSRF(跨站请求伪造)
GitHub:https://github.com/axios/axios
中文文档:http://www.axios-js.com/~~~
由于Vue.js
是一个视图层框架并且作者(尤雨溪) 严格准守SoC(关注度分离原则)所以Vue.js
并不包含AJAX的通信功能, 为了解决通信问题, 作者单独开发了一个名为vue-resource
的插件, 不过在进入2.0版本以后停止了对该插件的维护并推荐了Axios
框架。少用jQuery, 因为它操作Dom太频繁!
3.1 第一个Axios应用程序
导入:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
-------------------------------
get请求:
axios.get(地址?key1=value&key2=values).then(function(response){},function(err){})
post请求:
axios.post(地址,{key:value,key2:value2}).then(function(response){},function(err){})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>25-网络应用- axios基本使用</title>
</head>
<body>
<input type="button" value="get请求" class="get">
<input type="button" value="post请求" class="post">
<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
/*
接口1:随机笑话
请求地址:https://autumnfish.cn/api/joke/list
请求方法:get
请求参数:num(笑话条数,数字)
响应内容:随机笑话
*/
//寻找class为get的元素节点,设置点击方法
//axios的get方法参数是请求地址,then方法里面是成功与失败时候运行的方法。
document.querySelector(".get").onclick=function(){
axios.get("https://autumnfish.cn/api/joke/list?num=3")
.then(function(response){
console.log(response);
},function(err){
console.log(err);
})
}
/*
接口2:用户注册
请求地址:https://autumnfish.cn/api/user/reg
请求方法:post
请求参数:username(用户名,字符串)
响应内容:注册成功或失败
*/
document.querySelector(".post").onclick=function(){
axios.post("https://autumnfish.cn/api/user/reg",{username:"阿香"})
.then(function(response){
console.log(response);
},function(err){
console.log(err);
})
}
</script>
</body>
</html>
案例: axios + vue
axios回调函数中的this已经改变,无法访问到data中数据
把this保存起来,回调函数中直接使用保存的this即可
和本地应用的最大区别就是改变了数据来源
------------------
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>25-网络应用- axios基本使用</title>
</head>
<body>
<div id="app">
{{joke}}
<input type="button" value="get请求" id="id1" @click="fun1">
<li v-for="item in joke">
{{item}}
</li>
</div>
<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script>
var vm = new Vue({
el: "#app",
data: {
joke: "笑话是"
},
methods: {
fun1: function () {
var that=this;
axios.get("https://autumnfish.cn/api/joke/list?num=3")
.then(function (response) {
console.log(response);
console.log(response.data.data);
console.log(response.data.data[0]);
that.joke=response.data.data;
}, function (err) {
console.log(err);
})
}
}
})
</script>
</body>
</html>
案例:网络应用[天知道]
1. 按下回车(v-on .enter)
2. 查询数据(axios 接口 v-model )
3. 渲染数据(v-for 数组 that)
应用的逻辑代码建议和页面分离,使用单独的js文件编写
axios回调函数中this指向改变了,需要额外的保存一份
服务器返回的数据比较复杂时,获取的时候需要注意层级结构
黑马代码(接口已报废)
main.js
--------------------------------
//查询天气
/*
请求地址:http://wthrcdn.etouch.cn/weather_mini
请求方法:get
请求参数:city(城市名)
响应内容:天气信息
1.点击回车
2.查询数据
3.渲染数据
*/
var app = new Vue({
el: "#app",
data: {
city: '',
weatherList: []
},
methods: {
searchWeather: function () {
// console.log('天气查询');
// 调用接口
// 保存this
var that = this;
axios.get("http://wthrcdn.etouch.cn/weather_mini?city="
+ this.city)
.then(function (response) {
that.weatherList = response.data.data.forecast;
console.log(response);
})
.catch(function (err) {
});
},
changeCity: function (city) {
this.city = city;
this.searchWeather();
}
}
})
html
------------------------
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</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">
搜索
</button>
</div>
</div>
<div class="hotkey">
<a href="javascript:;" @click="changeCity('北京')">北京</a>
<a href="javascript:;" @click="changeCity('上海')">上海</a>
<a href="javascript:;" @click="changeCity('广州')">广州</a>
<a href="javascript:;" @click="changeCity('深圳')">深圳</a>
</div>
<ul class="weather_list">
<li v-for="item in weatherList">
<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>
<!-- 官网提供的 axios 在线地址 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 自己的js -->
<script src="./js/main.js"></script>
</body>
</html>
我的代码(接口可用)
http://t.weather.itboy.net/api/weather/city/城市代码
101220201
但是TMD,跨域问题我解决不了,干
案例:音乐播放器
按下回车(v-on .enter)
查询数据(axios 接口 v-model)
渲染数据(v-for 数组 that)
服务器返回的数据比较复杂时,获取的时候需要注意层级结构
通过审查元素快速定位到需要操纵的元素
---
点击播放(v-on 自定义参数)
歌曲地址获取(接口 歌曲id)
歌曲地址设置(v-bind)
---
点击播放(增加逻辑)
歌曲封面获取(接口 歌曲id)
歌曲封面设置(v-bind)
在vue中通过v-bind操纵属性
本地无法获取的数据,基本都会有对应的接口
---
按下回车(v-on .enter)
查询数据(axios 接口 v-model)
渲染数据(v-for 数组 that)
---
点击播放(增加逻辑)
歌曲评论获取(接口 歌曲id)
歌曲评论渲染(v-for)
---
监听音乐播放(v-on play)
监听音乐暂停(v-on pause)
操纵类名(v-bind 对象)
audio标签的play事件会在音频播放的时候触发
audio标签的pause事件会在音频暂停的时候触发
通过对象的方式设置类名,类名生效与否取决于后面值的真假
---
mv图标显示(v-if)
mv地址获取(接口 mvid)
遮罩层(v-show v-on)
mv地址设置(v-bind)
不同的接口需要的数据是不同的,文档的阅读需要仔细
页面结构复杂之后,通过审查元素的方式去,快速定位相关元素
响应式的数据都需要定义在data中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" conte -nt="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>悦听</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 }}</b>
<span v-if="item.mvid!=0" @click="playMV(item.mvid)"><i></i></span>
</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>
</body>
</html>
/*
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.log(response);
that.musicList = response.data.result.songs;
console.log(response.data.result.songs);
},
function(err) {}
);
},
// 歌曲播放
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?id=" + 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;
}
}
});