对于我自己的网站我试图创建一个编辑器(基于contentEditables和HTML5拖放功能)。
这是小提琴:https://jsfiddle.net/5bw320zo/1/ 请注意代码很乱,它只是一个POC
每次悬停 占位符时,占位符的parentNode似乎都设置为null。
未捕获的TypeError:无法读取属性' removeChild'为null 在_detach 在HTMLDivElement._handleDragLeave
我在初始化时创建了一个简单的div元素:
placeholder = d.createElement('div');
placeholder.setAttribute('style', 'height: 25px; background-color: red;');
每个容器都有它自己的事件:
_on(elements, 'dragenter', _handleDragEnter);
_on(elements, 'dragover', _handleDragOver);
_on(elements, 'dragleave', _handleDragLeave);
_on(elements, 'drop', _handleDrop);
悬停时我会检查它是否有子项如果不是我只是追加元素,否则我会在之前或之后添加元素(取决于鼠标高度的位置):
function _handleDragOver(e) {
var targetBoundingBox,
targetMouseY;
targetBoundingBox = e.target.getBoundingClientRect();
targetMouseY = e.pageY - targetBoundingBox.top;
if (e.target.hasChildNodes()) {
// TODO check Y axis (/2)
} else {
c.log('within');
_within(e.target, placeholder);
}
}
在元素鼠标离开时,我将占位符(global var)与它自己的父级分开:
function _handleDragLeave(e) {
placeholder.parentNode.removeChild(placeholder);
}
它让我不知所措。在休假时检查源时,占位符元素仍然在正确的位置。有任何想法吗?
如果你们有更好的想法来整合占位符,请告诉(没有jquery或现有的库)。
答案 0 :(得分:1)
这里几乎没有问题......
首先,当您将_handleDragOver
悬停在占位符上时,它始终会执行其他条件,因为它没有子级。
function _handleDragOver(e) {
var targetBoundingBox,
targetMouseY;
targetBoundingBox = e.target.getBoundingClientRect();
targetMouseY = e.pageY - targetBoundingBox.top;
if (e.target.hasChildNodes()) {
// TODO check Y axis (/2)
} else {
c.log('within');
_within(e.target, placeholder); //<-- this guy
}
}
dragOver
在将鼠标悬停在有效的放置目标上时不断触发。
接下来,_within
功能:
function _within(target, element) {
target.appendChild(element);
}
如果占位符尚未被_detach
功能删除,那么这个小家伙会给您带来麻烦。如果您要放置占位符,并且它尚未被删除,那么您将尝试将其附加到自身...这将导致fireun为unfun类型。
现在是_detach
:
function _detach(element) {
element.parentNode.removeChild(element);
}
这会在您的_handleDragLeave
函数中调用。放下拖动时,dragLeave
事件会触发删除占位符。
这里是错误的来源...将鼠标悬停在占位符上会导致它被dragLeave分离,但随后它会被dragOver追回,依此类推,导致闪烁。你得到的错误是由于一个drop事件试图删除占位符引起的,当它已经被dragLeave删除但还没有被dragOver重新出现之后再尝试再次删除它。
答案 1 :(得分:1)
过去我做过一些拖放工作。我的问题是,当我使用拖放操作时,我没有注意到你需要使用DataTransfer对象。
第1步:拖动处理程序:
function _handleDragStart(e) {
e.dataTransfer.setData('myData', 'somedata');
e.dataTransfer.effectAllowed = 'move';
//no e.preventDefault() here or it will not work.
}
第2步:拖过处理程序:
function _handleDragOver(e) {
var data = e.dataTransfer.getData('myData');
if(data && //is this valid drop data){
e.dataTransfer.dropEffect = 'move';
e.preventDefault();
}
}
第3步:删除处理程序:
function _handleDrop(e) {
var data = e.dataTransfer.getData('myData');
if(data && //is this valid drop data){
//do something with your dropped data.
//re-render component inside editor-container
e.preventDefault();
}
}
第4步:拖动结束处理程序:
function _handleDragEnd(e) {
e.dataTransfer.clearData();
//Check if drop was completed and do cleanup.
//remove component from editor-item-list
}
e.dataTransfer.dropEffect
用于告诉拖放API可以执行放置操作。如果没有这个,drop
永远不会触发。它还用于更改光标的图标。
e.dataTransfer.setData
只将数据作为字符串。这可以通过将其转换为JSON来解决,也可以在编辑器中自己处理数据传输。
我发现在执行拖放操作时使用数据而不是DOM元素会更简单。传输数据并在删除操作后重新呈现它。
更新1
在e.dataTransfer.getData
和drag over
中,{59} drag end
无效。也许你最好自己做数据传输。请记住,您仍需要设置dropEffect
。