【vue笔记2】-自定义指令

版权声明:如要转发,请注明出处,小小喵的微博 https://blog.csdn.net/weixin_42881744/article/details/83691182

基础

除了内置指令,Vue.js也允许注册自定义指令。自定义指令提供一种机制将数据的变化映射为DOM行为。
Vue.js用Vue.directive(id,definition)方法注册一个全局自定义指令,它接受两个参数:指令ID与定义对象。也可以用组件的directives选项注册一个局部自定义指令(此方法相当于AngularJS restrict)属性值为A。

  1. 钩子函数
    bind——只调用一次,在指令第一次绑定到元素上时调用。
    update——在bind之后立即以初始值为参数第一次调用,之后每当绑定值变化时调用,参数为新值与旧值。
    unbind——只调用一次,在指令从元素上解绑时调用。
Vue.directive('my-directive',{
	bind:function(){
		//准备工作
		//例如,添加事件处理器或只需要运行一次的高耗任务
	},
	update:function(){
		//值更新时的工作
		//也会以初始值为参数调用一次
	},
	unbind:function(){
		//清理工作
		//例如,删除bind()添加的事件监听器
	}
})

在注册之后,便可以在Vue.js模板中这样用(记着添加前缀-v):

<div v-my-directive="someValue"></div>

当值需要update函数时,可以传入一个函数替代定义对象:\

Vue.directive('my-directive',function(value){
	//这个函数用作update()
})
  1. 指令实例属性
    所有的钩子函数都将被复制到实际的指令对象中,在钩子内this指向这个指令对象。这个对象暴露了一些有用的属性:
    el——指令绑定的元素。
    vm——拥有该指令的上下文ViewModel.
    expression——指令的表达式,不包括参数和过滤器。
    arg——指令的参数。
    name——指令的名字,不包括前缀。
    modifiers——一个对象,包括指令的修饰符。
    descriptor——一个对象,包括指令的解析结果。
    注:我们应当将这些属性视为只读,不要修改它们。我们也可以给指令对象添加自定义属性,但是注意不要覆盖已有的内部属性。代码示例如下:
<body id="example" @click=up">
	<div id="demo" v-demo:hello.a.b="msg"></div>
</body>
<sciprt>
	Vue.directive('demo',{
		bind:function(){
			console.log('demo bound');
		},
		update:function(value){
			this.el.innerHTML = 
				'name-'+this.name+'</br>'+
				'expression-'+this.expression+'</br>'+
				'argument-'+this.arg+'</br>'+
				'modifiers-'+JSON.stringify(this.modifiers)+'</br>'+
				'value-'+this.value+'</br>'+
				'vm-msg-'+this.vm.msg+'</br>'+
</script>
var demo = new Vue({
	el:'#example',
	data:{
		msg:'hello!'
	},
	methods:{
		up:function(){
			console.info('click');
		}
	}
}):

指令输出结果:
name-demo
expression-msg
argument-hello
modifiers-{“b”:true,“a”:true}
value-hello!
vm-msghello!

  1. 对象字面量
    如果指令需要多个值,则可以传入一个JavaScript对象字面量。记住,指令可以使用任意合法的JavaScript表达式。代码示例如下:
<body>
	<div id="demo" v-demo="{color:'white',text:'hello'}"></div>
</body>
<script>
	Vue.directive('demo',function(value){
		console.log(value.color) //white
		console.log(value.text) //hello!
	})
	var demo = new Vue({
		el:'#demo'
	})
</script>

输出结果:
white
hello!

  1. 字面修饰符

当指令使用了字面修饰符时,它的值将按普通字符串处理并传递给update方法。update方法将只调用一次,因为普通字符串不能响应数据变化。代码示例如下:

 <body>
 	<div id="demo" v-demo.literal="foo bar baz"></div>
 </body>
 <script>
	Vue.directive('demo',function(value){
		console.log(value)
	})
	var demo = new Vue({
		el:'#demo'
	})
</script>

foo bar baz

  1. 元素指令
    有时我们想以自定义元素的形式使用指令,而不是以属性的形式。这与AngularJS的E指令非常相似。元素指令可以看做是一个轻量组件。可以像下面这样注册一个自定义元素指令:
<body  id="demo">
	<my-directive class="hello" name="hi"></my-directive>
</body>
<script>
	Vue.elementDiective('my-directive',{
		//API同普通指令
		bind:function(){
			console.log(this.el.className)
			console.log(this.el.getAttribute("name"))
		}
	})
	var demo = new Vue({
		el:'#demo'
	})
</script>

元素指令不能接受参数或表达式,但是它可以读取元素的特性,从而决定它的行为。
不同于普通指令,元素指令是终结性的。这意味着,一旦Vue遇到一个元素指令,它将跳过该元素及其子元素。

高级选项

Vue允许注册自定义指令。自定义指令提供一种机制将数据的变化映射为DOM行为。

  1. params
    自定义指令可以接受一个params数组,指定一个特性列表,Vue编译器将自动提取绑定元素的这些特性。代码实例如下:
<body id="demo">
	<my-directive class="hello" name="hi" a="params"></my-directive>
</body>
<script>
	Vue.elementDirective('my-directive',{
		params:['a'],
		//API同普通指令
		bind:function(){
			console.log(this.params.a);
			console..log(this.el.getAttribute("name"));
		}
	})
	var demo = new Vue({
		el:'#demo'
   })
<script>

此API也支持动态属性。this.params[key]会自动保持更新。另外,可以指定一个回调,在值变化的时候,代码如下:

<body id="demo">
	<my-directive class="hello" name="hi" a="params"></my-directive>
</body>
<script>
	Vue.elementDirective('my-directive',{
		params:['a'],
		paramWatchers:{
				a:function(val,oldVal){
					console.log('a changed!')
				}
		}
	})
	var demo = new Vue({
		el:'#demo',
		data:{
			someValue:'value'
		}
   })
<script>
  1. deep
    如果自定义指令使用在一个对象上,当对象内部属性变化时要触发update,则在指令定义对象中指定deep:true
  2. twoWay
    如果指令想向Vue实例写回数据,则在指令定义对象中指定twoWay:true。该选项允许在指令中使用this.set(value)。代码示例如下:
<body id="demo">
	自定义组件:<input v-example="a.b.c"/><br/>
	父作用域:{a.b.c}
</body>
<script>
	Vue.directive('example',{
		twoWay:true,
		bind:function(){
			this.handler = function(){
				//把数据写回vm
				//如果指令这样绑定v-example="a.b.c"
				//这里将会给vm.a.b.c赋值
				this.set(this.el.value);
			}.bind(this)
			this.el.addEventListener('input',this.handler);
		}
	})
		var demo = new Vue({
		el:'#demo',
		data:{
			a:{b:{c:2}}
		}
   })
</script>
  1. acceptStatement
    传入acceptStatement:true可以让自定义指令接受内联语句,就像v-on那样。代码示例如下:
<body id="demo">
	<div v-my-directive="a++"></div>
	{{a}}
</body>
<script>
	Vue.directive('my-directive',{
		acceptStatement:true
		update:function(fn){
			//传入值是一个函数
			//在调用它时将在所属实例作用域内计算“a++”语句
			console.info(fn.toString());
			fn();
		}
	})
		var demo = new Vue({
		el:'#demo',
		data:{
			a:5
		}
   })
</script>
  1. Terminal(1.0.19及以后版本)
    Vue 通过递归遍历DOM树来编译模块,但是当它遇到terminal指令时会停止遍历这个元素的后代,这个指令将接管编译这个元素及其后代元素的任务。v-if和v-for都是terminal指令。
    编写自定义terminal指令是一个高级话题,需要较好的理解Vue的编程流程,但并不是说不可能编写自定义的terminal指令。用terminal:true指定自定义terminal指令,可能还需要用Vue.FragmentFactory来编译partial。下面是一个自定义的terminal指令,它编译其内容模板并将结果注入到页面的另一个地方。
  2. priority
    可以给指令指定一个优先级。如果没有指定优先级,普通指令默认是1000,terminal指令默认是2000。同一个元素上优先级高的指令会比其他指令处理得早一些,优先级一样的指令按照它在元素特性列表中出现的顺序依次处理,但是不能保证这个顺序在不同的浏览器中是一致的。
    另外,流程控制指令v-if和v-for在编译过程中始终拥有最高的优先级。

猜你喜欢

转载自blog.csdn.net/weixin_42881744/article/details/83691182