开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情
1.vue 自定义指令属性信息
指令定义函数提供了几个钩子函数 (可选)
bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。inserted: 被绑定元素插入父节点时调用 (父节点存在即可调用,不必存在于 document 中)。update: 所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。指令的值可能发生了改变也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。componentUpdated: 所在组件的 VNode 及其孩子的 VNode 全部更新时调用。unbind: 只调用一次,指令与元素解绑时调用。
钩子函数被赋予了以下参数
el: 指令所绑定的元素,可以用来直接操作 DOM 。binding: 一个对象,包含以下属性:name: 指令名,不包括v-前缀。value: 指令的绑定值,例如:v-my-directive=“1 + 1”, value 的值是2。oldValue: 指令绑定的前一个值,仅在update和componentUpdated钩子中可用。无论值是否改变都可用。expression: 绑定值的字符串形式。例如v-my-directive=“1 + 1”,expression 的值是"1 + 1"。arg: 传给指令的参数。例如v-my-directive:foo,arg 的值是"foo"。modifiers: 一个包含修饰符的对象。例如:v-my-directive.foo.bar, 修饰符对象 modifiers 的值是{ foo: true, bar: true }。vnode: Vue 编译生成的虚拟节点,查阅 VNode API 了解更多详情。oldVnode: 上一个虚拟节点,仅在update和componentUpdated钩子中可用。
2.vue 全局自定义指令
1). 在main.js内部写入
// 在main.js内部写入
Vue.directive('inputFn',{
// 钩子函数,被绑定元素插入父节点时调用 (父节点存在即可调用,不必存在于 document 中)。
inserted(el){
// 聚焦元素
el.focus()
console.log( 'inserted' );
},
// 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
bind(){
console.log( 'bind' );
},
// 所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。
// 指令的值可能发生了改变也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
update(){
console.log( 'update' );
},
// 所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
componentUpdated(){
console.log( 'componentUpdated' );
},
// 只调用一次,指令与元素解绑时调用。
unbind(){
console.log( 'unbind' );
}
})
2). 需要在main.js文件中引入
输入框只允许输入数字
// checkDigit.js
const checkDigit = {}
checkDigit.install = Vue => {
Vue.directive('checkDigit', {
inserted(el, binding) {
// 节点信息
const inputValue = el.getElementsByTagName('input')[0]
el.onkeyup = (event) => {
// 把不是数字的替换掉
inputValue.value = inputValue.value.replace(/[^0-9]/g, '')
}
}
})
}
export default checkDigit
// main.js 内部 sunNumber引进来
import checkDigit from './checkDigit'
Vue.use(checkDigit)
3). 批量自定义指令引入
- copy 复制目标值
- debounce 复制目标值
// directive.js
const copy = {
bind(el, { value }) {
el.$value = value
el.hendler = () => {
if (!el.$value) {
// 值为空跳出去不执行
console.log('空值啥也没有')
return;
}
// 动态创建textarea 标签
const textarea = document.createElement('textarea')
// 将 textarea 设为 readonly 防止 ios 下自动唤起键盘,同时将 textarea 移除可视区域
textarea.readOnly = 'readonly'
textarea.style.position = 'absolute'
textarea.style.left = '-9999999999px'
textarea.value = el.$value
// 将 textarea 插入到 body 中
document.body.appendChild(textarea)
// 选中值并复制
textarea.select()
const result = document.execCommand('Copy')
if (result) {
console.log('复制成功')
}
document.body.removeChild(textarea)
}
// 绑定点击事件,就是一键复制
el.addEventListener('click', el.hendler)
},
// 当传经来的值更新的时候触发
componentUpdated(el, { value }) {
el.$value = value
},
// 指令与元素解绑的时候,移除事件绑定
unbind(el) {
el.removeEventListener('click', el.hendler)
}
}
const debounce = {
inserted: function (el, binding) {
let timer
// 防止多次触发当前元素的点击事件
el.addEventListener('click', () => {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
binding.value()
}, 1000)
})
}
}
const directiveData = {
copy,
debounce
}
export default {
install(Vue) {
Object.keys(directiveData).forEach(item => {
Vue.directive(item, directiveData[item])
})
}
}
// main.js
import directive from './directive'
Vue.use(directive)
3.vue 局部自定义指令
- 在自己需要的
.vue文件中内部
<template>
<div>
<!-- 页面打开的时候就获得焦点 -->
<input type="text" v-inputFocus />
</div>
</template>
<script>
export default {
directives:{
// 自定义指令的名字
inputFocus:{
// 钩子函数,被绑定元素插入父节点时调用 (父节点存在即可调用,不必存在于 document 中)。
inserted(el){
el.focus() // 元素获取焦点时所触发的事件
console.log( 'inserted' );
},
// 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
bind(){
console.log( 'bind' );
},
// 所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。
// 指令的值可能发生了改变也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
update(){
console.log( 'update' );
},
// 所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
componentUpdated(){
console.log( 'componentUpdated' );
},
// 只调用一次,指令与元素解绑时调用。
unbind(){
console.log( 'unbind' );
}
},
"scroll-select": {
// 指令的名称
bind(el, binding) {
const SELECTWRAP = el.querySelector(".el-select-dropdown .el-select-dropdown__wrap");
SELECTWRAP.addEventListener("scroll", function () {
// scrollTop 这里可能因为浏览器缩放存在小数点的情况,导致了滚动到底部时
// scrollHeight 减去滚动到底部时的scrollTop ,依然大于clientHeight 导致无法请求更多数据
// 这里将scrollTop向上取整 保证滚到底部时,触发调用
const CONDITION = this.scrollHeight - Math.ceil(this.scrollTop) <= this.clientHeight;
// el.scrollTop !== 0 当输入时,如果搜索结果很少,以至于没看到滚动条,那么此时的CONDITION计算结果是true,会执行bind.value(),此时不应该执行,否则搜索结果不匹配
if (CONDITION && this.scrollTop !== 0) {
const Elvalue = el.querySelector(".el-input__inner") || el.querySelector(".el-select__input");
binding.value(Elvalue.value);
}
});
},
},
},
data () {
return {}
}
mounted(){},
}
</script>