2011-07-06 21 views
16

我已经成功实施了本地HTML5拖放在页面内移动HTML元素(就是说,一个div从一个地方到另一个地方,与主机操作系统的任何文件都无关)。这在PC上的Chrome和Safari中运行良好,但我无法在iPad的Safari中启动拖动操作。移动Safari(iPad,iPod,iPhone)中的原生HTML5拖放?

我发现这个至今:

使用拖放从JavaScript

Safari浏览器,仪表板,以及基于WebKit的 应用包括 定制拖放 下降的行为支持在您的HTML 页面内进行操作。

注意:仅在桌面版本的Safari上支持此技术 。 对于iPhone OS,使用DOM处理事件( Safari Web内容指南的一部分)和Safari DOM Additions Reference中描述的DOM Touch, 。

Here。但已经过时(2009-06-08)。

Doe的任何人都知道是否可以使用原生移动Safari中的HTML5? (我不需要像jQuery UI之类的解决方案的JavaScript框架)。

谢谢!

回答

5

我发现这非常有用的javascript代码,增加了iOS事件垫片为您提供:

https://github.com/timruffles/ios-html5-drag-drop-shim

完整的代码只是在情况代码在将来某个时候被删除(它经常发生):

(function(doc) { 

    log = noop; // noOp, remove this line to enable debugging 

    var coordinateSystemForElementFromPoint; 

    function main(config) { 
    config = config || {}; 

    coordinateSystemForElementFromPoint = navigator.userAgent.match(/OS 5(?:_\d+)+ like Mac/) ? "client" : "page"; 

    var div = doc.createElement('div'); 
    var dragDiv = 'draggable' in div; 
    var evts = 'ondragstart' in div && 'ondrop' in div; 

    var needsPatch = !(dragDiv || evts) || /iPad|iPhone|iPod/.test(navigator.userAgent); 
    log((needsPatch ? "" : "not ") + "patching html5 drag drop"); 

    if(!needsPatch) return; 

    if(!config.enableEnterLeave) { 
     DragDrop.prototype.synthesizeEnterLeave = noop; 
    } 

    doc.addEventListener("touchstart", touchstart); 
    } 

    function DragDrop(event, el) { 

    this.touchPositions = {}; 
    this.dragData = {}; 
    this.el = el || event.target 

    event.preventDefault(); 

    log("dragstart"); 

    this.dispatchDragStart() 
    this.elTranslation = readTransform(this.el); 

    this.listen() 

    } 

    DragDrop.prototype = { 
    listen: function() { 
     var move = onEvt(doc, "touchmove", this.move, this); 
     var end = onEvt(doc, "touchend", ontouchend, this); 
     var cancel = onEvt(doc, "touchcancel", cleanup, this); 

     function ontouchend(event) { 
     this.dragend(event, event.target); 
     cleanup(); 
     } 
     function cleanup() { 
     log("cleanup"); 
     this.touchPositions = {}; 
     this.el = this.dragData = null; 
     return [move, end, cancel].forEach(function(handler) { 
      return handler.off(); 
     }); 
     } 
    }, 
    move: function(event) { 
     var deltas = { x: [], y: [] }; 

     [].forEach.call(event.changedTouches,function(touch, index) { 
     var lastPosition = this.touchPositions[index]; 
     if (lastPosition) { 
      deltas.x.push(touch.pageX - lastPosition.x); 
      deltas.y.push(touch.pageY - lastPosition.y); 
     } else { 
      this.touchPositions[index] = lastPosition = {}; 
     } 
     lastPosition.x = touch.pageX; 
     lastPosition.y = touch.pageY; 
     }.bind(this)) 

     this.elTranslation.x += average(deltas.x); 
     this.elTranslation.y += average(deltas.y); 
     this.el.style["z-index"] = "999999"; 
     this.el.style["pointer-events"] = "none"; 
     writeTransform(this.el, this.elTranslation.x, this.elTranslation.y); 

     this.synthesizeEnterLeave(event); 
    }, 
    synthesizeEnterLeave: function(event) { 
     var target = elementFromTouchEvent(this.el,event) 
     if (target != this.lastEnter) { 
     if (this.lastEnter) { 
      this.dispatchLeave(); 
     } 
     this.lastEnter = target; 
     this.dispatchEnter(); 
     } 
    }, 
    dragend: function(event) { 

     // we'll dispatch drop if there's a target, then dragEnd. If drop isn't fired 
     // or isn't cancelled, we'll snap back 
     // drop comes first http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-and-drop-processing-model 
     log("dragend"); 

     if (this.lastEnter) { 
     this.dispatchLeave(); 
     } 

     var target = elementFromTouchEvent(this.el,event) 

     if (target) { 
     log("found drop target " + target.tagName); 
     this.dispatchDrop(target) 
     } else { 
     log("no drop target, scheduling snapBack") 
     once(doc, "dragend", this.snapBack, this); 
     } 

     var dragendEvt = doc.createEvent("Event"); 
     dragendEvt.initEvent("dragend", true, true); 
     this.el.dispatchEvent(dragendEvt); 
    }, 
    dispatchDrop: function(target) { 
     var snapBack = true; 

     var dropEvt = doc.createEvent("Event"); 
     dropEvt.initEvent("drop", true, true); 
     dropEvt.dataTransfer = { 
     getData: function(type) { 
      return this.dragData[type]; 
     }.bind(this) 
     }; 
     dropEvt.preventDefault = function() { 
     // https://www.w3.org/Bugs/Public/show_bug.cgi?id=14638 - if we don't cancel it, we'll snap back 
     this.el.style["z-index"] = ""; 
     this.el.style["pointer-events"] = "auto"; 
     snapBack = false; 
     writeTransform(this.el, 0, 0); 
     }.bind(this); 

     once(doc, "drop", function() { 
     log("drop event not canceled"); 
     if (snapBack) this.snapBack() 
     },this); 

     target.dispatchEvent(dropEvt); 
    }, 
    dispatchEnter: function() { 

     var enterEvt = doc.createEvent("Event"); 
     enterEvt.initEvent("dragenter", true, true); 
     enterEvt.dataTransfer = { 
     getData: function(type) { 
      return this.dragData[type]; 
     }.bind(this) 
     }; 

     this.lastEnter.dispatchEvent(enterEvt); 
    }, 
    dispatchLeave: function() { 

     var leaveEvt = doc.createEvent("Event"); 
     leaveEvt.initEvent("dragleave", true, true); 
     leaveEvt.dataTransfer = { 
     getData: function(type) { 
      return this.dragData[type]; 
     }.bind(this) 
     }; 

     this.lastEnter.dispatchEvent(leaveEvt); 
     this.lastEnter = null; 
    }, 
    snapBack: function() { 
     once(this.el, "webkitTransitionEnd", function() { 
     this.el.style["pointer-events"] = "auto"; 
     this.el.style["z-index"] = ""; 
     this.el.style["-webkit-transition"] = "none"; 
     },this); 
     setTimeout(function() { 
     this.el.style["-webkit-transition"] = "all 0.2s"; 
     writeTransform(this.el, 0, 0) 
     }.bind(this)); 
    }, 
    dispatchDragStart: function() { 
     var evt = doc.createEvent("Event"); 
     evt.initEvent("dragstart", true, true); 
     evt.dataTransfer = { 
     setData: function(type, val) { 
      this.dragData[type] = val; 
      return val; 
     }.bind(this), 
     dropEffect: "move" 
     }; 
     this.el.dispatchEvent(evt); 
    } 
    } 

    // event listeners 
    function touchstart(evt) { 
    var el = evt.target; 
    do { 
     if (el.hasAttribute("draggable")) { 
     evt.preventDefault(); 
     new DragDrop(evt,el); 
     } 
    } while((el = el.parentNode) && el !== doc.body) 
    } 

    // DOM helpers 
    function elementFromTouchEvent(el,event) { 
    var touch = event.changedTouches[0]; 
    var target = doc.elementFromPoint(
     touch[coordinateSystemForElementFromPoint + "X"], 
     touch[coordinateSystemForElementFromPoint + "Y"] 
    ); 
    return target 
    } 

    function readTransform(el) { 
    var transform = el.style["-webkit-transform"]; 
    var x = 0 
    var y = 0 
    var match = /translate\(\s*(\d+)[^,]*,\D*(\d+)/.exec(transform) 
    if(match) { 
     x = parseInt(match[1],10) 
     y = parseInt(match[2],10) 
    } 
    return { x: x, y: y }; 
    } 

    function writeTransform(el, x, y) { 
    var transform = el.style["-webkit-transform"].replace(/translate\(\D*\d+[^,]*,\D*\d+[^,]*\)\s*/g, ''); 
    el.style["-webkit-transform"] = transform + " translate(" + x + "px," + y + "px)"; 
    } 

    function onEvt(el, event, handler, context) { 
    if(context) handler = handler.bind(context) 
    el.addEventListener(event, handler); 
    return { 
     off: function() { 
     return el.removeEventListener(event, handler); 
     } 
    }; 
    } 

    function once(el, event, handler, context) { 
    if(context) handler = handler.bind(context) 
    function listener(evt) { 
     handler(evt); 
     return el.removeEventListener(event,listener); 
    } 
    return el.addEventListener(event,listener); 
    } 


    // general helpers 
    function log(msg) { 
    console.log(msg); 
    } 

    function average(arr) { 
    if (arr.length === 0) return 0; 
    return arr.reduce((function(s, v) { 
     return v + s; 
    }), 0)/arr.length; 
    } 

    function noop() {} 

    main(window.iosDragDropShim); 


})(document);