这是我参与「第四届青训营 」笔记创作活动的第5天
Vue核心语法
vue官网常用资源
- 网址:cn.vuejs.org
- 教程:cn.vuejs.org/tutorial/
- API文档:cn.vuejs.org/api/
- VueRoute:router.vuejs.org/
- Awesome Vue:github.com/vuejs/aweso…
Hello,Vue!
<div id="app">
<h1>Hello,Vue!</h1>
</div>
<script type="text/javascript">
const vm = new Vue({
el: '#app',
data: {
message : 'Hello,Vue!'
}
})
</script>
-
el: 指定了Vue实例操作的容器
-
data: 用于存储数据供指定的容器使用
- data中的所有属性都会变成vm的属性
-
{{}}: 插值语法,可以写一个js表达式
-
注意事项:
- Vue实例只会根据选择器接管第一个容器
- 一个容器只能被第一个Vue实例接管
- 真实开发中只有一个Vue实例,会配合着组件一起使用
模板语法
- 定义:在html中的语法
插值语法
-
使用范围:标签体内
-
语法:
<div id="app"> {{something}} </div>
-
something既可以是Vue实例中的属性,又可以是任意一个js表达式
指令语法
-
功能:用于解析标签,包括属性、绑定事件、标签体内容
-
基本格式:
v-xxx
,例如用于解析属性的v-bind (例子中url为app实例中一属性)<a id="app" v-bind:href="url"></a> <!--可以简写为以下形式--> <a id="app" :href="url"></a>
- 注意:仅有
v-bind
可以简写
- 注意:仅有
-
""
内也可以写入js表达式或者实例内的属性或方法
数据绑定
-
单向绑定:数据只能从data流向页面,如v-bind
<input type="text" v-bind:value="name">
- 此时,若Vue实例中的name发生变化,输入框的value会随之变化
- 反之不成立,即输入框value变化后,Vue实例中的name值不会变化
-
双向绑定:数据可以在data和页面之间双向流动,如v-model
<input type="text" v-model:value="name">
- 此时,name和value始终会保持一致,一个改变会导致另一个改变
- v-model只能绑定在输入类元素上的value上,所以也可简写为
v-model:"..."
el和data的替代写法
-
el的替代写法:挂载(app为一个无el的实例)
let app = new Vue({ ... }) app.$mount("#app")
-
data的替代写法:函数式,通过函数返回一个对象作为data
new Vue({ data: function(){ return { something here } } })
- 可以简写为
data(){}
- 组件中必需使用函数式
- 可以简写为
数据代理
- 定义:通过一个对象对另一个对象中的属性进行操作(读写)
基本用法
-
对一个object,想要添加一个属性,应使用defineProperty
let person = {}; Object.defineProperty(person,'age',{ value: 18 })
-
这样便添加了一个age:18的键值
-
此时他并不可被更改、删除或者删除,下面通过传入更多属性来修改该特性
let person = {}; Object.defineProperty(person,'age',{ value: 18, enumerable: true,//控制能否被遍历,默认false writable; true,//控制能否被修改,默认false configurable:true//控制能否被删除,默认false })
-
-
get函数(通过getter实现)
Object.defineProperty(person,'age',{ get(){ some code return xxx; } })
- 每次读取age属性时,通过调用get函数,将返回值作为age属性值
-
set函数(通过setter实现)
Object.defineProperty(person,'age',{ set(value){ some code } })
- 每次age的值被修改后set函数被调用
- value为age修改后的值
Vue中的数据代理
-
目的:更方便的操作data中的数据
-
基本原理:
- 通过Object.defineProperty()将data对象中所有属性添加到vm的_data上
- 为每一个被添加的属性设置getter和setter
- 在getter和setter内部去读写data
事件处理
绑定事件
-
实例中在methods中添加回调函数
f
-
使用
v-on:xxx="f"
绑定f函数<button id="app" v-on:click="hhh"></button> <script> new Vue({ el: "#app", data:{}, methods:{ hhh(){ } } }) </script>
- 可以传一个参数作为事件对象event
v-on:
可以简写为@click
-
注意:methods里面的函数使用this会指向vm
-
传入参数:
<button id="app" v-on:click="hhh(23)"></button> <script> new Vue({ el: "#app", data:{}, methods:{ hhh(number){ } } }) </script>
-
在绑定事件时之间写小括号传入参数
-
在methods内使用对应的变量接受参数
-
如果此时需要事件对象event,则用以下写法($event表示事件对象)
<button id="app" v-on:click="hhh(23,$event)"></button> <script> new Vue({ ... methods:{ hhh(number,event){ ... } } }) </script>
-
-
在处理函数较简单时可以直接放入标签属性
<button @click="count++"></button>
- 此时这个count为vm实例中的属性,与methods中函数不同,此处不需要加
this.
- 此时这个count为vm实例中的属性,与methods中函数不同,此处不需要加
事件修饰符
-
基本语法:
@xxx.xxx=""
例如,阻止默认行为
<button @click.prevent="hhh"></button>
-
事件修饰符及其作用
修饰符 作用 prevent 阻止默认行为 stop 阻止冒泡 once 事件仅触发一次 capture 使用捕获模式 self 只有event.target是当前操作元素才触发事件 passive 事件默认行为为立即执行,无需等待事件回调执行完毕 -
使用多个修饰符:直接写多个
.xxx
<a href="xxx" @click.prevent.stop="xxx"
键盘事件
-
在按下特定按键时触发事件,直接使用
@keyup.xxx=""
(xxx为按键别名) -
按键别名
-
Vue内置
原始按键 别名 回车 enter 删除(捕获退格和删除) delete 退出 esc 空格 space 换行 tab 上/下/左/右 up/down/left/right -
对未内置的
-
先通过
event.key
先查询按键名- 对单个单词组成的按键名(如
Alt
、Control
)直接使用@keyup.小写按键名
实现 - 对于多个单词组成的按键名(如
CapsLock
),先将全部字母改为小写,然后不同单词间使用-
连接,如@keyup.caps-lock
- 对单个单词组成的按键名(如
-
自定义按键名
- 先调用
Vue.config.keyCodes.自定义名称=键码
- 然后就可以用之前的方法使用自定义名称
- 先调用
-
-
-
注意:
-
对于响应按键一般采用keyup
-
但对于tab键,由于其具有切换焦点的功能,使用keyup会导致事件无法触发,所以采用keydown
-
对系统修饰键(ctrl、alt、shift、meta(win))
-
配合keyup使用:按下修饰键时,同时按下其它键并释放该其它键,事件触发
- 若要在特定的按键组合下触发,如
ctrl+y
,则写作@keyup.ctrl.y="xxx"
- 若要在特定的按键组合下触发,如
-
配合keydown使用:正常触发事件
-
-
计算属性
-
计算属性:使用的属性不存在,而是通过已有属性进行计算得到
-
优势:
- 比起methods实现,通过缓存提升了效率
-
语法:写在computed内,一定需要一个get()
new Vue({ xxx computed:{ key:{ get(){ some code return xxx; } } } })
-
注意:
-
computed里面的get不能直接读取data内的属性,需要用
this.xxx
读取 -
get的调用时机
- 初次读取计算属性时
- 所依赖的数据发生变化后读取计算属性时
-
-
如果需要修改计算属性,需要先定义该属性的
set(value)
响应修改 -
计算属性简写:只读取不修改时可以简写为
key(){ getter code here }
监视属性
-
当被监视属性变化时,调用回调函数
-
语法1:在watch中实现
new Vue({ xxx watch:{ watched:{ handler(newVal,OldVal){ some code here } } immediate: true;//默认为false,为true时初始化时handler会先被调用一次 } })
-
该语法不需要配置其它属性,只需要handler时,可简写为
watched(newVal,oldVal){ handler code here }
-
-
handler在watched变量被修改时被调用
-
watched为被监测变量,这个语句并不会声明它,它应在其它地方(一般是data)中声明
-
语法2:通过$watch实现
vm.$watch('被监视对象',{ 配置项,同上 })
深度监视
-
监视多级结构中某个属性的变化,需用
''
引用,如监测data中的number.awatch:{ 'number.a' : { handler(){...} } }
-
深度监视:监视多级结构中所有属性的变化
data: { number:{ a:1, b:2 } }, watch: { number:{ handler(){}, deep: true;//默认false,开启深度监视 } }
- 此时,number内任一属性变化都会引起handler的调用
监视原理
-
vue会监视data下所有层次的数据(包括数组内每个元素、对象内每组键值)
-
监视原理:通过getter和setter实现
-
对象中后追加的属性,Vue默认不做响应式处理
-
如果想要给后追加的属性响应式处理,需要使用set,有以下两种写法
Vue.set(vm.xxx.obj,'key','value') vm.$set(vm.xxx.obj,'key','value')
- 注意:该方法只能给data内的对象追加属性,不可给data或vm直接追加属性
-
-
监视原理(数组):给数组的修改方法进行包裹
-
包裹后的方法具有双重功能
- 使用原生的修改方法对数组进行修改
- 重新解析模板、更新页面,进而实现响应式
-
在vm中修改数组中一定要使用以下方法之一,否则Vue无法检测数组改变,进而没有响应式
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
- 整体替换
- 通过Vue.set()或vm.$set修改
-
计算属性与监视属性
-
关系:计算属性能完成的监视属性一定能完成,反之不成立
-
选择:
- 都能使用计算属性
- 使用监视属性实现监视才能实现的功能,如异步操作
绑定样式
绑定class
-
调整单个类名:将不变的样式写在
class
内,将变化的样式写在:class
内动态调整<p class="some fixed class" :class="dynamic class"></p>
-
在类的名字、个数均不确定时动态调整多个类名:
:class
内绑定数组(数组内每个元素为一个类名)<p :class="cssarr"></p>
-
通过操作vue内的cssarr数组即可动态调整样式
cssarr.shift()//删除第一个类名 cssarr.push(xxx)//添加xxx类名
-
-
在类的名字、个数均确定时:
:class
绑定对象<p :class='classarr'></p>
data:{ classarr:{ name1: false, name2: true, } }
- 对象内对每个类名设置一个bool值表示是否使用
绑定style
-
通过
:style
绑定对象,对象格式如例styleObj = { color: xxx, fontSize: xx + 'px', }
- 注意添加单位
- css中多个单词构成的词(如
font-size
)需要更改格式(如fontSize
)
-
也可以绑定样式对象数组,同时绑定多个style对象
条件渲染
-
通过
v-show
条件渲染- 语法:
<a v-show="exp"></a>
- exp为一个值为bool类型的表达式
- 原理:exp为false时添加
display:none
的样式
-
通过
v-if
条件渲染-
语法:
<a v-if="exp"></a>
-
原理:exp为false是从DOM中删除该节点
-
可以搭配
v-else-if
和v-else
(不带条件)使用,但注意不能被打断
-
-
批量条件渲染:通过template包裹
-
语法
<template v-if="exp"> something </template>
-
template在渲染时会被去掉
-
template只能配合v-if,不能配合v-show
-
列表
列表渲染
-
从数组内动态获得列表内的li
-
语法:使用v-for循环
<ul> <li v-for="p in liarr">{{p}}</li> </ul>
- liarr为存储了li的数组
-
一个更好的写法是为每一个li赋值一个key,例如
<ul> <li v-for="p in student" :key="p.id">p.name</li> </ul>
- key需要保证互不相同
-
循环遍历数组过程中可以获取两个参数,第一个为传入的数组对象,第二个为index索引值,可直接使用index为key赋值(在不写key时默认给key赋值index)
<ul> <li v-for="(p,index) in student" :key="index">p.name</li> </ul>
-
v-for其它用法
-
遍历对象
<ul> <li v-for="(value,key) in objname" :key="key">key:value</li> </ul>
- 可以获取两个数据,注意顺序是value key
-
遍历字符串
<ul> <li v-for="(char,index) in objname" :key="index">char</li> </ul>
-
遍历自然数(从1开始)
<ul> <li v-for="(num,index) in 5" :key="index">num</li> </ul>
- 上例中num遍历结果是1,2,3,4,5
-
key的原理
-
key的作用:key是虚拟DOM的标识,当数据发生变化时,Vue会根据key对新虚拟DOM和旧虚拟DOM进行比较(Diff算法)
-
key为Vue内部使用,只存在于虚拟DOM,不会进入真实DOM
-
Diff算法比较原则
-
对相同key的新旧虚拟DOM
- 若内容没变,则直接使用旧的真实DOM
- 若内容变化,则使用新虚拟DOM生成新真实DOM
-
对旧DOM不存在的key
- 创建新的真实DOM
-
-
index作为key的问题:
- 对数据进行逆序添加、逆序删除 等操作时导致效率低下
- 对数据进行逆序添加、逆序删除时,若存在如输入框这类的元素可能导致界面出现错误
-
开发中key的选择key的原则:
- 最好使用每个数据的唯一标识作为key,如id、手机号、身份证号、学号等唯一值
- 如果所有操作均不破坏数据原有顺序,也可以使用index
列表过滤(模糊搜索)
-
通过计算属性配合
array.filter
等函数过滤,例如根据data中的keyWord模糊搜索p.name里含keyWord的项comuted:{ keyWord(){ return originarr.filter((p)=>{ return p.name.indexOf(keyWord) !== -1 }) } }
- tip: 空串是任何字符串的子集
表单数据收集
不同类型的数据收集技巧
input元素
-
text类型:直接进行数据绑定即可得到用户输入
-
radio类型:需要手动配置value的值,选择时会手机配置的value值
-
checkbox类型:
- 用于多选:需要先手动配置value的值,并且将与之绑定的元素初始值设为
[]
,收集到的元素以数组的形式存储 - 用于单个选项:将与之绑定的元素初始值设为非数组,会收集到一个bool值表示是否选中
- 用于多选:需要先手动配置value的值,并且将与之绑定的元素初始值设为
select元素:配置每一项的value,元素与select绑定可手机被选择项的value
textarea元素:直接绑定收集用户输入
v-model的修饰符
-
语法:
v-model.xxx=""
(xxx为修饰符) -
修饰符列表
修饰符 作用 lazy 等待失去焦点再收集数据 number 将输入字符串转换为数字 trim 过滤首位空格
过滤器
-
作用:对要显示的数据进行一定的格式化
-
语法:
-
注册过滤器:在filter内注册
new Vue({ filter:{ fname(value){ xxx return yyy; } } })
-
使用过滤器:可以在插值语法或指令语法中使用
{{exp | filtername}}
-
使用后这段表达式将被解析为过滤器的返回值
-
exp的值将会作为过滤器的第一个参数
-
过滤器在使用时后面加小括号可以传递更多的参数,但exp的值始终作为第一个参数,其余参数在exp后面追加
-
可以连续调用多个过滤器处理,语法为
{{exp | filtername1 | filtername2| filtername3}}
-
-
其它内置指令
-
v-text与v-html
-
共同点:将变量绑定到显示的内容上(此时会忽略html里标签内原有的文本)
-
不同点:
v-text
不解析标签,v-html
会解析标签 -
注意:v-html存在安全性问题
- 在网站上动态渲染html是危险的,容易导致xss攻击
- 要在可信的网页上使用v-html
- 不能在用户输入上使用html
-
-
v-cloak
- 功能:一个不需要值的特殊属性,所有的v-cloak属性在Vue接管后会消失
- 作用:配合css可以解决网速过慢导致Vue未解析的内容直接显示的问题
-
v-once
- 功能:一个不需要值的特殊属性,添加后在初次动态渲染后将该属性所在标签改为静态内容
-
v-pre
- 功能:一个不需要值的特殊属性,添加后Vue不会解析该标签的内容
自定义指令
函数式
-
调用:
v-xxx=""
-
声明:
new Vue{ directives:{ xxx(element,binding){ some code } } }
- element是调用元素的真实DOM节点
- binding是绑定内容的对象,包含很多关于绑定内容的信息
-
directives内的函数调用时机:
- 指令与元素成功绑定时
- 指令所在的模板重新解析时
对象式
-
调用:
v-xxx=""
-
声明:
new Vue{ directories:{ xxx: { bind(){}, inserted(){}, update(){} } } }
- bind函数将会在绑定成功时调用
- inserted函数将会指令所在元素插入页面时调用
- update函数将会在所在模板被重新解析时被调用
- 上面三个函数均可接受
(element,binding)
两个参数
-
函数式声明可以看作把bind和update合并声明
注意事项
-
指令名:若有多个单词,则在调用时使用
v-xxx-xx-x
的形式,声明时书写如下完整版本(不可简写)'xxx-xx-x': function(){}
-
this指向:directives里调用this指向均为window
-
默认directives内的指令为局部指令,若要声明全局指令,则用
Vue.directive('name',{ function content })
- 注意:vm内为directives,Vue内directive
生命周期函数
-
别名:生命周期、生命周期回调函数、生命周期钩子
-
定义:Vue在一定事件会调用的一些特殊名称(名称不可更改)的函数
-
this指向:生命周期函数内this指向vm或对应组件实例对象
-
常用周期函数:
-
mounted():在页面挂载完毕时调用
- 一般用于初始化操作,如发送Ajax请求、启动定时器、绑定自定义事件、订阅消息等
-
beforeDestroy:在实例即将被销毁时调用
- 一般用于收尾工作,如清楚定时器、解绑自定义事件、取消订阅等
-