Vue2.x 的版本
据目前小道消息所知,3.x的版本基本语法没用变动,主要是对底层的特性重新封装内核进行升级,提高性能,语法和2.x大同小异
官网:https://cn.vuejs.org/
渐进式:从简单应用到复杂应用,Vue都支持,几乎可以覆盖整个项目的生命周期
框架和库:这个概念在目前已经越来越淡化了,只是一个叫法而已
- 框架:功能相对来说比较全面的,覆盖了方方面面
- 库:功能相对来说比较单一专精,提供具体的API(Application Program Interface)应用程序接口
Vue是一个牛B的国产框架,国内很多程序员把尤大大当生开源社区的领袖,不仅影响了国内,乃至在全球范围内都有影响
- 易用:意味着使用人(用户/程序员)数就会很多
- 灵活:锦上添花的,花里胡哨的
- 高效:必须的
虚拟DOM:所谓虚拟DOM,就是用JS对象描述的HTML结构
Vue的两个选项:
- el:挂载元素(可以是DOM对象或选择器),可以理解成模板的根元素,把创建出来的Vue实例对象和页面中的该元素进行关联,把这个元素交给Vue实例进行托管
- data:模板数据,是一个对象
插值表达式:{{ xxx }}
,类似art-template中的输入语句,可以写一些简单的表达式
前端渲染&后端渲染 === 客户端渲染&服务端渲染
- 客户端渲染:动态数据和HTML的拼接放在客户端处理
- 服务端渲染:动态数据和HTML的拼接是放在服务端拼接好了一次性响应返回给客户端的,客户端只需要解析显示即可,不需要做动态拼接操作
模板语法进化过程:
- 字符串拼接:维护难,风格不统一
- 普通模板引擎:虽然相比字符串拼接维护简单了,但是不支持事件绑定,需要通过事件委派来绑定
- Vue模板语法:既支持普通的模板语法,也支持高级的特性(事件绑定、属性绑定、指令…)
- 存在一个编译的过程,比如:
<div>{{ 1 + 2 }}</div>
,浏览器在Vue编译之前,会显示原始的花括号,编译后,才会显示最终的<div>3</div>
,存在一个过程(时间比较短,可能用户感知不到就已经编译完了)
- 存在一个编译的过程,比如:
指令:其实就是自定义属性,Vue里面的所有指令名称都是以v-
开头的
插值表达式:存在闪动问题,可以用v-cloak
解决,内部其实就是先用样式隐藏,等待Vue编译完成后再把元素显示出来,v-cloak
可以添加在根元素上,不用给每个子元素添加
数据绑定的3个指令:
- v-text:纯文本,不存在闪动问题
- v-html:会解析HTML标签,存在XSS(跨站脚本攻击)安全隐患,不存在闪动问题
- 注意:HTML5 之后,通过innerHTML插入的script标签 不会执行了
- v-pre:跳过编译,原模原样输出
- 补充说明: 注意指令中不要再加花括号了
- 比如:
<div>{{ msg }}</div>
,不要写成:<div v-text="{{ msg }}"></div>
,直接写成:<div v-text="msg"></div>
就行了
- 比如:
数据响应式(数据驱动视图):就是通过数据的变化而更新HTML的变化,Vue不会直接操作DOM了,是通过数据驱动视图的形式操作DOM的,大家现在要改变之前的编程思维(之前的编程思维是先获取元素,再修改元素值,现在的是直接操作数据,更新HTML的动作Vue会自动帮我们搞定,只用管数据就行了)
v-once:只会编译一次,编译之后如果相关数据发生了变化,也不会重新渲染HTML结构,如果你确定只需要编译一次,后续不会有变化了,我们就用v-once,这样可以提高一丢丢性能
MVVM设计模式:
- M(Model):模型/数据
- V(View):视图/HTML模板
- VM(ViewModel):视图模型,这个是M和V的纽带,就是它来做关联的,就是通过Vue构造函数new出来的实例对象
双向数据绑定(面试经常问):
-
数据到视图:数据劫持,Object.definePropery
-
视图到数据:DOM事件监听,事件机制
v-model:双向数据绑定的指令
Vue实例的methods选项:用来定义方法/函数,方法中的this是指向vm实例对象的
- 注意:不要写箭头函数,否则this指向不是vm实例
Vue事件绑定指令语法:
- v-on:事件类型=“事件处理方法”
- @事件类型=“事件处理方法”(推荐使用简写形式)
- 在绑定事件处理方法时有两种方式:
- 事件处理方法必须定义在vm实例选项的methods属性中
- 不带小括号,直接写函数名称
- 默认会携带事件对象作为第一个参数(畸形,不推荐)
- 带小括号的函数调用(推荐使用这种)
- 默认不会携带事件对象,需要显式通过
$event
传递 $event
必须作为最后一个参数传递(不成立)$event
名字不能改- 补充说明:为什么一定要叫
$event
?是因为Vue的作者,也就是尤雨溪规定的,编写Vue框架时,就确定了的,必须遵守,就跟你用jQuery查找元素时为什么要用$
符号是一个意思
- 补充说明:为什么一定要叫
- 默认不会携带事件对象,需要显式通过
事件修饰符:
-
语法:
<button @click.stop="clickHandle()">点击</button
-
stop:阻止事件冒泡
-
prevent:阻止事件默认行为
按键修饰符:
- 语法:
<input @keyup.enter="keyupHandle()" >
- enter:回车
- delete:退格键
- 一些常用的按键,Vue都内置了,如果发现没内置,还可以自定义按键修饰符
自定义按键修饰符:
- 定义:
Vue.config.keyCodes.xxx = 按键码
,这个按键码必须是有效按键码(event.keyCode) - 使用:
<input @keyup.xxx="xxFn()" >
- 注意:在自定义按键修饰符时,自定义的名称不要和内置的冲突了,起一个特别的名字
属性绑定:
- 基本语法:点击跳转,这个url应该在new Vue({ data: { url: ‘…’ } })中
- 简写语法:点击跳转(推荐使用简写语法)
- 注意:一定小心冒号
- 加冒号:就是Vue的属性绑定语法,会经过Vue的编译,也称动态属性绑定
- 不加冒号:就是传统的属性写法,就是死的,不会经过Vue的编译,也称静态属性绑定
Class绑定(推荐,重点掌握):
- 对象用法:
- 语法:<div :class="{ active: true, error: false, ... }"></div>
- 你可以把这整个对象定义到data中(推荐这样写)
new Vue({
data: {
classObj: { active: true, error: false, ... }
}
})
// 模板写法:<div :class="classObj"></div>
- 也可以把这个对象中的键值对的值分别单独的定义在data中(不推荐这样写)
new Vue({
data: {
isActive: true,
isError: false
}
})
// 模板写法:<div :class="{ active: isActive, error: isError }"></div>
- 对象中可以有多个键值对,每个键值对的键名就是类名,值是一个布尔值,用来控制是否有这个类,true:就有这个类,false:就没有这个类
- 数组用法:
- 语法:<div :class="[ 'active', 'error', ... ]"></div> - 你可以把这个数组定义到data中(推荐这样写) new Vue({ data: { classAry: [ 'active', 'error', ... ] } }) // 模板写法:<div :class="classAry"></div>
- 也可以把这个数组中的元素分别单独的定义在data中(不推荐这样写)
new Vue({
data: {
activeClass: 'active',
errorClass: 'error'
}
})
// 模板写法:<div :class="[ activeClass, errorClass ]"></div>
- 传统的class属性会保留,和Vue的class属性绑定取并集:
<div class="base hehe class1" :class="[ 'hehe', 'dada' ]"></div> <!-- 最终渲染成:<div clas="base hehe class1 dada"></div> -->
style绑定(不推荐):
- 对象用法:对象中可以有多个键值对,每个键值对的键名就是CSS属性名,值就是CSS属性值(推荐使用)
- 数组用法:包含对象用法,每个元素都是一个对象
样式绑定的两种方式(:class、:style)的相关语法细节:
- 对象绑定和数组绑定可以结合使用(不规范,不推荐使用,黑科技,不到迫不得已不要使用)
- class和style绑定的值都可以在data中定义为一个数据(推荐)
- 传统的class属性会保留,和Vue的class属性绑定取并集
- 如果只有几个简单的样式,并且只会被某一个元素用到,就用style绑定,如果样式比较复杂,千万不能用style,要提取到class中定义,然后用:class绑定
- style绑定中的对象形式,要注意键名的写法:
- 驼峰:new Vue({ data: { styleObj: { fontSize: '12px' } } })
- 单引号包起来的字符串:new Vue({ data: { styleObj: { 'font-size': '12px' } } })(推荐这样写,可以和原本的CSS语法保持一致)
分支结构语法(概念和art-template模板引擎都是通的,只不过语法不一样而已):
- v-if:控制结构,只有满足条件才会渲染(页面中才会有这个元素),否则,不会在渲染到html结构中
- 注意:v-if和v-else必须连着写,不能再中间穿插其他元素,否则v-if和v-else逻辑脱节,比如(错误范例):
<div v-if="score > 80">优秀</div>
<hr /><!-- 这里不能插入这个hr标签 -->
<div v-else>良好</div>
- v-show:控制样式,不管是否满足条件,都会渲染在页面中(页面中一直存在这个元素),只不过如果条件为假,则通过样式display: none;隐藏了
- 补充说明:什么时候用v-if?什么时候用v-show?如果元素需要频繁的显示隐藏,则用v-show,反之,则用v-if,因为频繁的操作样式,比频繁的在页面(DOM树)中插入删除元素效率要高的多
循环结构:
- 遍历数组:v-for="(值, 索引) in 数组数据"
<ul>
<!-- v-for 指令中定义的循环变量,仅在v-for所在元素的开始标签和结束标签内有效 -->
<!-- 如果不需要用到索引,那么就这样写就够了 -->
<li v-for="user in users">用户名:{{ user.name }}</li>
</ul>
<ul>
<!-- 如果需要用到索引,如下写法 -->
<li v-for="(user, index) in users">用户名:{{ user.name }} --- 索引:{{ index }}</li>
</ul>
<ul>
<!-- :key无脑加,只要写了v-for,就先把:key写上,可以提高Vue编译渲染的性能 -->
<!-- 我们都知道Vue是数据驱动视图的,只要数据有变化,Vue就会自动更新视图,这里面存在着复杂的算法,如果我们在v-for时指定了:key属性,那么当数据发生变化,Vue需要更新视图时,就可以定快速位到需要更新的节点,不用通过复杂的算法找到(因为你不加:key也是可以找到的) -->
<!-- :key属性的值,只要保证本次循环中节点之间没有重复的就行了,所以,如果有id,就用id,没用就用索引 -->
<li v-for="(v, i) in users" :key="v.id">用户名:{{ v.name }} --- 索引:{{ i }}</li>
</ul>
<script>
new Vue({
data: {
users: [
{ id: 1, name: '张三' },
{ id: 2, name: 'ls' },
{ id: 3, name: 'ww' },
{ id: 4, name: 'zl' },
{ id: 5, name: 'wemz' },
]
}
})
</script>
- 遍历对象:和遍历数组语法基本一致,仅仅是循环变量列表不一样:v-for="(值, 键, 索引) in 对象数据"
选项卡案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
.tab ul {
overflow: hidden;
padding: 0;
margin: 0;
}
.tab ul li {
box-sizing: border-box;
padding: 0;
float: left;
width: 100px;
height: 45px;
line-height: 45px;
list-style: none;
text-align: center;
border-top: 1px solid blue;
border-right: 1px solid blue;
cursor: pointer;
}
.tab ul li:first-child {
border-left: 1px solid blue;
}
.tab ul li.active {
background-color: orange;
}
.tab div {
width: 500px;
height: 300px;
display: none;
text-align: center;
font-size: 30px;
line-height: 300px;
border: 1px solid blue;
border-top: 0px;
}
.tab div.current {
display: block;
}
</style>
</head>
<body>
<div id="app">
<div class="tab">
<!-- tab栏 -->
<ul>
<!-- 加了class="active"的就是激活的 -->
<li v-for="(v, i) in fruits" :key="i" :class="activeIndex === i ? 'active' : ''" @click="onClickTab(i)">
{{ v.name }} -- {{ i }}</li>
</ul>
<!-- 对应显示的图片,加了class="current"的就是显示的 -->
<div v-for="(v, i) in fruits" :key="i" :class="activeIndex === i ? 'current' : ''">
<img :src="v.imgSrc">
</div>
</div>
</div>
<script src="js/vue.js"></script>
<script>
// 1) 指定模板根元素
// 2) 根据静态页面提取数据至data中
// 3) 根据data中的数据,用Vue的模板语法渲染页面结构
// 4) 监听tab头的点击事件
// 5) 切换显示图片
new Vue({
el: '#app', // 模板根元素
data: {
// fruits: ['apple', 'orange', 'lemon']
fruits: [
{ name: 'apple', imgSrc: 'img/apple.png' },
{ name: 'orange', imgSrc: 'img/orange.png' },
{ name: 'lemon', imgSrc: 'img/lemon.png' },
],
// 添加一个标记,用来存储当前的激活的tab栏的索引,假设默认是0,也就是第一个
activeIndex: 0
},
methods: {
// 当点击tab头的时候,把点击的元素的索引号传递过来
onClickTab(i) {
console.log('hehe....', i);
// 只需要把传递过来的索引号赋值给activeIndex数据即可,Vue会自动将页面更新,不需要我们操作DOM
this.activeIndex = i
}
}
})
</script>
</body>
</html>
表单基本操作v-model绑定:
- 对于input:用v-model绑定
- 对于radio:同一组数据,绑定同一个v-model
- 对于checkbox:同一组数据,绑定同一个v-model,由于有可能选中多个,所以data中的数据要用数组类型存储
- 对于select:只需要添加v-model即可,默认只支持单选,若要多选,则加上multiple属性,并且data中的数据要用数组类型存储
- 对于textarea:就和input一样,直接把v-model加在标签上即可,不能写在开始标签和结束标签之间