黑马 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=Elementel: "#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('天气查询');// 调用接口// 保存thisvar 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;},// 播放mvplayMV: 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;}}
});