首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >原生HTML5在Mobile Safari (iPad,iPod,iPhone)中的拖放?

原生HTML5在Mobile Safari (iPad,iPod,iPhone)中的拖放?
EN

Stack Overflow用户
提问于 2011-07-07 02:06:15
回答 3查看 52.1K关注 0票数 19

我已经成功地实现了原生HTML5拖放,用于在页面中移动元素(比如说,从一个位置到另一个位置的div,与与主机操作系统文件的交互无关)。这在个人电脑上的Chrome和Safari上运行得很好,但我不能在iPad的Safari上启动拖动操作。

到目前为止,我发现了这个:

使用JavaScript中的拖放进行

基于Safari、Dashboard和WebKit的应用程序支持在HTML页面中自定义拖放操作的行为。

注意:此技术仅在桌面版的Safari上受支持。对于iPhone OS,请使用DOM Touch,如处理事件( Safari Web内容指南的一部分)和Safari DOM添加参考中所述。

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

有没有人知道是否可以在Mobile Safari中使用原生 HTML5?(我不想要像jQuery UI这样的javascript框架解决方案)。

谢谢!

EN

回答 3

Stack Overflow用户

发布于 2014-10-12 07:36:04

我发现了这段非常有用的javascript代码,它为您添加了iOS事件填充:

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

完成代码,以防代码在将来某个时候被删除(这种情况经常发生):

代码语言:javascript
复制
(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);
票数 6
EN

Stack Overflow用户

发布于 2012-04-11 18:22:02

触摸事件现在也可以在Safari上运行(包括Mobile)。本文提供了一些不错的代码片段,您可以从这些代码片段开始:

http://www.html5rocks.com/en/mobile/touch/

票数 3
EN

Stack Overflow用户

发布于 2021-09-08 20:35:20

我一直在尝试在ios safari (ipad pro版本14.0.1)中使用本机拖放功能,我正在更新这个答案,因为它一直是我的第一个google搜索结果(似乎没有其他的问答是最新的)。

https://developer.apple.com/library/archive/documentation/AppleApplications/Conceptual/SafariJSProgTopics/DragAndDrop.html之后,我发现safari中的原生html5拖放现在可以工作,但有一些特别的注意事项;

你必须在OnDragStart的

  • 中设置一些数据;(效果设置似乎是可选的) Event.dataTransfer.setData('text/plain', 'hello');

  • 你必须Event.preventDefault(); in OnDrop,否则safari会加载你添加的数据(除非你是故意的)

  • OnDragOver事件处理程序需要Event.preventDefault();,否则drop fails (除非有意,如文档所述)

在ios safari上,如果你设置了OnDragStartEvent.dataTransfer.dropEffect='copy'OnDragOverEvent.dataTransfer.dropEffect='link',那么drop就会失败(no OnDrop());这似乎是失败的唯一组合

我以为你需要

  • CSS -webkit-user-drag: Element;和`-webkit-user-drop: element;或者如果您更喜欢

代码语言:javascript
复制
Element.style.setProperty('webkitUserDrag','element');
Element.style.setProperty('webkitUserDrop','element');

但是看起来仅仅是常用的draggable属性就足够了Element.setAttribute('draggable',true);

这似乎是拖放元素的最小要求

代码语言:javascript
复制
        Element.setAttribute('draggable',true);
        
        function OnDragOver(Event)
        {
            Element.setAttribute('DragOver',true);
            Event.stopPropagation();    //  let child accept and don't pass up to parent element
            Event.preventDefault();     //  ios to accept drop
            Event.dataTransfer.dropEffect = 'copy';//   move has no icon? adding copy shows +
        }
        function OnDragLeave(Event)
        {
            Element.removeAttribute('DragOver');
        }
        function OnDrop(Event)
        {
            Element.removeAttribute('DragOver');
            Event.preventDefault();     //  dont let page attempt to load our data
            Event.stopPropagation();
        }
        function OnDragStart(Event)
        {
            Event.stopPropagation(); // let child take the drag
            Event.dataTransfer.dropEffect = 'move';
            Event.dataTransfer.setData('text/plain', 'hello');
        }
        Element.addEventListener('dragstart',OnDragStart);
        Element.addEventListener('drop',OnDrop);
        Element.addEventListener('dragover',OnDragOver);
        Element.addEventListener('dragleave',OnDragLeave);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6600950

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档