文章目录
0. 简介
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性。但它支持所有兼容 ECMAScript 5 的浏览器。
1. Hello world
Vue.js 分为开发版本和生产版本,在学习过程中推荐使用开发版本。
可以使用字节跳动的CDN库:
<!-- 开发版本 -->
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<!-- 生产版本 -->
<script src="https://s1.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.min.js"></script>
下面是第一个 Vue 实例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">{{ message }}</div>
<input type="button" value="变换文字" onclick="change_text()">
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'Hello, world!',
}
});
function change_text() {
app.message = '你好,世界!';
}
</script>
</body>
</html>
2. Vue实例
介绍了如何创建一个 Vue 实例,详细内容可参考官方文档。
注:实例化时的 el 参数指定一个标签,该标签及其子标签才可以被渲染。意味着接下来的改动都在这个标签内,不会超出这个范围。
3. 模板语法
Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。
在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。
3.1 插值
3.1.1 文本
使用双大括号的形式进行文本插值。
如 Hello World 中所示,不再赘述。
3.1.2 原始HTML
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,需要使用 v-html 指令:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div>{{ html_text }}</div>
<div v-html="html_text"></div>
</div>
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
html_text: '<span style="color: greenyellow">绿油油的我</span>',
}
});
</script>
</body>
</html>
3.1.3 属性
双大括号语法不能作用于标签的属性,此时应该使用 v-bind 指令:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div v-bind:align="div_align">我会居中哦!</div>
<input type="button" value="居中" onclick="toggle_align()">
</div>
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
div_align: 'left',
}
});
function toggle_align() {
if (app.div_align === 'left') {
app.div_align = 'center';
} else {
app.div_align = 'left';
}
}
</script>
</body>
</html>
对于布尔属性(即只有出现这个属性就意味着其值为 true,如 hidden),设置相应变量的值为 true 或 false 即可。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div v-bind:hidden="is_hidden">我会隐身哦!</div>
<input type="button" value="显示/隐藏" onclick="toggle_hidden()">
</div>
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
is_hidden: false,
}
});
function toggle_hidden() {
app.is_hidden = !app.is_hidden;
}
</script>
</body>
</html>
3.1.4 JS表达式
对于所有数据绑定,都可以使用 JS 表达式,例如:
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
3.2 指令
指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
之后会详细讲解各个指令,以下演示 v-if 指令的用法:
(与 3.1.3 节第二个示例完全相同,仅仅修改了第 9 行)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div v-if="is_hidden">我会隐身哦!</div>
<input type="button" value="显示/隐藏" onclick="toggle_hidden()">
</div>
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
is_hidden: false,
}
});
function toggle_hidden() {
app.is_hidden = !app.is_hidden;
}
</script>
</body>
</html>
3.3 缩写
v-bind 和 v-on 指令可以简写。
3.3.1 v-bind缩写
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
3.3.2 v-on缩写
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
4. 计算属性和侦听器
4.1 计算属性
计算属性,就是将数据绑定到一个函数的返回值。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div>{{ msg }}</div>
<div>{{ reversed_msg }}</div>
</div>
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
msg: '给爷爬',
},
computed: {
// 计算属性的getter
reversed_msg: function () {
// this指向当前Vue实例,即app
return this.msg.split('').reverse().join('');
}
},
});
</script>
</body>
</html>
注:计算属性是有缓存的,计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 msg 还没有发生改变,多次访问 reversed_msg 计算属性会立即返回之前的计算结果,而不必再次执行函数。
4.2 侦听器
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。详细内容可参加官方文档。
5. Class与Style绑定
操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是 attribute,所以我们可以用 v-bind 处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将 v-bind 用于 class 和 style 时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
5.1 绑定class
我们可以传给 v-bind:class 一个对象,以动态地切换 class。常用的做法是绑定一个返回对象的计算属性。请认真体会下面的代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.center {
text-align: center;
}
.red {
color: red;
}
</style>
</head>
<body>
<div id="app">
<div v-bind:class="div_class">给爷爬</div>
<input type="button" value="切换颜色" onclick="toggle_color()">
<input type="button" value="切换居中" onclick="toggle_center()">
</div>
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
red2: false,
center2: false,
},
computed: {
div_class: function () {
return {
red: this.red2,
center: this.center2,
};
}
},
});
function toggle_center() {
app.center2 = !app.center2;
}
function toggle_color() {
app.red2 = !app.red2;
}
</script>
</body>
</html>
5.2 绑定style
使用 v-bind:style,传给它一个 JS 对象,CSS的属性名中有减号,处理的方法有两种,使用驼峰式命名(正如以下示例),或者用引号括起来。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div v-bind:style="{ color: text_color, textAlign: text_align }">给爷爬</div>
<input type="button" value="切换颜色" onclick="toggle_color()">
<input type="button" value="切换居中" onclick="toggle_center()">
</div>
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
text_color: 'red',
text_align: '',
},
});
function toggle_center() {
if (app.text_align === 'center') {
app.text_align = '';
} else {
app.text_align = 'center';
}
}
function toggle_color() {
if (app.text_color === 'red') {
app.text_color = '';
} else {
app.text_color = 'red';
}
}
</script>
</body>
</html>
效果与 5.1 节完全相同。
6. 条件渲染
6.1 v-if
v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值的时候被渲染。
也可以用 v-else 添加一个“else 块”。
如果想切换多个元素,可以使用 template 标签,它是不可见的包裹元素,如果在其上使用 v-if,最终渲染结果将不包含 template 元素。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<template v-if="login_type === 'username'">
<label>用户名:</label>
<input placeholder="请输入用户名">
</template>
<template v-else>
<label>邮箱:</label>
<input placeholder="请输入邮箱">
</template>
<input type="button" value="切换登录方式" onclick="toggle_login()">
</div>
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
login_type: 'username',
},
});
function toggle_login() {
if (app.login_type === 'username') {
app.login_type = 'email';
} else {
app.login_type = 'username';
}
}
</script>
</body>
</html>
6.2 v-show
v-show 与 v-if 的用法大致一样。不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display。v-show 不支持 template 和 v-else。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
7. 列表渲染
7.1 遍历数组
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="fruit in fruits">
{{ fruit }}
</li>
</ul>
</div>
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
fruits: ['苹果', '橘子', '香蕉', '葡萄'],
},
});
</script>
</body>
</html>
v-for 还支持一个可选的第二个参数,即当前项的索引。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="(fruit, index) in fruits">
{{ fruit }} - {{ index }}
</li>
</ul>
</div>
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
fruits: ['苹果', '橘子', '香蕉', '葡萄'],
},
});
</script>
</body>
</html>
7.2 遍历对象
可以遍历一个对象的所有属性,但感觉没什么用。
7.3 遍历整数
例如,遍历 1-10:
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
7.4 排序
如果想显示一个数组经过排序后的版本,但是又不修改原数组,可以创建一个计算属性。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="num in nums">
{{ num }}
</li>
</ul>
<ul>
<li v-for="num in sortedNums">
{{ num }}
</li>
</ul>
</div>
<script src="https://s2.pstatp.com/cdn/expire-1-M/vue/2.6.10/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
nums: [2, 8, 6, 3, 7, 1, 4],
},
computed: {
sortedNums: function () {
let sorted = this.nums.slice();
return sorted.sort();
}
}
});
</script>
</body>
</html>