Vue核心⑫(自定义指令)

导读:本篇文章讲解 Vue核心⑫(自定义指令),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

也许你感觉自己的努力总是徒劳无功,但不必怀疑,你每天都离顶点更进一步。今天的你离顶点还遥遥无期。但你通过今天的努力,积蓄了明天勇攀高峰的力量。加油!

函数式

我们先定义一个需求:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。

我们首先将代码框架写好,先不定义v-big指令,代码如下:

		<div id="root">
			<h2>当前的n值是:<span v-text="n"></span> </h2>
			<h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>
	
	<script type="text/javascript">
		Vue.config.productionTip = false
		
		new Vue({
			el:'#root',
			data:{
				n:1
			},
		})
		
	</script>

此时运行的话,数字n是可以实现增加的,控制台会报错:
在这里插入图片描述
注意报错报的式big,而不是v-big。有两种情况是没有前缀的:

  • 代码写错了,报错是不带v-的
  • 定义指令的时候,指令名直接定义为big,用的时候v-big

我们在Vue的实例对象中添加一个配置项 – directives,在其中我们就能定义自己的指令。

接下来我们的重点在于探索big方法身上其中的两个重要参数:

<body>
    <div id="root">
        <h2>当前的n值是:<span v-text="n"></span> </h2>
        <h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
        <button @click="n++">点我n+1</button>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false
    
    new Vue({
        el:'#root',
        data:{
            n:1
        },
        directives:{
            big(a,b){
                console.log(a,b);
            }
        }
    })
    
</script>

在这里插入图片描述

我们发现big方法中会有两个形参,一个是指令所处的元素(也可以说是指令所绑定的元素,它可以用来直接操作 DOM ),另一个是一个对象:
在这里插入图片描述

  • expression是表达式
  • value是表达式的值
  • name是我们定义的名字
  • rawname是我们使用的时候的名字

在文档中这两个形参的名字当然不是a和b,而是element(el)binding.此时我们可以补全我们的代码:

<body>
    <div id="root">
        <h2>当前的n值是:<span v-text="n"></span> </h2>
        <h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
        <button @click="n++">点我n+1</button>
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false
    
    new Vue({
        el:'#root',
        data:{
            n:1
        },
        directives:{
            big(el,binding){
                el.innerText = binding.value * 10
            }
        }
    })
    
</script>

我们发现随着n的增加,第二行放大10倍的n也会增加,这是因为big函数在以下两种情况都会被调用:

  • 指令与元素成功绑定时
  • 指令所在的模板被重新解析时

对象式

还是通过案例来理解:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。

我们的第一反应:

<body>
    <div id="root">
        <h2>当前的n值是:<span v-text="n"></span> </h2>
        <h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
        <button @click="n++">点我n+1</button>
        <hr/>
        <input type="text" v-fbind:value="n">
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false
    
    new Vue({
        el:'#root',
        data:{
            n:1
        },
        directives:{
            big(el,binding){
                el.innerText = binding.value * 10
            },
            fbind(el,binding){
                el.value = binding.value
                el.focus()
            }
        }
    })
    
</script>

当然如下方法是可以的我们不做讨论:
在这里插入图片描述

不过运行之后我们发现一开始的时候input框并没有获取焦点,在将n+1之后才会获取焦点,这是为什么呢?

一开始input框并没有获取焦点是因为fbind函数会在指令与元素成功绑定的时候执行一次,但是这只是一种关系的建立(内存层面上的操作),页面上此时并没有input(模板是经过Vue渲染了之后才会放在页面上的,并不是直接放上去),所以说我们的focus是不管用的。

而后来在n+1之后,n发生了变化,模板会重新被解析,此时fbind函数会再次被调用。不过在这次调用的时候input框已经被放在页面上了,它是存在的。所以这个focus()才可以起作用,让input框获得焦点。

也就说为了解决这一系列的问题,我们需要:在指令与元素绑定成功,并且元素已经在页面上存在了,我们再去执行focus().

如果我们继续使用函数式,这种需求是没有办法实现的。因为它永远只有那两种时候函数会被调用。我们拿不到那个时间点(Vue把元素放到页面上的时间点)

所以接下来我们使用对象式来解决这个问题!

对象中我们可以使用三个特别的函数(其他的我们在这里不做讨论),他们会在一些关键的时间点被调用:
在这里插入图片描述

  • bind():指令与元素成功绑定的时候调用
  • inserted():指令所在元素被插入页面时被调用
  • update():指令所在的模板被重新解析的时候被调用

完整的几个函数使用如下:
在这里插入图片描述

最后我们的解决代码:

<body>
    <div id="root">
        <h2>当前的n值是:<span v-text="n"></span> </h2>
        <h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
        <button @click="n++">点我n+1</button>
        <hr/>
        <input type="text" v-fbind:value="n">
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false
    
    new Vue({
        el:'#root',
        data:{
            n:1
        },
        directives:{
            big(el,binding){
                el.innerText = binding.value * 10
            },
            fbind:{
                bind(el,binding){
                    el.value = binding.value
                },
                inserted(el,binding){
                    el.focus()
                },
                update(el,binding){
                    el.value = binding.value
                }
            }
        }
    })
    
</script>

我们可以发现函数式的写法其实就是对象式写法的简略形式,也就是说函数式只取了bind()和update()。

其实bind、inserted、update这几个函数被称为钩子函数,在Vue的生命周期中我们会再次提到。

注意点

第一个注意点

前面我们使用的自定义指令都是单个单词,big、fbind,如果我们要使用多个单词怎么办?

注意不能使用驼峰命名法

Vue会把那个大写字母当成小写再去你的directives中去寻找你的自定义指令,结果当然是找不到。例如我们以bigNumber为例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

所以在有多个单词的时候我们使用-去分隔,在配置对象中使用原始写法:
在这里插入图片描述
在这里插入图片描述

当然可以再精简一点:
在这里插入图片描述

当key里面有-,就不能使用简写形式了

第二个注意点

还有一个问题:关于指令回调函数的this

我们可以将它们打印下来看看:
在这里插入图片描述
结果:
在这里插入图片描述
可以发现指令回调函数的this全是window

第三个注意点
我们前面定义的big指令、fbind指令都是局部指令。因为它们都定义在Vue的实例对象中,只能给当前的vm去用,别人用不了。

接下来我们可以把前面的big指令、fbind指令改为全局指令

在这里插入图片描述

在这里插入图片描述

总结

自定义指令总结:

一、定义语法:
(1).局部指令:
在这里插入图片描述

(2).全局指令:
在这里插入图片描述

二、配置对象中常用的3个回调:

  • bind:指令与元素成功绑定时调用。
  • inserted:指令所在元素被插入页面时调用。
  • update:指令所在模板结构被重新解析时调用。

三、备注:

  • 指令定义时不加v-,但使用时要加v-;
  • 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/122126.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!