【问题标题】:How to data bind to the CSS top, left, width, and height of a DOM element?如何将数据绑定到 DOM 元素的 CSS 顶部、左侧、宽度和高度?
【发布时间】:2011-06-10 16:33:01
【问题描述】:

我正在尝试使用 KnockoutJS 构建一个交互式仪表板,其中包含style 属性的不同方面的数据绑定;即lefttopwidthheight。例如,我使用 JQuery UI 以及 ui-draggable 和 ui-resizable 效果来使用户能够在画布上拖动面板并调整它们的大小,但他们认为合适。如果没有 KnockoutJS,我只是在遍历每个 div 并从 dom 元素中窃取这些属性。我确信使用 KnockoutJS 有更好的方法,对吧?

为了更好地解释我的问题,请并排考虑两个面板:

<div id='dashboard'> 
  <div id='panel1' class='ui-draggable ui-resizable' data-bind='?????'> 
    <!-- content goes here -->
  </div> 
  <div id='panel2' class='ui-draggable ui-resizable' data-bind='?????'> 
    <!-- content goes here --> 
  </div> 
  <button data-bind='click: send'>Update</button> 
</div> 

我的视图模型看起来像这样(注意:为简洁起见,伪编码):

var viewModel = { 
  panels: [ 
   { id: 'panel1', left: 0, top: 0, width: 50; height: 50 }, 
   { id: 'panel2', left: 50, top: 0, width: 50; height: 50 } ], 
  send: function() { 
   ko.utils.postJson( location.href , { panels: this.panels } ); 
  } 
}; 
ko.applyBindings( '#dashboard', viewModel ); 

我想以这样一种方式绑定它,当用户调整任何 div 元素(即面板)的大小时,它会使用内置数据绑定 OnMouseUp 更新底层 viewModel。然后,当用户单击“更新”按钮时,我会将坐标发布到服务器。

我认为这可能与自定义模板有关,但即便如此,我在管理每个面板上的鼠标事件时也遇到了一些我无法完全掌握的复杂性。

<script type='text/html' id='panelTemplate'>
    <div class='ui-draggable ui-resizable' 
         style='top: ${ top }; left: ${ left }; width: ${ width }px; height: ${ height }px;'>
        <!-- content goes here -->
    </div>
</script>

想法?

【问题讨论】:

    标签: javascript data-binding knockout.js


    【解决方案1】:

    这个问题在KnockoutJS Google Group 上由一位名叫 Green 的出色开发人员回答。

    他演示了如何使用 KnockoutJS 的自定义扩展库(他构建的)来做到这一点。他的解决方案允许额外的 JQueryUI 事件是“可绑定的”(即拖动和调整大小)。然后,他在 JSFiddle 上发布了他的解决方案以及他的 knockout-ext.js 文件,供我使用和学习。

    再次感谢格林! :)

    【讨论】:

    • 绿色确实很棒,而且淘汰赛摇滚!
    • 我不得不重新审视这个问题,发现不再支持这种方法。我在上面查看了 Awais Qami 的解决方案,它似乎运行良好。虽然 Green 的解决方案非常出色,但我现在接受 Awais 的帖子作为我接受的答案(因为我现在正在使用它)。 :)
    【解决方案2】:

    我遇到了完全相同的问题:将 KnockoutJS 模型绑定到可拖动和可调整大小的 div 集合。解决方案是使用自定义绑定并处理调整大小结束和拖动结束的事件,正如我解释的here

    $(document).ready(function () {
                $('#btnSave').click(function () {
                    $.ajax({
                        url: '/Save.ashx',
                        contentType: "application/json; charset=utf-8",
                        type: 'POST',
                        dataType: 'json',
                        data: ko.toJSON(viewModel),
                        error: function () { alert("ajax error"); }
                    });
                });
    
                ko.bindingHandlers.jqDraggableResizable = {
                    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
                        var obj = valueAccessor();
                        var $elem = $(element);
    
                        element.dataObj = obj;
    
                        $elem.resizable({
                            stop: function (event, ui) {
                                this.dataObj.H(ui.size.height);
                                this.dataObj.W(ui.size.width);
                            }
                        });
    
                        $elem.draggable({
                            stop: function (event, ui) {
                                this.dataObj.X(ui.position.left);
                                this.dataObj.Y(ui.position.top);
                            }
                        });
                    }
                }
    
                ko.applyBindings(viewModel);
            });
    

    【讨论】:

      【解决方案3】:

      随着时间的流逝,我无法在 JSFiddle 中看到 Green 的解决方案,而 Awais 的解决方案似乎有点长,所以我又费力地完成了一些。

      我发现以下绑定可用于设置宽度。括号和“px”似乎很重要。在我的例子中,'AWidth' 是 div 标签的宽度。

      data-bind="style: {width: AWidth() + 'px'}"
      

      【讨论】:

        【解决方案4】:

        我能够通过一个简单的解决方案让它工作,它建立在 Ryans 视图之上。

        这允许我使用 BreezeJS 在拖放元素时实时保存更改

        在视图模型中

        ko.bindingHandlers.draggable = {
            init: bindDraggable
        };
        
        function bindDraggable(element, value) {
            $(element).draggable({
                stop: onStopDrag
            });
        
            function onStopDrag(event, ui) {
                ko.dataFor(element).PositionX(ui.position.left);
                ko.dataFor(element).PositionY(ui.position.top);
                datacontext.saveChanges(); //if you want real time updating on drop
            }
        }
        

        在我看来

        <div data-bind="foreach: posts">
        <div class="BoardPost" data-bind="style: { top: PositionY() + 'px', left: PositionX() + 'px' }, draggable:null">
            <div class="Title" data-bind="text: Content"></div>
        </div>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-08
          • 2019-04-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多