Vue2 基础使用
约 11762 字大约 39 分钟
2025-04-09
1.Vue 的下载
之后的目录需要调整一下...
1.第一份代码
我们先来根据 Vue 的设计架构编写第一份代码,主要是来了解视图和模型是怎么回事,以及关于 vue.js 的引入安装过程。
<!-- 第一份 Vue 代码 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<!-- 编写视图 -->
<div id="app"> <!-- 这里必须写明对应的 id 来绑定 vue 应用 -->
<h1>{{ message1 + ' ' + message2 }}</h1> <!-- {{}} 可以直接获取模型中的选项数据 -->
<p>{{ method() }}</p> <!-- {{}} 内可以直接调用模型中的选项方法, 一定要带上括号 -->
<input type="text" v-model="message1"> <!-- 可以通过属性的方式来获取数据, 这里的 v-model 实际上被转化为 value -->
<input type="button" v-model="message2">
</div>
<!-- 定义模型 -->
<script>
var data = { message1: 'Hello', message2: 'Vue!' }
var vue = new Vue({ // 每个 vue 应用都需要通过实例化 Vue 来实现, 然后在实现内部加上 Vue 的相关选项
el: '#app', // el 值代表模型对应到 DOM 中的 id 值
data: data, // data 值代表模型中的所有数据
methods: { // methods 值代表模型中的所有方法
method: function() {
return this.message1 + " I'm limou3434!";
}
}
})
</script>
</body>
</html>吐槽:不知道为什么,
<script>标签编写的模型必须写在视图的后面,否则视图无法工作,我猜测是vue.js库是对原有.html进行动态修改的结果,而不是惰性加载...
2.自定属性和保留属性
Vue 允许 var vue= new Vue() 在 data 内自定义属性,但是 vue 本身也有自己的保留属性。保留属性如果需要被其他 JS 代码使用,就需要用 $ 字符起头属性。
<!-- 使用 $ 来区分保留的属性 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="vue_det">
<h1>name : {{name}}</h1>
<h1>url : {{url}}</h1>
<h1>age : {{age}}</h1>
</div>
<script type="text/javascript">
// 我们的数据对象
var data = { name: "limou", url: "www.limou3434.com", age: 18 }
var vm = new Vue({ el: '#vue_det', data: data })
document.write(vm.$data === data) // true
document.write("<br>")
document.write(vm.$data.$name === data.$name) // true
document.write("<br>")
document.write(vm.$el === document.getElementById('vue_det')) // true
</script>
</body>
</html>补充:但是数据本身不需要使用
$,直接使用Vue对象引用即可。
3.响应系统
Vue 的响应式系统是指 vue.js 提供的一套机制,用于追踪数据的变化并自动更新相关的视图。当 Vue 实例中的数据发生变化时,Vue 会自动更新页面上显示的内容,以保持数据和视图的一致性。这种机制使得开发者能够更加专注于业务逻辑,而不需要手动更新 DOM。
<!-- 尝试体验响应系统(从模型到视图的响应) -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<!-- 同时可以看到视图的结果是最后一次数据修改的结果 -->
<div id="vue_det">
<h1>name : {{name}}</h1>
<h1>url : {{url}}</h1>
<h1>age : {{age}}</h1>
</div>
<script type="text/javascript">
var data = { name: "limou", url: "www.limou3434.com", age: 18}
var vue = new Vue({ el: '#vue_det', data: data })
// data 和 vue 引用的数据其实是相同的对象
document.write(vue.name === data.name) // true
document.write("<br>")
// 设置 data 内部数据的会影响到 vue 数据
vue.name = "gimou"
document.write(data.name + "<br>") // gimou
// 设置 vue 内部数据的会影响到 data 数据
data.age = 20
document.write(vue.age) // 20
</script>
</body>
</html><!-- 尝试体验响应系统(从视图到模型的响应) -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<p>{{ message }}</p>
<input v-model="message">
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Runoob!'
}
})
</script>
</body>
</html>补充:
v-model通常用来给input, select, textarea, checkbox, radio等表单控件元素上创建双向数据绑定,同步更新value值和对应模型内的数据值。
上述的响应式,主要是体现在对数据的响应同步上,无论是使用特殊属性(例如 v-model),还是使用模板语法(例如 {{}}),都可以达到对应的效果。
4.模板语法
4.1.数据渲染
Vue 的核心是允许您采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统,而无需使用复杂的 DOM API,而达到这一简化操作的主要工具就是使用模板语法配合响应系统。
- 普通文本,最简单的方法就是直接使用
{{ 数据 }}把数据绑定进去 - 无属性
HTML文本,需要使用标签属性v-html="<x>...</x>"输出HTML代码 - 有属性
HTML文本,需要使用标签属性v-bind:属性="字面值/数据, ..."绑定属性的值(使用属性绑定的时候可以使用v-bind:属性="{'属性值1':字面值/数据1, '属性值2':字面值/数据2, ...}"中的数据值是否为真来控制该属性值是否绑定给标签,若为false则不会绑定该属性(因此也可以借此来编写有多个class属性的标签)。还可以把这些键值对直接作为一个整体,使用模型先存储起来再使用、通过计算方法返回、使用三元表达式、直接内联样式、设置样式对象为一个数据...) JS表达式文本,无需用到什么操作,只需要在{{}}内部直接写JS表达式即可对数据进行操作
<!-- 尝试使用模板语法 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<style>
.myclass { /* 类选择器 */
background: #444;
color: #eee;
}
</style>
<body>
<div id="app"> <!-- 注意 Vue 只允许绑定到唯一的 DOM 元素 -->
<!-- 文本 -->
<p>{{ message1 }}</p>
<!-- 无属性 HTML 文本 -->
<div v-html="message2"></div>
<!-- 有属性 HTML 文本 -->
<label for="r">修改颜色</label><input type="checkbox" v-model="message3" id="r"> <!-- 以防遗忘这里的 for 就是和左边的 id 绑定焦点 -->
<div v-bind:class="{'myclass': message3}">有属性标签</div><br> <!-- 注意上一行的 v-model 是双向绑定的, 因此选项的改动会导则模型也改动, 最终导致这里的 class 属性被设置, class 是 v-bind 的参数 -->
<!-- JS 表达式 -->
{{ message4 ? 'YES' : 'NO' }}<br>
{{ message1.split('').reverse().join('') }}
</div>
<script>
new Vue({
el: '#app',
data: {
message1: '纯文本',
message2: '<h1>无属性标签</h1>',
message3: false,
message4: true
}
})
</script>
</body>
</html>补充:
v-xxx这种属性也被称为 指令,而v-xxx:arg中的arg也被称为指令的 参数。注意,由两个常见的属性需要您注意。
v-on:缩写为@,主要用于监听DOM事件,并在事件触发时执行相应的Vue实例方法或JavaScript表达式v-bind:缩写为:,主要用于动态地绑定HTML元素的属性或者组件而
v-model="xxx"实际上是v-bind:value="xxx"和v-on:input="xxx = $event.target.value"两者的简化,前者负责填入value属性值,后者负责实现数据双向绑定在监听到input事件时将表单控件的值更新到属性值。当用户在
input元素中输入内容时,会触发input事件。这个事件会传递一个事件对象$event,通过$event.target.value可以获取到input元素的当前值。关于
v-on的使用,这里还不是特别频繁,本文章后续将会进行详解和实践...
补充:由于可以通过
v-bind修改标签的属性,因此通过对标签的动态绑定就可以让标签的样式动态修改。
修饰符是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。待补充...
4.2.过滤器
有些时候,有些数据需要遵从一点的格式进行过滤再进行显示,直接使用函数对文本处理又有些繁琐,干脆就使用过滤器来简化一些代码(实际上过滤器本质上也是一种 JS 函数)。
<!-- 尝试使用过滤器 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<p>{{ data1 | currency('€') }}</p>
<p>{{ data2 | capitalize }}</p>
</div>
<script type="text/javascript">
// 我们的数据对象
var vm = new Vue({
el: '#app',
data: {
data1: '18.12',
data2: 'limou'
},
filters: {
currency: function (value, symbol) {
if (isNaN(value)) return ''
let num = parseFloat(value) // 将字符串转换为数字
symbol = symbol || '$' // 检查参数是否传递,若未传递则使用默认值
return symbol + num.toFixed(2) // 保留两位小数并返回
},
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
})
</script>
</body>
</html>补充:
|可以连续多次传递使用,也就是说在一个{{}}中可以有多个|,例如{{ data1 | data2 | data3 }}。
补充:另外过滤器不会影响数据的改变,只会影响数据的拷贝也就是参数的改变(除非在过滤器内部直接把数据改了)。
吐槽:类似的语法糖我第一次应该是
shell的管道符和Cpp较高版本中的管道符,作用也挺类似...
5.渲染控制流
不出意料,控制流也可以使用 v-xxx 的指令来实现,也就是 v-if="", else-if="", v-else-if="", v-for=""。
<!-- 尝试使用控制流 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<button @click="toggleHeader">显示开关</button>
<h2 v-if="showEnable">标题</h2>
<ul v-if="showEnable">
<li v-for="item in items" :key="item.id">
{{ 'id: ' + item.id + ', ' + 'item: ' + item.name }}
</li>
</ul>
<div v-else> <!-- 其实还有一个 v-else-if -->
<p>内容已被隐藏</p>
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
showEnable: true,
items: [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' }
]
},
methods: {
toggleHeader: function () {
this.showEnable = !this.showEnable;
}
}
});
</script>
</body>
</html>补充:
v-show=""可以直接根据布尔值来达到是否显示标签的目的。
补充:
v-for指令还可以获取索引,只需要v-for="(value, index) in values"即可。
补充:还有一种控制流的使用形式就是使用模板。
<!-- 使用模板 --> {{#if ok}} <h1>Yes</h1> {{/if}}
6.对象
6.1.生命周期
Vue 中的生命周期是指一个对象从开始创建到销毁完毕的整个过程。
beforeCreate创建前created创建后beforeMount挂载前mounted挂载后beforeUpdate更新前updated更新后beforeDestroy销毁前destroyed销毁后
这八个阶段之前做好了对应的工作,八个阶段各自到来时,就会触发对应的同名的钩子函数(不过要加上 ()),其中最重要的钩子函数就是 mounted(),因为需要在挂载后请求服务端的数据。

另外,除了这些基本的八个钩子函数,还有一些比较特殊的钩子函数,也是在生命周期阶段时被调用,后面有介绍...
6.2.关键属性
之前我们关顾着快速使用了,关于 new Vue() 中 Vue() 的内部属性还没怎么详细说明,现在重新梳理一下。
4.1.挂载属性(el)
这里的 #app 其实是一个 CSS 选择器,用来定位页面中的某个元素,Vue 实例将会控制这个元素及其内部,您其实有多种选择。
- 使用
id选择器el: '#id'来指定一个标签为挂载点 - 使用
class选择器el: '.class'来指定一个类的所有标签作为挂载点 - 使用属性选择器
el: '[attribute]'来指定一个元素的属性作为挂载点(挂载到第一个具有该属性的元素上) - 使用标签选择器
el: 'tag'可以直接使用HTML标签名作为挂载点 - 使用
DOM元素选择器el: dom可以直接传入一个使用DOM API获取到的DOM元素(变量)作为挂载点 - 使用动态绑定可通过
el: JS变量来动态地指定挂载点(此时的JS变量可以动态修改为上面的任意一种方法)
4.2.数据属性(data)
数据属性也就是 data 属性,内部可以存储 {data1: 1, data2: "str", data3: 3.14} 等 <key, value> 数据,可以通过 {{ key }} 的形式在标签内部直接被访问,也可以通过标签的属性直接填入 "key" 属性值。
注意:不要忘记数据属性是具有
Vue的一个强大特征之一,即响应式特征。
4.3.方法属性(methods)
methods 可以在内部以键值对的形式存储 { func1: function() {}, func2: function() {} } 等 <key, value> 方法,可以被 {{ func1() }} 的形式在标签内部直接被调用,也可以通过标签的属性直接填入 "key" 属性值。
警告:不过值得警惕的是,这种方法属性内的
key直接被调用则会导致方法在渲染完毕后立刻被调用而达不到监视的作用(例如按钮按下事件的触发),这种情况通常使用v-on指令来完成。
注意:同时不要忘记方法可以通过管道符进行串联。
4.4.计算属性(computed)
有一说一,计算属性和方法属性完全类似,但是从理论上计算属性效率可能要高一些。我们完全可以使用 methods 来替代 computed,效果上两个都是一样的,但 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods 在重新渲染的时候,函数总会重新调用执行。另外 computed 属性默认只有 getter,不过在需要时您也可以提供一个 setter。
<!-- 尝试使用监听属性 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<script>
var vue = new Vue({
el: '#app',
data: {
firstName: 'John',
lastName: 'Doe'
},
computed: {
fullName: {
get: function () {
return this.firstName + ' ' + this.lastName;
},
set: function (newValue) {
var names = newValue.split(' ');
this.firstName = names[0];
this.lastName = names[names.length - 1];
}
}
}
});
vue.fullName = 'limou 3434'
document.write('firstName: ' + vue.firstName);
document.write('<br>');
document.write('lastName: ' + vue.lastName);
</script>
</body>
</html>4.5.监听属性(watch)
为了更加方便根据数据的变化自动调用某些方法,Vue 对象内部还有监听属性方法,只要对应的数据发送了变动就会调用属性内对应数据标签的方法。
<!-- 尝试使用监听属性 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id = "app">
千米: <input type = "text" v-model = "kilometers">
米: <input type = "text" v-model = "meters">
</div>
<p id="info"></p>
<script>
var vm = new Vue({
el: '#app',
data: {
kilometers : 0,
meters: 0
},
watch: {
kilometers: function(newVal, oldVal) { // 自动接收当前监测的发生变动的数据的新值和旧值作为参数(也可以只接受一个参数, 默认先接受新值)
if (newVal == oldVal) return
console.log("newVal: " + newVal + ", oldVal: " + oldVal) // 另外这里会打印两次, 因为下一句的修改会导致 meters 被修改调用对应的监听方法
this.meters = this.kilometers * 1000
},
meters: function(newVal, oldVal) {
if (newVal == oldVal) return
this.kilometers = newVal / 1000
}
}
})
// 也可以在实例外部设置监听方法, 和上面的是等价的
vm.$watch('kilometers', function(newValue, oldValue) {
// 这个回调将在 vm.kilometers 改变后调用
document.getElementById("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue
})
</script>
</body>
</html>吐槽:不过我还挺好奇的,这里去掉监听方法内的
if(newVal == oldVal)竟然不会出现循环调用,上述代码中修改了kilometers数据的同时会触发对应的监听方法,而监听方法内部则会修改meters,进而导致调用该数据对应的监听方法。因此理论上来说是会造成循环调用的,但是vue貌似把这个逻辑给做好了,能够判断当newVal和oldVal相等时不会发生循环调用,不过为了健壮性和避免一些意外的情况,我还是对此做了防护...并且比较也无法使用
===来比较相等,这也是我感觉非常疑惑的一点,只能使用==否则日志会被输出两次...
7.事件处理器
7.1.内联 JS 事件
我们之前有提到过,事件处理通常会使用到 v-on 指令,这里来详细展开一下,这里提醒您一句,可以用 @ 简化 v-on 的书写,这里我将大量采用这种写法。
<!-- 尝试使用 v-on 监听事件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<button @click="counter += 1">增加 1</button>
<p>这个按钮被点击了 {{ counter }} 次。</p>
</div>
<script>
new Vue({
el: '#app',
data: {
counter: 0
}
})
</script>
</body>
</html>7.2.调用 JS 事件
上面写法比较简单,只是简单内联 JS 表达式,没有直接调用 JS 函数,但一般需要的都是调用 JS 函数的。
<!-- 尝试使用 v-on 监听事件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<!-- greet 是在下面 Vue 实例中定义的方法名 -->
<button @click="greet">Greet</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
name: 'Vue.js'
},
// 在 methods 属性中直接定义方法
methods: {
greet: function (event) {
alert('Hello ' + this.name + '!')
// event 是原生 DOM 事件的事件对象
if (event) {
alert(event.target.tagName) // 调用提示弹窗, 这将会打印出事件对象就是 BUTTON 自己
}
}
}
})
// 也可以用 JavaScript 直接调用方法(下面两种是等价的)
app.greet() // -> 'Hello Vue.js!'
</script>
</body>
</html>7.3.JS 事件修饰符
Vue 为 v-on 提供了许多事件修饰符来处理 DOM 事件的细节,可以通过由点 . 表示的指令后缀来调用修饰符,修饰符可以在设置好某些细节的情况下更好执行事件。
.prevent阻止默认事件.stop阻止冒泡.capture阻止捕获.self只监听触发该元素的事件.once只触发一次事件,然后事件被移除无法生效.left左键事件.right右键事件.middle中间滚轮事件.keyCode编号限制按键条件,不过由于记住keyCode编号比较困难,因此Vue提供了小写的许多功能按键来替代这一功能
补充:关于事件的传递,为了知识的完整性,这里我也稍微补充一下事件传播的三个阶段。
- 捕获阶段:事件从
document(或者更高层的祖先节点)开始,向目标元素的父节点传递,直到到达目标元素- 目标阶段:事件到达目标元素,即事件的实际触发点
- 冒泡阶段:事件从目标元素开始,向上冒泡,经过目标元素的父节点,直到到达
document(或者更高层的祖先节点)<!-- 演示三个阶段 --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Capture Phase Example</title> <style> .container { padding: 50px; background-color: lightgrey; } .box { padding: 50px; background-color: lightblue; } </style> </head> <body> <div id="app" class="container"> <div class="box" id="box"> Click me </div> </div> <script> // 捕获阶段事件处理器 document.querySelector('.container').addEventListener('click', function() { console.log('Container clicked during capturing phase'); }, true); // true 表示捕获阶段 // 目标阶段事件处理器 document.querySelector('#box').addEventListener('click', function() { console.log('Box clicked'); }, false); // false 表示冒泡阶段 // 冒泡阶段事件处理器 document.querySelector('.container').addEventListener('click', function() { console.log('Container clicked during bubbling phase'); }, false); // false 表示冒泡阶段 </script> </body> </html>
<!-- 尝试使用事件修饰符 .prevent -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<form @submit.prevent="handleSubmit">
<button type="submit">Submit</button>
</form>
</div>
<script>
new Vue({
el: '#app',
methods: {
handleSubmit() {
alert('Form submitted');
}
}
});
</script>
</body>
</html><!-- 尝试使用事件修饰符 .stop -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<button @click.stop="handleClick">Click Me</button>
</div>
<script>
new Vue({
el: '#app',
methods: {
handleClick() {
alert('Button clicked');
}
}
});
</script>
</body>
</html><!-- 尝试使用事件修饰符 .capture -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app" class="container">
<div class="box" @click.capture="handleCaptureClick">
Click me
</div>
</div>
<script>
new Vue({
el: '#app',
methods: {
handleCaptureClick() {
alert('Box clicked during capturing phase');
}
}
});
</script>
</body>
</html>self 没懂,待补充...
<!-- 尝试使用事件修饰符 .once -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<button @click.once="handleOnceClick">Click Me</button>
</div>
<script>
new Vue({
el: '#app',
methods: {
handleOnceClick() {
alert('Clicked once');
}
}
});
</script>
</body>
</html><!-- 尝试使用事件修饰符 .left -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<button @click.left="handleLeftClick">Left Click</button>
</div>
<script>
new Vue({
el: '#app',
methods: {
handleLeftClick() {
alert('Left mouse button clicked');
}
}
});
</script>
</body>
</html><!-- 尝试使用事件修饰符 .right -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<button @contextmenu.right="handleRightClick">Right Click</button>
</div>
<script>
new Vue({
el: '#app',
methods: {
handleRightClick() {
alert('Right mouse button clicked');
}
}
});
</script>
</body>
</html><!-- 尝试使用事件修饰符 .middle -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<button @click.middle="handleMiddleClick">Middle Click</button>
</div>
<script>
new Vue({
el: '#app',
methods: {
handleMiddleClick() {
alert('Middle mouse button clicked');
}
}
});
</script>
</body>
</html><!-- 尝试使用事件修饰符 .keyCode编号 或 .键 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<!--- <input @keyup.13="handleEnterKey" placeholder="Press Enter"> 13 就是 Enter 键的键码 -->
<input @keyup.enter="handleEnterKey" placeholder="Press Enter"> <!-- 13 就是 Enter 键的键码 -->
</div>
<script>
new Vue({
el: '#app',
methods: {
handleEnterKey() {
alert('Enter key pressed');
}
}
});
</script>
</body>
</html>8.表单双向绑定
我们之前有说过 v-model 的双向数据绑定,而准确来说,这种现象是主要是为了表单标签来服务的,因此这里我要细细展开 v-model 和表单的结合使用。
8.1.输入框
<!-- 尝试使用使用 v-model -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<p>input 元素: <input v-model="message1" placeholder="编辑我……"></p>
<p>由于双向数据绑定, 视图更新也会导致模型更新: {{ message1 }}</p>
<p>textarea 元素: <textarea v-model="message2" placeholder="多行文本输入……"></textarea></p>
<p>由于双向数据绑定, 视图更新也会导致模型更新: {{ message2 }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message1: 'limou',
message2: 'gimou'
}
})
</script>
</body>
</html>8.2.复选框
复选框如果是单个则为逻辑值,如果是多个则将 value 绑定到模型中的同个数据数组中。
<!-- 尝试使用使用 v-model -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<p>单个复选框: </p>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
<p>多个复选框: </p>
<input type="checkbox" id="runoob" value="Runoob" v-model="checkedNames"><label for="runoob">Runoob~</label>
<input type="checkbox" id="google" value="Google" v-model="checkedNames"><label for="google">Google~</label>
<input type="checkbox" id="taobao" value="Taobao" v-model="checkedNames"><label for="taobao">taobao~</label>
<br><span>选择的值为 {{ checkedNames }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
checked: false,
checkedNames: []
}
})
</script>
</body>
</html>8.3.单选按钮
单选框直接将 value 绑定为模型中的一个数据。
<!-- 尝试使用使用 v-model -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<input type="radio" id="runoob" value="Runoob" v-model="picked">
<label for="runoob">Runoob~</label>
<br>
<input type="radio" id="google" value="Google" v-model="picked">
<label for="google">Google~</label>
<br>
<span>选中值为: {{ picked }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
picked : 'Runoob'
}
})
</script>
</body>
</html>8.4.下拉列表
下拉列表直接将 value 绑定为模型中的一个数据。
<!-- 尝试使用使用 v-model -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<select v-model="selected" name="fruit">
<option value="">选择搜索引擎</option>
<option value="www.bing.com">Bing</option>
<option value="www.google.com">Google</option>
</select>
<div id="output">
选择的网站是: {{selected}}
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
selected: ''
}
})
</script>
</body>
</html>补充:有几个事件修饰符这里可以补充一下。
.lazy,在默认情况下,v-model在input事件中同步输入框的值与数据,但你可以添加一个修饰符lazy,从而转变为在change事件中同步。<!-- 尝试使用使用 v-model.lazy --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="vue2.js"></script> <!-- 引入 vue2.js 库 --> </head> <body> <div id="app"> <input v-model.lazy="msg" placeholder="输入一些文字"> <p>输入的内容是: {{ msg }}</p> </div> <script> new Vue({ el: '#app', data: { msg: '' } }); </script> </body> </html>
.number,如果想自动将用户的输入值转为Number类型(如果原值的转换结果为NaN则返回原值),可以添加一个修饰符number给v-model来处理输入值。这通常很有用,因为在type="number"时HTML中输入的值也总是会返回字符串类型。<!-- 尝试使用使用 v-model.number --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="vue2.js"></script> <!-- 引入 vue2.js 库 --> </head> <body> <div id="app"> <input v-model.number="numberInput" placeholder="输入一个数字"> <!-- 如果不加上 .number 就会导致就算输入数字也会变成 string 类型 --> <p>输入的数字是: {{ numberInput }}</p> <p>数据类型是: {{ typeof numberInput }}</p> <!-- 这里的 typeof 也是关键字, 可以求出类型 --> </div> <script> new Vue({ el: '#app', data: { numberInput: '' } }); </script> </body> </html>
.trim,如果要自动过滤用户输入的首尾空格,可以添加trim修饰符到v-model上过滤输入。<!-- 尝试使用使用 v-model --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="vue2.js"></script> <!-- 引入 vue2.js 库 --> </head> <body> <div id="app"> <input v-model.trim="textInput" placeholder="输入一些文字(首尾空格会被自动去除)"> <!-- 尝试去掉 .trim 试试 --> <p>输入的内容是: "{{ textInput }}"</p> </div> <script> new Vue({ el: '#app', data: { textInput: '' } }); </script> </body> </html>
9.组件
组件是 Vue 最强大的功能之一,可以扩展 HTML 元素,封装可重用的代码。
组件系统让您可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树。
注册一个组件的语法一般如下,但其实也可以定义在 Vue 实例化对象的内部。
<!-- 注册全局组件语法格式 -->
<script>
Vue.component(tagName, options)
// tagName 为组件名
// options 为配置选项
new Vue({ el:... }
</script>
<tagName>...</tagName> <!-- 注册后可以直接调用该组件: -->其中根 Vue 实例 new Vue({ el:... }) 是父组件,它内部可以创建并且包含子组 tagname,接下来我们来应用一下。
9.1.全局范围子组件
<!-- 尝试使用创建一个全局范围子组件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app1">
<myelemen></myelemen>
</div>
<div id="app2">
<myelemen></myelemen>
</div>
<script>
// 注册全局自定义组件(每个 Vue 实例都可以使用)
Vue.component('myelemen', {
template: '<h1>全局自定义组件</h1>'
})
// 创建 Vue 实例 1
new Vue({
el: '#app1'
})
// 创建 Vue 实例 2
new Vue({
el: '#app2'
})
</script>
</body>
</html>9.2.局部范围子组件
<!-- 尝试使用创建一个全局范围子组件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app1">
<myelemen></myelemen>
</div>
<div id="app2">
<myelemen></myelemen> <!-- app2 内部无法使用 myelemen -->
</div>
<script>
// 定义一个自定义组件
var Child = {
template: '<h1>局部自定义组件</h1>'
}
// 创建 Vue 实例 1
new Vue({
el: '#app1',
components: {
'myelemen': Child
}
})
// 创建 Vue 实例 2
new Vue({
el: '#app2'
})
</script>
</body>
</html>9.3.子组件内部属性
子组件 component(tagName, options) 的 options 内部也有属性,我来给您来讲解一下这些属性的具体含义和用法。
9.3.1.template
我们之前在 template: 属性中存放了 HTML 代码,这就意味着子组件再奇怪,也是由 HTML 的基本组件构成的。用法我们上面已经用过了,这里不再多介绍。
9.3.2.props
还有一个非常重要的数据传输属性 props:。该属性可以把数据从父组件传输给子组件,有两种方式 (1)静态传输 (2)动态传输。通常来讲,使用动态传输的情况会更多一些。
<!-- props 静态传输 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<child mess1="message1: hello limou3434!" mess2="message2: hello limou3434!"></child> <!-- 这里就是利用 mess1 和 mess2 把数据传递给了子组件 -->
</div>
<script>
Vue.component('Child', {
props: ['mess1', 'mess2'],
template: `
<div>
<span>{{ mess1 }}</span><br>
<span>{{ mess2 }}</span>
</div>
`
})
new Vue({
el: '#app'
})
</script>
</body>
</html><!-- props 动态传输 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue2.js"></script> <!-- 引入 vue2.js 库 -->
</head>
<body>
<div id="app">
<!-- 父组件传递用户信息给子组件 -->
<mymodule :name="userName" :age="userAge"></mymodule> <!-- 这里其实就是利用了 v-bind 的特性, 让传输的数据不再手动, 而是取决于 Vue 实例内部的数据 -->
</div>
<script>
// 注册全局子组件 'mymodule'
Vue.component('mymodule', {
// 声明 props 接收父组件传递的数据
props: ['name', 'age'],
// 使用 template 定义组件的模板
template: `
<div>
<h2>User Information</h2>
<p>Name: {{ name }}</p>
<p>Age: {{ age }}</p>
</div>
`
});
// 创建 Vue 根实例
new Vue({
el: '#app',
data: {
userName: 'Alice',
userAge: 30
}
});
</script>
</body>
</html>另外,习惯直接使用 v-model 的一点要注意使用 props 的坑点。prop 是单向绑定的,当父组件的属性变化时,将传导给子组件,但不会反过来传导。
因此如果需要反过来传导就需要定义一些事件。
<!-- 待补充... -->吐槽:关于子组件表单验证,这玩意设计的好蠢,以后再看...
10.指令
10.1.内置的指令
内置的指令有很多,我们之前讲过很多了,这里不在赘述,这里提一下只是为了帮助您构建比较完整的知识体系,顺便帮您复习一下...
10.2.自定义指令
vue 允许您使用 Vue.directive() 自定义属于自己的指令,也有全局和局部之分。
<!-- 尝试使用全局自定义指令 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue Props Validation</title>
<script src="vue2.js"></script>
</head>
<body>
<div id="app1">
<input v-focus>
</div>
<div id="app2">
<input v-focus>
</div>
<script>
// 创建全局指令
Vue.directive('focus', { // 注册一个全局自定义指令 v-focus
inserted: function (el) { // 当绑定指令的元素插入到 DOM 中时
el.value = 'hello' // 填充字符串内容
}
})
// 创建根实例
new Vue({
el: '#app1'
})
new Vue({
el: '#app2'
})
</script>
</body>
</html><!-- 尝试使用局部自定义指令 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue Props Validation</title>
<script src="vue2.js"></script>
</head>
<body>
<div id="app1">
<input v-focus>
</div>
<div id="app2">
<input v-focus> <!-- 这里是无法生效的, 因为下面设置的局部指令只有 id: app1 的元素才能生效 -->
</div>
<script>
// 创建根实例
new Vue({
el: '#app1',
directives: { // 创建局部指令
focus: { // 注册一个局部自定义指令 v-focus
inserted: function (el) { // 当绑定指令的元素插入到 DOM 中时
el.value = 'hello' // 填充字符串内容
}
}
}
})
new Vue({
el: '#app2'
})
</script>
</body>
</html>另外 focus 指令内部的函数是 钩子函数 而不是随便编写的函数,这些函数在特定的生命周期阶段被调用,用于在元素的生命周期内执行特定操作,Vue.js 提供了几个钩子函数来处理指令的不同阶段。
- bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作
- inserted: 被绑定元素插入父节点时调用,父节点存在即可调用,不必存在于
document中 - update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化,通过比较更新前后的绑定值,可以忽略不必要的模板更新
- componentUpdated: 被绑定元素所在模板完成一次更新周期时调用
- unbind: 只调用一次,指令与元素解绑时调用
而钩子函数的参数也有很多,具体如下。
- el: 指令所绑定的元素,可以用来直接操作
DOM - binding: 一个对象,包含以下属性:
- name: 指令名,不包括
v-前缀 - value: 指令的绑定值,例如:
v-my-directive="1 + 1",此时value的值是2 - oldValue: 指令绑定的前一个值,仅在
update和componentUpdated钩子中可用。无论值是否改变都可用 - expression: 绑定值的表达式或变量名。 例如
v-my-directive="1 + 1",expression的值是"1 + 1" - arg: 传给指令的参数。例如
v-my-directive:foo,arg的值是"foo" - modifiers: 一个包含修饰符的对象。例如
v-my-directive.foo.bar,修饰符对象modifiers的值是{ foo: true, bar: true }
- name: 指令名,不包括
- vnode:
Vue编译生成的虚拟节点 - oldVnode: 上一个虚拟节点,仅在
update和componentUpdated钩子中可用
吐槽:这些钩子函数的概念有些多,以后有机会补充...
补充:钩子函数是一种编程概念,用于在特定事件发生时执行自定义代码。它允许开发者在特定事件发生前或发生后插入自定义代码,以实现对系统行为的个性化控制。在
Web开发、桌面应用程序和操作系统中,钩子函数都具有广泛的应用。钩子函数的概念最早出现在操作系统领域,用于在特定系统事件发生时通知应用程序。
11.切换视图/切换路由
11.1.router-link 的使用
Vue.js 路由允许我们通过不同的 URL 访问不同的内容。通过 Vue.js 可以实现多视图的单页 Web 应用(single page web application, SPA),而 Vue.js 路由需要载入 vue-router 库。
<!-- 尝试使用路由设计单页应用 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue Props Validation</title>
<script src="vue2.js"></script>
<script src="vue-router2.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件在单页上进行导航, 通过传入 to 属性指定链接, <router-link> 默认会被渲染成一个 <a> 标签 -->
<router-link to="/foo">Go to Foo</router-link> <!-- 因此这里实际上是 <a href="#/foo">Go to Foo</a> -->
<router-link to="/bar">Go to Bar</router-link> <!-- 因此这里实际上是 <a href="#/bar">Go to Bar</a> -->
</p>
<!-- 路由出口, 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
<script>
// 定义各类组件
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 定义路由映射
const routes = [
{ path: '/foo', component: Foo }, // foo 路由映射到 Foo 组件
{ path: '/bar', component: Bar } // bar 路由映射到 Bar 组件
]
// 设置路由管理
const router = new VueRouter({
routes // 这里采用了简写, 因为只有一个参数要床底, 相当于 routes: routes
})
// 创建并挂载根实例, 注入路由管理(让整个应用都有路由功能)
const app = new Vue({
router
}).$mount('#app')
// 现在应用已经启动成功
</script>
</body>
</html>补充:使用
el:和$mount()挂载Vue实例的区别不大,其挂载的使用过程类似,但是挂载的时机可能不同,el:在new Vue()实例创建时自动挂载到指定的DOM元素。而后者需要在Vue实例创建后调用$mount()方法来手动指定挂载点。前者让代码更简洁,后缀适用于需要在Vue实例创建后动态决定挂载点的场景。
11.2.router-link 的属性
<!-- 尝试使用 router-link 的属性 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue Props Validation</title>
<script src="vue2.js"></script>
<script src="vue-router2.js"></script>
<style>
._active{
background-color : red;
}
</style>
</head>
<body>
<div id="app">
<!-- 字符串设置跳转目标, 当被点击后内部会立刻把 to 的值传到 router.push(), 这个值可以是字符串或者是描述目标位置的对象 -->
<router-link to="/home">Home</router-link>
<br> <!-- 渲染结果 <a href="home">Home</a> -->
<!-- 使用 v-bind 的 JS 表达式设置跳转目标, 这里必须使用 'home' 而不是直接 home, 否则就解析为查找模型中的数据了 -->
<router-link :to="'/blog'">Blog</router-link>
<br>
<!-- 效果同上类似, 设置 replace 属性的话点击时会调用 router.replace() 而不是 router.push(), 跳转后不会留下 history 记录(也就是无法回退网页) -->
<router-link :to="{ path: '/other' }" replace>Other</router-link>
<br>
<!-- 给路由设置了名字来设置跳转目标, 且还传递了路径参数, 并且使用 active-class 可以设置路由触发活动状态后的样式, 这种触发是路径不严格匹配触发, 严格触发可以使用 exact-active-class -->
<router-link :to="{ name: 'LOGIN', params: { userId: 123 }}" active-class="_active">Login</router-link>
<br>
<!-- 字符串设置跳转目标, 且带查询参数 /logout?plan=private, 并且允许使用 tag 来把本标签渲染成其他对应的 HTML 标签, 并且路由效果生效, 并且这里的 event 的值是一个 JS 数组 ['mouseover', 'focus'] 可以让 Vue 解析这个数组并将其传递给组件, 设置后只要获取到鼠标或焦点后就可以触发路由状态 -->
<router-link :to="{ path: '/logout', query: { plan: 'private' }}" tag="li" :event="['mouseover', 'focus']">Logout</router-link>
<br>
<!-- 路由出口, 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
<script>
// 定义各类组件
const MyHome = {template: '<div>--Home--</div>'}
const MyBlog = {template: '<div>--Blog--</div>'}
const MyOthers = {template: '<div>--Others--</div>'}
const MyLogin = {template: '<div>--Login--</div>'}
const MyLogout = {template: '<div>--Logout--</div>'}
// 定义路由映射
const routes = [
{path: '/home', component: MyHome},
{path: '/blog', component: MyBlog},
{path: '/other', component: MyOthers},
{path: '/login/:userId', name: 'LOGIN', component: MyLogin},
{path: '/logout', component: MyLogout}
]
// 设置路由管理
const router = new VueRouter({
routes: routes
})
// 创建并挂载根实例, 注入路由管理(让整个应用都有路由功能)
const app = new Vue({
router
}).$mount('#app')
// 现在应用已经启动成功
</script>
</body>
</html>警告:在
Vue.js路由中,设置path属性时,加/还是不加/是有很大区别的,不加/就会在当前url中直接进行跳转,但是加上/就会从默认的根路由进行跳转。例如上面这个代码,如果不加上/在跳转第四个路由后,跳转其他路由就会有些奇怪(无法跳转),只要观察url就可以看出端倪来...不过这种相对设置可以显示使用router-link的属性append来设置...
12.动画
12.1.过渡效果
Vue.js 动画原理的本质是使用 CSS,需要依赖标签 <transition> 的使用,还有其属性 name 自动生成对应的类名,再根据用户对类选择器的设置,即可快速完成动画设计。生成的类名和对应的动画阶段如下图可以展示出来,我在代码中都有用到。

v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡彻底完成后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效(与此同时v-enter被移除),在过渡/动画完成之后移除。v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡彻底完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效(与此同时v-leave被删除),在过渡/动画完成之后移除。
<!-- 尝试使用过渡 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue Props Validation</title>
<script src="vue2.js"></script>
<style>
/* 可以通过 Vue.js 提供的类来设置动画 */
.fade-enter {
opacity: 0; /* 设置透明度 */
color: red; /* 设置颜色 */
}
.fade-enter-active {
transition: opacity 5s, color 5s; /* 设置透明度和颜色的过渡时间 */
}
.fade-enter-to {
opacity: 1; /* 设置透明度 */
color: blue; /* 设置颜色 */
}
.fade-leave {
opacity: 1; /* 设置透明度 */
color: blue; /* 设置颜色 */
}
.fade-leave-active {
transition: opacity 5s, color 5s; /* 设置透明度和颜色的过渡时间 */
}
.fade-leave-to {
opacity: 0; /* 设置透明度 */
color: green; /* 设置颜色 */
}
</style>
</head>
<body>
<div id="databinding">
<button @click="show = !show">点我</button> <!-- 点击后就会执行 show = !show 这个表达式 -->
<transition name="fade"> <!-- 使用 <transition> 进行包裹就会把 Vue.js 中关于动画的 CSS 类设置应用到这里来 -->
<p v-show="show">动画实例</p> <!-- 根据 show 的结果决定是否显示组件 -->
</transition>
</div>
<script>
var vm = new Vue({
el: '#databinding',
data: {
show: true
}
});
</script>
</body>
</html>12.2.动画效果
高级点的还有 @keyframes 关键帧这种东西的使用,不过如果不是专门的设计师,只需要稍微了解一下就可以。
<!-- 尝试使用动画 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue Props Validation</title>
<script src="vue2.js"></script>
<style>
/* 可以通过 Vue.js 提供的类来设置动画 */
.fade-enter {
opacity: 0; /* 设置透明度 */
color: red; /* 设置颜色 */
}
.fade-enter-active {
transition: opacity 5s, color 5s; /* 设置透明度和颜色的过渡时间 */
animation: bounce-in .5s;
}
.fade-enter-to {
opacity: 1; /* 设置透明度 */
color: blue; /* 设置颜色 */
}
.fade-leave {
opacity: 1; /* 设置透明度 */
color: blue; /* 设置颜色 */
}
.fade-leave-active {
transition: opacity 5s, color 5s; /* 设置透明度和颜色的过渡时间 */
animation: bounce-in .5s reverse;
}
.fade-leave-to {
opacity: 0; /* 设置透明度 */
color: green; /* 设置颜色 */
}
/* @keyframes bounce-in 定义一个名为 bounce-in 的关键帧动画 */
@keyframes bounce-in { /* 设置关键帧 */
0% { /* 0% 动画的起始点, 此时元素的 transform: scale(0), 即元素缩小到0倍, 完全不可见 */
transform: scale(0);
}
50% { /* 50% 动画进行到一半的位置, 此时元素的 transform: scale(1.5), 即元素放大到1.5倍 */
transform: scale(1.5);
}
100% { /* 100% 动画的终点, 此时元素的 transform: scale(1), 即元素恢复到原来的大小 */
transform: scale(1);
}
}
</style>
</head>
<body>
<div id="databinding">
<button @click="show = !show">点我</button> <!-- 点击后就会执行 show = !show 这个表达式 -->
<transition name="fade"> <!-- 使用 <transition> 进行包裹就会把 Vue.js 中关于动画的 CSS 类设置应用到这里来 -->
<p v-show="show">动画实例</p> <!-- 根据 show 的结果决定是否显示组件 -->
</transition>
</div>
<script>
var vm = new Vue({
el: '#databinding',
data: {
show: true
}
});
</script>
</body>
</html>注意:动画设置的
<transition>中属性name很重要,会自动生成对应的类名来帮助类选择器进行动画设置。
13.混入
待补充...
14.Ajax
14.1.原生 Ajax
Ajax 的全称为 Asynchronous JavaScript And XML,也就是异步的 JS 和 XML,并且通过请求得到的服务端数据通常都是 json 数据。其中异步其实是指不需要重新加载整个页面的情况下,就可以实时更新数据,这比一些早期依靠后端模板渲染的网站要更加高效,本质是通过更新部分的网页让渲染更加快速,并且这种方式还可以让用户等待页面的部分内容更新的时候,继续浏览本页面,也提高了用户体验。
吐槽:最典型的体现就是搜索引擎的搜索栏自动更新关键字的补全,但是整个网页无需重新加载。
原生 Ajax 用起来其实也不难,不过有些许繁琐,还有可能出现浏览器兼容的问题。

14.2.axios-Ajax
Vue.js-2.0 版本推荐使用 axios 来完成 ajax 请求,Axios 是一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中。这里我推荐使用服务器进行测试,否则很难理解。
// Cpp 的服务端代码, 用于 Ajax 网络接口测试并且返回响应
$ cat main.cpp
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define PORT 8082
#define BUFFER_SIZE 1024
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = {0};
std::cout << "输入要发送的消息: ";
std::string message;
std::getline(std::cin, message);
const char* message_body = message.c_str();
std::string http_response = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: " + std::to_string(strlen(message_body)) + "\r\n"
"Access-Control-Allow-Origin: *\r\n" // 添加这行代码解决跨域问题
"Connection: close\r\n"
"\r\n" +
std::string(message_body);
// 创建 socket 文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 绑定 socket 到端口
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt failed");
close(server_fd);
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
perror("bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(server_fd, 3) < 0) {
perror("listen failed");
close(server_fd);
exit(EXIT_FAILURE);
}
std::cout << "Server is listening on port " << PORT << std::endl;
while (true) {
// 接受新连接
if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept failed");
close(server_fd);
exit(EXIT_FAILURE);
}
// 读取客户端请求
read(new_socket, buffer, BUFFER_SIZE);
std::cout << "Received request: " << buffer << std::endl;
// 发送HTTP响应
send(new_socket, http_response.c_str(), http_response.length(), 0);
std::cout << "Sent response: " << http_response << std::endl;
// 关闭连接
close(new_socket);
}
return 0;
}<!-- Vue 的客户端代码, 用于对服务端进行请求并且处理响应 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<script src="vue2.js"></script>
<script src="axios.js"></script>
</head>
<body>
<div id="app">
<p>response: {{ response }}</p>
<br><br>
<p>request: {{ request }}</p>
<br><br>
<p>headers: {{ headers }}</p>
<br><br>
<p>data: {{ data }}</p>
<br><br>
<p>message: {{ message }}</p>
<br><br>
<p>status: {{ status }}</p>
<br><br>
<p>statusText: {{ statusText }}</p>
<br><br>
<p>config: {{ config }}</p>
</div>
<script>
new Vue({
el: '#app',
data () {
return {
request: null,
response: null,
headers: null,
data: null,
message: null,
status: null,
statusText: null,
config: null
}
},
mounted () {
axios
.post('http://47.121.195.60:8082/'/* , 可以在这里加上请求参数 */) // 请求方法以及对应的网络接口
// .then(response => (this.response = response)) // 接着处理响应, 这里使用的是 Lambda 表达式, this.response 就是上面定义的模型数据
.then(function(response) { // 这种调用方式也很常见
this.response = response
this.request = response.request
this.data = response.data
this.message = response.data.message // 这里的 messgae 是对端 JSON 中的键名
this.status = response.status
this.statusText = response.statusText
this.config = response.config
}.bind(this)) // 绑定 this 到 Vue 实例
.catch(function (error) { // 请求失败处理
console.log(error);
});
/* 箭头函数会继承外部函数的 this, 但普通函数 的 this 在函数调用时才确定 */
}
})
</script>
</body>
</html>这一部分虽然重要,但是比较简单,以后再补充。
补充:看到上面的
mounted没?就是之前提到的钩子函数,这会导致组件渲染完毕后就会进行异步请求,也可以被JS函数包装起来,例如function function_name() {axios({method: "http方法", url:"..."}).then(...).catch(...);}。
补充资料 https://www.runoob.com/vue2/vuejs-ajax-axios.html 待补充...
14.3.vue-resource-Ajax
该学习 axios 还是 vue-resource?首先要明确两者都是 JS 的网络框架,一般我们推荐使用前者,因为生态更好,使用更加广泛。
- axios: 是一个独立的
HTTP客户端库,不依赖于Vue.js,因此可以在任何JS环境。本身是基于Promise的,适用于现代JS开发。并且,axios 的社区支持和维护更为活跃。 - vue-resource: 是专门为
Vue.js开发的HTTP客户端库,早期Vue.js项目中比较常用,但Vue官方团队后来推荐使用axios,最终导致vue-resource的维护和社区支持相对较弱。
因此如果有需要再去进行学习...
15.响应接口
待补充...
结语:...