Vue.js
1. 什么是Vue
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。
官方链接: https://cn.vuejs.org
渐进式框架
没有大型框架的强制要求,可以只是用Vue的核心内容。
可以与其他的前端框架的混用。
学习可以循序渐进的学习。
1.1 Vue特点
- 易用:了解关于 HTML、CSS 和 JavaScript 的中级知识,能够完成基础的前端开发。
- 灵活:不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。
- 高效:20kB min+gzip 运行大小,超快虚拟 DOM,最省心的优化。
1.2 什么是MVVM模式(熟记 面试有可能问到)
Vue.js采用的是MVVM模式(Model-view-viewmodel),其中Model为模型(我们在JS中操作的数据),view为视图(也就是我们看到的界面),viewmodel为控制器,它的出现,将模型与视图分离开,两者只能通过该控制器间接通信。
在该模式下,当数据也就是模型发生改变的时候,控制器就会接到通知,然后告知视图,实现同步数据刷新。
1.3 MVVM模式与MVC模式的对比(熟记 面试有可能问到)
MVC
- Model-模型:我们通过JS操作的数据
- View-视图:我们看到的页面
- Control-控制器:用于处理用户的请求,将指定数据手动渲染到指定页面的DOM节点
MVVM
- Model-模型:我们通过JS操作的数据
- View-视图:我们看到的页面
- ViewModel:用于处理请求的数据,将数据自动渲染到指定页面的DOM节点
2. 基础的使用
2.1 环境搭建(熟记)
开发版本(包含完整的警告和调试模式):https://cn.vuejs.org/js/vue.js
生产版本(删除了警告,33.30KB min+gzip):https://cn.vuejs.org/js/vue.js
引入框架:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>引入Vue.js</title>
</head>
<body>
<!-- 引入Vue.js 框架 -->
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
</body>
</html>
2.2 Vue实例(熟记)
注意事项:
一个 Vue 应用由一个通过 newVue 创建的根 Vue 实例
2.2.1 创建Vue实例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>创建vue实例</title>
</head>
<body>
<div id="app">
<h1>{{message}}</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
let vm = new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
});
</script>
</body>
</html>
Vue实例中的data数据是响应式的,当我们通过控制台修改message数据值的时候,可以看到视图立即更新
2.2.2 实例初始值的绑定
如果希望Vue中的数据能够与视图响应式更新,那么数据需要先给出初始值
没有给初始值,对应数据改变不会即时响应
如果初始不需要,晚些时候需要用到某个属性,那么初始值为空或不存在
let vm = new Vue({
el: '#app',
data: {
txt: '', //String初始值
count: 0, //number初始值
isSuccess: false, //boolean初始值
list: [], //array初始值
obj: {}, //object初始值
other: null, //其它初始值
}
});
3. Vue实例生命周期钩子(简单记忆)
在vue对象从创建到销毁过程的每一个状态都会提供一个函数,便于外界根据需求加入适当的处理代码。(个人参考翻译,非标准)
参考链接: https://cn.vuejs.org/v2/guide/instance.html#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%9B%BE%E7%A4%BA
官网看生命周期
- 创建对象
- 对象创建前 - beforeCreate
- 初始化事件,数据还没有进行双向绑定
- 执行后,进行属性的注入和响应式双向绑定 - 执行created钩子函数
- 对象创建后 - created
- 可以访问配置的data属性对象 $data已存在
- 此时页面元素还没有进行挂载 $el 不存在
- 元素挂载
- 元素挂载前 - beforeMount
- 检查配置对象中是否有 el 属性(如果没有,那么等待调用vm.$mount(el)手动挂在时,再执行后续逻辑)
- 检查配置对象中是否 template 属性
- 如果有template属性,就把template中的内容编译到render函数中渲染
- 如果没有template,就把 el 中的内容作为 template编译
- 此时 this.$el 已存在,但页面数据并没有渲染
- 此钩子函数结束后,立即执行使用 $el 渲染显示数据并替换掉 el
- 元素挂载后 - mounted
- 此时页面的内容,已经渲染完成
- $el元素的对象已经挂载到DOM结构中
- 数据更新
- 数据更新前 - beforeUpdate
- 数据已修改,但是页面内容还没有修改
- 数据更新后 - updated
- 此时页面一定已修改
- 对象销毁
- 对象销毁前 - beforeDestory
- 对象销毁后 - destoryed
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>vue生命周期钩子</title>
</head>
<body>
<div id="app">
<h1>{{message}}</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例(但是一开始不挂载)
let vm = new Vue({
data: {
message: 'Hello,Vue.js!'
}
});
//延迟2秒之后,再挂载
setTimeout(() => {
vm.$mount('#app');
},2000);
</script>
</body>
</html>
4. 模板语法(熟记)
参考链接: https://cn.vuejs.org/v2/guide/syntax.html
使用Vue的模板,在渲染时Vue会自动计算渲染的组件个数,最少的DOM操作次数
4.1 文本
Vue使用“Mustache”语法(即双大括号),将数据解释为普通文本
<h1>{{message}}</h1>
通过v-once可以使得数据只执行一次插值,以后将不再更新(用的较少)
<h1 v-once>{{message}}</h1>
4.2 原始HTML渲染
使用v-html将数据解释为html内容
这种操作方式是非常危险的,它***很容易导致 XSS 攻击***,绝对不要对用户提供的内容使用插值
<div v-html="htmlContent"></div>
4.3 attribute属性绑定
Mustache 语法不能作用在 HTML attribute 上,我们需要用v-bind指令
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>vue模板语法-attribute</title>
</head>
<body>
<div id="app">
<form action="" method="post">
<div>
<label>
<span>用户编号:</span>
<input type="text" name="id" v-bind:value="userId" disabled />
</label>
</div>
<div>
<label>
<span>姓名:</span>
<input type="text" name="name" placeholder="请输入姓名" />
</label>
</div>
<input type="submit" v-bind:disabled="isDisabled" value="提交" />
</form>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
userId: 10000,
isDisabled: true
}
});
//给姓名输入框绑定输入事件
document.querySelector('input[name="name"]').addEventListener('input',e => {
vm.isDisabled = e.target.value === "";
});
</script>
</body>
</html>
如果属性是布尔形式,当值为null、undefined或false,那么对应的属性甚至不会包含在元素中
4.4 使用表达式
模板语法只支持表达式,不支持语句、方法等
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>vue模板语法-使用表达式</title>
</head>
<body>
<div id="app">
<input type="text" placeholder="请输入您的年龄" />
<h1>{{age >= 18 ? '你可以进去上网了!' : '未成年人,禁止进入!'}}</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
age: 0
}
});
//给姓名输入框绑定输入事件
document.querySelector('input').addEventListener('input',e => {
vm.age = e.target.value;
});
</script>
</body>
</html>
4.5 指令与参数
4.5.1 概念
指令是带有 v- 前缀的特殊 attribute,例如v-bind。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
一些指令能够接收一个“参数”,在指令名称之后以冒号表示
以下代码表示:告知v-bind
指令将该元素的href属性与bdSrc表达式的值绑定
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>vue模板语法-指令概念</title>
</head>
<body>
<div id="app">
<a v-bind:href="bdSrc">跳转至百度搜索</a>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
bdSrc: 'http://www.baidu.com'
}
});
</script>
</body>
</html>
4.5.2 动态参数
从2.6.0 开始,可以使用方括号
[]
括起来的JavaScript表达式作为一个指令的参数(需要注意,动态参数必须全部小写)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>vue模板语法-动态参数</title>
</head>
<body>
<div id="app">
<a v-bind:[attrname]="bdSrc">跳转至百度搜索</a>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
attrname: 'href',
bdSrc: 'http://www.baidu.com'
}
});
</script>
</body>
</html>
4.5.3 指令缩写
Vue提供了
v-bind
前缀的语法糖缩写形式
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>vue模板语法-指令缩写</title>
</head>
<body>
<div id="app">
<a v-bind:href="bdSrc">完整语法</a>
<a :href="bdSrc">语法糖缩写</a>
<a :[attrname]="bdSrc">动态参数语法糖缩写</a>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
attrname: 'href',
bdSrc: 'http://www.baidu.com'
}
});
</script>
</body>
</html>
5. 计算属性(熟记)
参考链接: https://cn.vuejs.org/v2/guide/computed.html
使用表达式来进行一些数据的简单处理,但是当表达式过于复杂的时候,就违背了“简单”这个初衷了
Vue为我们提供了计算属性的方式,将复杂的表达式剥离出来
5.1 基本用法
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>vue计算属性</title>
</head>
<body>
<div id="app">
<h1>{{reverseMessage}}</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
message: 'Hello World'
},
computed: {
reverseMessage: function () {
return this.message.split('').reverse().join('');
}
}
});
</script>
</body>
</html>
5.2 计算属性的setter(了解)
默认情况下只有getter,也可以提供一个setter
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
name: '张三',
content: '感谢关注老九公众号!'
},
computed: {
welcome: {
get: function () {
return `${this.name}同学,${this.content}`;
},
set: function (newValue) {
this.content = newValue;
}
}
}
});
6. 实例中的方法(熟记)
在实例中定义方法,我们需要用到methods
注意调用方法的时候,需要在后面加
()
6.1 基本用法
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>vue实例中的方法</title>
</head>
<body>
<div id="app">
<h1>{{reverseMessage()}}</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
message: 'Hello World'
},
methods: {
reverseMessage: function () {
return this.message.split('').reverse().join('');
}
}
});
</script>
</body>
</html>
6.2 计算属性与方法的区别(熟记 面试经常会问到)
计算属性:
- 是基于它们的响应式依赖进行缓存的,只在相关响应式依赖发生改变时它们才会重新求值。意味着只要数据没有发生改变,那么多次访问计算属性,它会立即返回之前的计算结果,而不会再次执行函数
- 计算属性没有参数
方法:
- 不会缓存,每当触发再次渲染时,就会再次执行函数
- 方法允许传递参数
如果有一个对性能开销较大的计算,例如需要遍历一个巨大的数组并进行大量计算,选择计算属性;否则选择方法,或者我们不希望缓存,也选择方法;或者我们需要使用到参数,来动态的处理逻辑,需要选择方法;
下列代码,在控制台中,输出计算属性以及调用方法看看区别:
//创建Vue实例
let vm = new Vue({
el: '#app',
computed: {
getDate: function () {
return Date.now();
}
},
methods: {
getDateFunc: function () {
return Date.now();
}
}
});
7. 侦听器(熟记)
当对应的数据发生变化时,我们可以做一些事情
不要滥用watch,出于性能考虑,我们优先考虑计算属性
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>vue模板语法-指令概念</title>
</head>
<body>
<div id="app">
<h1>{{message}}</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
age: 0,
message: '请输入一个年龄',
},
watch: {
age: function (newVal,oldVal) {
if(newVal >= 18 && newVal <= 200) {
this.message = "你可以进去上网了!";
}else {
this.message = "18岁以下,禁止入内!";
}
}
}
});
</script>
</body>
</html>
8. 样式绑定(熟记)
参考链接: https://cn.vuejs.org/v2/guide/class-and-style.html
8.1 class样式绑定
8.1.1 对象语法
使用数据与它们做绑定时,使用的表达式结果除了字符串外还可以是对象
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>绑定Class-对象语法</title>
<style type="text/css">
.bold {
font-weight: 700;
}
.font-big {
font-size: 36px;
}
</style>
</head>
<body>
<div id="app">
<p :class="{bold:isBold,'font-big': isBig}">老九学堂</p>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
isBold: true,
isBig: false,
},
});
</script>
</body>
</html>
数据对象可以不写在模板语法中
<div id="app">
<p :class="fontClass">老九学堂</p>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
fontClass: {
bold: false,
'font-big': true,
}
},
});
</script>
数据也可以是一个返回对象的计算属性
<div id="app">
<p :class="fontClass">老九学堂</p>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
computed: {
fontClass: function () {
return {
bold: true,
'font-big': true,
}
}
}
});
</script>
8.1.2 数组语法
除了上述绑定方式以外,我们还可以使用数组的方式,将原始样式与动态样式综合使用
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>绑定Class-对象语法</title>
<style type="text/css">
.bold {
font-weight: 700;
}
.font-big {
font-size: 36px;
}
.style {
font-style: italic;
}
</style>
</head>
<body>
<div id="app">
<p :class="['style',fontClass]">老九学堂</p>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
fontClass: {
bold: true,
'font-big': true,
}
}
});
</script>
</body>
</html>
8.2 style样式绑定
8.2.1 对象语法
css属性名可以使用骆驼命名法、短横线分割(需要用引号)两种形式
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>绑定style-对象语法</title>
</head>
<body>
<div id="app">
<p :style="{fontWeight: fontWeight,'font-size': fontSize + 'px'}">老九学堂</p>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
fontWeight: 700,
fontSize: 36
}
});
</script>
</body>
</html>
数据同样可以不用写在模板语法中;同样也可以放在计算属性中(这里不再演示)
8.2.2 数组语法
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>绑定style-数组语法</title>
</head>
<body>
<div id="app">
<p :style="[{fontWeight: fontWeight,'font-size': fontSize + 'px'},fS]">老九学堂</p>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
fontWeight: 700,
fontSize: 36,
fS: {
fontStyle: 'italic'
}
}
});
</script>
</body>
</html>
9. 条件渲染(熟记)
参考链接(条件):https://cn.vuejs.org/v2/guide/conditional.html
Truthy说明:https://developer.mozilla.org/en-US/docs/Glossary/Truthy
参考链接(循环):https://cn.vuejs.org/v2/guide/list.html
9.1 v-if
当指令中的表达式返回
truthy
值时,内容将被渲染配套的还有
v-else
和v-else-if
,需要注意:v-else-if
元素必须紧跟v-if
或者其他v-else-if
后面;v-else
元素必须紧跟v-if
或者v-else-if
后面,否则它们不会被识别;
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>v-if</title>
</head>
<body>
<div id="app">
<input type="text" name="age" placeholder="请输入年龄" />
<h1 v-if="age > 0 && age <= 12">你是小学生!</h1>
<h1 v-else-if="age > 0 && age <= 15">你是初中生!</h1>
<h1 v-else-if="age > 0 && age <= 18">你是高中生!</h1>
<h1 v-else-if="age > 18">你是大学生!</h1>
<h1 v-else>年龄不正确!</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
age: 0
}
});
document.querySelector('input[name="age"]').addEventListener('input',e => {
vm.age = e.target.value;
});
</script>
</body>
</html>
v-if必须放在元素上方可生效,当我们需要控制一组元素,但是我们希望这组元素不需要额外的元素包裹,此时我们可以借用元素
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>v-if</title>
</head>
<body>
<div id="app">
<template v-if="isShow">
<p>第一段内容</p>
<p>第二段内容</p>
<p>第三段内容</p>
<p>第四段内容</p>
</template>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
isShow: false
}
});
</script>
</body>
</html>
9.2 v-show
它的作用是隐藏显示对应的元素,被渲染的元素始终保留在DOM中,同样的是采用
truthy
来判断
v-show
只是简单的切换元素的css属性display,因为v-show
是使用 display 来实现的,因此 它对<template>
元素无效
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>v-show</title>
</head>
<body>
<div id="app">
<h1 v-show="isShow">这里是一段文字</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
isShow: false
}
});
</script>
</body>
</html>
9.3 v-if与v-show的区别
v-if:
- 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建
- 是惰性的:如果在初始渲染时条件为假,则什么也不做。直到条件第一次变为真时,才会开始渲染条件块
- 有更高的切换开销,如果运行时条件很少改变,使用v-if较好
v-show:
- 不管初始条件是什么,元素总是会被渲染,只是简单地基于 CSS 进行切换
- 内容需要频繁的切换,使用v-show较好
10. 列表渲染 v-for(熟记)
10.1 数组渲染
v-for指令使用(item,index) in items形式的特殊语法,其中index参数是可选参数
使用v-for,推荐加上key,便于vue跟踪每一个节点身份
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>v-for</title>
<style type="text/css">
td,th {
border: 1px solid black;
}
table {
border-collapse: collapse;
}
</style>
</head>
<body>
<div id="app">
<table>
<thead>
<tr>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
</tr>
</thead>
<tbody>
<tr v-for="(stu,index) in students" :data-index="index" :key="stu.id">
<td>{{stu.name}}</td>
<td>{{stu.sex}}</td>
<td>{{stu.age}}</td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
students: [
{
id: 1,
name: '张三',
sex: '男',
age: 18
},
{
id: 2,
name: '李四',
sex: '女',
age: 21
},
{
id: 3,
name: '王五',
sex: '男',
age: 17
}
]
}
});
</script>
</body>
</html>
10.2 对象渲染(了解)
v-for指令还可以用来遍历对象的属性
第一个参数为对象的属性值,第二个参数为对象的属性名称,第三个参数为索引index
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>v-for</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="(value,name,index) in student">
{{index}} - {{name}} : {{value}}
</li>
</ul>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
student: {
name: '张三',
sex: '男',
age: 18
}
}
});
</script>
</body>
</html>
10.3 变异方法与非变异方法(记忆)
10.3.1 变异方法
原生JS中提供了一系列操作数组的方法,而Vue对其中的一部分方法进行了包裹,当我们使用这些方法时,将会触发视图的更新,被包裹的方法有:
push
、pop
、shift
、unshift
、splice
、sort
、reverse
(我们可以发现这些方法,都是在原本数组上操作,因此可以触发视图刷新)
10.3.2 非变异方法
filter
、concat
、map
,它们不会改变原来的数组,而是返回新的数组我们可以将新的数组赋值给原来的数组,以触发视图的刷新
10.4 Vue.set API
我们利用索引直接设置一个数组项时或者一个对象属性时,Vue无法检测,导致视图不会刷新,此时我们需要用Vue.set来处理
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
students: [
{
id: 1,
name: '张三',
sex: '男',
age: 18
},
{
id: 2,
name: '李四',
sex: '女',
age: 21
},
{
id: 3,
name: '王五',
sex: '男',
age: 17
}
]
}
});
setTimeout(() => {
/*vm.students[1] = {
id: 10000,
name: '赵六',
sex: '女',
age: 36
}*/
Vue.set(vm.students,1,{
id: 10000,
name: '赵六',
sex: '女',
age: 36
});
},2000);
11. 事件处理(熟记)
参考链接: https://cn.vuejs.org/v2/guide/events.html
使用v-on 指令监听各种事件
11.1 基本用法
该指令支持缩写语法糖,我们使用@来表示
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>v-on事件</title>
</head>
<body>
<div id="app">
<!-- <button v-on:click="onBtnClick">点击</button>-->
<button @click="onBtnClick">点击</button>
<h1>用户当前点击了{{count}}次!</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
count: 0
},
methods: {
onBtnClick: function () {
this.count += 1;
}
}
});
</script>
</body>
</html>
11.2 事件传参
事件可以传递自定义的参数
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>v-on事件传参</title>
</head>
<body>
<div id="app">
<button @click="onWelcomeBtnClick('张三')">点击</button>
<button @click="onWelcomeBtnClick('李四')">点击</button>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
methods: {
/**
* 欢迎按钮点击事件
* @param name 名称
*/
onWelcomeBtnClick: function (name) {
alert(`你好啊,${name},欢迎来到Vue的世界!`);
}
}
});
</script>
</body>
</html>
如果需要使用事件的Event对象,那么需要使用特殊变量
$event
<div id="app">
<button @click="onWelcomeBtnClick('张三',$event)">点击</button>
<button @click="onWelcomeBtnClick('李四',$event)">点击</button>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
methods: {
/**
* 欢迎按钮点击事件
* @param name 名称
* @param e
*/
onWelcomeBtnClick: function (name,e) {
console.log(e);
alert(`你好啊,${name},欢迎来到Vue的世界!`);
}
}
});
</script>
11.3 动态参数(了解)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>v-on事件传参</title>
</head>
<body>
<div id="app">
<button @[eventname]="onWelcomeBtnClick('张三',$event)">点击</button>
<button @[eventname]="onWelcomeBtnClick('李四',$event)">点击</button>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
eventname: 'click',
},
methods: {
/**
* 欢迎按钮点击事件
* @param name 名称
* @param e
*/
onWelcomeBtnClick: function (name,e) {
console.log(e);
alert(`你好啊,${name},欢迎来到Vue的世界!`);
}
}
});
</script>
</body>
</html>
11.4 事件修饰符(了解)
在事件方法中调用event.preventDefault()等是常见的需求
更好的方式是,方法中只有纯粹的逻辑,而不需要去处理DOM事件细节
这些修饰符可以串联一起使用,但是要注意:不要把
.passive
和.prevent
一起使用
修饰符名称 | 作用 |
---|---|
.stop | 阻止事件冒泡 |
.prevent | 禁止默认事件 |
.capture | 捕获子元素对应的事件,可以预先进行处理一些事情,之后再交由子元素处理 |
.once | 2.1.4新增,事件只触发一次 |
.passive | 2.3.0新增,让滚动的默认行为立即触发,优化滚动效果,在移动端尤为明显 |
11.5 按键修饰符(了解)
Vue提供了键盘事件的修饰符,只有按下对应按键时方可触发:
<input @keyup.a="onKeyUp" />
也可以串联:
@keyup.a.b="onKeyUp" />
除了字母外,其他的按键用横杠来分割:
<input @keyup.page-down="onKeyUp" />
Vue提供了一些常用的按键码别名
原按键码名 | 别名 |
---|---|
.delete | 同时捕获.delete和.backspace |
.up | .arrow-up |
.down | .arrow-down |
.right | .arrow-right |
.left | .arrow-left |
可以通过全局配置,自定义按键修饰符别名(左边是别名, 右边是keyCode)
Vue.config.keyCodes= {
test: 65,
"test-space": 32,
qwer: [81,87,69,82]
};
11.6 系统修饰键(了解)
2.1.0新增了系统修饰键
其仅在按下相应按键时才触发鼠标或键盘事件的监听器(
meta
在Mac系统上对应command键⌘
;在Windows系统上对应微标键⊞
)
.ctrl
、.alt
、.shift
、.meta
修饰键与修饰符不同,在和 keyup 事件一起用时,必须要组合其他键才能生效
<!-- Ctrl+c -->
<input @keyup.ctrl.c="onKeyUp($event)" />
<!-- Ctrl键+鼠标点击 -->
<input @click.ctrl="onTouchClick($event)" />
11.7 .exact修饰符(了解)
2.5.0新增,可以精确的控制系统修饰符的组合
<!-- 同时按住Ctrl + Alt、Shift等系统键也会触发-->
<button @click.ctrl="onTouchClick($event)">点击测试</button>
<!-- 只有Ctrl按下才会触发(实际与普通键同时按住,依然会触发) -->
<button @click.ctrl.exact="onTouchClick($event)">点击测试</button>
<!-- 无系统键按下时才会触发 -->
<button @click.exact="onTouchClick($event)">点击测试</button>
11.8 鼠标修饰符(了解)
2.2.0新增,
.left
鼠标左键、.right
鼠标右键、.middle
鼠标中键
12. 表单绑定
12.1 表单双向绑定v-model
- v-model会忽略所有表单元素的value、checked、selected的初始值并将Vue实例的数据作为数据来源
- v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
- text 和 textarea 元素使用 value 属性和 input 事件
- checkbox 和 radio 使用 checked 属性和 change 事件
- select 字段将 value 作为 属性并将 change 作为事件
12.2 文本与多行文本
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>v-model文本与多行文本</title>
</head>
<body>
<div id="app">
<div>
<input type="text" v-model="title" placeholder="请输入文章的标题" />
</div>
<div>
<textarea v-model="description" placeholder="请输入文章的描述信息"></textarea>
</div>
<h1>文章的标题是:{{title}}</h1>
<p>{{description}}</p>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
title: '',
description: ''
},
});
</script>
</body>
</html>
12.3 复选框
12.3.1 单个复选框
<div id="app">
<label>
<input type="checkbox" v-model="isAgree" />
<span>是否同意协议</span>
</label>
<h1>当前是否同意协议:{{isAgree}}</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
isAgree: false
},
});
</script>
12.3.2 多个复选框
<div id="app">
<label>
<input type="checkbox" value="apple" v-model="fruits" />
<span>苹果</span>
</label>
<label>
<input type="checkbox" value="pear" v-model="fruits" />
<span>梨子</span>
</label>
<label>
<input type="checkbox" value="banana" v-model="fruits" />
<span>香蕉</span>
</label>
<h1>当前选择的水果有:{{fruits}}</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
fruits: []
},
});
</script>
12.4 单选按钮
<div id="app">
<label>
<input type="radio" value="apple" v-model="fruit" />
<span>苹果</span>
</label>
<label>
<input type="radio" value="pear" v-model="fruit" />
<span>梨子</span>
</label>
<label>
<input type="radio" value="banana" v-model="fruit" />
<span>香蕉</span>
</label>
<h1>当前选择的水果是:{{fruit}}</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
fruit: ''
},
});
</script>
12.5 下拉列表
<div id="app">
<select v-model="address">
<option disabled value="">请选择</option>
<option>成都</option>
<option>重庆</option>
<option>北京</option>
</select>
<h1>当前选择的地址是:{{address}}</h1>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
address: ''
},
});
</script>
13. 组件(熟记)
参考链接(基础): https://cn.vuejs.org/v2/guide/components.html
参考链接(深入):https://cn.vuejs.org/v2/guide/components-registration.html
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rrjGTxfi-1612060269466)( https://lao-jiu-jun.gitee.io/xuetang9-markdown-graph-bed/Java实训/Vue/Vue基础/组件.png )]
13.1 组件注册
13.1.1 全局注册
使用Vue.component注册全局组件,使用该方式注册的组件,在所有的实例中都可以使用
全局注册有一个问题在于,不再使用某个组件了,它仍然会被包含在最终的构建结果中。这造成文件无谓的增加
组件名的规则:
- kebab-case :短横线分隔命名
- PascalCase :首字母大写命名,该方式在单文件组件中使用
注意,每个组件只允许存在一个根节点
<div id="app">
<md-button></md-button>
<md-button></md-button>
<md-button></md-button>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
Vue.component('md-button', {
data() {
return {
count: 0
}
},
template: '<button @click="count++">点了我{{count}}次</button>'
});
//创建Vue实例
let vm = new Vue({
el: '#app',
});
</script>
13.1.2 局部注册
在实例中使用components来配置需要的组件
注意在使用的时候,必须用短横线的方式
<div id="app">
<component-a></component-a>
<component-b></component-b>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
let ComponentA = {
template: '<h1>这是第1个组件</h1>'
};
//创建Vue实例
let vm = new Vue({
el: '#app',
components: {
ComponentA,
ComponentB: {
template: '<p>这是第2个组件</p>'
}
}
});
</script>
13.2 prop
我们可以使用prop向子组件传递数据
prop 名称最好采用 kebab-case 形式,可以避免一些不必要的问题
prop 是单向数据流,不应该在子组件中修改 prop 的值
13.2.1 基本用法
<div id="app">
<section>
<md-article title="通过Prop 向子组件传递数据1"></md-article>
<md-article title="通过Prop 向子组件传递数据2"></md-article>
</section>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
Vue.component('md-article',{
props: ['title'],
template: '<h1>{{title}}</h1>'
});
//创建Vue实例
let vm = new Vue({
el: '#app'
});
</script>
13.2.2 prop类型(了解)
<div id="app">
<md-user name="张三" :age="21" :sex="false"></md-user>
<md-user name="李四" :age="18" :sex="true"></md-user>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
Vue.component('md-user',{
props: {
name: String,
age: Number,
sex: Boolean,
love: Array,
info: Object,
action: Function,
},
template: `
<div>
<p>姓名:{{name}}</p>
<p>年龄:{{age}}</p>
<p>性别:{{sex?'男':'女'}}</p>
</div>
`
});
//创建Vue实例
let vm = new Vue({
el: '#app'
});
</script>
13.2.3 prop验证(了解)
基本的检查类型有:String 、 Number 、Boolean 、 Array 、Object 、 Date 、Function 、Symbo
注意,要想看到警告内容,需要使用未压缩的版本!
Vue.component('md-user',{
props: {
//多个类型
name: [Number,String],
//必填
age: {
type: Number,
required: true
},
//默认值
sex: {
type: Boolean,
default: true
},
//自定义验证
password: {
validator: function (value) {
let reg = /^[A-z0-9]{4,12}$/;
return reg.test(value);
}
}
},
template: `
<div>
<p>姓名:{{name}}</p>
<p>年龄:{{age}}</p>
<p>性别:{{sex?'男':'女'}}</p>
</div>
`
});
13.2.4 多prop优化
当存在多个prop导致使用组件传递很多参数,我们可以综合对象来处理
<div id="app">
<md-user :stu-info="stuList[0]"></md-user>
<md-user :stu-info="stuList[1]"></md-user>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
Vue.component('md-user',{
props: ['stuInfo'],
template: `
<div>
<p>姓名:{{stuInfo.name}}</p>
<p>年龄:{{stuInfo.age}}</p>
<p>性别:{{stuInfo.sex?'男':'女'}}</p>
</div>
`
});
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
stuList: [
{
name: '张三',
age: 18,
sex: false
},
{
name: '李四',
age: 23,
sex: true
}
]
}
});
</script>
13.2.5 组件事件监听
使用 e m i t , 可 以 给 组 件 设 置 自 定 义 事 件 逻 辑 , emit,可以给组件设置自定义事件逻辑, emit,可以给组件设置自定义事件逻辑,emit中第一个为绑定的事件名称,第二个及之后为方法的参数
<div id="app">
<md-article
content="一段内容"
:size="size"
@add-font-size="addFontSize"
@sub-font-size="subFontSize"
></md-article>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
Vue.component('md-article',{
props: ['content','size'],
data() {
return {
fontSize: 16
}
},
template: `
<div>
<p :style="{fontSize: fontSize + size + 'px'}">{{content}}</p>
<p>
<button @click="$emit('add-font-size')">点击增加字号</button>
</p>
<p>
<button @click="$emit('sub-font-size')">点击减少字号</button>
</p>
</div>
`
});
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
size: 0
},
methods: {
addFontSize: function () {
this.size += 1;
},
subFontSize: function () {
this.size -= 1;
}
}
});
</script>
13.2.6 sync修饰符
原则上,prop属性是不能在组件中修改的,但是我们可以通过.sync修饰符,给属性设置同步,之后配合$emit来实现呼叫父级修改对应值
<div id="app">
<md-article :content.sync="content"></md-article>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
Vue.component('md-article',{
props: ['content'],
template: `
<div>
<p>{{content}}</p>
<button @click="onUpdateBtnClick">修改内容</button>
</div>
`,
methods: {
onUpdateBtnClick: function () {
this.$emit('update:content',"新的一段内容")
}
}
});
//创建Vue实例
let vm = new Vue({
el: '#app',
data: {
content: '一段内容'
},
});
</script>
13.3 插槽
使用slot,将内容插入到指定位置,组件中的内容会自动替换slot
13.3.1 基本用法
<div id="app">
<md-box title="盒子标题">
<p>第1段内容</p>
<p>第2段内容</p>
</md-box>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
Vue.component('md-box',{
props: ['title'],
template: `
<div>
<h1>{{title}}</h1>
<slot></slot>
</div>
`
});
//创建Vue实例
let vm = new Vue({
el: '#app',
});
</script>
13.3.2 后备插槽(了解)
可以设置插槽的默认值
<div id="app">
<md-box title="盒子标题"></md-box>
<md-box title="盒子标题">
<p>第1段内容</p>
<p>第2段内容</p>
</md-box>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
Vue.component('md-box',{
props: ['title'],
template: `
<div>
<h1>{{title}}</h1>
<slot>
<p>这里是插槽后备的内容</p>
</slot>
</div>
`
});
//创建Vue实例
let vm = new Vue({
el: '#app',
});
</script>
13.3.3 多个插槽与具名插槽(了解)
给slot设置name属性即可使用多个插槽,在使用组件时,使用
template
元素以及v-slot
指令就可以将内容传递到指定的插槽中,指令可以使用缩写#
<div id="app">
<md-layout>
<template v-slot:header>
<h1>这里是头部的内容</h1>
</template>
<template v-slot:default>
<p>一些正文内容</p>
<p>一些其它的正文内容</p>
</template>
<template #footer>
<h3>这里是底部的内容</h3>
</template>
</md-layout>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
Vue.component('md-layout',{
template: `
<div>
<header>
<slot name="header"></slot>
</header>
<section>
<slot></slot>
</section>
<footer>
<slot name="footer"></slot>
</footer>
</div>
`
});
//创建Vue实例
let vm = new Vue({
el: '#app',
});
</script>
{{title}}
//创建Vue实例
let vm = new Vue({
el: '#app',
});
```
13.3.2 后备插槽(了解)
可以设置插槽的默认值
<div id="app">
<md-box title="盒子标题"></md-box>
<md-box title="盒子标题">
<p>第1段内容</p>
<p>第2段内容</p>
</md-box>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
Vue.component('md-box',{
props: ['title'],
template: `
<div>
<h1>{{title}}</h1>
<slot>
<p>这里是插槽后备的内容</p>
</slot>
</div>
`
});
//创建Vue实例
let vm = new Vue({
el: '#app',
});
</script>
13.3.3 多个插槽与具名插槽(了解)
给slot设置name属性即可使用多个插槽,在使用组件时,使用
template
元素以及v-slot
指令就可以将内容传递到指定的插槽中,指令可以使用缩写#
<div id="app">
<md-layout>
<template v-slot:header>
<h1>这里是头部的内容</h1>
</template>
<template v-slot:default>
<p>一些正文内容</p>
<p>一些其它的正文内容</p>
</template>
<template #footer>
<h3>这里是底部的内容</h3>
</template>
</md-layout>
</div>
<script type="text/javascript" src="./lib/vue-2.6.12/vue.min.js"></script>
<script type="text/javascript">
Vue.component('md-layout',{
template: `
<div>
<header>
<slot name="header"></slot>
</header>
<section>
<slot></slot>
</section>
<footer>
<slot name="footer"></slot>
</footer>
</div>
`
});
//创建Vue实例
let vm = new Vue({
el: '#app',
});
</script>