vue自定义指令的基础使用这里就不阐述,看官网文档:https://cn.vuejs.org/v2/guide/custom-directive.html

本文用一个实例描述自定义指令的要点,自定义一个数据上报的指令。

你可能会这样写demo:

// 自定义v-datacenter命令埋点,点击节点发送埋点数据
// demo : <div v-datacenter="{ei: 'learning_center_click'}">进入学习中心</div>
const dataCenter = function(data){
// 这里处理数据上报
}
Vue.directive('datacenter', {
bind(el, binding) {
     // 或者使用dataset(要注意兼容性):https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/dataset
el._dataCenter = function(el) {
dataCenter(binding.value);
}
el.addEventListener('click', el._dataCenter)
},
unbind(el) {
// 移除监听
el.removeEventListener('click', el._dataCenter);
delete el._dataCenter;
}
})

这个demo对节点的点击做了响应,处理了数据埋点。有什么问题呢?只处理了初次绑定的数据,如果你的数据是通过ajax异步获取的,就可能出现问题,比如

<div v-datacenter="{ei: info.dataEvent}">进入学习中心</div>

其中info.dataEvent最开始是空字符,从后台拉取数据以后info.dataEvent才有值。那么上面的自定义指令中bind中的binding.value的值应当是为空字符。点击上报数据时“ei”的值一直为空字符

改进:

// 自定义v-datacenter命令埋点,点击节点发送埋点数据
// demo : <div v-datacenter="{ei: 'learning_center_click'}">进入学习中心</div>
Vue.directive('datacenter', {
bind(el, binding) {
el._dataCenter = function(el) {
dataCenter(binding.value);
}
el.addEventListener('click', el._dataCenter)
},
update(el, binding) {
// 处理value一开始没有值,后面才有值的情况
if (binding.value && (JSON.stringify(binding.value) !== JSON.stringify(binding.oldValue))) {
// 移除之前的监听
el.removeEventListener('click', el._dataCenter);
delete el._dataCenter; // 新增监听
el._dataCenter = function(el) {
dataCenter(binding.value);
}
el.addEventListener('click'
, el._dataCenter)
}
},

unbind(el) {
// 移除监听
el.removeEventListener('click', el._dataCenter);
delete el._dataCenter;
}
})

添加了update(当所在组件的 VNode 更新时调用),由于update时指令的value可能完全没有改动,所以要判断当值有更改且有效时重新绑定click监听。这样和bind配合就满足了同步/异步的所有场景。

真的就OK了么?显然不是,还有一种异常情况:在特殊情况下(如路由切换),节点既要响应click监听,也要移除节点。unbind就会在响应click监听之前调用。监听在响应之前就被移除,导致失败。

二次改进:

// 自定义v-datacenter命令埋点,点击节点发送埋点数据
// demo : <div v-datacenter="{ei: 'learning_center_click'}">进入学习中心</div>
Vue.directive('datacenter', {
bind(el, binding) {
el._dataCenter = function(el) {
dataCenter(binding.value);
}
el.addEventListener('click', el._dataCenter)
},
update(el, binding) {
// 处理value一开始没有值,后面才有值的情况
if (binding.value && (JSON.stringify(binding.value) !== JSON.stringify(binding.oldValue))) {
// 移除之前的监听
el.removeEventListener('click', el._dataCenter);
delete el._dataCenter; // 新增监听
el._dataCenter = function(el) {
dataCenter(binding.value);
}
el.addEventListener('click', el._dataCenter)
}
},
unbind(el) {
// 移除监听
// 在特殊情况下节点既要响应click,也要移除节点。避免在响应click之前就被移除监听,
// 所以要延时移除,放到下一个宏任务
setTimeout(() => {
el.removeEventListener('click', el._dataCenter);
delete el._dataCenter;
}
)
}
})

要避免在响应监听前监听被移除,所以将移除监听放到下一个宏任务。OK,收工!

如果觉得本文不错,请点击右下方【推荐】!

vue自定义指令要点的更多相关文章

  1. vue自定义指令

    Vue自定义指令: Vue.directive('myDr', function (el, binding) { el.onclick =function(){ binding.value(); } ...

  2. vue 自定义指令的使用案例

    参考资料: 1. vue 自定义指令: 2. vue 自定义指令实现 v-loading: v-loading,是 element-ui 组件库中的一个用于数据加载过程中的过渡动画指令,项目中也很少需 ...

  3. vue自定义指令(Directive中的clickoutside.js)的理解

    阅读目录 vue自定义指令clickoutside.js的理解 回到顶部 vue自定义指令clickoutside.js的理解 vue自定义指令请看如下博客: vue自定义指令 一般在需要 DOM 操 ...

  4. Vue自定义指令报错:Failed to resolve directive: xxx

    Vue自定义指令报错 Failed to resolve directive: modle 这个报错有2个原因: 1.指令单词拼错 2.Vue.directive() 这个方法没有写在 new Vue ...

  5. vue自定义指令clickoutside使用以及扩展用法

    vue自定义指令clickoutside使用以及扩展用法 产品使用vue+element作为前端框架.在功能开发过程中,难免遇到使用element的组件没办法满足特殊的业务需要,需要对其进行定制,例如 ...

  6. vue自定义指令clickoutside扩展--多个元素的并集作为inside

    都是个人理解,如果发现错误,恳请大家批评指正,谢谢.还有我说的会比较啰嗦,因为是以自身菜鸡水平的视角来记录学习理解的过程,见谅. 1.前言 产品使用vue+element作为前端框架.在功能开发过程中 ...

  7. 每个人都能实现的vue自定义指令

    前文 先来bb一堆废话哈哈.. 用vue做项目也有一年多了.除了用别人的插件之外.自己也没尝试去封装指令插件之类的东西来用. 刚好最近在项目中遇到一个问题.(快速点击按钮多次触发多次绑定的方法),于是 ...

  8. vue自定义指令,比onerror更优雅的方式实现当图片加载失败时使用默认图,提供三种方法

    首先,来看下效果图(演示一下图片正常加载与加载失败时的效果) 在线体验地址:https://hxkj.vip/demo/vueImgOnerror/ 一.常规方法解决 我们都知道,img标签支持one ...

  9. Vue自定义指令使用场景

    当你第一次接触vue的时候,一定会使用到其中的几个指令,比如:v-if.v-for.v-bind...这些都是vue为我们写好的,用起来相当的爽.如果有些场景不满足,需要我们自己去自定义,那要怎么办呢 ...

随机推荐

  1. Java常用基本类库总结

    1.String成员方法 boolean equals(Object obj);//判断字符串的内容是否相同,区分大小写. boolean equalsIgnoreCase(String str);/ ...

  2. Android drawable 加载效果

    <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:ones ...

  3. 微软不将《帝国时代》终极版上架Steam的原因到底是什么?

    毋庸置疑的是,<帝国时代>绝对是一款经典游戏.作为一款RTS名作,在过去的20年时间中<帝国时代>销量超过2000万部.数以千万计的玩家都沉溺于这款游戏中,<帝国时代&g ...

  4. 向通用自动驾驶部门Cruise投资22.5亿美元,软银打得什么主意?

    5月29日,加利福尼亚州的一辆特斯拉Model S撞上停在路边的警车.据透露,当时这辆特斯拉正处于自动辅助驾驶即Autopilot模式.而在今年,这已经不是第一次特斯拉自动驾驶模式出问题了.此外,Ub ...

  5. JVM相关面试题

    1.JVM 基本机构 1.1 类加载子系统负责从文件系统或者网络中加载Class信息,加载的类信息存放于一块称为方法区的内存空间.除了类的信息外,方法区中可能还会存放运行时常量池信息,包括字符串字面量 ...

  6. form提供的两种数据传输方式 get和post method=”post“和method=”get”

    虽然它们都是数据的提交方式,但是在实际传输时确有很大的不同,并且可能会对数据产生严重的影响.虽然为了方便的得到变量值,Web容器已经屏蔽了二者的一些差异,但是了解二者的差异在以后的编程也会很有帮助的. ...

  7. php通过身份证判断性别

    /** 已测试,百度很多写法不行的 * 1就是男性 2就是女性* 通过身份证获取性别类型* @param type $card* @return int*/function getCardSex($i ...

  8. auth模块用法

    Auth模块: 如果你想用auth模块   那么你就用全套 createsuperuser  创建超级用户 这个超级用户就可以拥有登陆django admin后台管理的权限 Auth模块是Django ...

  9. MIO、EMIO、AXI_GPIO区别与联系

    https://blog.csdn.net/u014485485/article/details/78141594            点灯实验

  10. java中Redis5大基本类型的用法

    存储格式 基本用法 通过Jedis(封装了redis的Java客户端)对redis进行操作. Jedis工具类 public class JedisPoolUtil { private static ...