使用Knockout JS和Durandal 2.0实现HTML5拖放照片

3

我有一个 knockout js 的 viewmodel 包含了一组照片列表, 我想能够在它们之间进行切换(实际上更准确的术语是将一张照片复制到另一张上方)。 这是我的简化 viewmodel:

define(['durandal/app', 'knockout', 'jquery'], function(app, ko, jquery) {
    var miscPhotos = ko.observableArray();
    var draggedPhoto = ko.observable();

    function handleDragStart(data, e) {
        // e.preventDefault();
        draggedPhoto(data);
        console.log('dragStart');
        return true;
    }

    function handleDragOver(e) {
        e.preventDefault();
        console.log('dragOver');

    }

    function handleDrop(e) {
        e.preventDefault();
        e.stopPropagation();
        console.log('drop');

    }

    return {
        miscPhotos: miscPhotos,
        handleDrop: handleDrop,
        handleDragOver: handleDragOver,
        handleDragStart: handleDragStart
    }

});

现在连简化的用户界面也出现了:

<div id="holder" data-bind="foreach: miscPhotos">
    <div class="pull-left well well-small"  draggable="true" 
        data-bind="event:{
                dragstart: function(data, e){ $root.handleDragStart($data, e);},
                dragover:function(data, e){ $root.handleDragOver( e);},
                drop:function(data, e){ $root.handleDrop(e, $data);}}
     ">
    <div class="thumb">
        <img class="thumb" 
            title="" style="display: block" 
            data-bind="attr: {src: 'data:image;base64,' + PhotoData()}"
        />
    </div>  
</div>

当我试图将一张照片复制到另一张上面时,只有dragstart事件被触发,dragover和drop则不会被触发。

你尝试在 handleDragOver 和 handleDrop 中添加 'return true' 吗? - Jerry
1个回答

8
解决方案:
您需要在dragstart定义中添加return true:

你需要在dragstart函数内加入return true语句:

dragstart:   function(data, e){ $root.handleDragStart($data, e); return true;},

更多信息:

dragover事件没有被触发,因为Knockout阻止了dragstart的默认操作,没有默认操作就不会从dragstart过渡到dragover。

我认为您尝试通过在此处添加“return true”来启用默认操作:

function handleDragStart(data, e) {
   // e.preventDefault();
    draggedPhoto(data);
    console.log('dragStart');
    return true;   
}

然而,由于您已绑定了事件的方式,您需要做的是(这是最快的修复方法)将“return true”移动到绑定中的内联函数中:

dragstart:   function(data, e){ $root.handleDragStart($data, e); return true;},

我认为这会为您解决问题。但如果您愿意,可以简化您的代码。您在事件绑定的内联函数中没有传递任何额外的参数,因此您实际上不需要内联函数。您可以直接提供您的视图模型函数:

   dragstart: $root.handleDragStart,
   dragover:  $root.handleDragOver,
   drop:      $root.handleDrop

为了使这个工作起来,您需要更改处理程序函数签名以适应Knockout约定的(data, event)格式:
 handleDragStart(data, e)
 ...
 handleDragOver(data, e)
 ...
 handleDrop(data, e)

我制作了一个演示来测试这个问题...我稍微修改了你的视图模型,跳过了依赖声明,因为在没有它的情况下更容易做演示。但是代码基本上与你的相同,所以希望你能够轻松阅读它。我还向视图模型添加了一些测试数据URL,以便有一个可工作的演示。 http://jsfiddle.net/NLvm7/ 当我在那里时,我还继续展示了如何在handleDrop函数中将拖动的照片数据写入到放置它的照片中,从而实现将一张照片复制到另一张照片的目标。
    // The next 3 lines shows how you can copy the dragged photo onto the dropped target...
    var context = ko.contextFor(e.target);
    var index = context.$index();
    this.miscPhotos()[index].PhotoData(this.draggedPhoto().PhotoData());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接