不变的就是变化本身(Vue学习笔记one)
奋斗是这么个过程,当时不觉累,事后不会悔。走一段再回头,会发现一个更强的自己,宛如新生。
你好,我是梦阳辰!期待与你相遇!
文章较长,切勿心急气躁,否则将一事无成!
学习Vue前,我们需要先了解一些MVVM,因为它很重要。
虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。
文章目录
- 01.MVVM
- 02.Vue
- 03.Vue基本语法
- v-once
- v-html
- v-text
- v-pre
- v-cloak
- v-bind(绑定元素属性)
- 条件(v-if)
- v-show
- 循环(v-for)
- v-on事件(处理用户输入)
- Vue双向绑定(v-model)
- 04.组件化应用构建
- 组件模板分离的写法
- 组件可以访问vue实例的数据吗?
- 父子组件的通信
- 父传子
- 子传父
- 父子通信案例
- 父访问子
- 子访问父
- 05.计算属性
- 06.Axios异步通信
- Vue的生命周期
- 07.书籍购物车案例
- js的高阶函数
01.MVVM
1.什么是MVVM?
MVVM (Model-View-ViewModel)是一种软件架构设计模式,由微软WPF(用于替代
WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight(类似于Java Applet,简单点说就是在浏览器上运行的 WPF)的架构师Ken Cooper和Ted Peters开发,是一种简化用户界面的事件驱动编程方式。由John Gossman(同样也是WPF和Silverlight的架构师)于2005年在他的博客上发表。
MVVM源自于经典的MVC ( Model-View-Controller)模式。MVVM的核心是ViewModeA层,负责转换 Model中的数据对象来让数据变得更容易管理和使用,其作用如下:
该层向上与视图层进行双向数据绑定
向下与 Model层通过接口请求进行数据交互
MVVM已经相当成熟了,主要运用但不仅仅在网络应用程序开发中。当下流行的MVVM框架有Vue.js , Angulars等。
02.为什么要使用MVVM
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处
。
低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View 上,当View变化的时候Model可以不变,当Model变化的时候View 也可以不变。
可复用:你可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。
独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
3.MVVM的组成部分
View
View是视图层,也就是用户界面。前端主要由 HTNL和Css来构建,为了更方便地展现ViewNodel或者Model层的数据,已经产生了各种各样的前后端模板语言,比如FreeMarker.Thymeleaf等等,各大 MVVM框架如Vue.js,AngularJS,EJS等也都有自己用来构建用户界面的内置模板语言。
Model
Model是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,主要围绕数据库系统展开。这里的难点主要在于需要和前端约定统一的接口规则
ViewModel
ViewModel是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model数据进行转换处理,做二次封装,以生成符合View层使用预期的视图数据模型。
需要注意的是ViewModel所封装出来的数据模型包括视图的状态和行为两部分,而Model层的数据模型是只包含状态的。
比如页面的这一块展示什么,那一块展示什么这些都属于视图状态(展示)。
页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互)视图状态和行为都封装在了ViewModel里。这样的封装使得ViewModel可以完整地去描述View层`。由于实现了双向绑定,ViewModel的内容会实时展现在View层,这是激动人心的,因为前端开发者再也不必低效又麻烦地通过操纵DOM去更新视图。
MVVM框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护ViewModel,更新数据视图就会自动得到相应更新,真正实现事件驱动编程。
View层展现的不是Model层的数据,而是viewModel 的数据,由ViewModel负责与Model层交互,这就完全解耦了View层和Model层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。
02.Vue
Vue(读音/vju/,类似于view)是一套用于构建用户界面的渐进式框架,发布于2014年2月。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库(如: vue-router,vue-resource,vuex)或既有项目整合。
渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验。
或者如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统。
比如Core+Vue-router+Vuex,也可以满足你各种各样的需求。
Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框架。
Vue 只关注视图层, 采用自底向上增量开发的设计。
Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
1.MVVM模式的实现者
Model:模型层,在这里表示JavaScript对象
View:视图层,在这里表示 DOM(HTML操作的元素)
ViewModel:连接视图和数据的中间件,Vue.js 就是 MVVM中的ViewModel层的实现者在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个 Observer观察者
ViewModel能够观察到数据的变化,并对视图对应的内容进行更新
ViewModel能够监听到视图的变化,并能够通知数据发生改变
至此,我们就明白了,Vue.js 就是一个MVVM的实现者,他的核心就是实现了DOM监听与据绑定
Vue有很多特点和Web开发中常见的高级功能
解耦视图和数据
可复用的组件
前端路由技术
状态管理
虚拟DOM
2.为什么要使用Vue.js
轻量级,体积小是一个重要指标。Vue.js压缩后有只有20多kb (Angular压缩后56kb+,React压缩后44kb+)
移动优先。更适合移动端,比如移动端的Touch事件·易上手,学习曲线平稳,文档齐全
吸取了Angular(模块化)和React(虚拟DOM)的长处,并拥有自己独特的功能,如:计算属性
开源,社区活跃度高
3.vue初体验
Vue.js的安装
方式一:
导入在线的cdn
对于制作原型或学习,你可以这样使用最新版本:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
方式二:到官网下载文件:
https://vuejs.org/js/vue.js
方式三:NPM安装(重点)
在用 Vue 构建大型应用时推荐使用 NPM 安装[1]。NPM 能很好地和诸如 webpack 或 Browserify 模块打包器配合使用。同时 Vue 也提供配套工具来开发单文件组件。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>helloVue</title><!--1.导入vue.js--><script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
</head>
<body>
<div id="app">{{message}}
</div>
<script>var vm = new Vue({el: "#app",data: {message: "helloVue"}});
</script>
</body>
</html>
为了能够更直观的体验Vue 带来的数据绑定功能,我们需要在浏览器测试一番,操作流程如下:
1、在浏览器上运行第一个Vue应用程序,进入开发者工具
2、在控制台输入vm.message = ‘Hello World’,然后回车,你会发现浏览器中显示的内容会直接变成Hello World
此时就可以在控制台直接输入vm.message来修改值,中间是可以省略data的,在这个操作中,我并没有主动操作DOM,就让页面的内容发生了变化,这就是借助了Vue的数据绑定功能实现的;MVVM模式中要求ViewModel层就是使用观察者模式来实现数据的监听与绑定,以做到数据与视图的快速响应。
03.Vue基本语法
创建Vue实例传入的选项(options)
目前掌握这些选项:
el
√类型: string | HTMLlement
√作用∶决定之后Vue实例会管理哪一个DOM。
data:
√类型:Object | Function(组件中data必须是一个函数)
√作用:Vue实例对应的数据对象。
methods:
√类型∶{ [key: string]: Function }
√作用∶定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中使用。
Mustache语法:双括号表达式。
mustache语法中,不仅可以直接写变量,也可以写简单的表达式。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app">{{message}}{{message + name}}{{price*3}}
</div><script>const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",name:"梦阳辰",price:1000}});
</script>
</body>
</html>
v-once
不随数据的改变而改变
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app">{{message}}<h3 v-once>{{name}}</h3><!--不会随着数据的改变而改变-->
</div><script>const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",name:"梦阳辰",price:1000}});
</script>
</body>
</html>
v-html
服务器返回的是带html标签的数据,v-html将数据展示。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"><h3 v-html="url"></h3><!---->
</div><script>const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",url:'<a href="https://www.baidu.com">百度一下</a>'}});
</script>
</body>
</html>
v-text
作用和Mustache比较类似。但mustache更加灵活。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"><h3 v-html="url"></h3><h2 v-text="message"></h2>
</div><script>const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",url:'<a href="https://www.baidu.com">百度一下</a>'}});
</script>
</body>
</html>
v-pre
将标签中的内容原封不动的输出。不进行任何解析。
v-cloak
解决js代码执行慢而导致的内容闪烁问题。(后面采用虚拟dom,就不会存在这个问题)
因为是先加载标签,在运行js代码。
在vue解析之前,div中有一个属性v-cloak
在vue解析之后,div中没有一个属性v-cloak.
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script><style>[v-cloak]{display: none;}</style>
</head>
<body>
<div id="app" v-cloak><h2>{{message}}</h2>
</div><script>setTimeout(function () {const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",url:'<a href="https://www.baidu.com">百度一下</a>'}});},1000)</script>
</body>
</html>
v-bind(绑定元素属性)
注意我们不再和 HTML 直接交互了。一个 Vue 应用会将其挂载到一个 DOM 元素上 (对于这个例子是 #app) 然后对其进行完全控制。那个 HTML 是我们的入口,但其余都会发生在新创建的 Vue 实例内部。
除了文本插值,我们还可以像这样来绑定元素 attribute:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><!--view层 模板-->
<div id="app2"><span v-bind:title="message">鼠标悬停几秒钟查看此处动态绑定的提示信息!</span>
</div>
</body><!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>var vm = new Vue({el: "#app2",data: {message: "hello,vue"}})
</script>
</html>
语法糖::
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script><style>[v-cloak]{display: none;}</style>
</head>
<body>
<div id="app" v-cloak><img :src="imgUrl" alt="风景">
</div><script>setTimeout(function () {const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",imgUrl:"https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2853553659,1775735885&fm=26&gp=0.jpg"}});},1000)</script>
</body>
</html>
v-bind attribute 被称为指令。指令带有前缀 v-,以表示它们是 Vue 提供的特殊 attribute。可能你已经猜到了,它们会在渲染的 DOM 上应用特殊的响应式行为。在这里,该指令的意思是:“将这个元素节点的 title attribute 和 Vue 实例的 message property 保持一致”。
如果你再次打开浏览器的 JavaScript 控制台,输入 app2.message = ‘新消息’,就会再一次看到这个绑定了 title attribute 的 HTML 已经进行了更新。
绑定classs
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script><style>.first{color: lawngreen;}</style>
</head>
<body>
<div id="app"><h3 :class="active">{{message}}</h3>
</div><script>const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",active:'first'}});</script>
</body>
</html>
案例二(对象语法)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script><style>.active{color: lawngreen;}</style>
</head>
<body>
<div id="app"><!--<h3 :class="active">{{message}}</h3>--><h3 :class="{active:isActive,line:isLine}">{{message}}</h3><!--对象--><h3 :class="getClasses()">{{message}}</h3><!--对象--><button v-on:click="btn">改变颜色</button>
</div><script>const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",isActive:true,isLine:false},methods:{btn:function () {this.isActive=!this.isActive;},getClasses:function () {return {active:this.isActive,line:this.isLine};}}});</script>
</body>
</html>
案例三(数组语法)了解
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script><style>.active{color: lawngreen;}</style>
</head>
<body>
<div id="app"><h3 class="title" :class="[active,line]">{{message}}</h3></div><script>const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",active:"active",line:"fasd"}});</script>
</body>
</html>
v-bind动态绑定样式(style)
组件开发时常用。
如果不加单或双引号会当作变量使用。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script><style>.active{color: lawngreen;}</style>
</head>
<body>
<div id="app"><!--<h3 class="title" :style="{key(属性名):value(属性值))}">{{message}}</h3>--><h3 class="title" :style="{color:'red'}">{{message}}</h3><h3 class="title" :style="{color:red}">{{message}}</h3></div><script>const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",red:"yellow"}});</script>
</body>
</html>
数组语法:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script><style>.active{color: lawngreen;}</style>
</head>
<body>
<div id="app"><h3 class="title" :style="[style1,style2]">{{message}}</h3></div><script>const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",style1:{fontSize:"50px"},style2:{color:"green"}}});</script>
</body>
</html>
条件(v-if)
控制切换一个元素是否显示相当简单:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><!--view层 模板-->
<div id="app-3"><p v-if="seen">现在你看到我了</p>
</div>
</body><!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>var app3 = new Vue({el: '#app-3',data: {seen: true}})
</script>
</html>
继续在控制台输入 app3.seen = false,你会发现之前显示的消息消失了。
例二:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><!--view层 模板-->
<div id="app"><h3 v-if="type==='A'">A</h3><h3 v-else-if="type==='B'">B</h3><h3 v-else>C</h3>
</div>
</body><!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>var vm = new Vue({el: "#app",data: {type: "1"}})
</script>
</html>
登录切换:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"><span v-if="isUser"><label for="userName" key="userName">用户账号</label><input type="text" id="userName" placeholder="用户账号"></span><span v-else><label for="email" key="email">用户邮箱</label><input type="text" id="email" placeholder="用户邮箱"></span><button @click="isUser = !isUser">切换登录</button>
</div>
<script>const app = new Vue({el:"#app",data:{message:"你好,梦阳辰!",isUser:true}});
</script>
</body>
</html>
vue在进行Dom渲染时,出于性能的考虑会进行复用已经存在的元素,会根据key的值决定是否复用。
v-show
和v-if作用相同。
区别:
当v-show为false不显示时:它的元素还是存在,只不过它的display属性的值为none。
而v-if为false时:它的元素根本就不会存在在dom中。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"><h3 v-if="isUser">你好,梦阳辰!</h3><h3 v-show="isUser">你好,梦阳辰!</h3>
</div>
<script>const app = new Vue({el:"#app",data:{message:"你好,梦阳辰!",isUser:false}});
</script>
</body>
</html>
循环(v-for)
遍历数组:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"><ul><li v-for="(item,index) in names">{{index+1}}.{{item}}</li></ul>
</div>
<script>const app = new Vue({el:"#app",data:{message:"你好,梦阳辰!",names:["梦阳辰","mengyangchen"]}});
</script>
</body>
</html>
遍历对象:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"><ul><li v-for="(value,key) in info">{{key}}.{{value}}</li></ul><ul><li v-for="(value,key,index) in info">{{key}}:{{value}}---{{index}}</li></ul>
</div>
<script>const app = new Vue({el:"#app",data:{message:"你好,梦阳辰!",info:{name:"梦阳辰",age:20,height:171}}});
</script>
</body>
</html>
v-for绑定key与不绑定key区别:
绑定key可以高效的更新虚拟DOM。
在中间插入元素:(diff算法)
绑定的key如果值没有变化,可以复用。
但是没有绑定的话,会将指定的值改为插入的值,后续的值依次改(效率较低)
绑定的key的值应该和显示的内容一致。
数组哪些方法是响应式的:
数据改变,界面内容也随之改变。
push()后面添加
pop()最后一个删除
shift()第一个删除
unshift()数组最前面添加元素
splice()删除/插入/替换元素
splice(start,删除元素的个数)
splice(start,0,你要插入的元素)
splice(start,替换元素的个数,新的替换值)
sort()排序
reverse()反转
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"><ul><li v-for="item in names" :key="item" >{{item}}</li></ul><button @click="way">操作数组</button>
</div><script>const app = new Vue({el:"#app",data:{message:"你好,梦阳辰!",names:["梦阳辰","mengyangchen"]},methods:{way(){this.names.splice(0,1,"你好");/*Vue.set(this.names,0,"fafd");*/}}});</script>
</body>
</html>
点击哪个值,哪个值就亮色
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script><style>.active{color: lawngreen;}</style>
</head>
<body>
<div id="app"><ul><li v-for="(item,index) in moives" :class="{active:currentIndex===index}" @click="way(index)">{{item}}</li></ul>
</div><script>const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",moives:["海王","海贼王","魁拔"],currentIndex:0},methods:{way(index){this.currentIndex=index;}}});</script>
</body>
</html>
v-on事件(处理用户输入)
为了让用户和你的应用进行交互,我们可以用 v-on 指令添加一个事件监听器,通过它调用在 Vue 实例中定义的方法:
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>Title</title><script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
</head>
<body>
<div id="app-5"><p>{{ message }}</p><button v-on:click="reverseMessage">反转消息</button>
</div>
<script>var app5 = new Vue({el: '#app-5',data: {message: 'Hello Vue.js!'},methods: {reverseMessage: function () {this.message = this.message.split('').reverse().join('')}}})
</script></body>
</html>
计数器:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body><div id="app"><h2>当前计数:{{counter}}</h2><!--<button v-on:click="counter++">+</button><button v-on:click="counter--">-</button>--><button v-on:click="way1">+</button><button @click="way2">-</button></div><script>const app = new Vue({el:"#app",data:{counter:0,},methods:{way1:function () {this.counter++;},way2:function () {this.counter--;}}});</script>
</body>
</html>
@click为v-on:click的简写。
methods属性:定义方法。
注意在 reverseMessage 方法中,我们更新了应用的状态,但没有触碰 DOM——所有的 DOM 操作都由 Vue 来处理,你编写的代码只需要关注逻辑层面即可。
当通过methods中定义方法,以供@click调用时,需要注意参数问题:情况一∶如果该方法不需要额外参数,那么方法后的()可以不添加。
但是注意:如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去
情况二∶如果需要同时传入某个参数,同时需要event时,可以通过**$event**传入事件。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"><button @click="way1">1</button><button @click="way1('你好')">2</button><button @click="way2('梦阳辰',$event)">3</button></div>
<script>const app = new Vue({el:"#app",data:{counter:0,},methods:{way1:function (abc) {alert(abc);},way2:function (abc,event) {alert(event);}}});
</script>
</body>
</html>
v-on的修饰符:
Vue提供了修饰符来帮助我们方便的处理一些事件
.stop-调用event.stopPropagation()阻止冒泡.prevent -调用event.preventDefault().{(keyCode | kelyAlias}-只当事件是从特定键触发时才触发回调。.native -监听组件根元素的原生事件。
.once -只触发一次回调。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"><!--.stop--><div @click="divClick">aaaaa<button @click.stop="btnClick">按钮</button></div><!--2.prevent修饰符--><form action="baidu"><input type="submit" value="提交" @click.prevent="submitClick"></form><!--监听某个键帽--><input type="text" @keyup.enter="keyUp">
</div>
<script>const app = new Vue({el:"#app",data:{counter:0,},methods:{divClick(){alert("div触发")},btnClick(){alert("按钮触发")},submitClick(){alert("阻止提交")},keyUp(){alert("它按我了!")}}});
</script>
</body>
</html>
Vue双向绑定(v-model)
Vue 还提供了 v-model 指令,它能轻松实现表单输入和应用状态之间的双向绑定。
1. 什么是双向绑定
Vue.js是一个MVVM框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是Vue.js的精髓之处了。
值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突。
2. 为什么要实现数据的双向绑定
在Vue.js 中,如果使用vuex ,实际上数据还是单向的,之所以说是数据双向绑定,这是用的UI控件来说,对于我们处理表单,Vue.js的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。
3. 在表单中使用双向数据绑定
你可以用v-model指令在表单 、 及 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但v-model本质上不过是语法糖。它负责监听户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
自己实现双向绑定:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head><body>
<div id="app">
<!--<input type="text" v-model= "message">-->
<input type="text" :value="message" @input="valuechange">
<!--<input type="text" :value="message" @input= "message =$event.target.value">--><h2 :key="message">{{message}}</h2><!--key表示-->
</div><script>
const app = new Vue({el:"#app",data: {message: "你好"},methods: {valuechange(event){this.message = event.target.value;}}
})
</script>
</body>
</html>
注意:v-model会忽略所有元素的value、checked、selected特性的初始值而总是将Vue实例的数据作为数据来源,你应该通过JavaScript在组件的data选项中声明。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
</head>
<body>
<div id="app-6"><p>{{ message }}</p><input v-model="message">
</div><script>var app6 = new Vue({el: '#app-6',data: {message: 'Hello Vue!'}});
</script>
</body>
</html>
radio:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head><body>
<div id="app"><input type="radio" value="男" v-model="gender">男<input type="radio" value="女" v-model="gender">女<h3 :key="gender">你选择的是:{{gender}}</h3>
</div><script>const app = new Vue({el:"#app",data: {message: "你好",gender:""}})
</script>
</body>
</html>
select:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
</head>
<body><!--view层 模板-->
<div id="app">下拉框:<select v-model="selected"><option value="" disabled>-请选择-</option><option>A</option><option>B</option><option>C</option></select><p>value:{{selected}}</p>
</div>
</body><script>var vm = new Vue({el: "#app",data: {selected: ""}})
</script>
</html>
在select标签上加multiple
可以选择多个值。
单选框和多选框:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head><body>
<div id="app"><label for="agree"><input type="checkbox" id="agree" v-model="isAgree">同意协议</label><h3>你选择的是:{{ isAgree}}</h3><button :disabled=!isAgree>下一步</button><!--多选框-->
<p>---------------------爱好-------------------</p><input type="checkbox" value="篮球" v-model="hobbies">篮球<input type="checkbox" value="足球" v-model="hobbies">足球<input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球<h3 :key="hobbies">你的爱好是:{{hobbies}}</h3>
</div><script>const app = new Vue({el:"#app",data: {message: "你好",isAgree:false,hobbies:[]}})
</script>
</body>
</html>
值绑定
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head><body>
<div id="app"><label v-for="item in originHobbies" ><input type="checkbox" :value=item v-model="hobbies">{{item}}</label><h3 :key="hobbies">你的爱好是:{{hobbies}}</h3>
</div><script>const app = new Vue({el:"#app",data: {message: "你好",isAgree:false,hobbies:[],originHobbies:['篮球','足球','乒乓球']}})
</script>
</body>
</html>
v-model的修饰符
lazy 取消实时绑定,当按下回车键或失去焦点时进行数据的更新。number v-model默认给变量赋值的时候,赋值为string类型。加上number修饰符后...trim 去除左右两边的空格
04.组件化应用构建
组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:
它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。
任何的应业用都会被抽象出一颗组件树。
有了组件化的思想,我们在之后的开发中就要充分的利用它。尽可能的将页面拆分成一个个小的、可复用的组件。
这样让我们的代码更加方便组织和管理,并且扩展性也更强。
组件的使用分成三个步骤:
创建组件构造器
注册组件
使用组件
原始方式(不推荐使用,建议使用语法糖)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body><cpn></cpn>
<div id="app"><my-cpn></my-cpn><my-cpn></my-cpn><my-cpn></my-cpn>
</div><script>/*es6可以使用`来代替"和'* *///1.创建组件构造器对象const cpn = Vue.extend({template:`<div><h3>我是标题</h3><p>我是内容1</p><p>我是内容2</p></div>`})//2.注册组件Vue.component('my-cpn',cpn)const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",}})
</script>
</body>
</html>
在 Vue 里,一个组件本质上是一个拥有预定义选项的一个 Vue 实例。在 Vue 中注册组件很简单:
语法糖:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
</head>
<body><ol id="app"><!-- 创建一个 todo-item 组件的实例 --><todo-item></todo-item>
</ol>
</body><script>// 定义名为 todo-item 的新组件Vue.component('todo-item', {template: '<li>这是个待办项</li>'});var app = new Vue({el:"#app"});
</script>
</html>
但是这样会为每个待办项渲染同样的文本,这看起来并不炫酷。我们应该能从父作用域将数据传到子组件才对。让我们来修改一下组件的定义,使之能够接受一个 prop:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
</head>
<body><ol id="app"><!--现在我们为每个 todo-item 提供 todo 对象todo 对象是变量,即其内容可以是动态的。我们也需要为每个组件提供一个“key”,稍后再作详细解释。--><todo-itemv-for="item in groceryList"v-bind:todo="item"v-bind:key="item.id"></todo-item></ol>
</body><script>Vue.component('todo-item', {// todo-item 组件现在接受一个// "prop",类似于一个自定义 attribute。// 这个 prop 名为 todo。props: ['todo'],template: '<li>{{ todo.text }}</li>'})var app7 = new Vue({el: '#app',data: {groceryList: [{ id: 0, text: '蔬菜' },{ id: 1, text: '奶酪' },{ id: 2, text: '随便其它什么人吃的东西' }]}})
</script>
</html>
我们已经设法将应用分割成了两个更小的单元。子单元通过 prop 接口与父单元进行了良好的解耦。我们现在可以进一步改进 <todo-item>
组件,提供更为复杂的模板和逻辑,而不会影响到父单元。
全局组件和局部组件
可以在多个vue实例下使用。
在Vue实例中注册就是局部组件:
//1.创建组件构造器对象const cpn = Vue.extend({template:`<div><h3>我是标题</h3><p>我是内容1</p><p>我是内容2</p></div>`})var app = new Vue({el:"#app",components:{//mycpn就是使用组件时的标签名
mycpn:cpn
}});
父组件和子组件的区别:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body><div id="app"><mycpn2></mycpn2>
</div><script>/*es6可以使用`来代替"和'* *///1.创建组件构造器对象//子const cpn1 = Vue.extend({template:`<div><h3>我是标题</h3><p>我是内容1</p><p>我是内容2</p></div>`})//父const cpn2 = Vue.extend({template:`<div><h3>我是头部</h3><p>我是内容1</p><p>我是尾部</p><cpn></cpn></div>`,components:{cpn:cpn1}})//2.注册组件Vue.component('my-cpn',cpn1);const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",},components:{mycpn2:cpn2}});
</script>
</body>
</html>
组件模板分离的写法
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body><cpn></cpn>
<div id="app"><my-cpn></my-cpn>
</div>
<!--方法1-->
<!--<script type="text/x-template" id="cpn"><div><h3>我是标题</h3><p>我是内容1</p><p>我是内容2</p></div>
</script>--><!--方法二-->
<template id="cpn"><div><h3>我是标题</h3><p>我是内容1</p><p>我是内容2</p></div>
</template><script>/*es6可以使用`来代替"和'* *///2.注册组件Vue.component('my-cpn',{template:id='#cpn'})const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",}})
</script>
</body>
</html>
组件可以访问vue实例的数据吗?
我们发现不能访问,而且即使可以访问,如果将所有的数据都放在Vue实例中,Vue实例就会变的非常臃肿。
结论: Vue组件应该有自己保存数据的地方。
组件对象也有一个data属性(也可以有methods等属性,下面我们有用到)只是这个data属性必须是一个函数。
而且这个函数返回一个对象,对象内部保存着数据
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body><cpn></cpn>
<div id="app"><my-cpn></my-cpn>
</div><template id="cpn"><div><h3>{{title}}</h3><p>我是内容1</p><p>我是内容2</p></div>
</template><script>/*es6可以使用`来代替"和'* *///2.注册组件Vue.component('my-cpn',{template:`#cpn`,data(){return{title:'有点东西!'}}})const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",}})
</script>
</body>
</html>
data属性为什么必须是一个函数?
如果是一个属性(对象),应用重复来利用这个主键,但是希望各个组件中的数据是互不影响的,data是属性就无法做到,但是是函数的话就可以做到各个组件实例互不影响。
父子组件的通信
我们提到了子组件是不能引用父组件或者Vue实例的数据的。但是,在开发中,往往一些数据确实需要从上层传递到下层∶
比如在一个页面中,我们从服务器请求到了很多的数据。
其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。
这个时候,并不会让子组件再次发送一次网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)。
如何进行父子组件的通信呢?
通过props向子组件传递数据通过事件向父组件发送消息
vue实例可以看作是根组件。
props的使用
父传子
在组件中,使用选项props来声明需要从父级接收到的数据。
props的值有两种方式︰
方式一︰字符串数组,数组中的字符串就是传递时的名称。
方式二∶对象,对象可以设置传递时的类型,也可以设置默认值等。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body><cpn></cpn>
<div id="app"><mycpn v-bind:cmovies="movies" :cmessage="message"></mycpn>
</div><template id="cpn"><div><p>我是内容1</p><p>我是内容2</p>{{cmessage}}<ul><li v-for="item in cmovies">{{item}}</li></ul></div>
</template><script>const cpn ={template:`#cpn`,// props:['cmovies','cmessage'],//类型限制/* props:{cmovies:Array,cmessage:String,},*///提供默认值/* props:{cmessage:{type:String,default:"fasdf",required:true//加上后表示必传的值}}*///类型是对象或者数组时,默认值必须时一个函数props:{cmovies:{type:Array,default(){return []}}},data(){return{title:'有点东西!'}},methods:{}}const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",movies: ["海王","海贼王"]},components:{mycpn:cpn}})
</script>
</body>
</html>
对于命名问题:
标签(如img)、属性名(如class) 均会自动在浏览器转化为小写,对大小写不敏感,所以用驼峰命名对存在问题。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body><cpn></cpn>
<div id="app"><mycpn v-bind:c-info="info" ></mycpn>
</div><template id="cpn"><div><p>我是内容1</p><p>我是内容2</p><h3>{{cInfo}}</h3></div>
</template><script>const cpn ={template:`#cpn`,//类型是对象或者数组时,默认值必须时一个函数props:{cInfo:{type:Object,default(){return {}}}},data(){return{title:'有点东西!'}},methods:{}}const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",info:{name:"梦阳辰",age:20,gender:"男"}},components:{mycpn:cpn}})
</script>
</body>
</html>
子传父
当子组件需要向父组件传递数据时,就要用到自定义事件了。
我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body><div id="app"><mycpn v-bind:c-info="info" v-on:item-click="cpnClick"></mycpn>
</div><template id="cpn"><div><button v-for="item in categories" @click="btn(item)">{{item.name}}</button></div>
</template><script>/*子组件*/const cpn ={template:`#cpn`,//类型是对象或者数组时,默认值必须时一个函数props:{cInfo:{type:Object,default(){return {}}}},data(){return{categories:[{id:"a",name:"热门推荐"},{id:"b",name:"笔记本电脑"},{id:"c",name:"手机"},{id:"d",name:"化妆品"},]}},methods:{btn(item){/*将信息传递给父组件,自定义事件*/this.$emit('item-click',item);}}}/*父组件*/const app = new Vue({el:"#app",data:{message:"梦阳辰你好!",info:{name:"梦阳辰",age:20,gender:"男"}},components:{mycpn:cpn},methods:{cpnClick(item){console.log(item)}}})
</script>
</body>
</html>
父子通信案例
父子互相影响数据
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body><div id="app"><cpn :number1="num1" :number2="num2"@num1_change="num1_change" @num2_change="num2_change"></cpn></div><template id="cpn"><div><h3 :key="number1">{{number1}}</h3><h3 :key="temp_number1">{{temp_number1}}</h3><input type="text" :value="temp_number1" @input="num1Input"><h3 :key="number2">{{number2}}</h3><h3 :key="temp_number2">{{temp_number2}}</h3><input type="text" :value="temp_number2" @input="num2Input"></div>
</template><script>//子组件//父组件const app = new Vue({el:"#app",data:{message:"梦阳辰",num1:0,num2:1},methods:{num1_change(num){this.num1=parseFloat(num)},num2_change(num){this.num2=parseFloat(num)}},components:{cpn:{//子组件template:`#cpn`,props:{number1:Number,number2:Number},data(){return{temp_number1:this.number1,temp_number2:this.number2,}},methods:{num1Input(event){this.temp_number1=event.target.value;/*将信息传递给父组件,自定义事件*/this.$emit("num1_change",this.temp_number1);},num2Input(event){this.temp_number2=event.target.value;/*将信息传递给父组件,自定义事件*/this.$emit("num2_change",this.temp_number2)}}}}})
</script>
</body>
</html>
父访问子
有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问根组件。
父组件访问子组件:使用$children $refs reference
(引用)
子组件访问父组件:使用$parent
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"><cpn></cpn><cpn></cpn><cpn ref="aa"></cpn><button @click="btn">按钮</button>
</div><template id="cpn"><div><div>子组件</div></div>
</template><script>//子组件//父组件const app = new Vue({el:"#app",data:{message:"梦阳辰",},methods:{btn(){console.log(this.$children);this.$children[0].showMessage();//alert(this.$children[2].name);//下标会改变,所以尽量不要用下标拿属性(这种适合遍历拿所有的)/*$refs是对象类型,默认是一个空的对象,必须在组件上加ref属性*/alert(this.$refs.aa.name);//用这种方式最佳}},components:{cpn:{//子组件template:`#cpn`,data(){return{name:"我是梦阳辰!"}},methods:{showMessage(){alert("你好!")}}}}})
</script>
</body>
</html>
子访问父
子组件访问父组件:使用$parent
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"><cpn></cpn>
</div><template id="cpn"><div><div>子组件1</div><cpn1></cpn1></div>
</template><template id="cpn1"><div><div>子组件2</div><button @click="btn">按钮</button></div>
</template><script>//子组件//父组件const app = new Vue({el:"#app",data:{message:"梦阳辰",},components:{cpn:{//子组件template:`#cpn`,/*第二个子组件,这里不建议嵌套,只为练习使用(因为耦合度高,复用性差)*/data(){return{name:"我是梦阳辰1"}},components: {cpn1:{template: `#cpn1`,methods:{btn(){//访问父组件console.log(this.$parent)alert(this.$parent.name)/*访问根组件*/console.log(this.$root)}}}}}}})
</script>
</body>
</html>
05.计算属性
计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数;简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存!
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:
<div id="example">{{ message.split('').reverse().join('') }}
</div>
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串。当你想要在模板中的多处包含此翻转字符串时,就会更加难以处理。
所以,对于任何复杂逻辑,你都应当使用计算属性。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><!--view层 模板-->
<div id="app"><div>currentTime1: {{currentTime1()}}</div><div>currentTime2: {{currentTime2}}</div>
</div>
</body><!--导入js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>var vm = new Vue({el: "#app",data: {message: "hello,world!"},methods: {currentTime1: function () {return Date.now(); // 返回一个时间戳}},computed: {//计算属性:methods,computed 方法名不能重名,重名字后,只会调用methods的方法currentTime2: function () {this.message;// 返回一个时间戳return Date.now();}}})
</script>
</html>
结论:
调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销。
06.Axios异步通信
Vue的生命周期
实例生命周期钩子
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
比如 created 钩子可以用来在一个实例被创建之后执行代码:
new Vue({data: {a: 1},created: function () {// `this` 指向 vm 实例console.log('a is: ' + this.a)}
})
// => "a is: 1"
也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted、updated 和 destroyed。生命周期钩子的 this 上下文指向调用它的 Vue 实例。
不要在选项 property 或回调上使用箭头函数,比如 created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。
生命周期图示
Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载DOM、渲染→更新→渲染、卸载等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue 实例从创建到销毁的过程,就是生命周期。
在Vue的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册JS方法,可以让我们用自己注册的JS方法控制整个大局,在这些事件响应方法中的this直接指向的是Vue 的实例。
1. 什么是Axios
Axios是一个开源的可以用在浏览器端和NodeJS 的异步通信框架,它的主要作用就是实现AJAX异步通信,其功能特点如下:
从浏览器中创建XMLHttpRequests
从node.js创建http请求
支持Promise API [JS中链式编程]
拦截请求和响应
转换请求数据和响应数据
取消请求
自动转换JSON数据
客户端支持防御XSRF (跨站请求伪造)
GitHub: https://github.com/ axios/axios
中文文档: http://www.axios-js.com/
cdn:
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script>
2. 为什么要使用Axios
由于Vue.js是一个视图层框架且作者(尤雨溪) 严格准守SoC (关注度分离原则),所以Vue.js并不包含Ajax的通信功能,为了解决通信问题,作者单独开发了一个名为vue-resource的插件,不过在进入2.0 版本以后停止了对该插件的维护并推荐了Axios 框架。少用jQuery,因为它操作Dom太频繁 !
测试:
模拟后台返回的json数据:
{"name": "mengyangchen","age": "20","sex": "男","url":"https://www.baidu.com","address": {"street": "文苑路","city": "南京","country": "中国"},"links": [{"name": "bilibili","url": "https://www.bilibili.com"},{"name": "baidu","url": "https://www.baidu.com"},{"name": "cqh video","url": "https://www.4399.com"}]
}
vue
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<!--view层 模板-->
<div id="vue"><div>{{info.name}}</div><div>{{info.address.street}}</div><a v-bind:href="info.url">点我进入</a>
</div>
</body><!--1.导入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<!--导入axios-->
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script>
<script>var vm = new Vue({el: "#vue",data: {items: ['Java','Python','Php']},//data:vm的属性//data():vm方法data(){return{//请求的返回参数,必须和json字符串一样info:{name: null,age: null,sex: null,url: null,address: {street: null,city: null,country: null}}}},//钩子函数,链式编程,ES6新特性mounted(){axios.get("../res/package.json").then(res => (this.info=res.data))}})
</script>
</html>
07.书籍购物车案例
首页
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="style.css" ><script src="../res/js/vue.js"></script></head>
<body>
<div id="app"><div v-if="books.length"><table><thead><tr><th></th><th>书籍名称</th><th>出版日期</th><th>价格</th><th>购买数量</th><th>操作</th></tr></thead><tbody><tr v-for="(item,index) in books"><td>{{item.id}}</td><td>{{item.name}}</td><td>{{item.date}}</td><td>{{item.price | showPrice}}</td><td><button @click="way1(index)">+</button>{{item.count}}<button @click="way2(index)" v-bind:disabled="item.count<=1">-</button></td><td><button @click="remove(index)">移除</button></td></tr></tbody></table><h3>总价为:{{totalPrice | showPrice}}</h3></div><h3 v-else>购物车为空!</h3>
</div><script src="main.js"></script>
</body>
</html>
js代码
const app = new Vue({el:"#app",data:{books:[{id:23,name:"算法第四版",date:"1999-9-26",price:198,count:5},{id:24,name:"计算机基础",date:"1999-9-26",price:198,count:5},{id:25,name:"Java核心卷",date:"1999-9-26",price:198,count:5},{id:26,name:"深入理解计算机原理",date:"1999-9-26",price:198,count:5}]},methods:{way1(index){this.books[index].count++;},way2(index){this.books[index].count--;},remove(index){this.books.splice(index,1)}},/*过滤器*/filters:{showPrice(price){return '¥'+price.toFixed(2);}},computed:{totalPrice(){let totalPrice=0;for(let i=0;i<this.books.length;i++){totalPrice+=this.books[i].price*this.books[i].count;}return totalPrice;}}});
css代码
table {border: 1px solid #e9e9e9;border-collapse: collapse;border-spacing: 0;
}
th,td {padding: 8px 16px;border: 1px solid #e9e9e9;text-align: left;
}
th {background-color: #f7f7f7;color: #5c6b77;font-weight: 600;
}
for of直接取出数组的内容
i即代表数组中的每一项。
for(let i of this.books){
}
js的高阶函数
filter/map/reducefilter中的回调函数:必须返回一个boolean值
当返回true时,函数内部会自动将这次回调的n假如到新的数组中。如果为false,函数内部就会过滤掉这次的n。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="../res/js/vue.js"></script>
</head>
<body>
<div id="app"></div>
<script>const app = new Vue({el:"#app",data:{message:"你好,梦阳辰!",isTrue:1}});const nums=[1,344,5,64,45,78];/*filter函数的使用*/let newNums = nums.filter(function (n) {return n < 100})console.log(newNums)/*map函数的使用,对原数组进行操作*/let newNums2 = nums.map(function (n) {return n*2;})alert(newNums2)/*reduce函数,对数组中所有的内容进行汇总*/let newNums3 = nums.reduce(function (preValue,n) {return preValue+n;},0)alert(newNums3)
</script>
</body>
</html>
简洁的写法(箭头函数):
let total = nums.filter(n => n <100).map(n=>n*2).reduce((pre,n)=>pre+n);
If you find a path with no obstacles, it probably doesn’t lead anywhere.
不变的就是变化本身(Vue学习笔记one)相关推荐
- Vue学习笔记01——Vue开发基础
一.Vue实例配置选项 选项 说明 data Vue实例数据对象 methods 定义Vue中的方法 components 定义子组件 computed 计算属性 filters 过滤器 el 唯一根 ...
- Vue学习笔记入门篇——数据及DOM
本文为转载,原文:Vue学习笔记入门篇--数据及DOM 数据 data 类型 Object | Function 详细 Vue 实例的数据对象.Vue 将会递归将 data 的属性转换为 getter ...
- vue学习笔记-02-前端的发展历史浅谈mmvm设计理念
vue学习笔记-02-前端的发展历史浅谈mmvm设计理念 文章目录 1. MVVM模式的实现者 2.第一个vue程序 3.什么是mvvm? 4.为什么要用mvvm? 5.mvvm的组成部分 7.MVV ...
- vue学习笔记-01-前端的发展历史(从后端到前端,再到前后端分离,再到全栈)
vue学习笔记-01-前端的发展历史(从后端到前端,再到前后端分离,再到全栈) 这篇文章是博主在看vue-前端发展简史的时候做的笔记,以供后续学习复习 文章目录 vue学习笔记-01-前端的发展历 ...
- Vue学习笔记(五)—— 状态管理Vuex
介绍 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.Vuex 也集成到 Vue 的官方调试 ...
- Vue学习笔记(四)—— 前端路由
介绍 本文主要介绍路由的相关知识,当然主要是以Vue的路由为主要介绍对象. 有兴趣的朋友可以看看之前的文章: Vue学习笔记(一)-- 常用特性 Vue学习笔记(二)-- 组件开发 Vue学习笔记(三 ...
- day4 vue 学习笔记 组件 生命周期 数据共享 数组常用方法
系列文章目录 day1学习vue2笔记 vue指令 day2 学习vue2 笔记 过滤器 侦听器 计算属性 axios day3 vue2 学习笔记 vue组件 day4 vue 学习笔记 组件 生命 ...
- 「Vue 学习笔记 1」Vue 项目快速搭建,初始项目各个文件夹作用介绍和启动代码执行流程分析
「Vue 学习笔记 1」Vue 项目快速搭建,初始项目各个文件夹作用介绍和启动代码执行流程分析 前言 一.我的开发环境 二.使用 Vue CLI (Vue 脚手架)快速搭建项目 三.初始项目的目录结构 ...
- 狂神说 vue学习笔记
vue学习笔记 文章目录 vue学习笔记 一.第一个vue程序 1. 什么是MVVM 2. 为什么要使用MVVM 3.直接新建项目 4.导入vue.js 5.简单绑定元素 6 vue的声明周期 二.V ...
- Vue学习笔记(2) 在html文件中创建Vue实例,并使用http-vue-loader注册单文件组件
本篇博客基于Vue2.x 官方文档:https://cn.vuejs.org/v2/guide/instance.html 最近和同学合作一个设备信息管理的小项目,而同学找的模板不是前后端分离的 因此 ...
最新文章
- Google的面试题长啥样?看完被吊打!
- 【TCP/IP】一张图带你读懂TCP/IP协议
- OpenGL 基于PBR的specular textured 镜面纹理的实例
- leetcode 1339. Maximum Product of Splitted Binary Tree | 1339. 分裂二叉树的最大乘积(树形dp)
- 笔记本关于虚拟机桥接小问题
- 在SAP CAL(Cloud Application Library)上搭建ABAP HANA系统
- 制作 Windows8 to Go
- 编程实现 无符号减法溢出判断
- 在Windows上搭建Go开发环境
- Mac比较知名的数据库开发工具Navicat Premium 15.0.30
- [转载] 七龙珠第一部——第012话 向神龙许愿
- 计算机并行配置,windows10无法启动应用程序提示并行配置不正确解决方法
- 企业级数据模型主题域模型划分(NCR FS-LDM)
- 【电蜂优选科普】USB数据线接口有哪些类型呢?
- 二本考中南计算机学硕,二本考上中南财经政法大学经济法学硕的经验
- IIC方式读驱动AT24C16芯片
- android自定义相机带方框,Android摄像头开发:拍照后添加相框,融合相框和图片为一副 图片...
- Java实现 洛谷 P1914 小书童——凯撒密码
- 麦克斯韦方程的积分形式及应用、麦克斯韦方程组的微分形式及应用
- JavaEE - Tomcat和HTTP协议