element-ui dom.js和repeat-click.js文件源码学习

2018年12月03日Web前端

继续看element-ui中input-number组件,先看下该组件用到的repeat-click.js文件和dom.js文件。 repeat-click.js中引用了dom.js文件,先看下dom.js文件。

一、dom.js

看到这个文件名字,就应该能猜到该文件处理的是和dom有关的操作。

trim()方法

利用正则匹配掉字符串的前后空格,利用||的特性做了容错处理。

camelCase()方法

用于将css的属性名转成驼峰型的属性名,比如-webkit-box-sizing则转成了webkitBoxSizing,第一个replace的回调函数中的return就是做了这个处理的,正好通过数字0转成false,其他数字则是true的原理。 第二个replace则是匹配第一个repalce的结果,当有出现moz开头的,转化成Moz,做特殊处理。

on()方法

是不是第一想到jQuery中的绑定方法的on方法,实际上这儿的用途也是这样。 简化on方法,大体是这样:

const on = (return function() {})();

on方法整体是一个自执行函数的结果,这样on方法只要在第一次时去计算if和else中的内容,得到对应的处理函数,而以后调用on时,只需直接使用引用就行了。这是惰性函数的用法,有兴趣的可以自行去了解下。

看下对应的内容,

if (!isServer && document.addEventListener) {
// ...
} else {
}

刨去isServer,再加上个on+‘事件名’,就是典型的事件绑定的兼容方法了。

off()方法

与on方法是相对的,是用于解绑定的。结构与实现和on方法相反。

once()方法

功能类似于jQuery的one()事件绑定。

内部实际仍是用on()方法实现,不同的只是,当使用者传入的fn被调用后,会主动掉下off()解除绑定,所以该方法只会触发函数一次。

hasClass()方法

第一个if则是做参数的错误检测。

if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');

第二个 if 特别判断了下空格字符串,因为后面要利用空格字符串与字符串的组合来查找,所以提前过滤了,当然这也说明,次方法只支持检测单个className了。

第三个if,当支持classList的,则直接获取一个集合,利用数组的contain方法,直接判断。若不支持,则直接取className并用indexof去判断。匹配方法是,给两匹配数据增加前后空格,这样防止要判断的cls字符串被包含在el.className中一个样式名中,比如cls是'aaa',而className是'aaabb haha'这两个样式名,这种匹配上的情况就会避免了。

当然此处也可以将el.className split成数组通过indexOf来判断,即el.className.split(' ').indexOf(cls) 。

addClass()方法

给指定元素增加class样式。 将要增加的样式以空格分隔成数组,循环处理其中的每一项,当支持classList时,则直接调用其增加样式的方法add(),不支持则判断原className中是否有要添加的属性名,无则先添加到临时存储的变量之中。

最后才将curClass赋值给className,因为className是字符串,是基本类型,一开始只是赋值,现在又重新赋值回去,个人猜这样的好处是,一次直接增加所有的样式,即使有重复的样式属性,也只用渲染一次,而如果在else if 中,则每次for循环都会有渲染。

removeClass()方法

用于删除el元素的指定样式,与addClass一样,支持批量多个className

结构和实现基本一致,只有在不支持classList时,利用正则replace了需要删除的属性,不得不说这也是种不错的方法,一般只会想到先split成数组,再用splice方法去删除。

最后trim后,再赋值给className。 前面的方法是不是在jQuery中都有?后面的这两个方法其实也有,不过在jQuery中是css()这个方法。

getStyle()方法

首先是对ie版本判断与兼容,不过vue都是支持IE9+的,9以下的还用处理么?

当时IE9一下的版本时,首先是参数的兼容,并使用camelCase()方法转化属性名,并特殊处理下float这个属性名,需要转化成styleFloat,这块或getStyle的实现可以看我的这篇文章:原生js操作css样式。 获取对应属性值时,对opacity属性做了兼容处理的,低版本的ie使用滤镜实现opacity的。

return (element.style[styleName] || element.currentStyle ? element.currentStyle[styleName] : null);

正常的属性都是通过currentStyle或取的,异常的则还是从style中获取。

w3c标准与低版本ie不同的则是,w3c是从getComputedStyle返回结果中获取的,只是w3c下float是cssFloat,需要小兼容下。

setStyle()方法

由于currentStyle和getComputedStyle都是只读结果,所以要修改属性还是得用style属性。 该方法支持单个的属性设置,也支持批量的如对象键值对的方式修改,和jQuery中的css()方法设置一样。

当我们传入的是对象时,利用for  in循环来批量设置,并用hasOwnProperty()方法保证是该对象的自有属性,知道遍历到非object时,用else去逐个设置属性,除了ie9一下对opacity做下特殊处理,其他都直接赋值给style就行了。

带注释的文件下载:dom.js

二、repeat-click.js

该文件是用来处理长按鼠标时的函数触发的,他用到了dom.js文件中的on和once方法,返回的是一个bind函数。

看下bind函数中,用on()方法实现绑定的部分,

on(el, 'mousedown', (e) => {

他利用on()方法给el元素绑定mousedown事件,

if (e.button !== 0) return;

第一个if则是限制只允许鼠标左键才有效,并记录了点击的开始时间,又用once绑定了mouseup事件,并使用setInterval每0.1秒触发一次handler,也就是当用户mousedown后,一直有个定时器在不停的触发处理函数。

对应的mouseup的回调时怎么处理的呢?他并非只有简单的clearInterval,

if (new Date() - startTime < 100) {
    handler();
}

这个if则是处理当用户只是简单的点击时的问题,因为简单点击肯定不会超过0.1s的,所以需要特殊处理下。

有注释的文件下载:repeat-click.js