引入mousewheel事件及兼容性处理

项目实现过程中需要对一个已经有纵向滚动条的table表格增加鼠标滚轮(mousewheel)事件,方便查看数据;其实现原理与我上一篇博客中的拖动事件类似,利用模拟出来的同一个滚动条来实现

滚动条设置的要点在于

1、滚动条与滚动槽的高度比例 应该等于 内容区(动态变化)和可视区的高度比例;滚动槽与可视区平齐,高度一样;滚动条的高度则根据内容的高度等比例计算;

2、各元素的定位采用绝对定位,其父元素采用相对定位,这样就能很好地设置样式;

布局与样式做好后,只需要在组件methods注册方法,在元素就位后调用该方法,在方法内部为表格绑定(mousewheel)事件;在这里需要考虑兼容性问题,firefox并不支持mousewheel事件,它对应的鼠标滚动事件为DOMMouseScroll事件,并且该事件仅能通过DOM2级(addEventListener)添加处理程序;并且判断鼠标滚动方向的方式也不一样,firefoxt通过detail属性判断,向前滚动该属性为-3,向后 3;其余浏览器通过wheelDelta属性,向前时为 120的倍数,向后为-120的倍数;

具体内容可参考《js高级程序设计》事件一章;添加函数如下:

    scroll(){
        this.wrapDiv = document.getElementById("wrap");
        this.contentDiv = document.getElementById("context-table");
        this.contentDiv1 = document.getElementById("context-table1");
        this.sliderWrap = document.getElementById("sliderWrap");
        this.slider = document.getElementById("slider");
        //设置比例
        let scale =  this.wrapDiv.clientHeight /  this.contentDiv.clientHeight;
        if (scale < 1) {
          this.mouseFlag = true;
          let h1 =  this.sliderWrap.clientHeight * scale;
          h1 = (h1 < 50) ? 50 : h1;
          this.slider.style.height = h1   "px";/*滚动条高度动态变化*/
          let y = 0;
          let that = this;
          //为firefox添加滚轮事件
          if (document.addEventListener){
            document.addEventListener('DOMMouseScroll',function (e) {
                if(that.mouseFlag){
                  //console.log('scroll');
                  let event1 = window.event|| e;
                  y = (event1.detail > 0) ? y   8 : y - 8;
                  y = (y < 0) ? 0 : y;
                  let max = that.sliderWrap.clientHeight - that.slider.clientHeight;
                  y = (y > max   1) ? max   1 : y;
                  that.slider.style.top = y   "px";
                  scale = that.wrapDiv.clientHeight / that.contentDiv.clientHeight;
                  let y1 = -y / scale;
                  that.contentDiv.style.top = y1   "px";
                  that.contentDiv1.style.top = y1   "px";
                }
            },false)
          }
          this.wrapDiv.onmousewheel = function (e) {
            if (scale < 1) {
              let event1 = window.event || e;
              y = (event1.wheelDelta < 0) ? y   8 : y - 8;
              y = (y < 0) ? 0 : y;/*限定滚动范围*/
              let max =  that.sliderWrap.clientHeight -  that.slider.clientHeight;
              //console.log(scale, y, sliderWrap.clientHeight, slider.clientHeight);
              y = (y > max   1) ? max   1 : y;
              that.slider.style.top = y   "px";
              scale =  that.wrapDiv.clientHeight /  that.contentDiv.clientHeight;
              let y1 = -y / scale;
              that.contentDiv.style.top = y1   "px";
              that.contentDiv1.style.top = y1   "px";
            }
          }
        }
        else{/*当内容区高度小于等于可视区时,去除绑定的事件和滚动条*/
          this.wrapDiv.onmousewheel =null;
          if(document.addEventListener){
             this.mouseFlag = false;
          }
          this.sliderWrap.style.visibility = 'hidden';
          let height = this.contentDiv.clientHeight;
          tableRight.style.height  = height 72 'px';
          this.wrapDiv.style.height = height 2 'px';
        }
      },

该函数在给firefox绑定的事件解绑时遇到了问题,由于removeEventListener()需要通过句柄来解绑,而addEventListener()通过句柄添加处理函数会导致event参数无法传递的问题;即使在需要解绑时给document绑定空的处理函数也无法覆盖前一个绑定函数;最后只好添加一个标志,在需要解绑函数时改变标志的值;在绑定函数中通过判断该标志的值来确定是否要做操作;

通过上述方式即可很好地实现鼠标滚动事件的效果,并不会有兼容性的问题出现。

注:若仅仅是为表格绑定单一的滚动事件,则可以不显示滚动条,甚至不设置滚动条;滚动条的作用仅仅是用来指示内容区滚动的位置,以及配合拖动事件使用; 

关于scroll和mousewheel事件的问题

需要注意的点

火狐的鼠标滚轮事件是DOMMouseScroll

事件参数兼容:e=window.event||e;(下面省略)

preventDefault()函数取消的是默认事件,不会把我们自己添加的事件处理删除

实验开始

在下面验证例子的基础上实验,实验之间代码没有干涉:

1.原样输出

在元素内无论是手动拉动滚动条还是滚动鼠标滚轮,'d'都是无法出现的。而当元素滚动到达顶部或底部的时候,输出的是就有'd'了,但是这个时候并没有输出'b',说明scroll事件本来就没有发生冒泡。而document的scroll事件是由于其他因素触发的。

2.在element的mousewheel事件处理里把冒泡取消

e.stopPropagation();

这时候在元素内滚动鼠标滚轮,'c'始终是无法出现的,说明我们阻止mousewheel事件的冒泡成功了。但是在滚动条到达底部或顶部时,虽然'c'依旧没有出现,但是'd'却出现了,说明这个时候的document的scroll事件是靠element的mousewheel来触发的。

到这里就出现一个问题:element的mousewheel事件在默认处理里对这一情形进行了处理吗?

3.在element的mousewheel事件处理里取消默认处理

e.preventDefault();

这时候在元素内滚动鼠标,只会有'a'、'c'会出现,页面也不会滚动。说明鼠标滚轮滚动element页面的效果是由element的mousewheel默认事件处理来的。这个时候留意实验1中滚轮滚动一下'b'的输出数量,大概就能猜到默认处理的过程。

4.在element的mousewheel里添加一个自己的页面滚动(与默认处理的滚动方向相反)

element.scrollTop =e.wheelDelta>0?30:-30;//手动添加的页面滚动

这个时候在元素内滚动鼠标,你会发现即使滚动到顶部或底部,元素外的页面并不会滚动,且并没有输出'd',也就是document的scroll事件没有触发。不好的一点是你在滚动到底部或顶部时,继续滚动鼠标的话,元素内还是会滚动,只不过是先下再上(或先上再下)地波动一下。

5.在element的mousewheel里添加一个自己的页面滚动(与默认处理的滚动方向相同)

element.scrollTop =e.wheelDelta<0?30:-30;//手动添加的页面滚动

这个时候在元素内滚动鼠标,你会发现即使滚动到顶部或底部,元素外的页面跟着滚动,且输出'd',也就是document的scroll事件触发了。

这里需要注意到一点:元素的scrollTop属性是无法无限增加和减少的,到了滚动的顶部或底部后只能反向变化(可以自行输出测试)。

6.在实验5的基础上,将滚动的距离调整到很大

element.scrollTop =e.wheelDelta<0?300:-300;(值要大等于滚动行程)

认真观察输出的'b'的个数,和实验1的对比,你会发现这次只有1个'b',而且还输出了'd',而且'd'的数量还不少。经过一些其他的实验,得到:默认事件处理里的判断大概如下:

(function scroll(element){
    for(var i=0;i<12;i  ){
        var temp=element.scrollTop;
        element.scrollTop =e.wheelDelta<0?10:-10; //滚动算法肯定不是这个,这里只是简单演示
        if(temp!= element.scrollTop){
            //滚动‘消息树'的下一个元素(和冒泡是一个列表)
            var newEle=....//消息树怎么获取我不懂
            scroll(newEle);
            return;
        }
    }
})();

验证例子:

       addEventListener(element,'mousewheel',function(e){
            console.log('a');
        });
        addEventListener(element,'scroll',function(e){
            console.log('b');
        });
        addEventListener(document.documentElement,'mousewheel',function(e){
            console.log('c');
        });
        addEventListener(document,'scroll',function(e){
            console.log('d');
        });

结论:通过上面的6个实验,很容易发现在元素的mousewheel的默认处理事件里对scrollTop属性进行变化和判断,如果没有发生变化就对外部元素进行滚动一下(具体滚动算法不懂,滚动距离和鼠标滚一下是一样的),以此类推,如果下一个元素到边界了,就再下一个。而这个过程和冒泡是没有关系的,只是当前元素的mousewheel默认事件处理进行的。

应用:因此为了实现元素滚动到底时继续滚动却不会使外部元素滚动,我们可以直接取消它的默认处理,然后给一个自己的滚动函数就可以了。至于怎么滚就看自己给什么函数了,而冒泡取不取消也看自己,上面的默认处理在冒泡和捕获阶段是不进行的。

例子如下:

       addEventListener(element,'mousewheel',function(e){
            console.log('a');
            e.preventDefault();
            // e.stopPropagation();
            ulObj.scrollTop =e.wheelDelta<0?20:-20;
        });
        addEventListener(element,'scroll',function(e){
            console.log('b');
        });
        addEventListener(document.documentElement,'mousewheel',function(e){
            console.log('c');
        });
        addEventListener(document,'scroll',function(e){
            console.log('d');
        });

以上为个人经验,希望能给大家一个参考,也希望大家多多支持Devmax。

vue中引入mousewheel事件及兼容性处理方式的更多相关文章

  1. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  2. iOS 6 API和向后兼容性

    可以在支持早期iOS版本的应用中使用iOS6中引入的API和框架吗?这只能通过解决方法和代码来实现,例如:或者我可以在支持早期版本的iOS而不指定版本的应用程序中使用更新的框架,API等?而且,我能否使用Xcode4.5,还是要坚持现在的公开发行版?

  3. ios – Swift 4向后兼容性

    一起使用.有没有办法在两个版本的Xcode中使这个工作?Swift4是否应该向后兼容?

  4. 译:Swift ABI (一)

    作为Swift社区的一份资源,这份文档也为SwiftABI的发展指明了方向。这些内容记录了和SwiftABI相关的工程和设计任务。在运行时,通过Swift编写的二进制程序通过ABI和其他的程序库或组件进行交互。但Swift是一门和C截然不同的语言,它需要为每一种平台定义自己的ABI。而这份文档中中的绝大部分内容都是和平台无关的,和具体平台相关的考量会影响到SwiftABI的设计和实现细节。

  5. 苹果公司揭秘首批列入 Swift 源代码兼容性开源项目清单

    源代码兼容性是Swift未来的目标。为了实现这一目标,建立了一个源兼容性测试套件,用于根据Swift源代码语料库对编译器进行回归测试更改。添加向项目模板等更多内容请查看Swift官方网站

  6. Swift 3 iOS兼容性

    所以现在我使用Swift3,默认情况下部署目标设置为iOS10.0这意味着我将无法使其运行在例如iOS8-9?“CosinSwift3我使用新的功能,在后来的操作系统中不可用您可以在iOS8&9将DeploymentTarget设置为其中一个版本。Swift3.x与iOS8兼容较新。与Swift2.2的唯一区别是您必须使用Xcode8。当您将部署目标设置为比iOS10更早版本的应用程序时,您应该意识到不能使用iOS10中新增的API,但使用Swift3应该没有问题。编辑:您现在可以使用Xcode8.0GM

  7. Android P预览上的Espresso测试:检测到API兼容性错误的问题

    我正在使用Espresso进行仪器测试并在AndroidPreviewPEmulator上运行它们.我的测试类中有5个测试用例,其中一个测试在运行测试套件时失败并得到以下错误.DetectedproblemswithAPIcompatibility失败的测试用例在单独运行而不是在套件中运行时通过.由于对话框显示在显示检测到的API兼容性问题的视图上,因此在层次结构异常中找不到匹配的视图以及上述错误

  8. android – 如果最低SDK = 14,则为Lollipop提供Appcompat,兼容性和支持库

    我们有一个现有的Android应用程序支持最高级别为18的API级别.我们使用了兼容性库19.1.0.现在我们正在改变/升级到:>最低SDK=14>目标=android-22现在假设有不同版本的v4,v7,v13支持,兼容性和appcompat库,我不确定要包含哪些,哪些不包含.我们使用maven进行依赖管理并使用MavenSDKdeployer解决方法如果您使用的是14的minSDK,那么从技术

  9. 使用Android API Level 15时如何保持向后兼容性?

    冰淇淋三明治介绍了很多新的UI设计元素,但市场渗透率仍然只有4%左右.如果想要面向未来的应用程序,并利用Honeycomb/IceCreamSandwich引入的一些设计元素,例如动作栏,配色方案等,那么确保您保持一些向后的方式是最好的方法兼容性?解决方法虽然我同意@OllieC,我认为除了使用ActionbarSherlock图书馆之外,还有其他选择可以添加,而这个我会积极参与ABS社区,并同意

  10. vue自定义加载指令v-loading占位图指令v-showimg

    这篇文章主要为大家介绍了vue自定义加载指令和v-loading占位图指令v-showimg的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部