实现Flash背景上的拖动以及解决被Flash覆盖的问题

相信对于很多前端的同学来说,拖动并不陌生,网上随随便便搜一下能搜出很多关于拖动的文章,github上也有很多关于拖动的库可以用。最近接到一个需求,需要修改线上一个拖动窗口的功能。类似下图:

看似简单的问题背后却隐藏着很多坑,让我不得不写这么一篇文章梳理一下。

我们之前的拖动代码也许就是某位同学从网上找的一篇拖动的文章写的,存在的问题如下:

1. 第一个问题:拖动不流畅,卡顿

2. 第二个问题:背景是个Flash游戏,窗口经常被Flash盖住


对于第一个问题,拖动不流畅,卡顿。理所当然我必须看下代码

// 鼠标按下div1时

obj.onmousedown = function(e) {

var evnt = e || event;                  // 得到鼠标事件

disX = evnt.clientX - obj.offsetLeft;  // 鼠标横坐标 - div1的left

disY = evnt.clientY - obj.offsetTop;    // 鼠标纵坐标 - div1的top

// 鼠标移动时

document.onmousemove = function(e) {

var evnt = e || event;

var x = evnt.clientX - disX;

var y = evnt.clientY - disY;

var window_width  = document.documentElement.clientWidth  - obj.offsetWidth;

var window_height = document.documentElement.clientHeight - obj.offsetHeight;

x = ( x < 0 ) ? 0 : x;

x = ( x > window_width ) ? window_width : x;

y = ( y < 0 ) ? 0 : y;

y = ( y > window_height ) ? window_height : y;

}

// 鼠标抬起时

document.onmouseup = function() {

document.onmousemove =null;

document.onmouseup = null;

}

return false;

};

我觉得这种写法不好,而且有bug,所以我改写了个方法。

var ox = 0;//原始坐标

var oy = 0;//原始坐标

var moveObj = $('move-div')

moveObj.on('mousedown', function(event) {

    ox = parseInt(event.pageX);

    oy = parseInt(event.pageY);

    that.target = that.videoBox;

});

$(document).on('mouseup', function(event) {

    that.target = null;

    ox = 0;

    oy = 0;

});

$(document).on('mousemove', function(event) {

    if (that.target) {

        var nX = parseInt(event.pageX);

        var nY = parseInt(event.pageY);

        var newX = nX - ox;

        var newY = nY - oy;

        var realX = targteOffsetObj.left + newX;

        var realY = targteOffsetObj.top + newY;

        that.target.css({left: realX, top: realY});

}

});

我只需要将绑定范围扩大到document下,这样就不会丢失焦点。然后每次点击的时候设定target,然后计算移动的相对位置,修改下css就搞定移动的问题。

理想很丰满,现实很骨感。

这样做依然存在问题,那就是移动快的时候,鼠标移动速度太快移到了背景的Flash上面,瞬间就会失去event对象,这种情况下还是会出现卡顿现象。

我第一个方法是绑定个mouseout,希望通过监听mouseout时实时fix一下坐标。但是这样并不理想,mouseout只能监听到刚移出几像素的时候,移动范围大了还是会丢失,还是会非常卡。所以,我后来想了个方案,在点击的时候给移动的对象加一个class,class里面是给宽高各加了200px。这样,即使移动很快,只要不超过这200px的范围,那么就一直可以监听到事件。后来试了下效果确实还不错。

第一个问题算是解决了,那么就开始搞第二个问题。

对于Flash背景来说,即使扩大了宽高,只要进入Flash的范围,就会被其抢走焦点。所以我第一个方案是将绑定改成draggable的方式,因为drag毕竟是HTML5的新属性,没准能抢过Flash。带着这种希望,我实现了第二种拖动方法。

moveObj.attr('draggable', 'true');

moveObj.on('dragstart', function(event) {

ox = parseInt(event.originalEvent.x);

oy = parseInt(event.originalEvent.y);

that.target = that.videoBox;

moveObj.addClass('choose');

//让火狐浏览器支持drag事件

event.originalEvent.dataTransfer.setData("text", event.target.innerHTML);

});

moveObj.on('drag', function(event) {

if (that.target) {

//松开那一下修改

if (event.originalEvent.x == 0 && event.originalEvent.y == 0) {

return false;

}

var nX = parseInt(event.originalEvent.x);

var nY = parseInt(event.originalEvent.y);

var newX = nX - ox;

var newY = nY - oy;

var realX = targteOffsetObj.left + newX;

var realY = targteOffsetObj.top + newY;

that.move(realX, realY);

}

});

moveObj.on('dragend', function(event) {

that.target = null;

ox = 0;

oy = 0;

moveObj.removeClass('choose');

callback();

//防止个别恶心浏览器下进行搜索

event.preventDefault();

});

写完试了一下,效果不错,而且毕竟是HTML5原生支持的,效率会比自己写的js效率高。但是这里还是遇到了两个坑,第一个是火狐下draggable不执行,解决方法是在dragstart的时候hack一下。

event.originalEvent.dataTransfer.setData("text", event.target.innerHTML);

但是第二个坑是即使hack成功,他的对象里没有可用来计算相对位移的属性,所以最终火狐下还是要屏蔽这种方法。

当然还有一个最关键的问题,draggable的元素并不能抢过Flash,焦点还是让Flash无情的抢走了。

所以,我们又回归到了问题的核心:

到底什么东西能够抢过Flash,焦点不会被Flash抢走呢?

后来我灵光一现,既然Flash这么牛逼,为什么我不用Flash来做我的容器,这样就不会被Flash抢走焦点了。于是,就有了第三个拖动的方法。

//通过swfobject创建flash,替换掉原来的move-object

window.onload = function () {

that.createFlash();

};

//生成了flash需要需要时间,所以不能直接绑定在move-object上面

$(document).on('mousedown', '#move-object', function(event) {

ox = parseInt(event.pageX);

oy = parseInt(event.pageY);

that.target = $('#video_content');

moveObj.addClass('choose');

event.preventDefault();

event.stopPropagation();

});

$(document).on('mouseup', '#move-object', function(event) {

that.target = null;

ox = 0;

oy = 0;

moveObj.removeClass('choose');

event.preventDefault();

event.stopPropagation();

});

$(document).on('mousemove', function(event) {

//document.onmousemove = function(event) {

if (that.target) {

var nX = parseInt(event.pageX);

var nY = parseInt(event.pageY);

var newX = nX - ox;

var newY = nY - oy;

var realX = targteOffsetObj.left + newX;

var realY = targteOffsetObj.top + newY;

that.move(realX, realY);

event.preventDefault();

event.stopPropagation();

}

});

这个Flash是请我同事帮我写的空的Flash,什么操作都没有,它只是做一件事,不让背景Flash抢去焦点。事实证明,确实做到了。即使鼠标范围移出到Flash背景上,只要鼠标不松开,事件就不会消失。而且不管我鼠标移动多快,焦点都在这个Flash元素上。

所以,困扰已久的Flash背景下拖动的问题算是解决了。

最终我的程序会自动选择适合拖动方式,支持Flash的优先使用Flash,如果不支持Flash优先使用drag,如果不支持drag就用最初的js拖动。

但是,特殊浏览器下比如IE,窗口游戏中被Flash覆盖的问题却始终还未解决。我试了很多方案,最终针对游戏中被Flash覆盖,我用了重新设置宽高的方式强制调用浏览器重绘机制,可以解决被覆盖的问题,窗口不会再被盖掉。

this.videoBox.css('width',  this.videoBox.width());//调用重绘机制

(这里需要注意的是,网上很多说修改zoom属性,我这里并没有效果,所以用的只是宽。)

实际测试中,又发现了一个新的问题,就是窗口虽然因为重绘显示了,但是只显示了一部分,还有一部分不显示。

最终,我们用Iframe作为垫片,做一个等大的Iframe在我的窗口下,然后移动窗口的时候同步移动这个垫片。但是美中不足的是这个Iframe不能透明,是一个黑色的背景色,设置透明也会透出Flash本身的黑底。

这点美中不足暂时还没办法解决。但是这个拖动问题已经算解决了。

最后,说一下忙了这一通总结出的两点结论:

1.只有Flash可以抢过Flash的焦点

2.只有Iframe可以盖住Flash


我知道这个问题、这个场景可能很奇葩,很多同学并不会遇到。而我因为要解决这个问题,去查了很多资料,从一个拖动,引发出很多不同的技术,不一样的思维,学到了很多其他的知识。

所以,我这里想说的是,作为前端,一定要有发散的思维,要从不同的维度考虑问题。拖动的问题可以从Flash上解决,那么其他的问题呢?

希望我写的这篇文章大家看了有那么一点点收获,获得一些不一样的灵感。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 单例模式 适用场景:可能会在场景中使用到对象,但只有一个实例,加载时并不主动创建,需要时才创建 最常见的单例模式,...
    Obeing阅读 2,045评论 1 10
  • @转自GitHub 介绍js的基本数据类型。Undefined、Null、Boolean、Number、Strin...
    YT_Zou阅读 1,129评论 0 0
  • 校园暴力的事件里,最令人厌恶,恨不得把他打死的那个,是带头欺负别人的那个吧? 可我觉得,最最卑鄙的,是那些跟在“老...
    李某多么想改个名字阅读 171评论 0 0
  • 并没有添加光照效果,导致虽然模型在旋转,但是我们看到的画面却像一个平面。今天我们开始学习如何给模型添加灯照效果,以...
    CHSmile阅读 717评论 0 0
  • 今天看了一篇文章,是说孩子磨蹭的,我想了想,在平常我没少催促她,看来是有问题的,以前王倩讲的陪蜗牛散步,自己实在应...
    董涛_1dcd阅读 266评论 0 0