1.认识Vuejs
Vue是一个渐进式框架, 什么是渐进式的呢?
声明式渲染→组件系统→客户端路由→集中式状态管理→项目构建渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验。
Vue有很多特点和Web开发中常见的高级功能
解耦视图和数据可复用的组件前端路由技术状态管理虚拟DOM
一句话总结:用数据绑定的思想,vue可以简单写单个页面,也可以写一个大的前端系统,也可以做手机app的界面。
(1)Vue初体验
(2)Vue中的MVVM
View层
视图层前端开发中, 通常就是DOM层主要的作用是给用户展示各种信息
Model层
数据层数据可能是我们固定的死数据, 更多的是来自我们的服务器, 从网络上请求下来的数据
VueModel层
视图模型层视图模型层是View和Model沟通的桥梁一方面它实现了 Data binding, 也就是数据绑定, 将Model的改变实时的反应到了View中另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击、滚动、touch等)时,可以监听到,并在需要的情况下改变对应的Data。
(3)Vue实例传入的options
(4)Vue生命周期
2.插值指令
- Mustache
(1)插值表达式 {{}}
数据绑定最常见的形式就是使用 “Mustache” 语法(双大括号)的文本插值。例如:
<span>Message: {{ msg }}</span>
Mustache 标签将会被替代为对应数据对象上 msg 属性(msg定义在data对象中)的值。
无论何时,绑定的数据对象上 msg 属性发生了改变,插值处的内容都会自动更新。
- v-once
该指令后面不需要跟任何表达 该指令表示元素只渲染一次,不会随着数据的改变而改变。
<h2 v-once>{{message}}</h2>
- v-html
解析数据中的html代码,渲染到页面中
<h2 v-html="url"></h2>
- v-text
v-text作用和Mustache比较相似:都是用于将数据显示在界面中, 不同的是 v-text 是写在属性中 v-text通常情况下,接收一个string类型
<h2 v-text="text"></h2>
- v-pre
v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法。
<h2 v-pre>{{message}}</h2>
- v-cloak
在某些情况下,我们浏览器可能会直接显然出未编译的Mustache标签。 v-cloak指令和CSS 规则一起用的时候,能够解决插值表达式闪烁的问题(即:可以隐藏未编译的标签直到实例准备完毕)
<!-- 在vue解析之前, div中有一个属性v-cloak
在vue解析之后, div中没有一个属性v-cloak -->
<div id="app" v-cloak>
<h2>{{message}}</h2>
</div>
- v-text和v-html的区别
用v-html指令插值
效果:
用v-text指令插值
将上图的v-html改成v-text,其他不变。
区别:
v-html 输出标签中的内容
v-text输出结果为带标签 的
- 总结
(1)Mustache: {{}}语法, 可以写变量/逻辑表达式/计算值…
(2)v-once : 元素只渲染一次,不会随着数据的改变而改变。
(3)v-html="" : 解析数据中的html代码,渲染到页面中
(4)v-text=“msg”: 写在属性当中, 将数据显示在界面中
(5)v-pre: 原文输出, 显示原本的Mustache语法
(6)v-cloak : 一般配合CSS规则一起使用, 够解决插值表达式闪烁的问题
3.v-bind绑定属性
- v-bind介绍
前面我们学习的指令主要作用是将值插入到我们模板的内容当中。但是,除了内容需要动态来决定外,某些属性们也希望动态来绑定。
作用:可以给html元素或者组件动态地绑定一个或多个特性,例如动态绑定style和class:比如动态绑定a元素的href属性;比如动态绑定img元素的src属性
这个时候,我们可以使用v-bind指令:
作用:动态绑定属性
缩写: :
预期:any (with argument) | Object (without argument)
参数:attrOrProp (optional)
- v-bind绑定class
绑定class有两种方式:对象语法和数组语法
(1)对象语法
对象语法的含义是:class后面跟的是一个对象。
<!-- 用法一:直接通过{}绑定一个类 -->
<h2 :class="{'active': isActive}">Hello World</h2>
<!-- 用法二:也可以通过判断,传入多个值 -->
<h2 :class="{'active': isActive, 'line': isLine}">Hello World</h2>
<!-- 用法三:和普通的类同时存在,并不冲突 -->
<!--注:如果isActive和isLine都为true,那么会有title/active/line三个类-->
<h2 class="title" :class="{'active': isActive, 'line': isLine}">Hello World</h2>
<!-- 用法四:如果过于复杂,可以放在一个methods或者computed中 -->
<!--注:classes是一个计算属性 -->
<h2 class="title" :class="classes">Hello World</h2>
(2)数组语法
数组语法的含义是:class后面跟的是一个数组。
<!-- 1. ['active','news'] 当字符串使用 -->
<h2 class="title" :class="['active','news']">{{message}}</h2>
<!-- [active, new] 当变量使用 -->
<h2 class="title" :class="[active,news]">{{message}}</h2>
<!-- 3. 函数返回值使用 -->
<h2 class="title" :class="getClasses()">{{message}}</h2>
- v-bind绑定style
我们可以利用v-bind:style来绑定一些CSS内联样式,有两种方式对象语法和数组语法
(1)对象语法
style后面跟的是一个对象类型,对象的key是css属性名,对象的value是具体赋的值, 可以来自data中的属性
:style="{color: currentColor, fontSize: fontSize + 'px'}"
(2)数组语法
style后面跟的是一个数组类型, 多个值以 , 分隔
<div v-bind:style="[baseStyles, fontColor]"></div>
/* js */
baseStyle: {background: 'lime'},
fontSize: {fontSize: '80px'}
4.computed计算属性
- 基本概念
(1)计算属性出现的目的是解决模板中放入过多的逻辑会让模板过重且难以维护的问题
(2)计算属性是基于它们的响应式依赖进行缓存的
(3)在某些情况,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示
比如我们有firstName和lastName两个变量,我们需要显示完整的名称。但是如果多个地方都需要显示完整的名称,我们就需要写多个{{firstName}} {{lastName}}
将上面代码转换成计算属性:
/* html */
<h2>{{fullNmae}}</h2>
/* js */
computed: {
fullNmae: function () {
return this.firstNmae + ' ' + this.lastNmae;
}
}
- 计算属性的setter和getter
每个计算属性都包含一个getter和一个setter- 在上面的例子中,我们只是使用getter来读取。
- 在某些情况下,你也可以提供一个setter方法(不常用)。
- 在需要写setter的时候,代码如下
- 计算属性的缓存
methods和computed区别
methods里面的数据不管发没发生变化, 只要调用了都会执行函数(有的时候数据没发生变化我们不希望调用函数)
computed计算属性会进行缓存, 如果数据没发生变化,函数只会被调用一次(数据发生变化才会调用函数)
总结:
methods不管数据发没发生变化都会调用函数
computed只有在依赖数据发生变化时才回调函数
优点:
computed 计算属性,它的性能是比较高的,只有当他依赖的属性发生变化时,它才会重新请求计算,否则使用上一次的缓存值。所以如果一个庞大的数据项目,需要有缓存的,就可以用这种方法。可以减少请求次数,达到优化。
5.事件监听指令
在前端开发中,我们需要经常和用户交互,这个时候我们就必须监听用户的发生时间,比如点击, 拖拽事件等等
v-on 介绍
作用: 绑定事件监听器
缩写: @
(1)v-on参数
- 当methods中定义方法, 以供@click调用时, 需要注意参数问题
- 情况一: 如果该方法不需要额外参数, 方法后()可以省略
没有传入参数, 接收形参时默认会将原生事件event参数传递进去 - 情况二: 如果需要同时传入某个参数, 同时需要event时, 可以通过$event传入事件
(2)v-on修饰符
v-on 提供了很多事件修饰符来辅助实现一些功能。事件修饰符有如下
(3)v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。
效果:当你点“点我”时,就弹出“你点到我了”。
- 代码解读
事件写在Vue实例的methods对象里
v-on可以简写为:@ - 改变插值
效果:点击“我是标题”,变成“哈哈哈”。
6.条件渲染指令
(1)vi-f与v-else-if与v-else
- Vue的条件指令可以根据表达式的值在DOM中渲染或销毁元素或组件
<h2 v-if="score>=90">优秀</h2>
<h2 v-else-if="score>=80">良好</h2>
<h2 v-else-if="score>=60">及格</h2>
<h2 v-else>不及格</h2>
- 逻辑较多不建议在模板中使用v-if-else-if
(2)复用元素渲染问题
一个问题: 涉及到了Vue底层, 虚拟DOM virtual DOM 点击切换表单后,input的value值并没有被清空,为什么?
引出: 当实现点击按钮切换input表单时, 我们输入上的value, 点击按钮切换表单时会发现value值还存在, 但是input元素确实切换了, 这是因为什么呢?
<span v-if="isUser">
<label for="user">用户名</label>
<input type="text" placeholder="用户名" id="user" key="user">
</span>
<span v-else>
<label for="email">邮箱</label>
<input type="text" placeholder="邮箱" id="email" key="email">
</span>
<button @click="isUser=!isUser">切换类型</button>
<script>
const app = new Vue({
el: '#app',
data: {
isUser: true
}
})
</script>
原因:
- 1.这是因为Vue在进行DOM渲染时, 出于性能考虑, 会尽可能服复用已经存在的元素, 而不是创建新的元素
- 2.上面的案例中, Vue内部会进行对比发现两部分都相似只会替换属性, 不会给你创建全新的元素
- 3.上面 if 的 input不再使用, 直接作为 else 的 input来使用
解决方案:
- 1.如果我们不希望 Vue出现类似重复利用的问题, 可以给对应的input添加 key
- 2.并且保证要们需要的key不同, 这样 vue就会创建一个全新 input元素
(3)v-show
v-show的用法和v-if非常相似,也用于决定一个元素是否渲染
- v-if 和 v-show对比
v-if 当条件为false时,压根不会有对应的元素在DOM中
v-show 当条件为false时, 仅仅是将元素的 display 属性设置 none 而已
开发中如何选择呢?
当需要在显示与隐藏之间切换很频繁时,使用v-show
当只有一次切换时,通过使用v-if
<h2 v-show="isShow">{{message}}</h2>
- v-if 和 v-show的区别
第一种情况,显示的时候
以上代码,我通过在data的showOrhide的ture来控制显示,明显看出两者都显示在dom结构中。很容易理解!
第二种情况,隐藏时候
以上代码,我将data的showOrhide的ture改为false来控制隐藏,可是,我们看dom结构,通过v-if的那个div已经在dom中移除了。而v-show的div则是通过display:none来达到隐藏。但dom结构依然存在。
7.循环遍历指令
(1)v-for遍历数组
作用:根据数组中的元素遍历指定模板内容生成内容。
语法: v-for="(item, index) in items"
<ul>
<!-- item: 是每一项元素 index: 下标/索引 -->
<li v-for="(item, index) in name">
{{index+1}}.{{item}}
</li>
</ul>
(2)v-for遍历对象
作用: 遍历对象
语法: v-for="(value, key, index) in items"
<ul>
<!-- value:属性值 key:属性名 index:下标/索引 -->
<li v-for="(value, key, index) in info">
{{index+1}}.{{value}}
</li>
</ul>
(3)Vue中Key属性
- 官方推荐我们在使用v-for时,给对应的元素或组件添加上一个:key属性。
- 为什么需要这个key属性呢(了解) ?
这个其实和Vue的虚拟DOM的Diff算法有关系。 - 当某一层有很多相同的节点时,也就是列表节点时,我们希望插入一个新的节点
我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的。即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率? - 所以我们需要使用key来给每个节点做一个唯一标识
Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点 - key的作用主要是为了高效的更新虚拟DOM
使用v-for更新已渲染的元素列表时,默认用就地复用策略; 如果列表数据修改的时候, 它会根据key值去判断某个值是否修改, 如果修改, 则重新渲染这一项, 否则复用之前的元素; 我们在使用的使用经常会使用index(即数组的下标)来作为key,但其实这是不推荐的一种使用方法;
(4)数组响应式方法
因为Vue是响应式的, 所以当数据发生变化时, Vue会自动检测数据变化, 视图会对应的更新
Vue中包含了一组观察数组编译的方法, 使它们改变数组也会触发更新视图
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
(5)Vue.set修改响应式数据
Vue.set(vm.items, indexOftem, newValue)
vm.$set(vm.items ,indexOften,newValue)
参数1: 要修改的数组/对象
参数2: 要设置的索引/添加的属性名
参数3: 设置的值
(6)v-if 和 v-for
当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着v-if 将分别重复运行于每个v-for循环中。避免 v-if 和 v-for用在一起
原因:
如果使用了 if 判断, 每次渲染在Vue内部都会遍历整个列表, 不论判断条件是否发生了变化
使用计算属性的好处:
- 1.过滤后的列表只会在users数组发生相关变化时才被重新运算,过滤更高效。
- 2.使用v-for="user in activeusers"之后,我们在渲染
- 3.的时候只遍历活跃用户,渲染更高效。
- 4.解耦渲染层的逻辑,可维护性(对逻辑的更改和扩展)更强。
8.表单绑定v-model
(1)基本概念
-
Vue中使用v-model指令来实现表单元素和数据的双向绑定
数据与模板是相互影响的, 一方发生变化, 另一方立即做出更新 -
引出:
1.在之前的案例, 我们通过v-bind,给标签绑定了data对象里的name属性。data中的name的值发生改变时, 标签里的内容会自动更新。
2.可现在要做的是: 在标签里修改内容, 要求data中的name的属性值自动更新。从而实现双向数据绑定。该怎么做呢? 这就可以利用v-model这个属性。
区别: -
v-bind: 只能实现数据的单向绑定, 从M自动绑定到v。
-
v-model: 只有v-model才能实现双向数据绑定。注意, v-model后面不需要跟冒号
注意:
v-model只能运用在表单元素中, 或者用于自定义组件。常见的表单元素包括: input(radio,text,address,email…) ,select, checkbox, textarea.
(2)v-model原理
v-model其实是一个语法糖, 他背后本质是包含两个操作
- v-bind绑定一个value属性
- v-on指令绑定当前元素的input事件
<input type="text" v-model="message">
<!-- 等同于下面的代码 -->
<input type="text" :value="message" @input="message = $event.target.value">
(3)表单绑定v-model
Vue中使用v-model指令来实现表单元素和数据的双向绑定
案例解析:
- 当我们在数据框输入内容时
- 因为input中v-model绑定了message, 所以会实时将输入的内容传递给message, message发生变化
- 当message发生变化时, 因为上面我们使用Mustanche语法, 将message的值插入到DOM中, 所以DOM会发生响应式的改变
- 所以, 通过v-model实现了双向的绑定
当然, 我们可以将v-model用于textarea元素
表单绑定v-model案例:
textarea绑定v-model案例:
(4)表单中其它类型绑定v-model
表单中其它类型, 绑定v-model
v-model: radio
v-model: checkbox
v-model: select
(5)值绑定
动态的给value赋值而已
- 我们前面之前写的value中的值, 都是在定义input中直接给定的
- 但是真是开发中, 这些input中的value值可能是从服务器中获取, 然后定义的
- 所以我们可以通过v-bind:value动态的给value绑定值
值绑定:
(6)v-model的修饰符
9.Vue常用特性
(1)自定义指令
为何需要自定义指令:内置指令不满足需求
Vue.directive 注册全局指令
自定义指令语法(获取焦点)
Vue.directive('focus', {
inserted: function (el) {
el.focus()// 获取元素的焦点
}
})
// 使用自定义指令
<input type="text" v-focus>
带参数的自定义指令
Vue.directive('color', {
// bind声明周期, 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
// el 为当前自定义指令的DOM元素
// binding 为自定义的函数形参 通过自定义属性传递过来的值 存在 binding.value 里面
bind: function(el, binding){
// 根据指令的参数设置背景色
// console.log(binding.value.color)
el.style.backgroundColor = binding.value.color;
}
});
// 使用带参数自定义指令
<input type="text" v-color='msg'>
自定义局部指令
- 局部指令,需要定义在 directives 的选项 用法和全局用法一样
- 局部指令只能在当前组件里面使用
- 当全局指令和局部指令同名时以局部指令为准
directives: {
focus: {
inserted: function(el) {
el.focus();
}
}
}
(2)侦听器 watch
侦听器的应用场景
- 数据变化时执行异步或开销较大的操作
注意: watch 中的属性 一定是data 中 已经存在的数据
// 当data中的: firstName属性或lastNames属性改变时, 会自动触发对应的watch
watch: {
firstName(val) { // val: 表示变化后的值
this.fullName = val + ' ' + this.lastName;
},
lastName(val) {
this.fullName = this.firstName + ' ' + val;
}
}
(3)过滤器
概念: Vue.js允许我们自定义过滤器,可被用作一些常见的文本格式化/处理。
- 过滤器可以用在两个地方: mustache插值表达式、v-bind表达式。
- 过滤器应该被添加在JavaScript表达式的尾部,由“管道”符指示。
- 过滤器不改变真正的data,而只是改变渲染的结果,并返回过滤后的版本
- 全局注册时是filter,没有s的。而局部过滤器是filters,是有s的
- 支持级联操作(对前一个过滤的数据再次进行过滤处理)
自定义全局过滤器
我们可以用全局方法Vue.filter()自定义一个全局过滤器。这样的话,每一个Vue的对象实例(每一个VM实例)都可以拿到这个过滤器。它接收两个参数: 过滤器的名称、过滤器函数。
<div>{{msg | upper}}</div>
<div>{{msg | upper | lower}}</div>
<div :class="msg | upper"></div>
<!-- 带参数过滤 -->
<div>{{date | format('yyyy-MM-dd')}}</div>
<script>
// 1.全局过滤器
Vue.filter('upper', (val) => {
// val就是要处理的数据
return val.charAt(0).toUpperCase() + val.slice(1);
})
// 2.处理带参数过滤器
Vue.filter('format', (date, arg) => {
// arg: 传递的参数
if (arg === 'yyyy-MM-dd') {
return date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();
}
})
</script>
自定义私有过滤器
私有过滤器: 在某一个vue对象内部定义的过滤器称之为私有过滤器
这种过滤器只有在当前vue对象的el指定的监管区域有用。
<!-- 管道符前面的price: 要把price这段文本进行过滤 -->
<!-- 管道符后面的showPrice: 是通过showPrice这个过滤器来进行操作 -->
<td>{{price | showPrice}}</td>
<script>
const app = new Vue({
filters: {
showPrice(price) {
return '¥' + price.toFixed(2);
}
}
})
</script>
(4)生命周期
事物从出生到死亡的过程
- Vue实例从创建到销毁的过程,这些过程中会伴随着一些函数的自调用。我们称这些函数为钩子函数
主要阶段
-
挂载(初始化相关属性)
(1)beforeCreate
(2)created
(3)beforeMount
(4)mounted -
更新(元素或组建的变更操作)
(1)beforeUpdate
(2)updated -
销毁(销毁相关属性)
(1)beforeDestroy
(2)destroyed