×
文章路径: WEB前端 > JS

jquery.zclip生成的flash坐标位置不对

发表于2年前(Jun 5, 2016 9:05:02 AM)  阅读 669  评论 0

分类: WEB前端 JS

标签: jquery.zclip ZeroClipboard 操作剪贴板 offsetParent scrollTop scrollLeft

出于安全的考虑,浏览器对代码操作的内容有所限制,像不允许不经用户同意就下载文件到本地,不经用户确定就进入全屏状态,不经用户点击就操作剪贴板等。今天要讲的内容就是关于操作剪贴板的。

由于各浏览器对操作剪贴板的支持不一致,有的甚至不支持操作剪贴板,如果要写一个通用的操作剪贴板的代码,几乎是不可能的事。现在比较完善的一个方案是采用flash的方式,ZeroClipboard就是用来解决跨浏览器操作剪贴板兼容的问题,jquery.zclip是其jquery插件的封装。

ZeroClipboard的原理就是将要点击的按钮,替换成一个透明的flash,然后用户点击按钮的时候,实际上是点击的flash文件,这时flash操作剪贴板完成复制功能,因为flash的跨浏览器特性,使得这一功能也不受浏览器类型影响。当然,前提是要装有flash插件。

示例代码:

            $(".op-link").zclip({
                path:'/plugins/jQuery-zclip/ZeroClipboard.swf',
                copy:function(e){
                    var filePath = $(e.currentTarget).parents(".file-item").attr("data-path");
                    return filePath;
                },afterCopy: function(event, text){//复制成功
                    console.log(text);
                }
            });

笔者在使用过程中,发现经常点击按钮并没有实现复制功能,经过仔细测试,终于发现是flash生成的坐标位置不对,导致未能复制成功。调试代码的过程中,笔者发现,添加了zclip方法后,当用户移到目标按钮上时,即hover时,将会触发flash的reposition操作,在reposition操作中,会计算目标按钮的坐标,left值和top值,以及目标按钮的width和height。目标按钮的坐标是相对于body的坐标,我们来看下源码:

var _getDOMObjectPosition = function(obj) {
    var info = {
      left: 0,
      top: 0,
      width: obj.width || obj.offsetWidth || 0,
      height: obj.height || obj.offsetHeight || 0,
      zIndex: 9999
    };
    var zi = _getStyle(obj, "zIndex");
    if (zi && zi != "auto") {
      info.zIndex = parseInt(zi, 10);
    }
    while (obj) {
      var borderLeftWidth = parseInt(_getStyle(obj, "borderLeftWidth"), 10);
      var borderTopWidth = parseInt(_getStyle(obj, "borderTopWidth"), 10);
      info.left += isNaN(obj.offsetLeft) ? 0 : obj.offsetLeft;
      info.left += isNaN(borderLeftWidth) ? 0 : borderLeftWidth;
      info.top += isNaN(obj.offsetTop) ? 0 : obj.offsetTop;
      info.top += isNaN(borderTopWidth) ? 0 : borderTopWidth;
      obj = obj.offsetParent;
    }
    return info;
  };

可以看到它一直遍历offsetParent,直到offsetParent为undefined。什么是offsetParent?

offsetParent属性返回一个对象的引用,这个对象是距离调用offsetParent的元素最近的(在包含层次中最靠近的),并且是已进行过CSS定位的容器元素。 如果这个容器元素未进行CSS定位, 则offsetParent属性的取值为根元素(在标准兼容模式下为html元素;在怪异呈现模式下为body元素)的引用。 当容器元素的style.display 被设置为 "none"时(译注:IE和Opera除外),offsetParent属性 返回 null。

笔者在网上找了很多资料,有人也出现过坐标计算错误的情况,笔者一一进行了测试,均还是不行,jquery.zclip笔者使用的好像已经是最高版本1.1.7,不过ZeroClipboard已经出了2.x版本了,但jquery.zclip没有更新,笔者只好静下心来,自己计算一下坐标。

经过努力,终于修改成功,这是修改后的方法:

var _getDOMObjectPosition = function(obj) {
    var info = {
      left: 0,
      top: 0,
      width: obj.width || obj.offsetWidth || 0,
      height: obj.height || obj.offsetHeight || 0,
      zIndex: 9999
    };
    var zi = _getStyle(obj, "zIndex");
    if (zi && zi != "auto") {
      info.zIndex = parseInt(zi, 10);
    }
    while (obj) {
      var borderLeftWidth = parseInt(_getStyle(obj, "borderLeftWidth"), 10);
      var borderTopWidth = parseInt(_getStyle(obj, "borderTopWidth"), 10);
      info.left += isNaN(obj.offsetLeft) ? 0 : obj.offsetLeft;
      info.left += isNaN(borderLeftWidth) ? 0 : borderLeftWidth;
      info.top += isNaN(obj.offsetTop) ? 0 : obj.offsetTop;
      info.top += isNaN(borderTopWidth) ? 0 : borderTopWidth;
      if(obj.tagName!="BODY"&&obj.tagName!="HTML") {
        info.top -= isNaN(obj.scrollTop) ? 0 : obj.scrollTop;
        info.left -= isNaN(obj.scrollLeft) ? 0 : obj.scrollLeft;
      }
      obj = obj.offsetParent;
    }
    return info;
  };

在原来的计算方法上,加上了对scrollTop喝scrollLeft的计算,不错,笔者之所以开始测试有时不成功,就是因为有些dom元素出现了滚动条,源码没有考虑到这种情况才出现bug的。

可以预见,一般如果jquery.zclip失效的话,很可能就是坐标计算错误,用户可以先确定这一点,然后分析自己所处的情况,修改一下计算方法。上面的计算方法也不一定对于所有情况都正确。用户还可以对坐标和大小进行微调,以便flash更好地覆盖目标按钮,使体验更加友好。

发表评论