如何结合 KnockoutJS 使用 HTML5 拖放?

Posted

技术标签:

【中文标题】如何结合 KnockoutJS 使用 HTML5 拖放?【英文标题】:How to use HTML5 drag and drop in combination with KnockoutJS? 【发布时间】:2011-11-05 07:11:20 【问题描述】:

我似乎无法绑定到 html5 拖放事件。

这是来自模板的示例:

<script id="tabsTemplate" type="text/html">
    <div class="dropzone" for="tab"
        data-bind="event:dragover: function(event)event.preventDefault();,
                          dragenter: function(event)event.target.addClass('dragover'); event.preventDefault();,
                          dragleave: function(event)event.target.removeClass('dragover'); event.preventDefault();
                          drop: function(event)console.log('blahblah!')"></div>
    <h1 class="tab" draggable="true"
      data-bind="attr: selected: $data.name === $item.selected(),
                 click: function()$item.selected($data.name),
                 event: dragstart: function(event)console.log('blah!!'),
                         dragend: function(event)document.getElementsByClassName('dragover')[0].removeClass('dragover')">
        $name

        <img src="icons/close-black.png" class="close button" role="button"
            data-bind="click: function(e)$item.close($data)">
    </h1>
</script>

我所拥有的应该可以按预期工作......只要我使它们成为正常的内联对象,它就会起作用。但是,然后其他绑定不起作用!

我收到此错误消息:

未捕获的语法错误:意外的标记 '||' jquery-tmpl.js:10

这里发生了什么?是不是我做错了什么?

【问题讨论】:

如果您还没有实现dragstart 事件,您如何确定它是否有效?如果不setData,则不会发生拖动。 你所要做的就是输入'draggable: true'然后你就可以拖动了。我的 dragend 处理程序不需要知道任何数据,并且当它内联时它工作得很好......只是当它在绑定中时就不行。 我可以说的是,在 dragenter 上添加的 'dragover' 类会显着改变 css。 Dragend 应该从最后一个 dropzone 中删除该类以触发 dragenter 事件。在绑定中它不会...内联它。 我有 just checked - Chrome 可以工作,Firefox 需要 dragstart。因此,我假设您使用的是 Chrome,这不是您的问题。我会下载 knockout.js 并玩一下。 【参考方案1】:

对于那些(像我一样)需要 SSCCE 工作的人;该解决方案遵循 [cybermotron] 的建议,还修复了处理程序期望参数 dataevent 的问题。

http://jsfiddle.net/marrok/m63aJ/

HTML

<script type="application/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

<ul id="people" data-bind='template:  name: "personTmpl", foreach: people '>
</ul>
<div class="trash" data-bind ="visible:dragging, event:
       dragover: function(data, event)
          event.preventDefault();
       ,
       drop: function(data, event)
          console.log('trash', $root.drag_start_index())
          $root.trash($root.drag_start_index())     
          event.preventDefault();
       
"> <span>DELETE</span> </div> 

<script id="personTmpl" type="text/html">
    <li class="draggable" draggable="true" data-bind="event:
      dragstart:   function(data, event) 
                    $(event.target).addClass('dragSource')
                    $root.drag_start_index($index());
                    return $(event.target).hasClass('draggable');,    

       dragend:   function(data, event)  
                   $root.drag_start_index(-1);
                   $(event.target).removeClass('dragSource')
                   return true;
       ,    
       dragover:  function(data, event)event.preventDefault();,
       dragenter: function(data, event)
                $root.drag_target_index($index());
                var element = $(event.target)
                if(element.hasClass('draggable'))
                     element.toggleClass('dragover'); 
                event.preventDefault();
    ,
       dragleave: function(data, event, $index)
                var element = $(event.target)
                if(element.hasClass('draggable'))
                     element.toggleClass('dragover');
                event.preventDefault();
    ,
       drop: function(data, event)
                $(event.target).removeClass('dragover'); 
                console.log('swap', $root.drag_start_index(),  $root.drag_target_index() )
                $root.swap($root.drag_start_index(),  $root.drag_target_index())
               
             ">

        <span data-bind='text: name'></span>
    </li>
</script>

淘汰赛

var Person = function(name) 
    this.name = ko.observable(name);

;

var PeopleModel = function() 
    var self = this;

    self.drag_start_index = ko.observable();
    self.drag_target_index = ko.observable();
    self.dragging = ko.computed(function() 
        return self.drag_start_index() >= 0;
    );
    self.people = ko.observableArray([
        new Person("Oleh"), new Person("Nick C."), new Person("Don"), new Person("Ted"), new Person("Ben"), new Person("Joe"), new Person("Ali"), new Person("Ken"), new Person("Doug"), new Person("Ann"), new Person("Eve"), new Person("Hal")]);


    self.trash = function(index) 
        self.people.splice(index, 1)
    
    self.swap = function(from, to) 
        if (to > self.people().length - 1 || to < 0) return;

        var fromObj = self.people()[from];
        var toObj = self.people()[to];
        self.people()[to] = fromObj;
        self.people()[from] = toObj;
        self.people.valueHasMutated()
    
;
ko.applyBindings(new PeopleModel());​

【讨论】:

不错的小提琴,非常有帮助和简洁!【参考方案2】:

好的,我已经解决了。似乎我在文档中错过了它说在淘汰赛中,默认情况下它使所有事件都阻止默认/返回 false。所以我所要做的就是让我的 dragstart 处理程序返回 true,现在它可以工作了。呼!!

【讨论】:

【参考方案3】:

您可能遇到与提到的here 相同的问题,尽管它指的是嵌套模板:

警告

如果您将 templateOptions 从嵌套模板传递给模板绑定(因此,从模板中指定模板绑定),请特别注意您的语法。如果您的绑定如下所示,您将遇到问题:

 <div data-bind="template:  name: 'items', data: newItems, templateOptions:  header: “New Items!”"></div> 

jQuery 模板插件在绑定结束时会被 混淆,因为这是其语法的一部分。在大括号之间添加一个空格可以正常工作。希望这可以防止某人受到一些不必要的挫败感。

 <div data-bind="template:  name: 'items', data: newItems, templateOptions:  header: “New Items!” "></div>

【讨论】:

哇...我没想到 jquery 模板会因为我对 的轻率使用而感到困惑...好吧,我修复了它们,现在我不再收到错误...现在当我开始拖动时,控制台会说“废话!”,就像我要求它...但是现在元素实际上并没有拖动!它注册了 dragstart 事件,但元素保持不变......并且您的链接似乎已损坏。 链接现已修复 :) 好文章,但不是我想要的。 我意识到 :) 还没有时间仔细研究它。

以上是关于如何结合 KnockoutJS 使用 HTML5 拖放?的主要内容,如果未能解决你的问题,请参考以下文章

KnockoutJS + My97DatePicker b

KnockoutJS 设置 jQuery Mobile 滑块的最大选项

JS组件系列——KnockoutJS用法

如何使用 jQuery、RequireJS 和 KnockoutJS 创建基本的 TypeScript 项目

如何使用 KnockoutJS 通过 AJAX 观察服务器上的数据?

如何调试 KnockoutJS 的模板绑定错误?