学习测试环境可通过 CDN 地址引入 Vue(项目开发和线上环境一般使用 vue-cli、webpack 打包)
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
可使用构造函数创建 Vue 实例,即应用的入口:
<div id="app">
{{msg}}
</div>
<script>
let app = new Vue({
el: '#app', // 指定页面中存在的 DOM 元素挂载
data: { // 声明需要双向绑定的数据(渲染到页面上)
msg: 'Hello World!'
}
})
console.log(app.$el) // 访问 Vue 实例中的属性
console.log(app.msg) // 访问 Vue 实例 data 域中的属性
</script>
与 jQuery 对比
使用 jQuery 实现 todo-list:
<div>
<ul id="ul-list"></ul>
</div>
<script type="text/javascript">
var $txtTitle = $('#txt-title')
$('#btn-submit').click(function () {
var title = $txtTitle.val()
if (!title)
return
var $li = $('<li>' + title + '</li>')
$('#ul-list').append($li)
$txtTitle.val('')
})
</script>
使用 Vue 实现 todo-list:
<div id="app">
<div>
<input v-model="title">
<button v-on:click="add">submit</button>
</div>
<div>
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
</div>
</div>
<script type="text/javascript">
var data = {
title: '',
list: []
}
new Vue({
el: '#app',
data: data,
methods: {
add: function () {
this.list.push(this.title)
this.title = ''
}
}
})
</script>
- 区别在于:jQuery 以选择器获取并修改 DOM,Vue 以数据与 DOM 元素绑定、DOM 响应数据变化;
- 即数据和视图分离(开放封闭原则)、以数据驱动视图(DOM 操作被封装)。
生命周期
一些生命周期钩子:
- created:实例创建完成后调用,完成了数据的观测等而尚未挂载(
$el
还不可用)需要初始化处理一些数据时会用到; - mounted:el挂载到实例上后调用,一般第一个业务逻辑会在这里开始。相当于
$(document).ready()
; - beforeDestroy:实例销毁之前调用。主要解绑一些使用
addEventListener
监听的事件等; - ...
文本插值,表达式
使用双大括号( Mustache 语法){{value}}
是最基本的文本插值方法,可以将双向绑定的数据实时显示,还可以使用单行 JS 表达式:
{{1 + 1}}
{{6 > 5? msg1: msg2}}
{{var a = 6}} // 错误,这是多行表达式
{{if(6 > 3){}}}
实例:自动刷新的计时器
<div id="dateApp">
{{date}}
</div>
<script>
let app = new Vue({
el: '#dateApp',
data: {
date: new Date()
},
mounted: function() {
let _this = this; // this 表示 Vue 实例
this.timer = setInterval(
() => {
_this.date = new Date(); // 每秒刷新1次
}, 1000
)
},
beforeDestroy: function() {
if (this.timer) {
clearInterval(this.timer) // 如定时器存在即销毁
}
}
})
</script>
过滤器
在 {{}}
插值的尾部添加一或多个管道符 |
可对数据进行过滤,常用于格式化文本(字母全部大写、货币千位使用逗号分隔等):
以刚才的计时器为例
{{date | formatDate}}
在 Vue 实例中定义过滤器函数:
let plusDate = function(value) {
return value < 10? '0' + value: value
}
let app = new Vue({
el: '#dateApp',
data: {
date: new Date()
},
filters: {
formatDate: function(value) {
let date = new Date(value); // 将字符串转换为date类型
let year = date.getFullYear();
let month = plusDate(date.getMonth() + 1);
let day = plusDate(date.getDate());
return `{year}-{month}-{day}`
}
}
过滤器中也可以传参数,如 {{date | formatDate(66,99)}}
中 formatDate
的第一个和第二个参数,分别对应过滤器函数的第二个和
第三个参数(第一个参数为 date
)
计算属性
- 在一个计算属性里可以完成复杂的逻辑(运算、函数调用),最终返回一个结果;
- 计算属性还可以依赖多个 Vue 实例的数据,只要其中任一数据变化,计算属性就会重新执行并更新视图;
- 可以为计算属性(默认为 getter )定义 getter 和 setter 方法对属性进行读写;
- 缓存: 不管渲染不渲染,只要计算属性依赖的数据未发生变化,就永远不变(使用计算属性还是
methods
取决于是否需要缓存,当遍历大数组和做大量计算时应当使用计算属性做缓存)。
实例:计算购物车总价
<div id='app'>
{{price}}
</div>
<script>
let app = new Vue({
el: '#app',
data: {
package1: [
{name: 'x', price: 6999, count: 2},
{name: 'y', price: 7999, count: 3}
],
package2: [
{name: 'x', price: 2999, count: 5},
{name: 'y', price: 3999, count: 6}
]
},
computed: {
price: function() {
let price = 0
for (let i = 0; i < this.package1.length; i++) {
price += this.package1[i].price * this.package1[i].count;
}
for (let j = 0; j < this.package2.length; j++) {
price += this.package2[j].price * this.package2[j].count;
}
return price
}
// 计算属性直接跟一个 function,默认是 getter 方法,等价于
/**
price: {
get: function() {
...
}
}
*/
// 也可以定义计算属性的 setter 方法,在外部可以调用:app.price = 'xxx'
/**
price: {
set: function() {
...
}
}
*/
}
})
</script>
监听属性变化
除了使用计算属性 computed
以外,还可以使用 watch
监听单个属性的变化,两者对比:
computed:
<div id="app">
firstName: <input type="text" v-model="firstName">
lastName: <input type="text" v-model="lastName">
<br>
{{ fullName }}
</div>
<script>
let app = new Vue({
el: "#app",
data: {
firstName: "",
lastName: ""
},
computed: {
fullName() {
return `${this.firstName} ${this.lastName}`
}
}
})
</script>
watch:
<div id="app">
firstName: <input type="text" v-model="firstName">
lastName: <input type="text" v-model="lastName">
<br>
{{ fullName }}
</div>
<script>
let app = new Vue({
el: "#app",
data: {
firstName: "",
lastName: "",
fullName: ""
},
watch: {
firstName(val) {
this.fullName = `${val} ${this.lastName}`
},
lastName(val) {
this.fullName = `${this.firstName} ${val}`
}
}
})
</script>
基本指令
指令是 Vue 模板中最常用的一项功能,在 HTML 元素中带有前缀 v-
表示,有助于快速完成 DOM 操作,最常用的几个指令:
-
v-text
:解析文本,和{{ }}
作用一样 -
v-html
:解析html元素 -
v-bind
:动态更新元素上的属性,如 id、class 等,当数据变化时就会重新渲染。 -
v-on
:绑定事件监听器
<div v-bind:class='className'></div>
<button v-on:dbclick='count'></button>
语法糖:指在不影响功能的情况下,添加某种简洁方法实现同样的效果,从而更加方便程序开发:
-
v-bind
=》 : -
v-on
=》 @
v-bind
绑定值:
<div id='app'>
<a v-bind:href="url">baidu</a> <!-- 使用v-bind绑定活的属性 -->
<img :src="imgUrl" alt="">
</div>
<script>
new Vue({
el: "#app",
data: {
url: "http://www.baidu.com"
imgUrl: "https://www.baidu.com/img/bd_logo1.png?where=super"
}
})
</script>
绑定Class(绑定Style同理):
- 给
vbind:class
设置一个对象/数组可以动态地切换 class ,条件复杂时可以使用计算属性 - Vue 中驼峰式命名的大写字母都会被转换成中划线分隔的小写字母(建议统一写驼峰);
<div :class="{divStyle: isActive, borderStyle: isBorder}"></div> <!-- isActive的值为 true 为激活,false 为不激活 -->
<div :class="[activeClass,errorClass]"></div> <!-- 数组中的元素(变量)即为 class 类名 -->
v-cloak
解决初始化慢导致页面闪动的问题,一般与 display: none
结合使用
<style>
[v-cloak]: {
display: none
}
</style>
v-cloak: <p v-cloak:>{{msg}}</p> <!-- Vue 实例结束编译时移除,才会渲染msg -->
<script>
while (true) {
}
new Vue({
el: "#app",
data: {
msg: "Hello World!"
}
})
</script>
v-once
只渲染一次,后续修改不会重新渲染
条件渲染指令:v-if,v-else-if,v-else
-
v-if
、v-else-if
后接等号和必须返回布尔值的条件,满足条件(结果为 True)才渲染,否则会从 DOM 中移除; -
v-if
在渲染元素时出于效率考虑,会尽可能复用已有元素而非重新渲染,所以可能出错(只渲染变化的元素,实例:用户名与密码的 input 框); - 上述问题的解决方法:为元素加上
key=keyName
(使元素有差异而重新渲染)。
条件渲染指令:v-show
- 与
v-if
类似,显现与否取决于布尔值; - 与
v-if
的区别在于v-show
值为 false 时相当于display: none
,页面上仍然存在该元素。
列表渲染指令:v-for
数组遍历或枚举对象属性时可使用 v-for
:
<ul>
<!-- arr: [{name: 'ywh'}, 'name': 'hwy'] -->
<li v-for="item in arr">
{{item.name}}
</li>
<li v-for="(item, index) in arr">
{{index}}-{{i.name}}
</li>
<!-- obj: {name: 'ywh', 'age': 18, gender: 'male'} -->
<li v-for="(value, key, index) in obj">
{{value}}-{{key}}-{{index}}
<li>
<ul>