单文件使用Vue
入门
单文件使用Vue只需导入cdn即可
引入Vue后会在全局新增一个构造函数Vue(),使用该函数创建实例使用Vue
该函数只接收一个对象类型的参数,这种对象称为配置对象,可以通过修改属性值来配置Vue
例:
<!-- 创建一个容器 -->
<div id="box">
<h1>{{name}},{{age}}</h1>
</div>
// 创建一个Vue实例
const v=new Vue({
el:'#box',//指定当前容器为哪个容器服务
data:{//用于存储数据,供指定容器使用
name:"Orange",
age:18
}
})
el和data的两种写法:el- 直接指定属性值
- 修改vue内部的mount (挂载) 属性:
v.$mount('#box')也可实现同样的功能
data-
对象式:将data写为一个对象:
data:{} -
函数式:data写为函数,将data中的数据作为返回值返回,组件化开发会强制使用函数式写法,注意不能写成箭头函数(
()=>{}),data:function(){ return{ name:"Orange", } } //或 data(){ ...... }
-
- 实际上凡是Vue管理的方法都不能使用箭头函数
{{}}是Vue提供的语法,可以快速调用vue.js中定义的变量,还可以使用简单的JS表达式:
<div id="vm">
<p>{{number+1}}</p>
<p>{{ok?'Ture':'False'}}</p>
<p>{{message.split('')}}</p>
<p>{{message.split('').reverse()}}</p>
<p>{{message.split('').reverse().join('')}}</p>
</div>
<script>
new Vue({
el:'#vm',
data: {
number: 9,
ok: false,
message: "ABC",
}
})
</script>
但是不能使用JS代码,如if(){} for(){}等
模板语法详见单文件使用Vue#模板语法
显示的效果为:
10
False
[ "A", "B", "C" ]
[ "C", "B", "A" ]
CBA
.split()、.reverse()、.join()都是内置方法,输出结果分别为:
[ "A", "B", "C" ] [ "C", "B", "A" ] CBA
- 一个实例只能对应一个容器,一个容器也只能由一个实例管理,是一一对应关系
模板语法
插值语法
即使用关键字{{}}替换
<div id="vm">
<h1>{{name}}</h1>
</div>
<script>
new Vue({
el:'#vm',
data: {
name:"Orange"
}
})
</script>
除了可以插入data中的数据,还可以插入methods中的方法,相当于亲自调用回调函数
<p id="pid" >{{showName()}}</p>
注意这个和事件绑定的函数调用不同,不加()就是相当于没有调用函数
指令语法
<div id="vm">
<h1>{{fellows.name}}</h1>
<h1><a v-bind:href="fellows.url">点击跳转</a></h1>
</div>
<script>
new Vue({
el: '#vm',
data: {
fellows:{//设计为多级结构有利于避免重复
name: "Orange",
age:18,
url: "https://www.runoob.com/"
}
}
})
</script>
v-bind将引号中的字符转换为语句执行,将执行结果绑定给href
另外v-bind:可以简写为:
插值语法常用于标签体内容
指令语法常用于标签属性,解析标签
数据绑定
单向数据绑定
v-bind可以实现数据绑定,但是只能单向,即标签内容改变不会改变data中的值
<input type="text" v-bind:value="name">
双向数据绑定
v-model可以实现双向绑定,但是不会改变源代码,刷新后又会恢复
<input type="text" v-model:value="name">
v-model但是该指令只能应用于表单类元素上,防止页面原有元素被改变,换言之该指令只能绑定在value这个属性上
由于特定绑定属性的特性,可以简写为:
<input type="text" v-model="name">
MVVM模型

- MVVM由三部分组成:
- M:模型(Model) :对应 data 中的数据
- V:视图(View) :模板
- VM:视图模型(ViewModel) : Vue 实例对象
使用一段代码理解:
<div id="vm">
<h1>{{fellows.name}}</h1> <!-- 视图 -->
<h1><a v-bind:href="fellows.url">点击跳转</a></h1>
</div>
<script>
new Vue({//视图模型
el: '#vm',
data: {//模型
fellows:{
name: "Orange",
age:18,
url: "https://www.runoob.com/"
}
}
})
</script>
- 关系:
- 模型通过视图模型实现DOM操作
- 视图通过视图模型接受模型监听
- 发现:
- data中的所有属性最后都出现在vm中
- vm中的属性及Vue原型中的属性都可以在Vue模板中直接调用
在浏览器的控制台中可以验证,访问vm发现name和age都变成了vm中的属性:

数据代理
基本数据代理技术
数据代理技术涉及Object的方法defineProperty(),详见[[Object#defineProperty()]]
- 下面的代码实现了几个基本的数据代理:通过
obj2实现修改obj1的元素属性值
var obj1 = { x: 100 };
var obj2 = { y: 200 };
Object.defineProperty(obj2, 'x', {
get() {
return obj1.x;
},
set(value) {
obj1.x = value;
},
})
Vue中的数据代理
在Vue中,data中的数据会放入创建的Vue实例中,即#MVVM模型中的vm中,同时还会创建响应的getter和setter函数用于访问和修改数据

所以通过控制台或脚本可以直接修改data中的属性值

创建实例后,Vue会先将data中的数据存入新建对象的 _data 属性中,所以实际上{{_data.name}}也可以正常访问name,但是为了写起来方便,又在外部创建了name和age属性,通过数据代理技术实现对_data中的数据进行访问和修改
事件处理
基本使用
在实例中配置事件的回调函数即可在其控制的容器中使用这个回调函数:
<div id="box">
<button v-on:click="showInfo">click!</button>
<button @click="showInfo2(66)">click!</button>
</div>
<script>
const vm = new Vue({
el: '#box',
methods: {
showInfo() {
alert("Hello");
}
showInfo2(number) {
alert("Hello ",number);
}
}
})
</script>
v-on:或@都可以配置事件- 注意vm中的方法不能写成箭头函数,箭头函数的this指向外部的window ,vm中的所有方法的
this均是vm即vue中的实例对象 - 回调函数的传参直接在标签中进行即可,没有参数可以不加
(),但是此时也会默认传入一个事件参数event - 另外为了防止丢失默认传入的鼠标事件的参数event,可以加一个
$event占位,即:
相应的方法的形参也要加上event,先后顺序要对应<button v-on:click="showInfo2(66,$event)">click!</button>showInfo2(number,event) { alert("Hello ",number); }
事件修饰符
实例:超链接点击时有一个跳转的默认事件一般在方法中定义属性preventDefault()来阻止默认事件
<div id="box">
<a href="https://zh.wikipedia.org" @click="alert">wikipedia</a>
</div>
<script>
const vm = new Vue({
el: '#box',
methods: {
alert(e) {
e.preventDefault();
alert("Hello");
}
}
})
</script>
更加优雅的方法就是使用事件修饰符prevent:
<div id="box">
<a href="https://zh.wikipedia.org" @click.prevent="alert">wikipedia</a>
</div>
<script>
const vm = new Vue({
el: '#box',
methods: {
alert(e) {
alert("Hello");
}
}
})
</script>
Vue中提供了6个事件修饰符:
- prevent 阻止默认事件,对应方法
preventDefault() - stop 阻止事件冒泡,对应方法
stopPropagation()
<div id="box" @click="alert">
<button @click.stop="alert">click</button>
</div>
-
once 事件只触发一次
-
capture 使用事件的捕获模式,浏览器处理事件时是先捕获再冒泡,即事件的响应是先内层后外层,使用捕获模式就是由外向内响应事件
<div id="box"> <div id="box1" @click="alert(1)"> <div id="box2" @click="alert(2)"> </div> </div> </div> <script> const vm = new Vue({ el: '#box', methods: { alert(e) { console.log(e) } } }) </script>- 此时控制台显示的是2 1
<div id="box"> <div id="box1" @click.capture="alert(1)"> <div id="box2" @click="alert(2)"> </div> </div> </div> <script> const vm = new Vue({ el: '#box', methods: { alert(e) { console.log(e) } } }) </script>- 此时就是显示1 2
-
self 只有event.target是当前触发的元素时才能触发事件,一定程度上也可以防止冒泡
-
passive 事件的默认行为立即执行,无需等待事件回调执行完毕
修饰符可以连续写
键盘事件
实例:下面的代码实现只有按下enter键才显示输入的内容
<div id="box">
<input type="text" @keyup="show">
<p id="pid"></p>
</div>
<script>
const vm = new Vue({
el: '#box',
methods: {
show(e) {
console.log(e.keyCode)
if (e.keyCode === 13) {
var p = document.getElementById('pid');
p.innerHTML = e.target.value;
}
}
}
})
</script>
实际上可以使用键盘事件修饰符来代替判断语句:
<input type="text" @keyup.enter="show">
- Vue为常用的键盘按键都定义了别名,共9个:
- 回车 =>
enter - 删除 =>
delete(捕获“删除”和“退格”两个键) - 退出 =>
esc - 空格 =>
space - 换行 =>
tab(特殊,必须配合keydown去使用) - 上 =>
up(方向键) - 下 =>
down - 左 =>
left - 右 =>
right
- 回车 =>
- 没有定义的按键也可以自己按照按键名绑定,但注意需要全部转换为小写,若不止一个单词则每个单词使用
-链接,如CapsLock键<input type="text" @keyup.caps-lock="show">- 使用keyCode方法查看按键的按键名
methods: { show(e) { console.log(e.keyCode) }
- 使用keyCode方法查看按键的按键名
- 注意
tab键比较特殊,按下时会使当前元素失去焦点,所以只能配合keydown事件使用 - 另外还有四个系统修饰键比较特殊:
ctrlaltshiftmeta(win)- 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发(即忽略掉原本的功能)
- 配合keydown使用:正常触发事件
- Vue也提供了自定义别名按键的方法:
Vue.config.keyCode.Fuck = 13// 将Fuck和回车绑定
计算属性与监视属性
- 计算属性在computed中配置,要求写出完整的计算过程
- 和data一样,computed也是Vue实例的属性,可以通过插值语法访问
<p id="pid">{{fullName}}</p>
get()
- 在内部使用
get()函数实现属性计算,get()见[[Object#get()和set()]]功能相同 - Vue将computed中属性的
get()方法的this指向了实例对象,直接通过this即可访问实例对象的属性值
computed: {
fullName: {
get() {
return this.first + '-' + this.last;
}
}
}
相比其他方式,计算属性有一个缓存特性,即若前面已经调用过该方法,后面就不会重复调用,而是直接读取缓存中的内容,如下面的计算属性被调用了4次,但是只有一次get()方法的调用
<p id="pid">{{fullName}}</p>
<p id="pid">{{fullName}}</p>
<p id="pid">{{fullName}}</p>
<p id="pid">{{fullName}}</p>
get()调用时机:- 初次读取计算属性
- 依赖的数据发生变化时
- 这种机制保证了最大限度的节约资源,提高响应速度同时保证改变及时响应
set()
get()用于属性被调用时的响应,set()用于属性被改变时的响应,不是必须
和[[Object#defineProperty()]]相同,参数是被改变后的值
get()和set()不能写成箭头函数,此时this就是window,无法访问到实例对象
简写:
当确定不会改变计算属性时 ,可以采用简写形式,将计算属性写为一个函数,实现get()的功能
computed: {
fullName(){
return this.first + '-' + this.last;
}
}
}
总结
- 定义:要用的属性不存在,要通过已有属性计算得来
- 原理:底层借助了Objcet.defineproperty方法提供的getter和setter
- 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
- 备注
- 计算属性最终会出现在vm上,直接读取使用即可
- 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变
监视属性
- 语法:
- 使用内部属性watch修改指定属性的配置
watch: { isHot: { handler(a, b) { console.log(a, b); } } }- 或创建实例后使用
$watch修改,接受两个参数,监视的对象和配置
vm.$watch('isHot', { handler(a, b) { console.log(a, b); } }); - 常见配置项有:
handler(newValue,oldValue)第一个参数为新值,第二个为旧值immediate为布尔值,为true时无论是否改变都执行deep为布尔值,为true时可以是实现深度监视,即可以检测到多级结构的改变
监视属性可以监视所有属性值,如还可以监视计算属性的变化
watch: {
info: {
handler(a, b) {
console.log(a, b);
}
}
}
监视多级结构中某个属性的变化
// 内部的写法
watch: {
'number.a': {
handler(a, b) {
console.log('a: ', a, b);
}
},
}
// 外部的写法
vm.$watch('number.a', {
handler(a, b) {
console.log(a, b);
}
});
简写:
配置项只需要handler时,可以采用简写写法:
// 内部
watch: {
isHot(a, d) {
console.log(a, b);
}
}
// 外部
vm.$watch('isHot', function (a, b) {
console.log(a, b);
})
注意不能使用箭头函数,会造成this指向问题
watch和computed的比较
计算属性可以更加简单的实现属性的修改等操作,而监视属性则可以轻松的实现异步任务,如:
实现延迟1秒输出结果:
// watch实现
handler(n, o) {
setTimeout(() => {
this.fullname = n.first + '-' + n.last;
}, 1000);
}
// computed实现
fullname() {
setTimeout(() => {
return this.name.first + '-' + this.name.last;
}, 1000)
}
事实上计算属性无法实现这个任务,返回值被setTimeout接收,而fullname没有返回值
注意这里的setTimeout()的回调函数一定要写成箭头函数,否则this就会指向window
总结
- computed能完成的功能,watch都可以完成
- watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
- 两个重要的小原则:
- 所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象
- 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm或组件实例对象。
数据更新检测的原理
- watch是认为配置检测属性更新,Vue本身也会检测属性的变化从而改变原有的内容,二者底层实现是相类似的逻辑
- 在实例中定义的属性都会添加
get()和set()函数,由此就可以实现实时的访问和修改,所以后续直接添加的属性不会有这些对应的函数,此时应该使用Vue.set()实现后添加的数据也具有响应式的功能
监测对象
Vue.set()
- 语法:
// 选项式API
Vue.set(target,key,val)
// 命令式API
vm.$set(target,key,val)
- 参数:
{Object | Array} target{string | number} propertyName/index{any} value
- 示例
Vue.config.productionTip = false
const vm = new Vue({
el: '#box',
data: {
student: {
name: "Orange",
},
}
});
Vue.set(vm.student, 'sex', 'male');
vm.$set(vm.student, 'sex', 'male');
由于存在数据代理,直接索引vm中的数据即可,无需在_data中寻找
- 缺陷:不能直接在实例上加属性,需要加在原有对象属性中
监测数组
和对象属性不同,Vue中的数组属性不依靠get和set函数进行监视,而是监测数组对象push() pop() shift() unshift()等是否被调用,若调用则更新数据
数组方法详见Array对象
Vue使用了包装的技术,实际上在Vue中调用的方法已经不是原生的数组方法,Vue将其进行了包装,以便调用时可以检测到
见列表渲染
在上一小节Vue.set()中发现参数还可以传数组和索引,所以实际上也可以使用Vue.set()函数实现数组元素的修改
样式绑定
class 绑定
:class='xxx'- 即变化的样式使用
v-bind(或简写为:)绑定,xxx即为对应类名
- 即变化的样式使用
- 表达式是字符串:
'classA' - 表达式是对象:
{classA:isA, classB:isB}- 绑定的样式个数和名字都确定时使用,但是需要动态决定是否使用样式
- 表达式是数组:
['classA', 'classB']- 当需要应用多个类的样式个数和名字都不确定时,使用数组,相当于
class="classA classB classC"
- 当需要应用多个类的样式个数和名字都不确定时,使用数组,相当于
style 绑定
:style="{ color: activeColor, fontSize: fontSize + 'px' }"- 其中 activeColor/fontSize 是 data 属性
- 样式和数据名相同时可以简写(即直接绑定内联样式)内联样式绑定
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
一道小题:颜色变换
条件渲染
指令
v-if与v-else-if
v-if值也为布尔值
<button @click="n<=3?n++:n=1">我爱你</button>
<h1 v-if="n===1">我</h1>
<h1 v-else-if="n===2">爱</h1>
<h1 v-else-if="n===3">你</h1>
<h1 v-else>haha</h1>
不同点在于不是隐藏样式,而是彻底使其消失
注意该语法不允许中间有其他语句,打断后面的都会失效
v-show
值为布尔值或结果为布尔值的表达式,也可以调用实例中定义的方法
<h1 v-show="false">My name is {{name}} !</h1>
底层是调整了dispaly属性值
在控制台查看时源码变为:
<h1 style="display: none;">My fucking name is Orange !</h1>
若内容需要频繁切换建议使用v-show,存在效率的问题
在需要同时对多个内容进行条件渲染时,若使用div标签统一显隐会破坏原来的css代码结构,此时可以使用<template>标签,特点是解析后就会消失,不会破坏原有css代码的功能,但是只能配合v-show使用
<template>
<h1>爱</h1>
<h1>你</h1>
<h1>我</h1>
<h1>haha</h1>
</template>
列表渲染
基本列表
v-for
实现循环执行指令
基本语法:形参 in 数据集,数据集的大小即为执行次数
形参有两个,数据和唯一的编号:(Obj,index) in 数据集
下面的示例是遍历数组
<body>
<div id="box">
<ul>
<li v-for="(per,index) in perosnList":key="index">
{{per.name}}-{{per.age}}
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false
const vm = new Vue({
el: '#box',
data: {
name: "Orange",
perosnList: [
{ id: '001', name: 'Lihua', age: 18 },
{ id: '002', name: 'Xiaoming', age: 19 },
{ id: '003', name: 'Laoba', age: 17 }
],
},
})
</script>
</body>
另外遍历对象也比较常用
key
- 一定要配置key的原因
- key用于给节点进行标识,一般使用数据本身的唯一标识,不能使用形参中的index
一个形象的例子:
<div id="box">
<h1>Orange</h1>
<button @click.once="add">click!</button>
<ul>
<li v-for="(per,index) in perosnList" key="per.id">
{{per.name}}-{{per.age}}
<input type="text">
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false
const vm = new Vue({
el: '#box',
data: {
name: "Orange",
perosnList: [
{ id: '001', name: 'Lihua', age: 18 },
{ id: '002', name: 'Xiaoming', age: 19 },
{ id: '003', name: 'Laoba', age: 17 }
],
},
methods: {
add() {
var p = { id: '004', name: 'Xiaohaha', age: 2.5 };
this.perosnList.unshift(p);
}
}
})
</script>
在输入框输入数据后点击按钮添加新的数据

如果将key值设置为index或不设置key,会发现

发生了错位
- 原因:
index作为key时

id作为key时

干脆不写key时,Vue将index自动作为key - 总结 (面试题:key的内部原理)
- 虚拟DOM中key的作用:key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM, 随后Vue进行新虚拟DOM与旧虚拟DOM的差异比
- 对比规则:
- 旧虚拟DOM中找到了与新虚拟DOM相同的key:
- 若虚拟DOM中内容没变, 直接使用之前的真实DOM
- 若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
- 旧虚拟DOM中未找到与新虚拟DOM相同的key创建新的真实DOM,随后渲染到到页面
- 旧虚拟DOM中找到了与新虚拟DOM相同的key:
- 用index作为key可能会引发的问题:
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新,界面效果没问题, 但效率低
- 如果结构中还包含输入类的DOM,会产生错误DOM更新,界面有问题
- 开发中如何选择key?
- 最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值
- 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的
列表过滤
实例见模糊搜索、列表排序
实际上就是使用数组和字符串方法操作
收集表单数据
使用v-model实现双向数据绑定来获取表单数据
v-model默认获取value值,对于一些没有value值的输入类型,需要人为指定,如单选框:
性别:
男<input type="radio" name="gender" v-model="userInfo.gender"value="male">
女<input type="radio" name="gender" v-model="userInfo.gender" value="female">
复选框也需要相应改变
爱好:
学习<input type="checkbox" v-model="userInfo.hobby" value="study">
打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
相应的在data中需要将hobby设置为数组,因为hobby初始值会改变表单的值
data:{
userInfo:{
hobby:[],
}
},
对于不需要收集值的数据可以不设置value,自动读取true或false
使用按钮也可提交表单,使用时间绑定配置提交相应,并阻止刷新页面的默认行为(prevent)
<form @submit.prevent="demo">
修饰符
.lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步,可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步:
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg"><br>
一般为失去焦点时
.number
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:
<input v-model.number="age" type="number"><br>
这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值
通常和表单number类型一起使用,使得只能输入数组并且存储为数字
年龄:<input type="number" v-model.number="userInfo.age">
.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:
<br><input v-model.trim="msg"><br>
过滤器
过滤器本质是一个函数
- 语法:
<h1>{{time | timeFormater}}</h1>
|分隔数据和过滤器,过滤器的返回值替换掉整个插值语法的内容,接受的是前方的数据
-
参数:由于是函数,也可以传递参数,第一个参数永远不变,是数据,后面的参数依次排列,按顺序调用即可
-
过滤器可以串联
<body>
<div id="root">
<h1>当前时间为:</h1>
<h1>{{time | timeFormater('YYYY年MM月DD日')|onlyYear}}</h1>
</div>
<script>
const vm=new Vue({
el:'#root',
data:{
time:Date.now()
},
filters:{
timeFormater(value,format){
return dayjs(value).format(format);
},
onlyYear(value){
return value.slice(0,4);
}
}
})
</script>
</body>
上面的写法是局部过滤器,只能本实例调用,下面给出全局过滤器写法
Vue.filter('onlyYear',function(value){
return value.slice(0,4);
})
注意全局过滤器需要一个一个定义,并且需要在可能调用该过滤器的实例之前声明
指令
内置指令
v-on
v-bind
v-model
v-text
向所在标签插入文本,替换整个标签中的内容,作为文本解析,不会作为vue语法解析
<h1 v-text="name"></h1>
可以实现和插值语法相同的功能,但是不如插值语法灵活
v-html
改变指定标签的innerHTML,作为html文本解析,不会作为vue语法解析
在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击
一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
v-cloak
不是clock :-(
- 这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如
[v-cloak] { display: none }一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。 - 示例:
[v-cloak] {
display: none;
}
<div v-cloak>{{ message }}</div>
不会显示,直到编译结束
- 总结
- v-cloak指令没有值
- 本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
- 使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题
v-once
- 总结
- v-once所在节点在初次动态渲染后,就视为静态内容了
- 以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
<h1 v-once>初始值为:{{n}}</h1>
<h1>现在为:{{n}}</h1>
<button @click="n++">点我n+1</button>
一道小题:优化性能的指令
v-pre
- 作用:
- 跳过其所在节点的编译过程
- 可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译
自定义指令
应用见自定义指令
语法
局部定义
在实例对象内部的属性directives中定义
和过滤器的逻辑类似内部注册的指令只能本实例调用
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
全局定义
和过滤器的逻辑类似,在外部定义时为单数,一个一个注册,其后注册的实例均可以调用
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
钩子函数
对象内部的函数称为钩子函数,关于钩子函数有一篇博客写的比较清晰:Vue中的钩子函数,要配合生命周期理解
bind():只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置inserted():被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)update():所在模板被重新解析时,实际上是VNode改变,暂时不了解,见链接钩子函数
自定义指令#对象式中使用了三个钩子函数
钩子函数的this是window
钩子函数参数
钩子函数均接收如下几个参数:
el:指令所绑定的元素,可以用来直接操作 DOMbinding:一个对象,包含以下 property:name:指令名,不包括v-前缀。value:指令的绑定值,例如:v-my-directive="1 + 1"中,绑定值为2。oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用。无论值是否改变都可用。expression:字符串形式的指令表达式。例如v-my-directive="1 + 1"中,表达式为"1 + 1"。arg:传给指令的参数,可选。例如v-my-directive:foo中,参数为"foo"。modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar中,修饰符对象为{ foo: true, bar: true }
- 其他参数见钩子函数参数
对象式是最标准的写法,可以照顾到很多细节问题,如何时调用什么函数等
如果实现较为简单的功能,可以使用函数形式
- 函数形式调用时机:
- 指令与元素成功绑定时,对应
bind() - 指令所在的模板被重新解析时,对应
update()
- 指令与元素成功绑定时,对应
所以如果没有在插入时调用的需求,就可以直接写为函数式