VUE之全局API(自定义指令directive)

本文详细介绍了Vue的全局API中的自定义指令,从自定义指令的起源、分类、注册到全局与局部指令的区别。并通过实际案例,如自动聚焦、变色、图片墙、随机色等,深入解析了自定义指令的生命周期钩子及其参数,帮助读者掌握自定义指令的使用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

全局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+几个案例,如有疑问请随时联系小编!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值