全局API
- (1)什么是全局API?
- 全局API并不在构造器里,而是先声明全局变量或者直接在Vue上定义一些新功能,Vue内置了一些全局API,比如本节要介绍的指令Vue.directive
- 通俗理解:就是在构造器外部用Vue提供的API函数来定义新的功能。
- (2)常用vue 的全局 API列表
- 1、Vue.directive 自定义指令
- 2、Vue.extend 扩展实例构造器
- 3、全局操作Vue.set + Vue.delete
- 4、Vue 的生命周期
- 5、Vue component 组件 + Vue template模板
- 6、Vue.nextTick线程操作、Vue.filter筛选、Vue.use调用
- 小结:全局API就是在构造器外部用Vue提供的API函数来定义新的功能。
自定义指令起源
- (2)缘由:
- Vue2.0开始代码复用性和抽象的主要形式是组件,然而个别情况下仍然需要对普通DOM元素进行底层操作。
- 之前所学的v-if、v-show等都是vue内置指令,有时部分功能是无法通过内置指令实现,此时便需要用到自定义指令。
- (3)场景:
- 页面加载完毕后要求输入框自定聚焦,这种功能在很多场景都会用到,例如百度、京东、淘宝等
自定义指令分类
- (4)自定义指令分类
- 自定义指令分为全局和局部,正式介绍自定义指令之前,先来回顾下组件的相关知识
- 组件分类:全局组件和局部组件,语法如下
- 全局组件注册语法为Vue.component()
- 局部组件注册需要借助components选项
自定义指令注册
- (5)注册自定义指令
- 同理,自定义指令注册语法与之类似,如下所示
- 全局自定义指令注册语法为Vue.directive()
- 局部自定义指令注册需要借助directives选项
全局指令VS局部指令
- 自定义指令分为全局+局部
- 全局注册为Vue.directive()
- 局部注册为directives选项内注册
- 区别:
- 作用域不同,全局注册的自定义指令可以在全局调用,局部注册的自定义指令只能在当前构造器作用域内使用(类似于全局组件与局部组件)。
自定义指令调用
- (6)自定义指令调用
- 注册完毕后,在在需要使用的组件里进行调用
- 在介绍自定义指令调用前,先来回顾下组件的调用
- 注册完毕后,在在需要使用的组件里进行调用,语法v-directive-name
- 调用自定义指令时,语法类似调用组件,如下所示
自定义指令
- 案例:
- 利用自定义指令,实现一个输入框自动聚焦功能,代码如下
自定义指令钩子/生命周期
- 上例只是注册了自定义指令v-auto-focus,还没有实现具体功能,要想实现自动聚焦功能,需要结合选项去实现。下面具体介绍自定义指令的各个选项。
自定义指令的选项是由几个生命周期钩子函数组成的,每个都是可选的。 - 常见生命周期钩子如下
- 1、bind第一次绑定到元素时调用
- 2、inserted被绑定元素插入父节点时调用
- 3、update被绑定元素所在的模板更新时调用
- 4、componentUpdated被绑定元素所在模板完成一次更新周期时调用
- 5、unbind指令与元素解绑时调用
- (7-1)bind初始化钩子
- 含义:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。验证如下
- (7-2)inserted绑定钩子
- 含义:被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于document中)
- (7-3)update更新钩子
- 含义:被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新
- (7-4)componentUpdated模板更新完毕钩子
- 含义:被绑定元素所在模板完成一次更新周期时调用,即所在组件的 vnode 及其孩子的 vnode 全部更新时调用
- (7-5)unbind解绑钩子
- 含义:指令只调用一次,指令与元素解绑时调用
- 测试:刷新页面后执行bind与inserted钩子,更新时执行update和componentUpdated钩子,接下来添加解绑操作,看看会不会触发unbind解绑钩子… …
- 添加按钮,点击实现vue实例解绑
- 销毁实例绑定,即可实现解绑
- 注意:销毁的不是DOM元素,而是该vue实例相关的方法和属性,也就是说以后再更新元素时,也不会触发update和componentUpdated更新等相关的生命周期钩子
自定义指令
- (8)自动聚焦案例
- 目前为止,常用自定义指令相关的生命周期钩子已经介绍完毕,但仍然未实现输入框自动聚焦功能。
- 该功能还需要一些钩子函数参数el、binding、vnode,参数解析:
- ①el:指令所绑定的元素,可以用来直接操作DOM
- ②binding: 一个对象,包含指令的很多信息
- ③vnode: Vue编译生成的虚拟节点virtual node
自定义指令参数
- (9)钩子函数参数
- 接下来介绍下钩子函数相关参数,验证如下
- 随意选择一个生命周期,在里面测试即可
- 结合控制台输出结果可以分析出el为绑定元素、binding为一个对象(包含指令相关信息)、vnode为虚拟节点
- 所以如果想操作DOM,可以利用el
- (10)自动聚焦案例
- 接下来结合生命周期钩子和相关参数el实现聚焦功能
- 分析:
- 页面加载完毕后触发bind和inserted,但DOM元素聚焦操作需要等待被绑定元素插入父节点后才能执行,所以将聚焦功能写到inserted绑定钩子里即可,如下所示
- (11)钩子函数参数binding对象详解
- 接下来详细介绍下自定义指令钩子函数的参数binding对象
- binding: 一个对象,包含指令的很多信息
- 1、name:指令名,不包括v-前缀。
- 2、value:指令的绑定值,例如:v-my-directive=“1 + 1”, value 的值是2。
- 3、oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用。无论值是否改变都可用。
- 4、expression:绑定值的字符串形式。例如v-my-directive=“1 + 1”,expression 的值是"1 + 1"
- 5、arg:传给指令的参数。例如v-my-directive:foo,arg 的值是"foo"。
- 6、modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar, 修饰符对象 modifiers
的值是{ foo: true, bar: true }。 - 7、vnode:Vue 编译生成的虚拟节点,查阅 VNode API 了解更多详情。
- 8、oldVnode:上一个虚拟节点,仅在update和componentUpdated钩子中可用。
自定义指令-钩子案例
- (12-1)bind初始化钩子之变色案例
- 接下来再做个变色的自定义指令v-color,要求绑定该自定义指令的元素字体颜色变红,如下所示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>自定义指令-聚焦+变色</title>
<link rel="stylesheet" type="text/css" href="../css/animate.min.css"/>
<script src="../js/velocity.js" ></script>
<script src="../js/vue-2.6.9.min.js" ></script>
</head>
<body>
<div id="root">
<input type="text" v-auto-focus v-color-red="color" v-model="name">
<button @click="destroyVue">销毁</button>
</div>
<script type="text/javascript">
/*注册全局自定义指令*/
Vue.directive('autoFocus', {
/*选项*/
bind(el, binding, vnode) {
console.log('bind-第一次绑定到元素时调用')
console.log(el)
console.log(binding)
console.log(vnode)
},
inserted(el) {
console.log('inserted-被绑定元素插入父节点时调用')
el.focus();
},
update() {
console.log('update-被绑定元素所在的模板更新时调用')
},
componentUpdated() {
console.log('componentUpdated-模板更新完毕钩子')
},
unbind() {
console.log('unbind-解绑时调用')
}
})
Vue.directive('colorRed', {
bind(el, binding) {
el.style = "color:" + binding.value
console.log(binding)
}
})
var root = new Vue({
el: '#root',
data: {
name: '',
color: 'red'
},
methods: {
destroyVue() {
this.$destroy(); /*销毁Vue实例*/
}
}
/*
局部注册自定义指令
directives:{
'autoFocus':{
}
}
*/
})
</script>
</body>
</html>
- (12-2)inserted绑定钩子之图片墙案例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>自定义指令案例-图片拖拽旋转</title>
<script src="../js/vue-2.6.9.min.js"></script>
<script src="../js/velocity.js" type="text/javascript"></script>
<style type="text/css">
.box {
width: 800px;
height: 800px;
position: relative;
background-color: #000000;
margin: auto;
}
.img {
width: 200px;
position: absolute;
left: 0;
top: 0;
transform: rotateZ(0deg);
}
</style>
</head>
<body>
<div id="root">
<div class="box">
<img src="../img/t1.png" class="img" v-ball>
<img src="../img/t2.png" class="img" v-ball>
<img src="../img/t3.png" class="img" v-ball>
<img src="../img/t4.png" class="img" v-ball>
<img src="../img/t5.png" class="img" v-ball>
<img src="../img/t6.png" class="img" v-ball>
<img src="../img/t7.png" class="img" v-ball>
</div>
</div>
<script type="text/javascript">
/* 1、注册 */
Vue.directive('ball', {
inserted: function(el) {
var i = 0;
el.onclick = function(e) {
i += 10;
el.style.transform = "rotateZ(" + i + "deg)"
};
el.onmousedown = function(e) {
var l = e.clientX - el.offsetLeft;
var t = e.clientY - el.offsetTop;
document.onmousemove = function(e) {
el.style.left = (e.clientX - l) + 'px';
el.style.top = (e.clientY - t) + 'px'
};
el.onmouseup = function() {
document.onmousemove = null;
el.onmouseup = null;
}
}
}
});
var root = new Vue({
el: '#root'
})
</script>
</body>
</html>
- (12-3)update更新钩子之随机色案例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>自定义指令案例-随机色</title>
<script src="../js/velocity.js" ></script>
<script src="../js/vue-2.6.9.min.js" ></script>
<style type="text/css">
#text {
width: 100px;
height: 100px;
resize: none;
}
</style>
</head>
<body>
<div id="root">
<textarea id="text" v-model="inputValue" v-box></textarea>
</div>
<script type="text/javascript">
/* 1、注册 */
Vue.directive('box', {
update: function(el) {
let color1 = Math.ceil(Math.random() * 225);
let color2 = Math.ceil(Math.random() * 225);
let color3 = Math.ceil(Math.random() * 225);
el.style.backgroundColor = 'rgb(' + color1 + "," + color2 + ',' + color3 + ")"
}
});
var root = new Vue({
el: '#root',
data: {
inputValue: ''
}
})
</script>
</body>
</html>
- (12-4)bind初始化钩子之下拉列表
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>自定义指令案例-开关下拉框</title>
<script src="../js/velocity.js" ></script>
<script src="../js/vue-2.6.9.min.js" ></script>
<style type="text/css">
[v-cloak] {
display: none;
}
.main {
width: 125px;
}
button {
display: block;
width: 100%;
color: #fff;
background-color: #39f;
border: 0;
padding: 6px;
text-align: center;
font-size: 12px;
border-radius: 4px;
cursor: pointer;
outline: none;
position: relative;
}
button {
top: 1px;
left: 1px;
}
.dropdown {
width: 100%;
height: 150px;
margin: 5px 0;
font-size: 12px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
}
.dropdown p {
display: inline-block;
padding: 6px;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<div class="main" v-click-outside="handleClose">
<button @click="show =!show">点击显示下拉菜单</button>
<div class="dropdown" v-show="show">
<p>下拉框的内容,点击外部区域可以关闭</p>
</div>
</div>
</div>
<script type="text/javascript">
/* 1、注册 */
Vue.directive('clickOutside', {
bind: function(el, binding) {
console.log(binding)
function documentHandler(e) {
//判断点击的区域是否是指令所在的元素内部,如果是,就跳出函数,不往下执行。
if (el.contains(e.target)) {
return false;
}
//判断当前的指令v-clickoutside有没有写表达式
if (binding.expression) {
//binding.value()就是用来执行当前上下文methods中指定的函数的
binding.value(e);
}
}
//用于在unbind钩子函数中移除对document的click事件监听。
el.__vueClickOutside__ = documentHandler;
document.addEventListener('click', documentHandler);
},
unbind: function() {
document.removeEventListener('click', el.__vueClickOutside__);
//如果不移除,当组件或元素销毁时,它仍存在于内存中
delete el.__vueClickOutside__;
}
})
var app = new Vue({
el: '#app',
data: {
show: false
},
methods: {
handleClose() {
this.show = false;
}
}
})
/*
要在document上绑定click事件,所以在bind钩子内声明了一个函数documentHandler
并将它作为句柄绑定在document的click事件上。documentHandler函数做了两个判断
第一个是判断点击的区域是否是指令所在的元素内部,如果是,就跳出函数,不往下继续执行。
contains方法是用来判断元素A是否包含了元素B,包含返回true,不包含返回false,示例代码如下:
<div id="parent">
父元素
<div id="children">子元素</div>
</div>
var A =document.getElementById('parent');
var B =document.getElementById('children');
console.log(A.contains(B));//true
console.log(B.contains(A));//false
*/
</script>
</body>
</html>
以上是Vue全局API+几个案例,如有疑问请随时联系小编!