通过本文,读者可以掌握以下的相关技能:
Vue
的 基本用法
Vue
的 模板语法
Vue
的 常用特性
Vue
实现 案例效果
优秀的一款 国产
框架,接下来我们就满怀敬意的去了解一下 Vue
的作者。
尤雨溪
,著名渐进式 JavaScript
框架 vuejs.org
的创造者,饱含我们程序员的特有气质 。Vue
(读音 /vjuː/,类似于 view) 是一套用于构建用户界面的 渐进式框架
(声明式渲染–>组件系统–>客户端路由–>集中式状态管理–>项目构建)。与其它大型框架不同的是,Vue
被设计为可以自底向上逐层应用。Vue
的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与 现代化的工具链 以及各种 支持类库 结合使用时,Vue
也完全能够为复杂的单页应用提供驱动。看看下面这张漂亮的 Logo.
Vue官网
特点:
接下来和笔者开始 Vue
的基本使用,无论我们学习什么框架,一般都是从最简单的一个案例 (Hello World)
入手,即在页面上显示输出一句 Hello World
,案例虽然简单,但是有句话是这么说的 麻雀虽小,五脏俱全.
接下来我们通过这个简单的案例去熟悉 Vue
的基本语法步骤和代码整体的语法结构,另外可以先用传统的方式去实现,接着用 Vue
去重构,体会会更加深刻一点。原生 JS
实现如下图所示:
jQuery
实现如下图所示:
因为考虑到有些读者不会使用 ES6
,所以本文会在某些地方采取ES5
的写法。尽管 jQuery
已经大大地提高了我们的编程体验,但是程序员嘛,对吧就是 懒.
所以才有了更加高级的框架诞生,接下来请读者穿上你的滑板鞋,跟着笔者在 Vue
知识的海洋里,摩擦摩擦又摩擦。使用 Vue
开发 Hello World
的基本步骤如下:
完整的使用 Vue
将 HelloWorld
渲染到页面上示例代码如下:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue之Hello Worldtitle>
head>
<body>
<div id="app">
<div>{{msg}}div>
<div>{{1+2}}div>
<div>{{"Amo " + "So " + "Cool~~~"}}div>
div>
body>
html>
<script src="js/vue.js">script>
<script>
let vm = new Vue({
el: "#app", // el: 元素的挂载位置(值可以是CSS选择器或者DOM元素)
data: { // data: 模型数据(值是一个对象)
msg: "Hello World"
}
});
script>
在学习模板语法之前,我们需要对 前端渲染
有一定的了解。前端渲染
:把数据填充到HTML标签中。如下图所示:
前端渲染
的方式大致有以下几种:
js
拼接字符串 基本上就是将数据以字符串的方式拼接到HTML标签中,前端代码风格大体上如下图所示。缺点
: 不同开发人员的代码风格差别很大,随着业务的复杂,后期的维护变得逐渐困难起来。art-template
的一段代码,与拼接字符串相比,代码明显规范了很多, 它拥有自己的一套模板语法规则。优点
: 大家都遵循同样的规则写代码,代码可读性明显提高了,方便后期的维护。 缺点
: 没有专门提供事件机制。Vue
特有的模板语法:
指令的本质就是 自定义属性
,指令的格式:以 v-
开始(如v-cloak)
v-text
指令用于将数据填充到标签中,作用于插值表达式类似,但是没有闪动问题。如果数据中有 HTML
标签会将 HTML
标签一并输出(即填充纯文本)。注意
:此处为单向绑定,数据对象上的值改变,插值会发生变化,但是当插值发生变化并不会影响数据对象的值。示例代码如下:v-html
用法和 v-text
相似,但是它可以将 HTML
片段填充到标签中。在网站上动态渲染任意 HTML
是非常危险的,因为容易导致 XSS 攻击。只在可信内容上使用 v-html
,永不用在用户提交的内容上。它与 v-text
区别在于 v-text
输出的是纯文本,浏览器不会对其再进行 HTML
解析,但 v-html
会将其当 HTML
标签解析后输出。示例代码如下:v-pre
显示原始信息跳过编译过程,跳过这个元素和它的子元素的编译过程。一些静态的内容不需要编译加这个指令可以加快渲染。示例代码如下:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据填充的三个指令title>
head>
<body>
<div id="app">
<div>{{msg}}div>
<div v-text="msg1">div>
<div v-html="msg1">div>
<div>{{msg}}div>
<div v-pre>{{msg}}div>
div>
body>
html>
<script src="js/vue.js">script>
<script>
let vm = new Vue({
el: "#app",
data: {
msg: "amo so cool~~~
",
msg1: "amo so cool~~~
"
}
});
script>
在学习 v-once
之前,我们需要了解一下数据的响应式。那么如何理解数据的响应式呢? HTML5
中的响应式(屏幕尺寸的变化导致样式的变化) 。数据
的响应式(数据的变化导致页面内容的变化)。数据绑定指的是将数据填充到标签中,例如在 4.1.2
中学习的三个指令,v-once
只编译一次,显示内容之后不再具有响应式功能。示例代码如下:
即 v-once
执行 一次性
的插值,当数据改变时,插值处的内容不会继续更新。视频讲解如下:
v-once指令讲解
什么是双向数据绑定? 如下图所示:
双向数据绑定分析,需要使用到 v-model
指令,用法如下:
关于双向数据绑定,还有一个非常重要的概念与之相关,其实就是所谓的 MVVM
设计思想,也是 Vue
比较核心的思想。简单理解是 分而治之
,就是将不同功能的代码放到不同的模块中,在以特定的方式让它们建立起关联。如下图所示:
Vue
如何处理事件? 语法格式如下:
<input type="button" v-on:click="num++" value="点击">
<input type="button" @click="num++" value="点击1">
事件函数的调用方式,如下:
<input type="button" @click="handle1" value="点击2">
<input type="button" @click="handle1()" value="点击3">
完整示例代码如下:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件基本用法title>
head>
<body>
<div id="app">
<div>{{num}}div>
<input type="button" v-on:click="num++" value="点击">
<input type="button" @click="num++" value="点击1">
<input type="button" @click="handle1" value="点击2">
<input type="button" @click="handle1()" value="点击3">
div>
body>
html>
<script src="js/vue.js">script>
<script>
let vm = new Vue({
el: "#app",
data: {
num: 0
},
methods: {
handle1: function() {
//注意这里要写上this 否则是没有效果的
this.num++;
}
}
});
script>
事件函数参数传递,普通参数和事件对象,示例代码如下:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件函数传参title>
head>
<body>
<div id="app">
<div>{{num}}div>
<button @click="handle1">传参1button>
<button @click="handle2(1,2,3,$event)">传参2button>
div>
body>
html>
<script src="js/vue.js">script>
<script>
let vm = new Vue({
el: "#app",
data: {
num: 0
},
methods: {
handle1: function(event) {
this.num++;
//输出打印标签名字
console.log(event.target.tagName);
//输出标签中的内容
console.log(event.target.innerHTML);
},
handle2: function(p, p1, p2, event) {
console.log(p, p1, p2);
console.log(event.target.tagName);
}
}
});
script>
在事件处理程序中调用 event.preventDefault()
或 event.stopPropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM
事件细节。
为了解决这个问题,Vue.js
为 v-on
提供了事件修饰符。修饰符是由点开头的指令后缀来表示的。
<a v-on:click.stop="doThis">a>
<form v-on:submit.prevent="onSubmit">form>
<a v-on:click.stop.prevent="doThat">a>
<form v-on:submit.prevent>form>
<div v-on:click.capture="doThis">...div>
使用修饰符时,顺序很重要,相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self
会阻止所有的点击,而 v-on:click.self.prevent
只会阻止对元素自身的点击。在 2.1.4
中新增了:
<a v-on:click.once="doThis">a>
不像其它只能对原生的 DOM
事件起作用的修饰符,.once
修饰符还能被用到自定义的组件事件上。
按键修饰符: 在监听键盘事件时,我们经常需要检查详细的按键。Vue
允许为 v-on
在监听键盘事件时添加按键修饰符:
<input v-on:keyup.enter="submit">
你可以直接将 KeyboardEvent.key
暴露的任意有效按键名转换为 kebab-case
来作为修饰符。
<input v-on:keyup.page-down="onPageDown">
在上述示例中,处理函数只会在 $event.key
等于 PageDown
时被调用。使用 keyCode attribute
也是允许的:
<input v-on:keyup.13="submit">
keyCode
的事件用法已经被废弃了并可能不会被最新的浏览器支持。为了在必要的情况下支持旧浏览器,Vue
提供了绝大多数常用的按键码的别名:
删除
和 退格
键)有一些按键 (.esc
以及所有的方向键) 在 IE9
中有不同的 key
值, 如果你想支持 IE9
,这些内置的别名应该是首选。 你还可以通过全局 config.keyCodes
对象 自定义按键修饰符别名
:
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
按键修饰符的案例如下:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>按键修饰符title>
head>
<body>
<div id="app">
<form action="">
<div>
用户名:
<input type="text" v-model="uname" v-on:keyup.delete="clearContent">
div>
<div>
密码:
<input type="text" v-model="upsd" v-on:keyup.enter="handleSubmit">
div>
<div>
<input type="button" value="提交" v-on:click="handleSubmit">
div>
<div>
<input type="text" v-on:keyup="handle">
div>
form>
div>
body>
html>
<script src="js/vue.js">script>
<script>
Vue.config.keyCodes.aaa = 13; //自定义键位别名
let vm = new Vue({
el: "#app",
data: {
uname: "",
upsd: ""
},
methods: {
//按delete键位的时候 清空用户名
clearContent: function() {
this.uname = "";
},
handleSubmit: function() {
console.log(this.uname, this.upsd);
},
handle: function(event) {
console.log(event.keyCode);
}
}
});
script>
在学习了上面的知识之后,我们可以去做一个关于加法计算器的小案例,请看下面视频讲解:
加法计算器小案例.mp4
HTML
中监听事件? 你可能注意到这种事件监听的方式违背了关注点分离(separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的
Vue.js
事件处理方法和表达式都严格绑定在当前视图的
ViewModel
上,它不会导致任何维护上的困难。实际上,使用
v-on
有几个好处:
HTML
模板便能轻松定位在 JavaScript
代码里对应的方法。JavaScript
里手动绑定事件,你的 ViewModel
代码可以是非常纯粹的逻辑,和 DOM
完全解耦,更易于测试。ViewModel
被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。基本用法: 如绑定 a
标签中的 href
属性,通过点击 button
切换 url
的地址,实现不同的跳转,示例代码如下:
在学习了基本的属性绑定使用之后,我们大致就能够知道 v-model
的实现原理了,html
结构如下:
<body>
<div id="app">
<div>
<div>{{msg}}div>
<input type="text" v-bind:value="msg" v-on:input="handle">
<input type="text" v-bind:value="msg" v-on:input="msg=$event.target.value">
<input type="text" v-model="msg">
div>
div>
body>
js
代码如下:
<script src="js/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
msg: "HelloWorld"
},
methods: {
handle: function(event) {
//使用输入域中最新的数据覆盖原来的数据
this.msg = event.target.value;
}
}
});
</script>
操作元素的 class
列表和 内联样式
是数据绑定的一个常见需求。因为它们都是 attribute
,所以我们可以用 v-bind
处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将 v-bind
用于 class
和 style
时,Vue.js
做了专门的增强。表达式结果的类型除了字符串之外,还可以是 对象
或 数组
。
对象语法: 我们可以传给 v-bind:class
一个对象,以动态地切换 class
:
<div v-bind:class="{ active: isActive }">div>
你可以在对象中传入更多字段来动态切换多个 class
。此外,v-bind:class
指令也可以与普通的 class attribute
共存。当有如下模板:
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
>div>
和如下 data
:
data: {
isActive: true,
hasError: false
}
结果渲染为:
<div class="static active">div>
当 isActive
或者 hasError
变化时,class
列表将相应地更新。例如,如果 hasError
的值为 true
,class
列表将变为 "static active text-danger"
。绑定的数据对象不必内联定义在模板里:
渲染的结果和上面一样。
数组语法:我们可以把一个数组传给 v-bind:class
,以应用一个 class
列表:
渲染为:
<div class="active text-danger">div>
如果你也想根据条件切换列表中的 class
,可以用三元表达式:
<div v-bind:class="[isActive ? activeClass : '', errorClass]">div>
这样写将始终添加 errorClass
,但是只有在 isActive
是 truthy
时才添加 activeClass
。不过,当有多个条件 class
时这样写有些繁琐。所以在数组语法中也可以使用对象语法:
<div v-bind:class="[{ active: isActive }, errorClass]">div>
v-bind:style
的对象语法十分直观——看着非常像 CSS
,但其实是一个 JavaScript
对象。CSS property
名可以用 驼峰式
(camelCase) 或 短横线
分隔 (kebab-case,记得用引号
括起来) 来命名:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">div>
data: {
activeColor: 'red',
fontSize: 30
}
直接绑定到一个样式对象通常更好,这会让模板更清晰:
<div v-bind:style="styleObject">div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
v-bind:style
的数组语法可以将多个样式对象应用到同一个元素上:
<div v-bind:style="[baseStyles, overridingStyles]">div>
当 v-bind:style
使用需要添加浏览器引擎前缀的 CSS property
时,如 transform
,Vue.js
会自动侦测并添加相应的前缀。
v-if
指令用于 条件性
地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。示例代码如下:
因为 v-if
是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 元素当做不可见的包裹元素,并在上面使用
v-if
。最终的渲染结果将不包含 元素。
html
结构如下所示:
<template v-if="ok">
<h1>Titleh1>
<p>Paragraph 1p>
<p>Paragraph 2p>
template>
js
代码如下:
<script src="js/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
ok: true
}
});
</script>
v-else-if
,顾名思义,充当 v-if
的 else-if 块
,可以连续使用,html
结构如下所示:
<div id="app">
<div v-if="score>90">优秀div>
<div v-else-if="score>80&&score<=90">良好div>
<div v-else-if="score>70&&score<=80">一般div>
div>
js
代码如下:
<script src="js/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
score: 73
}
});
</script>
也可以用 v-else
添加一个 else 块
,v-else
元素必须紧跟在带 v-if
或者 v-else-if
的元素的后面,否则它将不会被识别。如下所示:
Vue
会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue
变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:
<template v-if="loginType === 'username'">
<label>Usernamelabel>
<input placeholder="Enter your username">
template>
<template v-else>
<label>Emaillabel>
<input placeholder="Enter your email address">
template>
br>
<button v-on:click="handle0">Toggle login typebutton>
js
代码如下:
<script src="js/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
loginType: "username",
},
methods: {
handle0: function() {
this.loginType = (this.loginType) ? "" : "username";
}
}
});
</script>
这样也不总是符合实际需求,所以 Vue
为你提供了一种方式来表达 这两个元素是完全独立的,不要复用它们
。只需添加一个具有唯一值的 key attribute
即可:
注意, 元素仍然会被高效地复用,因为它们没有添加
key attribute
。另一个用于根据条件展示元素的选项是 v-show
指令。用法大致一样:
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM
中。v-show
只是简单地切换元素的 CSS property display
。
v-if
是 真正
的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。v-if
也是 惰性 的:如果在初始渲染时条件为假,则什么也不做—直到条件第一次变为真时,才会开始渲染条件块。v-show
就简单得多–不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS
进行切换。v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好。如果在运行时条件很少改变,则使用 v-if
较好。我们可以用 v-for
指令基于一个数组来渲染一个列表。v-for
指令需要使用 item in items
形式的特殊语法,其中 items
是源数据数组,而 item
则是被迭代的数组元素的别名。html
示例代码如下:
<body>
<ul id="example-1">
<li v-for="item in items" :key="item.message">
{{ item.message }}
li>
ul>
body>
js
示例代码如下:
<script src="js/vue.js"></script>
<script>
let example1 = new Vue({
el: '#example-1',
data: {
items: [{
message: 'Foo'
}, {
message: 'Bar'
}]
}
})
</script>
结果如下:
在 v-for
块中,我们可以访问所有父作用域的 property
。v-for
还支持一个可选的第二个参数,即当前项的索引。html
示例代码如下:
<body>
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
li>
ul>
body>
js
示例代码如下:
<script src="js/vue.js"></script>
<script>
let example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [{
message: 'Foo'
}, {
message: 'Bar'
}]
}
})
</script>
结果如下:
你也可以用 of
替代 in
作为分隔符,因为它更接近 JavaScript 迭代器
的语法:
你也可以用 v-for
来遍历一个对象的 property
。html
示例代码如下:
<body>
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
li>
ul>
body>
js
示例代码如下:
<script src="js/vue.js"></script>
<script>
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'Vue全家桶之Vue基础',
author: 'Amo',
publishedAt: '2020-05-23 20:20:15'
}
}
})
</script>
结果如下:
你也可以提供第二个的参数为 property
名称 (也就是键名):
结果如下:
还可以用第三个参数作为索引:
结果如下:
为了给 Vue
一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute
:
<div v-for="item in items" v-bind:key="item.id">
div>
建议尽可能在使用 v-for
时提供 key attribute
,除非遍历输出的 DOM
内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。因为它是 Vue
识别节点的一个通用机制,key
并不仅与 v-for
特别关联。不要使用对象或数组之类的非基本类型值作为 v-for
的 key
。请用字符串或数值类型的值。
v-for
与 v-if
一同使用(注意我们不推荐在同一元素上使用 v-if
和 v-for
),当它们处于同一节点,v-for
的优先级比 v-if
更高,这意味着 v-if
将分别重复运行于每个 v-for
循环中。当你只想为部分项渲染节点时,这种优先级的机制会十分有用,如下:
上面的代码将只渲染数据等于18的。
UI
效果UI
效果Vue模板语法
的形式js
控制逻辑<script src="js/vue.js"></script>
<script>
let vm = new Vue({
el: ".tab",
data: {
currentIndex: 0,
list: [{
id: 1,
title: "陈瑶",
path: "images/陈瑶.jpeg"
}, {
id: 2,
title: "宋妍霏",
path: "images/宋妍霏.jpeg"
}, {
id: 3,
title: "林允儿",
path: "images/林允儿.jpeg"
}, {
id: 4,
title: "李智恩",
path: "images/李智恩.jpg"
}, {
id: 5,
title: "迪丽热巴",
path: "images/迪丽热巴.jpeg"
}, ]
},
methods: {
change: function(index) {
this.currentIndex = index;
}
}
});
</script>