# Vue 基础
# 1. Vue.js 简介
在过去 10 年里,浏览器性能变得更加强大。通过 javascript,可以把以前在服务端处理的逻辑放在前端处理。这也造成了网页复杂度越来越高。
随着网页复杂度的增加,需要频繁的操作 DOM,如果使用 jquery 直接操作 DOM,代码会变得难以维护。这是 jquery 命令式操作 DOM 元素带来的弊端,为了解决这个问题,Vue.js 给提供声明式操作 DOM。
# 1.1 什么是 Vue.js
Vue.js 通常简称 Vue,是一款友好的、多用途且高性能的 JavaScript 框架,能够帮助我们创建可维护性更强的代码。它是目前所有主流框架中学习曲线最平缓的框架,非常容易上手,其官方文档也写得非常清晰、易懂。
Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
渐进性的特性,就好比现在的苹果笔记本(非渐进性)和其他笔记本(渐进性),苹果笔记本有自己的雷电接口和 type-c 接口,你使用我的产品就必须根据我的标准来。而其他笔记本不但提供标准的 USB 接口,还提供雷电接口和 type-c 接口,你插任何设备都有很强的兼容性。
# 1.2 Vue 的现状
Vue2.0 与 Vue1.0 之间内部变化非常大,整个渲染层都重写了,但 API 层的变化却很少,可以看出,Vue 是非常注重用户体验和学习曲线的,它尽量让开发者用起来爽,同时在应用场景上,其他框架能实现的 Vue 都能做到。
到目前为止,Vue 最新版本是 2.6.12,它在 github 上的 star 数超过 17 万,超越 15.6 万的 react。在 npm 上 vue 每周有 170 万次下载量,这表示每周有 170 万开发者使用 Vue 开发应用。
Vue.js 在国内的用户有阿里巴巴、腾讯、百度、字节跳动、美团、新浪、网易、饿了么等等。
所以,作为一名前端工程师,学习 Vue.js 是很有必要的。
# 2. 第一个 Vue 程序
Vue.js 作为一个 javascript 库,使用方法是非常简便的,只需要新建一个 html 页面,在头部引入 Vue 文件,然后按 Vue 的语法编写代码即可,下面是完整的代码。
代码有点像之前学习 art-template,Vue 还提供了很多强大的模版语法,下面我们将逐一学习。
运行结果:
# 2.1 el 挂载点
Vue 实例的作用范围是什么?
我们把模版标签写到 Vue 实例作用范围外,页面未能显示helloworld
,所以说 Vue 实例的作用范围只能在 el 标签内。
{{message}}
<div id="test">
{{message}}
</div>
const app = new Vue({
el: '#test',
data: {
message: 'hello world',
},
});
运行结果:
是否可以使用其他选择器?
完全没问题,el 可以是 id 选择器,class 选择器,或者标签选择器(但是不能使用 HTML 和 BODY 标签),强烈建议使用 id 选择器,因为每个 Vue 实例最好有一个唯一的元素。
下面代码演示使用 class 选择器。
<div class="myApp">
{{message}}
</div>
const app = new Vue({
el: '.myApp',
data: {
message: 'hello world',
},
});
运行结果:
总结:
- Vue实例只在el挂在点内,在el外的元素Vue没法解析
- el可以支持任何js选择器,例如id选择器、class选择器和标签选择器
# 2.2 data 对象
页面上用到的数据,都会在 data 对象中定义,data 对象除了可以定义 string 类型外,还可以定义 javascript 支持的任何类型。下面例子演示定义数组类型和对象类型。
<div id="demo_2_2">
<p>普通文本:{{message}}</p>
<p>数字:{{num}}</p>
<p>对象:{{student.name}}</p>
<p>数组:{{heros[0]}}</p>
</div>
const app = new Vue({
el: '#demo_2_2',
data: {
message: '普通文本',
num: 1,
student: { name: 'tom', age: 18 },
heros: ['兰陵王', '安琪拉'],
},
});
运行结果:
总结:
data对象可以是任意的javascript对象,例如字符串、对象、数组、数字、布尔值
在页面上读取数据的方法和普通js无异。`
# 3. 模版语法
我们以前学习的 art-template 有显示、循环、判断等语法,在 Vue 中它也有自己的模版语法,一般以v-
开头,我们把这种语法统一称为指令。
例如v-text
、v-html
、v-on
、v-show
、v-if
、v-bind
、v-for
、v-model
# 3.1 v-text
下面代码演示使用v-text
显示data
对象中的数据,也可以使用两个花括号输出内容。
一般在开发中,多有两个花括号 Mustache 语法输出内容,v-text
标签只作了解。
<div id="demo_3_1">
<!-- 使用v-text显示内容,标签内的内容会被覆盖 -->
<p v-text="message">原来的内容</p>
<!-- 拼接内容 -->
<p v-text="message + '好劲'">原来的内容</p>
<!-- 使用{{}}输出内容 -->
<p>{{message}}</p>
<!-- 拼接字符串 -->
<p>{{message + '好耶'}}</p>
</div>
const app = new Vue({
el: '#demo_3_1',
data: {
message: '少林功夫',
},
});
运行结果:
总结:
v-text
可以用来显示data中数据v-text
会覆盖标签原本内容v-text
内部也可以运行表达式
# 3.2 v-html
v-html
标签用于解析 html 元素,它和v-text
最大的区别是v-text
会把传入字符串作为普通字符串原形输出,而v-html
会把输入字符串作为 html 片段解析后再输出到页面上。
<div id="demo_3_2">
<!-- 使用v-html指令,会对传入字符串作为html片段进行解析 -->
<div v-html="message"></div>
<!-- 使用v-text指令,传入数据会作为普通文本解析 -->
<div v-text="message"></div>
</div>
const app = new Vue({
el: '#demo_3_2',
data: {
message: '<h1>我系铁头功</h1>',
},
});
运行结果:
总结:
v-html
指令会把传入字符串作为html元素解析
# 3.3 v-bind
v-bind 通常用给标签动态设置属性值,例如 id,class,src 等属性,因为 Mustache 语法不支持标签属性。
下面案例在 Vue 实例 data 对象中定义className
为yellowBox
,我们希望把className
属性应用到 div 的 class 属性中。
使用 Mustache 语法的第一个元素在页面上无法显示。
<style>
.yellowBox {
background: yellow;
width: 80px;
height: 80px;
border: 1px solid;
}
</style>
<div id="demo_3_3">
<!-- mustache语法没法显示属性,控制台会报错 -->
<div class="{{className}}"></div>
<!-- 正确写法是使用v-bind语法 -->
<div v-bind:class="className">v-bind写法</div>
<!-- 也可以通过冒号简写,和v-bind等效 -->
<div :class="className">冒号简写</div>
</div>
<script>
const app = new Vue({
el: '#demo_3_3',
data: {
className: 'yellowBox',
},
});
</script>
运行结果:
总结:
v-bind
语法用于标签属性设值可以在标签上使用
v-bind:属性名
设置属性可以省略
v-bind
,直接:属性名
设置属性
# 3.4 javascript 表达式
所有的数据绑定,Vue.js 都提供了完全的 javascript 表达式支持,所谓表达式,就是例如运算符、三目表达式、判断符之类的。
<!-- 运算符 -->
<div>{{number + 1}}</div>
<!-- 条件判断 -->
<div>{{gender === '男'}}</div>
<!-- 三目运算符 -->
<div>{{gender === '男' ? '男孩子': '女孩子'}}</div>
<!-- v-bind也可以使用表达式 -->
<div v-bind:id="'list' + number"></div>
const app = new Vue({
el: '#demo_3_4',
data: {
gender: '男',
number: 1,
},
});
运行结果:
总结:
- 无论Mustache语法或者
v-bind
语法,都支持javascript表达式 - 不支持js语句,例如变量定义、if语句之类的。
# 3.5 v-for 列表渲染
我们可以用 v-for
指令基于一个数组来渲染一个列表。v-for
指令需要使用 item in items
形式的特殊语法,其中 items
是源数据数组,而 item
则是被迭代的数组元素的别名。
<div id="demo_3_5">
<li v-for="(item, index) in items">
{{ index }} {{ item.message }}
</li>
</div>
const app = new Vue({
el: '#demo_3_5',
data: {
items: [{ message: 'Foo' }, { message: 'Bar' }],
},
});
运行结果:
总结:
v-for
指令用于根据数据生成列表结构语法是
(item,index) in 数组
,item表示当前数组数据,index表示数组下标
# 3.5.1 v-for 里使用对象
v-for
语句后面如果是一个对象,例如下例中的 student,在循环的时候会得到三个参数,分别是value
表示对象的值,key
表示对象的 key 值,index
表示循环索引。
<div id="demo_3_5_1">
<li v-for="(value, key, index) in student">
value: {{value}} key: {{key}} index: {{index}}
</li>
</div>
const app = new Vue({
el: '#demo_3_5_1',
data: {
student: {
name: 'tom',
age: 18,
gender: '男',
},
},
});
运行结果:
总结:
v-for
如果接收的是对象,将循环读取对象每个item语法:
(value, key, index) in 对象
,value表示对象的值,key表示对象的key,index表示索引
# 3.6 v-if 条件渲染
v-if
用于判断元素是否渲染,只有当指令收到真
值才会被渲染。
<div id="demo_3_6">
<div v-if="isShow">Vue好棒棒</div>
</div>
也可以添加一个v-else
块,它必须和v-if
块一起出现,不能单独使用:
<div id="demo_3_6">
<div v-if="isShow">Vue好棒棒</div>
<div v-else>😯opps~</div>
</div>
const app = new Vue({
el: '#demo_3_6',
data: {
isShow: true,
},
});
运行结果:
总结:
v-if
标签用于控制元素是否显示- 实际是通过移除DOM元素实现隐藏
- 如果有多个条件,可以用
v-else
实现。
# 3.7 v-show 条件渲染
v-show
和v-if
都可以用来决定元素是否显示,但是v-show
是利用display:none
的方式把元素隐藏起来,而v-if
会在页面移除元素。当你的元素需要频繁的切换可见和非可见状态,建议使用v-show
指令。
<div id="demo_3_7">
<div v-show="isShow">元素显示了吗</div>
</div>
const app = new Vue({
el: '#demo_3_7',
data: {
isShow: true,
},
});
运行结果:
总结:
v-show
指令用于切换元素显示状态- 原理是修改元素
display
实现显示隐藏 - 如果元素频繁切换显示隐藏状态,建议使用
v-show
指令
# 3.8 v-model 双向绑定
你可以用 v-model
指令在表单 <input>
、<textarea>
及 <select>
元素上创建双向数据绑定,指令会帮你自动把输入的值更新到数据中。
<div id="demo_3_8">
<!-- v-model用于实现双向绑定,当用户在输入框输入内容时,会改变data对象的name属性值 -->
<input type="text" v-model="name" />
<!-- 这里显示的内容和输入框的内容会保持一致 -->
<div>用户名:{{name}}</div>
</div>
const app = new Vue({
el: '#demo_3_8',
data: {
name: 'tom',
},
});
总结:
v-model
指令用于方便获取表单值- 绑定的数据会和表单形成关联
- 可通过读取绑定变量得到表单值
# 3.8.1 单选按钮
<div id="demo_3_8_1">
<input type="radio" value="男" id="man" v-model="gender" />
<label for="man">男</label>
<input type="radio" value="女" id="female" v-model="gender" />
<label for="female">女</label>
<div>当前选择的值:{{gender}}</div>
</div>
const app = new Vue({
el: '#demo_3_8_1',
data: {
gender: '男',
},
});
运行效果:
总结:
- 每个选项都需要绑定相同的数据
- 选择的项会自动把value值赋值给绑定数据
# 3.8.2 多项选择
多项选择只要把同一组选择框绑定到相同的v-model
即可。
<div id="demo_3_8_2">
<div>兴趣爱好:</div>
<input
type="checkbox"
name="basketball"
id="basketball"
value="篮球"
v-model="hobby"
/>
<label for="basketball">篮球</label>
<input
type="checkbox"
name="football"
id="football"
value="足球"
v-model="hobby"
/>
<label for="football">足球</label>
<input type="checkbox" name="music" id="music" value="音乐" v-model="hobby" />
<label for="music">音乐</label>
<div>选中的爱好:{{hobby}}</div>
</div>
const app = new Vue({
el: '#demo_3_8_2',
data: {
hobby: [],
},
});
运行效果:
总结:
- 选项需要绑定相同的数据
- 勾选选项后,会把选项value值添加到绑定数据中
# 3.9 事件处理
以前我们通过on事件名
给 DOM 元素添加事件,例如添加点击事件就是onclick
。
<div onclick="login()">登录</div>
在 Vue 中,也可以给元素添加事件,但是他的写法是通过指令v-on:事件名
。
<div id="demo_3_9">
<!-- 绑定的事件如果不传递参数,可以省略括号 -->
<button v-on:click="login">登录</button>
<!-- 如果要给函数传递参数,直接调用的时候传递即可 -->
<button v-on:click="register('tom')">注册</button>
<!-- v-on也可以用关键字@简写 -->
<button @click="register('tom')">简写注册事件</button>
</div>
被调用的函数要定义在methods
对象里面
const app = new Vue({
el: '#demo_3_9',
methods: {
login() {
alert('元素被点击了');
},
register(name) {
alert(name);
},
},
});
运行效果:
总结:
- 事件通过
v-on
指令或者@
简写,用于给元素添加事件 - 绑定的函数需要在
methods
对象定义
# 4. 黑马记事本案例
下面通过一个案例把前面学习的知识做一个整合
运行效果:
记事本包含功能如下:
显示任务列表。
实现思路:1.在data中定义一个
todoList
变量,用于存储任务列表。2.通过v-for
语法把数据todoList
显示到页面。删除单个任务。
实现思路:1.在
methods
中增加一个deleteTask
函数。2.在页面上给元素添加点击事件@click
3. 点击元素时,传递删除元素的索引值。删除所有任务。
实现思路:1.在
methods
中增加一个removeAll
函数,函数用于清空todoList
数据。2. 给页面的元素添加点击事件并绑定removeAll
函数。增加任务。
实现思路:1.使用
v-model
指令实现双向绑定,自动获取输入框的值。2.通过@keyup.enter
事件监听用户按下回车事件。3. 在methods
中定义addTask
函数,函数实现把用户输入内容添加到数组中。
# 5. 其他特性
# 5.1 指令
除了Vue提供的核心指令,例如v-show
、v-model
等,Vue也支持自定义指令,如果你需要对普通DOM元素进行底层操作,这时候就会用到指令。
思考一个场景,如果页面有一个输入框,我们希望进入页面后输入框自动获取焦点,可以怎么实现呢?
第一种方法:利用autofocus
属性,但是该方法在iOS系统不支持。查看文档
<input type="text" autofocus>
第二种方法:调用input元素内置focus
方法,在Vue中实现代码如下。查看文档
<div id="demo_5_1">
<input type="text" id="myInput">
<button @click="setFocus">获取焦点</button>
</div>
const app = new Vue({
el: '#demo_5_1',
methods: {
setFocus() {
document.querySelector('#myInput').focus()
}
}
});
第三种方法:虽然方法二解决了问题,但是逻辑代码和视图代码有耦合,不利于代码维护和服用,下面利用指令来实现相同效果。
<div id="demo_5_1">
<input type="text" v-focus />
</div>
const app = new Vue({
el: '#demo_5_1',
// 指令都放在directives对象里
directives: {
// focus表示指令的名字
focus: {
// inserted表示元素显示到页面上的回调
inserted(el) {
// 调用focus方法给元素获取焦点
el.focus();
},
},
},
});
总结:
- 当你需要操作DOM底层API可以考虑使用指令
- 指令统一定义在
directives
对象中 directives
对象里,对象的key值为指令的关键字,例如定义叫focus
那页面上就是v-focus
- 可以在
inserted
钩子函数监听元素是否进入页面 inserted
函数的el
参数是被添加指令的DOM
元素
# 5.2 过滤器
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind
表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示。
下面案例通过定义一个名upper
的过滤器,过滤器的作用是把传入的数据变为大写。
<div id="demo_5_2">
<!-- 双花括号插值 -->
<div>{{ name | upper }}</div>
<!-- v-bind使用拦截器 -->
<div v-bind:id="name | upper"></div>
</div>
const app = new Vue({
el: '#demo_5_2',
data: {
name: 'tom'
},
// 所有过滤器都定义在filters对象中
filters: {
// upper表示拦截器的名字,value表示拦截器管道前面的值
upper: function(value) {
return value.toUpperCase();
}
}
});
运行效果:
总结:
- 过滤器一般用于格式化文本内容
- 过滤器统一在
filters
对象中定义 filters
对象里,key值作为过滤器的名字,对象的value值是可以函数,可以在函数中获取过滤器传入数据。- 过滤器函数必须
return
值
# 5.3 计算属性
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:
<div id="demo_5_3">
<!-- 第一个方法,在表达式内截取字符串 -->
<div>{{ phone.substr(0, 4) + '****' + phone.substr(7)}}</div>
<!-- 第二个方法,用计算属性生成显示属性 -->
<div>{{ displayPhone }}</div>
</div>
const app = new Vue({
el: '#demo_5_3',
data: {
phone: '18664694721'
},
computed: {
displayPhone: function() {
return this.phone.substr(0, 4) + '****' + this.phone.substr(7)
}
}
});
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示隐藏中间四位数字的手机号。当你想要在模板中多处显示隐藏手机号,就会更加难以处理。
所以,对于任何复杂逻辑,你都应当使用计算属性。
运行结果:
总结:
- 计算属性一般用于处理界面复杂表达式
- 计算属性定义在
computed
对象 - 对象key值为计算后属性名,该值可以用于模版渲染
- 对象value值为函数,函数内定义计算逻辑,函数内包含data的属性当出现变化时,会自动重新运行该函数。
# 5.4 侦听属性
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch
选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
看下面例子,通过侦听关键字watch
侦听data下的num
属性,当num
属性发生改变时,就会触发侦听函数
<div id="demo_5_4">
购买数量:<input type="text" v-model="num">
<div>如果购买数大于5,提示"超出最大购买数"</div>
</div>
const app = new Vue({
el: '#demo_5_4',
data: {
num: 0
},
// 把需要侦听的属性放在watch对象中
watch: {
// 对象的key值为侦听的属性,该属性是data对象下的任意属性
// 对象的value值是一个函数,函数会得到两个参数,第一个参数是新的值,第二个参数是旧的值
num: function (newValue, oldValue) {
console.log(newValue, 'newValue')
console.log(oldValue, 'oldValue');
// 如果num大于10,提示“超出最大购买数”
const buyNum = parseInt(newValue);
if (buyNum > 4) {
alert('超出最大购买数')
}
}
}
});
运行结果:
总结:
- 侦听属性一般用于侦听现有属性的变化,常用于当需要在数据变化时执行异步或开销较大的操作时。
- 监听属性定义在
watch
对象下。 - 对象的key值为侦听的属性,该属性是data对象下的任意属性
- 对象的value值是一个函数,函数会得到两个参数,第一个参数是新的值,第二个参数是旧的值
# 5.4.1 深度侦听
侦听属性默认只侦听属性的第一级属性,如果需要侦听嵌套属性,需要加入deep
属性。
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>计算属性</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="demo_5_4_1">购买数量:<input type="text" v-model="a.b" /></div>
</body>
<script>
const app = new Vue({
el: '#demo_5_4_1',
data: {
a: {
b: 1,
},
},
watch: {
a: {
handler: function() {
console.log('是否能侦听');
},
deep: true
},
},
});
</script>
</html>
# 5.5 计算属性 vs 侦听属性
计算属性和侦听属性特性非常相似,都可以监听属性的变更,很容导致同学们不知道怎么准确的使用。
一般情况下优先考虑计算属性,当计算属性没法满足的场景,或者你根本不需要计算多一个值用于渲染页面时,可以考虑侦听属性。
下面例子分别通过侦听属性和计算属性实现名字的拼接。
<div id="demo">{{ fullName }}</div>
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
上面代码是命令式且重复的。将它与计算属性的版本进行比较:
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
# 5.6 购物车案例
使用计算属性实现购物车商品数量修改自动计算总价。
const app = new Vue({
el: '#demo_5_6',
data: {
cart: [
{ title: '这是第一个商品', price: 100, amount: 5 },
{ title: '这是第二个商品', price: 200, amount: 3 }
],
},
computed: {
totalPrice: function() {
let total = 0;
this.cart.forEach(item => {
total += item.price * item.amount;
})
return total;
}
},
});
# 5.7 实例生命周期钩子
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
比如 created
钩子可以用来在一个实例被创建之后执行代码:
new Vue({
data: {
a: 1
},
created: function () {
console.log('a is: ' + this.a)
}
})
# 6. 过渡 & 动画
# 6.1 HTML过渡动画实现
下面演示通过增加和删除class
实现元素的淡入淡出动画效果,主要依赖css3过渡属性transition
实现。
See the Pen 普通过渡动画 by 蟹老板 (@zhengguorong) on CodePen.
# 6.2 Vue过渡动画实现
因为在Vue中,是不建议直接操作DOM的,所以像上面的通过增加/删除类名的方式在Vue中不建议。
Vue提供了自己的过渡动画实现组件transition
。在下列情形中,可以给任何元素和组件添加进入/离开过渡
- 条件渲染 (使用
v-if
) - 条件展示 (使用
v-show
) - 动态组件
- 组件根节点
这里是一个典型的例子:
# 过渡的类名
在进入/离开的过渡中,会有 6 个 class 切换。
- 组件隐藏变为显示, 称为 enter, 会按顺序切换以下 class
- [动画名]-enter 是在变化开始, 出现之前
- [动画名]-enter-active 正在变化 正在出现
- [动画名]-enter-to 变化结束已经出现结束
- 组件显示变为隐藏, 称为 leave, 会按顺序切换以下 class
- [动画名]-leave 是在消失之前
- [动画名]-leave-active 正在消失
- [动画名]-leave-to 消失结束
对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>
,则 v-
是这些类名的默认前缀。如果你使用了 <transition name="my-transition">
,那么 v-enter
会替换为 my-transition-enter
。
# vue实现过渡动画步骤:
使用按钮控制 div 的显示和隐藏
v-if
使用 transition 标签包裹想要添加动画的 div
给 transition 标签添加 name 属性作为动画名
编写 css 样式谈出隐藏 div
编写 css 淡入显示 div
# 6.3 结合animate.css实现复杂动画
对于复杂的动画,自行编写会比较困难,可以借助animate.css第三方库实现。
# 6.3.1 在html中使用animate.css
1、引入animate.css
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
/>
2、给需要执行动画的元素添加类名
<h1 class="animate__animated animate__bounce animate__infinite">一个动画元素</h1>
animate__animated:是必须加入的,声明这是一个动画元素
animate__bounce:动画的类型,可以设置不同的动画名实现不同效果
animate__infinite:循环播放动画
See the Pen html使用animate.css by 蟹老板 (@zhengguorong) on CodePen.
# 6.3.2 在Vue中使用animate.css
Vue使用animate.css和普通页面使用方式是类似的,都是通过控制元素的class名实现。我们上面演示过Vue的transition
组件自动会给元素添加默认的类名,例如进入的有v-enter
、v-enter-active
、v-enter-to
,离开有v-leave
、v-leave-active
、v-leave-to
。如果需要应用animate.css的动画,那把默认的class名修改成animate.css就可以实现了。
Vue的transition
组件提供以下属性实现自定义过渡类名:
enter-class
enter-active-class
enter-to-class
leave-class
leave-active-class
leave-to-class
下面是vue实现例子
1、引入animate.css
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
/>
2、通过自定义属性修改过渡动画类名
<div id="demo_6_3_2">
<button @click="show = !show">
切换显示隐藏状态
</button>
<transition
enter-active-class="animate__animated animate__bounce"
leave-active-class="animate__animated animate__shakeX"
>
<h1 v-if="show">一个动画元素</h1>
</transition>
</div>
3、控制元素显示状态触发动画
const app = new Vue({
el: '#demo_6_3_2',
data: {
show: true
}
});
最终效果:
# 7. 组件入门
组件化是Vue等现代框架很重要的特性,其目的是把功能相似的代码封装到一个组件统一管理,减少重复代码和提升代码维护性。
# 7.1 基本示例
这里有一个 Vue 组件的示例:通过Vue.component('组件名', 组件配置) 创建组件
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data() {
return {
count: 0
}
},
template:
'<button @click="count++">组件被点击了{{count}}</button>',
});
组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <button-counter>
。我们可以在一个通过 new Vue
创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
<div id="demo_7_1">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
const app = new Vue({
el: '#demo_7_1',
data: {}
})
# 7.2 组件里的 data
必须是一个函数
当我们定义这个 <button-counter>
组件时,你可能会发现它的 data
并不是像这样直接提供一个对象:
data: {
count: 0
}
取而代之的是,一个组件的 data
选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
data: function () {
return {
count: 0
}
}
# 7.3 通过 Prop 向子组件传递数据
我们有一个新闻组件,如果在新闻组件写死内容,那组件就没有意义了,我们希望新闻组件可以根据传递内容显示不同信息,这就要用到prop属性了。
Vue.component('blog-post', {
// 组件接收多少属性,就要在props对象定义多少个
props: ['title', 'subtitle'],
// 注意:template只能包含一个根结点
template: `<div>
<h3>{{ title }}</h3>
<h4>{{ subtitle }}</h4>
</div>`
})
一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data
中的值一样。
一个 prop 被注册之后,你就可以像这样把数据作为一个自定义 attribute 传递进来:
<div id="demo_7_3">
<blog-post title="第一条新闻" subtitle="子标题"></blog-post>
<blog-post title="第二条新闻" subtitle="子标题"></blog-post>
<blog-post title="第三条新闻" subtitle="子标题"></blog-post>
</div>
运行效果:
# 7.4 传递动态数据
如果需要给组件传递动态数据,需要利用关键字bind
或者冒号:
传递变量。
<div v-for="article in articles">
<blog-post :title="article.title" :subtitle="article.subtitle"></blog-post>
</div>
const app = new Vue({
el: '#demo_7_3',
data: {
articles: [
{ title: '第一条新闻', subtitle: '第一条新闻子标题' },
{ title: '第二条新闻', subtitle: '第二条新闻子标题' },
{ title: '第三条新闻', subtitle: '第三条新闻子标题' }
]
},
});
运行效果:
# 7.5 监听子组件事件
下面例子演示通过事件监听子组件事件,子元素如果要通知父元素,通过this.$emit('事件名', 参数)
触发
See the Pen 监听子组件事件 by 蟹老板 (@zhengguorong) on CodePen.
# 7.6 兄弟组件值传递
See the Pen pobQBbV by 蟹老板 (@zhengguorong) on CodePen.