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

都是个人理解,如果发现错误,恳请大家批评指正,谢谢。还有我说的会比较啰嗦,因为是以自身菜鸡水平的视角来记录学习理解的过程,见谅。

1.前言

产品使用vue+element作为前端框架。在功能开发过程中,难免遇到使用element的组件没办法满足特殊的业务需要,需要对其进行定制,例如要求选择器的弹出框中,增加搜索过滤(跟目前element的输入建议不太一样)。于是想说说之前修改element组件,并定制为业务组件过程中遇到的问题。


ps:因为对某些组件改动很大,所以是直接拷贝了一份源码,然后再进行修改,但是这样会遇到挺多问题,建议对于vue组件如果改动不大,只是简单功能扩展,就直接使用继承的方式修改。

2.clickoutside指令

element中自定义vue的指令之一,clickoutside顾名思义,就是当鼠标点击了指令所绑定元素的外部时,就会触发绑定方法。用途就以el-select为例,当选择器的下拉框展示时,监听鼠标点击事件,如果鼠标位置在整个选择器外部时,进行隐藏下拉框。

2.1使用方式

引入Clickoutside.js


import Clickoutside from 'element-ui/src/utils/clickoutside'

声明指令使用


directives: { Clickoutside },

模板中正式使用


<div v-clickoutside="handleClickOutside">
</div>

2.2实现介绍

简要说明下原理,首先vue自定义指令本身(不了解可以点击链接查看官网介绍)。主要就是利用vue指令的功能,获取所绑定元素的dom对象dom_A以及传递过来的回调方法fun_A,然后监听浏览器的mousedown和mouseup事件(mousedown作为辅助信息,真正触发传递的回调方法的是mouseup事件),当前事件中鼠标位置对应的dom对象dom_B不属于dom_A,则代表鼠标点击了dom_A外部,触发clickoutside回调方法。

2.3扩展介绍

理论上clickoutside只能也只需要绑定一个元素作为inside,但是一些特殊的原因(可能是代码不够好),要求clickoutside可以选定多个元素作为inside,当鼠标点击了这些元素所构成的inside的外部时,再触发事件。
结合下图,A与B两个元素作为一个inside,当鼠标点击在click1位置时,触发clickoutside,当鼠标点击click2或者click3位置时都不触发clickoutside。

1504257-20181106225427540-1496256447.jpg

2.3扩展实现

要实现上述功能,就必须获取到A和B的dom对象,然后在原先鼠标事件的监听的基础上,判断鼠标位置是否都不包含在A和B中,如果是的话再触发clickoutside。
实现方式为,在A和B的父级parent元素上绑定v-clickoutside:yourClassName="handleClickOutside",在A和B元素上添加同一个class样式,样式名称与指令冒号后面内容一致class="yourClassName"。主要在处理指令绑定时,通过binding.arg即可获取到A和B共有的class,存放在dom变量中。在鼠标放开触发事件处理时,通过class获取到他们的dom对象。

2.3.1使用示例

clickoutside原来的使用方式不受影响,只是添加了多个元素并集作为inside的功能。
引入改为自己修改后的clickoutside.js,声明不变,扩展功能在模板中的使用方式


<div v-clickoutside:exactAreaClassName="handleClickOutside">Parent<div class="exactAreaClassName">A</div><div class="exactAreaClassName">B</div>
</div>

2.3.2代码


// 引入Vue用以判断当前运行环境
import Vue from 'vue'
// element封装的一些常用dom操作,这里on可以先当做是addEventListener的封装
import { on } from 'element-ui/src/utils/dom'
// 所有绑定了clickoutside指令的元素的dom对象数组
const nodeList = []
// 用来做存放于dom对象中clickoutside相关参数对象的key
const ctx = '@@clickoutsideContext'let startClick
let seed = 0
// 鼠标按下时,记录此时事件信息
!Vue.prototype.$isServer && on(document, 'mousedown', e => (startClick = e))
// 鼠标松开时候,遍历绑定clickoutside的节点,进行判断是否在节点外部以触发回调
!Vue.prototype.$isServer && on(document, 'mouseup', e => {nodeList.forEach(node => node[ctx].documentHandler(e, startClick))
})// 是否在特殊限定范围内
function ifInExact (exactElms, target1, taget2) {for (let i = 0; i < exactElms.length; i++) {let elm = exactElms[i]if (elm.contains(target1) || elm.contains(taget2) || elm === target1) return true}return false
}// 是否有特殊限定范围
function ifHasExact (el, exactArea) {if (!exactArea) return falsereturn el.getElementsByClassName(exactArea)
}function createDocumentHandler (el, binding, vnode) {return function (mouseup = {}, mousedown = {}) {if (!vnode ||!vnode.context ||!mouseup.target ||!mousedown.target ||(vnode.context.popperElm &&(vnode.context.popperElm.contains(mouseup.target) ||vnode.context.popperElm.contains(mousedown.target)))) returnlet exactElms = ifHasExact(el, el[ctx].exactArea)// 如果是有特殊限定范围的,则进行判断当前点击是否在 限定范围内if (exactElms) {if (ifInExact(exactElms, mouseup.target, mousedown.target)) {return}// 无特殊限定范围,则判断点击是否在默认的指令所在范围内} else if (el.contains(mouseup.target) || el.contains(mousedown.target) || el === mouseup.target) {return}if (binding.expression &&el[ctx].methodName &&vnode.context[el[ctx].methodName]) {vnode.context[el[ctx].methodName]()} else {el[ctx].bindingFn && el[ctx].bindingFn()}}
}export default {bind (el, binding, vnode) {nodeList.push(el)const id = seed++el[ctx] = {id,documentHandler: createDocumentHandler(el, binding, vnode),methodName: binding.expression,bindingFn: binding.value,// 特殊限定范围的class,限定范围为该class的所有元素的并集exactArea: binding.arg}},update (el, binding, vnode) {el[ctx].documentHandler = createDocumentHandler(el, binding, vnode)el[ctx].methodName = binding.expressionel[ctx].bindingFn = binding.value// 附加 真正起作用部分el[ctx].exactArea = binding.arg},unbind (el) {let len = nodeList.lengthfor (let i = 0; i < len; i++) {if (nodeList[i][ctx].id === el[ctx].id) {nodeList.splice(i, 1)break}}delete el[ctx]}
}

3.最后

以上就是关于clickoutside的学习和扩展。

  • 1.引用element的popup注意事项,如el-select-menu即el-select中的select-dropdown.vue。
  • 2.使用cropperjs制作头像裁剪。浏览器读取本地图片并展示,仿微博头像排版,裁剪后上传服务器。
  • 3.vue指令中的参数vnode学习

ps: 个人GayHub后面关于前端的学习内容也会放在这里,如果发现bug尽量及时改上去。

原文地址:https://segmentfault.com/a/1190000014213030

转载于:https://www.cnblogs.com/lalalagq/p/9919464.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/365057.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

35个让人惊讶的 CSS3 动画效果演示

本文收集了35个惊人的 CSS3 动画演示,它们将证明 CSS3 Transform 和 Transition 属性的强大能力。CSS 是网页设计非常重要的一部分,随着越来越多的浏览器对 CSS3 支持的不断完善,设计师和开发者们有了更多的选择。如今,用纯 CSS 就…

计算机社团活动丰富多彩,描写社团丰富多彩的句子

我们学校的社团活动真是丰富多彩用这个句子开头试着写一段话感恩生命,感谢她给予我们丰富的感情。喜怒哀乐,悲思忧惧,洒洒脱脱,原原本本,痛快淋漓,无拘无束;喜而笑,怒而吼&#xff0…

宝元系统u盘使用说明_教你如何使用U盘安装电脑系统

①到老毛桃官网首页下载老毛桃UEFI版u盘启动盘制作工具安装到电脑上;②准备一个容量在4G以上并能够正常使用的u盘。1第一步将u盘插入电脑usb接口,程序会自动扫描,我们只需在下拉列表中选择用于制作的u盘,然后点击“一键制作”按钮…

支持在iPad中播放的HTML5视频网站推荐

YouTube是最早支持HTML5视频的网站,随着iPad等平板电脑的流行,越来越多的视频网站开始支持HTML5视频播放。下面就向大家分享一些国内的HTML5视频网站,是根据网上信息整理而成,欢迎大家反馈和推荐更多的HTML5视频网站。 腾讯 优酷…

为什么用链路聚合_H3C ComwareV7平台网络设备可靠性配置——链路聚合

H3C ComwareV7平台网络设备可靠性配置——链路聚合链路聚合简介:链路聚合是通过多个物理接口(通常指以太网接口,串口只在特定场景且与以太网聚合技术等同故不再赘述)捆绑实现的逻辑接口,而这些被捆绑在一起的以太网接口就称为该聚合组的成员端…

获取 HTML5 网页设计灵感的10个网站推荐

这篇文章向大家推荐10个收集 HTML5 网页作品的网站,让大家感受一下 HTML5 的魅力。作为下一代网页标准,HTML5 增加了很多新标签以及新特性,正引领网页技术革命。希望这些优秀的 HTML5 网页案例能带给大家制作 HTML5 网页的灵感。 HTML5 Gall…

postgresql存图片字段类型_PostgreSQL让人着迷的多态性,另辟蹊径省时又省力

PostgreSQL 让人着迷的地方,不在于他比某些数据库的流行,也不在于比某些数据库的高“贵”, 更不如某些数据库的“简单”。Postgresql 让人无法自拔的是他的”多端变化”, 用开发的角度来说,叫多态性。PG本身支持着太多…

计算机怎么查看U盘品牌,如何查看电脑u盘使用

如何查看电脑u盘使用其实笔记本设置U盘启动也并不困难,小编这就教你怎样设置U盘启动!全是硬货!第一步:我们先把U盘插入笔记本的USB接口上,(注意:请不要通过USB延长线来连接笔记本)插上U盘后重启笔记本本。电…

Maven补全之生命周期(Lifecycle)

Maven补全之生命周期(Lifecycle) Maven生命周期基础概念 Maven是基于生命周期构建的,一个Maven项目的构建是已经被清晰定义的过程。 对于我们使用Maven构建项目来说,POM.xml文件可以确保我们得到自己想要的项目(项目名&#xff0c…

善用封盖

不久前,在博客文章中 ,我解释了Groovy中的Closure。 这篇博客文章将解释一个使用它们的好例子。 最近,我发现自己不得不为服务AJAX请求的大量后端Controller API编写相同的异常处理逻辑。 就像这样: class ApiRugbyPlayerControl…

12款精美的免费 HTML 网站模板下载

这篇文章收集了12款精美的免费HTML网站模板分享给大家,您可以免费下载使用。相信这些漂亮的HTML网站模板既能够帮助您节省大量的时间和精力,又能有很满意的效果。感谢那些优秀的设计师分享他们的劳动成果,让更多的人可以使用他们的创意设计&a…

两个数相乘积一定比每个因数都大_小升初数学知识点大全含公式+20类必考应用题(含答案解析),孩子考试一定用得上!...

小升初数学知识点大全含公式一、几何图形周长、面积和体积公式*三角形的面积=底高2。S ah2正方形的面积=边长边长 S a长方形的面积=长宽 公式 S ab平行四边形的面积=底高 S ah梯形的面积=(上底下底)高2 S(ab)h2内角和&…

WPF自定义TabControl样式

WPF自定义TabControl样式 原文:WPF自定义TabControl样式WPF自定义TabControl&#xff0c;TabControl美化 XAML代码&#xff1a; <TabControl x:Class"SunCreate.Common.Controls.TabControlEx"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentat…

H.264分层结构与码流结构

H.264分层结构 H.264编码器输出的Bit流中&#xff0c;每个Bit都隶属于某个句法元素。句法元素被组织成有层次的结构&#xff0c;分别描述各个层次的信息。 在H.264 中&#xff0c;句法元素共被组织成 序列、图像、片、宏块、子宏块五个层次。在这样的结构中&#xff0c;每一层…

20个很酷的CSS3导航菜单制作教程

CSS3 是对 CSS 规范的一个很大的改善和增强&#xff0c;它使得 Web 开发人员可以很容易的在网站中加入时尚的效果。以前很多需要编写 JavaScript 才能实现的效果&#xff0c;如今只需要简单的写几句 CSS3 代码就能实现。今天这篇文章就向大家推荐20个很酷的CSS3导航菜单制作教程…

金算盘高手论坛资料中心_3D006期 菜鸟论坛精英PK专栏 速来围观!!

点上方“菜鸟选号论坛”→点右上角“...”→选“星标★”每日上午更新&#xff0c;星标置顶与大神不走散苹果是置顶&#xff0c;安卓是星标 点击"菜鸟选号论坛"关注我们论坛明星版块&#xff0c;集全网各路高手之大乘&#xff0c;打造草根明星 展示舞台。同时主要是为…

非常酷!10个基于 HTML5 的字体应用演示网站

HTML5 是现在Web开发领域的热点&#xff0c;更多的开发人员开始使用HTML5来开发交互性强、效果出众的网站和各种应用。这是 HTML5 网站大观系列第四篇&#xff0c;本文与大家分享5个非常酷的基于 HTML5 的字体应用演示网站&#xff0c;一起欣赏。 Web Typography For The Lone…

ntp如何确认与服务器偏差_LED电子时钟显示屏如何实现时间同步统一校时?

LED电子时钟显示屏采用一体式铝合金边框设计&#xff0c;更坚固美观节能环保&#xff0c;更以其简单的操作和稳定的性能&#xff0c;广泛应用于学校、考场、医院、金融、移动通信、石油、电力、交通、工业以及国防等同步时钟系统的显示终端&#xff0c;LED电子时钟显示屏已成为…

HDP 2.6 requires libtirpc-devel

HDP 2.6 requires libtirpc-devel 个问题&#xff0c;截止 Mustafa Kemal MAYUK 2017年06月30日 06:30 hadoopPowerSystemsHello, I am trying to install HDP 2.6 on RHEL 7.2 ppc64le. Installation over ambari fails due to "Error: Package: hadoop_2_6_0_3_8-hdfs-2…

推荐10款非常有用的 Ajax 插件

这篇文章与大家分享的是10款非常有用的 Ajax 插件&#xff0c;有用于图片的&#xff0c;用于分页的&#xff0c;还有用于导航的。这些作者的想法特别新颖&#xff0c;希望你能从中找到自己需要的插件。 1. AJAX-ZOOM 非常强大的一款插件&#xff0c;可用鼠标滚轮进行缩放&…