奋斗是这么个过程,当时不觉累,事后不会悔。走一段再回头,会发现一个更强的自己,宛如新生。
你好,我是梦阳辰!期待与你相遇!
文章较长,切勿心急气躁,否则将一事无成!

学习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)相关推荐

  1. Vue学习笔记01——Vue开发基础

    一.Vue实例配置选项 选项 说明 data Vue实例数据对象 methods 定义Vue中的方法 components 定义子组件 computed 计算属性 filters 过滤器 el 唯一根 ...

  2. Vue学习笔记入门篇——数据及DOM

    本文为转载,原文:Vue学习笔记入门篇--数据及DOM 数据 data 类型 Object | Function 详细 Vue 实例的数据对象.Vue 将会递归将 data 的属性转换为 getter ...

  3. vue学习笔记-02-前端的发展历史浅谈mmvm设计理念

    vue学习笔记-02-前端的发展历史浅谈mmvm设计理念 文章目录 1. MVVM模式的实现者 2.第一个vue程序 3.什么是mvvm? 4.为什么要用mvvm? 5.mvvm的组成部分 7.MVV ...

  4. vue学习笔记-01-前端的发展历史(从后端到前端,再到前后端分离,再到全栈)

    vue学习笔记-01-前端的发展历史(从后端到前端,再到前后端分离,再到全栈)   这篇文章是博主在看vue-前端发展简史的时候做的笔记,以供后续学习复习 文章目录 vue学习笔记-01-前端的发展历 ...

  5. Vue学习笔记(五)—— 状态管理Vuex

    介绍 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.Vuex 也集成到 Vue 的官方调试 ...

  6. Vue学习笔记(四)—— 前端路由

    介绍 本文主要介绍路由的相关知识,当然主要是以Vue的路由为主要介绍对象. 有兴趣的朋友可以看看之前的文章: Vue学习笔记(一)-- 常用特性 Vue学习笔记(二)-- 组件开发 Vue学习笔记(三 ...

  7. day4 vue 学习笔记 组件 生命周期 数据共享 数组常用方法

    系列文章目录 day1学习vue2笔记 vue指令 day2 学习vue2 笔记 过滤器 侦听器 计算属性 axios day3 vue2 学习笔记 vue组件 day4 vue 学习笔记 组件 生命 ...

  8. 「Vue 学习笔记 1」Vue 项目快速搭建,初始项目各个文件夹作用介绍和启动代码执行流程分析

    「Vue 学习笔记 1」Vue 项目快速搭建,初始项目各个文件夹作用介绍和启动代码执行流程分析 前言 一.我的开发环境 二.使用 Vue CLI (Vue 脚手架)快速搭建项目 三.初始项目的目录结构 ...

  9. 狂神说 vue学习笔记

    vue学习笔记 文章目录 vue学习笔记 一.第一个vue程序 1. 什么是MVVM 2. 为什么要使用MVVM 3.直接新建项目 4.导入vue.js 5.简单绑定元素 6 vue的声明周期 二.V ...

  10. Vue学习笔记(2) 在html文件中创建Vue实例,并使用http-vue-loader注册单文件组件

    本篇博客基于Vue2.x 官方文档:https://cn.vuejs.org/v2/guide/instance.html 最近和同学合作一个设备信息管理的小项目,而同学找的模板不是前后端分离的 因此 ...

最新文章

  1. Google的面试题长啥样?看完被吊打!
  2. 【TCP/IP】一张图带你读懂TCP/IP协议
  3. OpenGL 基于PBR的specular textured 镜面纹理的实例
  4. leetcode 1339. Maximum Product of Splitted Binary Tree | 1339. 分裂二叉树的最大乘积(树形dp)
  5. 笔记本关于虚拟机桥接小问题
  6. 在SAP CAL(Cloud Application Library)上搭建ABAP HANA系统
  7. 制作 Windows8   to Go
  8. 编程实现 无符号减法溢出判断
  9. 在Windows上搭建Go开发环境
  10. Mac比较知名的数据库开发工具Navicat Premium 15.0.30
  11. [转载] 七龙珠第一部——第012话 向神龙许愿
  12. 计算机并行配置,windows10无法启动应用程序提示并行配置不正确解决方法
  13. 企业级数据模型主题域模型划分(NCR FS-LDM)
  14. 【电蜂优选科普】USB数据线接口有哪些类型呢?
  15. 二本考中南计算机学硕,二本考上中南财经政法大学经济法学硕的经验
  16. IIC方式读驱动AT24C16芯片
  17. android自定义相机带方框,Android摄像头开发:拍照后添加相框,融合相框和图片为一副 图片...
  18. Java实现 洛谷 P1914 小书童——凯撒密码
  19. 麦克斯韦方程的积分形式及应用、麦克斯韦方程组的微分形式及应用
  20. JavaEE - Tomcat和HTTP协议

热门文章

  1. 项目全生命周期管理、资产成果沉淀展示、算力资源灵活调度丨ModelWhale 云端协同创新平台全面赋能数据驱动科研工作
  2. 625SSM图书商城图书销售系统网上书店
  3. spring security filter获取请求的urlpattern
  4. 如何用openCV识别人脸
  5. 基于Python实现的模拟退火算法
  6. 2005网游——巨作不断国产发力韩流依强
  7. 2018年区块链落地的现状、阻碍与机遇
  8. 零知识证明:安全定义
  9. 网络安全的定义和行业背景如何
  10. 步数能捐款还能换保费?这样的轻松保还是第一次见