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

44 篇文章 0 订阅
1 篇文章 0 订阅

课程大纲

  • (1)全局API
  • (2)自定义指令—起源
  • (3)自定义指令—分类
  • (4)自定义指令—注册
  • (5)自定义指令—调用
  • (6)自定义指令—生命周期钩子

全局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)自定义指令调用
    注册完毕后,在在需要使用的组件里进行调用
    在介绍自定义指令调用前,先来回顾下组件的调用
    在这里插入图片描述

  • 上图对比两者,因为HTML对英文大小写不敏感,所以在注册时使用驼峰命名法,在调用时使用短横线分割法调用。
    -上图 总结:
    注册时→驼峰法;调用时→短横线法;

  • (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更新等相关的生命周期钩子
  • (7-5)unbind解绑钩子
    在这里插入图片描述

自定义指令

  • (8)自动聚焦案例
    目前为止,常用自定义指令相关的生命周期钩子已经介绍完毕,但仍然未实现输入框自动聚焦功能。
  • 该功能还需要一些钩子函数参数el、binding、vnode,参数解析:
    ①el:指令所绑定的元素,可以用来直接操作DOM
    ②binding: 一个对象,包含指令的很多信息
    ③vnode: Vue编译生成的虚拟节点virtual node

自定义指令参数

  • (9)钩子函数参数
    接下来介绍下钩子函数相关参数,验证如下
    随意选择一个生命周期,在里面测试即可
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • (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>demo</title>
		<style type="text/css">

		</style>
		<link rel="stylesheet" type="text/css" href="../css/animate.min.css" />
		<script src="../js/velocity.js" type="text/javascript" charset="utf-8"></script>
		<script src="../js/vue-2.6.9.min.js" type="text/javascript" charset="utf-8"></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" type="text/javascript" charset="utf-8"></script>
		<script src="../js/velocity.js" type="text/javascript" charset="utf-8"></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" type="text/javascript" charset="utf-8"></script>
		<script src="../js/vue-2.6.9.min.js" type="text/javascript" charset="utf-8"></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" type="text/javascript" charset="utf-8"></script>
		<script src="../js/vue-2.6.9.min.js" type="text/javascript" charset="utf-8"></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>

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

裴嘉靖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值