所以我首先通过构建可以拖动元素的核心可拖动位,然后当你放弃元素时,我使用document.elementFromPoint()获取游标位置的元素(注意:我必须隐藏可拖动元素,否则将返回).
现在我有最接近游标的元素,主要问题是找出可拖动元素需要相对于该元素的位置,因为有4个选项append – prepend – insertBefore – insertAfter.我已经设法得到附加 – 前置和放大insertBefore工作,但它不够可靠,因为我正在进行的是使用目标的高度和偏移来确定追加或前缀,并且我正在增加getFromPoint上的Y参数,以查看我是否在短距离内打了一个不同的元素确定insertBefore之前.这是我到目前为止的代码.
Box.addEventListener('mouseup',function (e) { if (!dragging) return; dragging = false; var thisEl = this; // the drag-able element // Hide this.style.display = 'none'; // hide the element so we can get // document.elementFromPoint var el = document.elementFromPoint(e.pageX,e.pageY),// target elH = el.offsetHeight,// height of target elT = el.offsetTop; // offset of target for (var i = 0; i < 15; i++) { // This is a weird part see the reference at the bottom var newEl = document.elementFromPoint(e.pageX,e.pageY + i); if (newEl !== el) { this.style.display = 'block'; this.style.position = 'static'; return newEl.parentNode.insertBefore(thisEl,newEl); } } if (e.pageY < elT + (elH / 2)) { // if the pageY is less than the target offset + half of the height,that's how I am calculating prepend el.appendChild(this); el.insertBefore(this,el.firstChild); } else { el.appendChild(this); // else append; } this.style.display = 'block'; this.style.position = 'static'; // Snap back in with 'static' });
这只是我的mouseup事件,这是所有的工作.其他事件只是使元素拖动,不是很重要.
这是一个小提琴
所以如果没有提出问题,那么这里是一个简短的版本.
我的可拖动元素需要能够被放置在任何地方,并嵌入.什么是最好的方式来做到这一点,因为我在小提琴中做到这一点绝对不是很好.如何在mouseup上检测元素需要相对于目标的位置.
参考奇怪的部分.
这是它的工作原理(警告它不好)
当我使用elementFromPoint获取目标元素时,我创建一个循环
这将循环15次,并增加进入elementFromPoint的Y值,以便基本上elementFromPoint向下移动15px,如果它在该空间内遇到一个新元素,我假设您不会在元素之前插入该元素.
如果你觉得这篇文章很漫长而令人困惑,那就是因为我已经在这几天了,而且我的头部旋转起来,让我疯狂.
我想要注意的是,可以拖放的容器是设计师的主要部分.所以对于我来说,这不是一个绝对定位的元素的选择,我不会真的把一个元素放在每一个可能的地方,这样我就可以发现可拖动元素必须去哪里,因为任何在该容器将是没有不必要内容的质量结果.
我还要注意,我的应用程序不会也不会支持旧的浏览器,即IE6,IE7,IE8,IE9
解决方法
HTML
<!--==== DragonDrop Demo HTML Here we have two contenteditable <div>'s -- they have a dashed bottom-border dividing them,and they contain varIoUs text content. The first <div> contains structured block content,and the second <div> contains Unstructured,unwrapped content. ====--> <div contenteditable="true"> <h1>Athenagora Lenoni Incommunicabile: Structured Content</h1> <h2>Cellam modico illius ergo accipiet si non ait est Apollonius.</h2> <a class="fancy"> <img src="http://imageshack.us/scaled/landing/809/picture195z.jpg" /> <caption>Hola!</caption> </a> <p>Volvitur ingreditur lavare propter increparet videns mihi cum. Tharsis ratio puella est Apollonius in deinde plectrum anni ipsa codicellos,jesus Circumdat flante vestibus lumine restat paralyticus audi anim igitur patriam Dianae. 'Iuraveras magnifice ex quae ad per te sed dominum sit Mariae Bone de his carpens introivit filiam. Plus damna nautis unum ad te. Puto suam ad quia iuvenis omnia. Etiam quantitas devenit regi adhibitis sedens loculum inveni.</p> </div> <div contenteditable="true"> <strong>Unstructured Content:</strong> Toto determinata se est se ad te finis laeta gavisus,laetare quod una non ait mea ego dum est Apollonius. Intrarem puella est in deinde cupis ei Taliarchum in,tharsiam vis interrogat Verena est Apollonius eius ad suis. Antiochus ac esse more filiam sunt forma ait Cumque persequatur sic. Imas rebum accusam in fuerat est se sed esse ait Cumque ego. Secundis sacerdotem habemus ibi alteri ad quia,agere videre Proicite a civitas exulto haec. Supponite facultatibus actum dixit eos. Neminem habere litore in deinde duas formis. Quattuordecim anulum ad nomine Hesterna studiis ascende meae puer ut sua,eiusdem ordo quos annorum afferte Apollonius non ait in. <br /><br /> Deducitur potest contremiscunt eum ego Pentapolim Cyrenaeorum tertia navigavit volente in fuerat eum istam vero cum obiectum invidunt cum. Christe in rei sensibilium iussit sed,scitote si quod ait Cumque persequatur sic. Amet consensit cellula filia in rei civibus laude clamaverunt donavit potest flens non solutionem innocentem si quod ait. Una Christi sanguine concomitatur quia quod non coepit,volvitur ingreditur est Apollonius eius non potentiae. Coepit cenam inhaeret Visceribusque esocem manibus modi regiam iriure dolore. Filiam in rei finibus veteres hoc ambulare manu in fuerat eum istam provoces. </div> <button name="toggleContentEditable">disable contenteditable</button>
CSS
/*====== DragonDrop Demo CSS Basically,user-select,and user-drag (and all their prefixes) need to be set in a way that lets the browser know which parts of our draggable element are selectable and draggable and which aren't. So I guess this is that. ======*/ @charset utf-8; /* these rules only apply to fancy Boxes when contenteditable is true: they are necessary for the drag-and-drop demo to work correctly */ [contenteditable="true"] .fancy { /**/-moz-user-select:none;-webkit-user-select:none; user-select:none; /* without this line,element can be dragged within itself! No-no! */ /**/-moz-user-drag:element;-webkit-user-drag:element; user-drag:element; /* makes the whole fancy Box draggable */ cursor:move !important; } /* switches to the move cursor */ [contenteditable="true"] .fancy * { /**/-moz-user-drag:none;-webkit-user-drag:none; user-drag:none; } /* hopefully disables the internal default dragging of the img */ /*====== Everything below this area is STRICLY for STYLE and VISUAL APPEAL. It shouldn't concern you. ======*/ html,body{ height:100%; } [contenteditable] { background:#f8f8f8; Box-sizing:border-Box; padding:2%; min-height:auto; font-size:10px; font-family:sans-serif; color:#444; border-bottom:2px dashed #888; } .fancy { display:inline-block; margin:10px; color:#444; text-align:center; font-style:italic; font-size:10px; font-family:sans-serif; background:#fff; border:8px solid white; Box-shadow:1px 2px 8px #444; cursor:pointer; } .fancy img { display:block; margin-bottom:2px; border:1px solid white; Box-shadow:0 1px 6px #888; } .fancy .caption { max-width:100px; } h1 { font-weight:bold; font-size:1.4em; } h2 { font-weight:bold; font-style:italic; text-indent:2px; } p { text-indent:8px; } strong { font-weight:bold; } button { display:block; margin:6px auto; }
使用Javascript
/* ==== Dragon Drop: a demo of precise DnD in,around,and between multiple contenteditable's. ================================= == MIT Licensed for all to use == ================================= Copyright (C) 2013 Chase Moskal Permission is hereby granted,free of charge,to any person obtaining a copy of this software and associated documentation files (the "Software"),to deal in the Software without restriction,including without limitation the rights to use,copy,modify,merge,publish,distribute,sublicense,and/or sell copies of the Software,and to permit persons to whom the Software is furnished to do so,subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS",WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER LIABILITY,WHETHER IN AN ACTION OF CONTRACT,TORT OR OTHERWISE,ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============ */ function DRAGON_DROP (o) { var DD=this; // "o" params: DD.$draggables=null; DD.$dropzones=null; DD.$noDrags=null; // optional DD.dropLoad=null; DD.engage=function(o){ DD.$draggables = $(o.draggables); DD.$dropzones = $(o.dropzones); DD.$draggables.attr('draggable','true'); DD.$noDrags = (o.noDrags) ? $(o.noDrags) : $(); DD.$dropzones.attr('dropzone','copy'); DD.bindDraggables(); DD.bindDropzones(); }; DD.bindDraggables=function(){ DD.$draggables = $(DD.$draggables.selector); // reselecting DD.$noDrags = $(DD.$noDrags.selector); DD.$noDrags.attr('draggable','false'); DD.$draggables.off('dragstart').on('dragstart',function(event){ var e=event.originalEvent; $(e.target).removeAttr('dragged'); var dt=e.dataTransfer,content=e.target.outerHTML; var is_draggable = DD.$draggables.is(e.target); if (is_draggable) { dt.effectAllowed = 'copy'; dt.setData('text/plain',' '); DD.dropLoad=content; $(e.target).attr('dragged','dragged'); } }); }; DD.bindDropzones=function(){ DD.$dropzones = $(DD.$dropzones.selector); // reselecting DD.$dropzones.off('dragleave').on('dragleave',function(event){ var e=event.originalEvent; var dt=e.dataTransfer; var relatedTarget_is_dropzone = DD.$dropzones.is(e.relatedTarget); var relatedTarget_within_dropzone = DD.$dropzones.has(e.relatedTarget).length>0; var acceptable = relatedTarget_is_dropzone||relatedTarget_within_dropzone; if (!acceptable) { dt.dropEffect='none'; dt.effectAllowed='null'; } }); DD.$dropzones.off('drop').on('drop',function(event){ var e=event.originalEvent; if (!DD.dropLoad) return false; var range=null; if (document.caretRangeFromPoint) { // Chrome range=document.caretRangeFromPoint(e.clientX,e.clientY); } else if (e.rangeParent) { // Firefox range=document.createRange(); range.setStart(e.rangeParent,e.rangeOffset); } var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); $(sel.anchorNode).closest(DD.$dropzones.selector).get(0).focus(); // essential document.execCommand('insertHTML',false,'<param name="dragonDropMarker" />'+DD.dropLoad); sel.removeAllRanges(); // verification with dragonDropMarker var $DDM=$('param[name="dragonDropMarker"]'); var insertSuccess = $DDM.length>0; if (insertSuccess) { $(DD.$draggables.selector).filter('[dragged]').remove(); $DDM.remove(); } DD.dropLoad=null; DD.bindDraggables(); e.preventDefault(); }); }; DD.disengage=function(){ DD.$draggables=$( DD.$draggables.selector ); // reselections DD.$dropzones=$( DD.$dropzones.selector ); DD.$noDrags=$( DD.$noDrags.selector ); DD.$draggables.removeAttr('draggable').removeAttr('dragged').off('dragstart'); DD.$noDrags.removeAttr('draggable'); DD.$dropzones.removeAttr('droppable').off('dragenter'); DD.$dropzones.off('drop'); }; if (o) DD.engage(o); } $(function(){ window.DragonDrop = new DRAGON_DROP({ draggables:$('.fancy'),dropzones:$('[contenteditable]'),noDrags:$('.fancy img') }); // This is just the enable/disable contenteditable button at the bottom of the page. $('button[name="toggleContentEditable"]').click(function(){ var button=this; $('[contenteditable]').each(function(){ if ($(this).attr('contenteditable')==='true') { $(this).attr('contenteditable','false'); $(button).html('enable contenteditable'); } else { $(this).attr('contenteditable','true'); $(button).html('disable contenteditable'); } }); }); });
小提琴: