javascript - 如何为 Knockout.js 的 If 绑定(bind)添加动画?

标签 javascript jquery knockout.js

我想使用 Knockout.js If 绑定(bind)但包含动画。我使用单个 View 模型容器来允许将大量单独的 View 加载到同一容器中。如果我在"template"上使用 visibility 绑定(bind),则绑定(bind)将被隐藏,并且所有绑定(bind)都会抛出错误,因为它们的 View 模型当前未加载。我担心如果所有内容都加载完毕,这些 View 模型将开始减慢页面速度。

来自 knockout If 文档:

The if binding, however, physically adds or removes the contained markup in your DOM, and only applies bindings to descendants if the expression is true.

knockout 动画过渡文档使用 jQuery 的显示/隐藏函数创建自定义绑定(bind)。但是,这些也会隐藏/显示 DOM 元素。

简而言之,我正在尝试学习两件事之一。

在 jQuery 中删除/添加 DOM 元素以便可以在自定义绑定(bind)中使用的适当方法是什么?

或者

knockout 中的 if 绑定(bind)如何工作,以便我可以对其进行逆向工程?

澄清编辑:

进一步阐明代码的设置方式。提出此问题的网站的管理部分将包含一个编辑所有标准内容页面以及访问业务报告的位置。

Html"template"就这样存储(需要明确的是,这些不是 knockout 模板,而是包含数据绑定(bind)的 html 文件。这可以通过令人信服的理由进行更改。)

Admin
  Page Edit
  User Edit
  etc
Reports 
  Product
  User
  etc

我们的 JavaScript 与此类似

BaseViewModel.js: 
  Content view model 

AdminEditViewModels.js: 
  UserEditViewModel
  ContentEditViewModel
  [1 view model per item]

AdminReportsViewModels.js
  [similar to above]

单击链接时,主页内容 View 模型将加载到基本 View 模型中,并通过激发此问题的绑定(bind)使其可见。然后每个 View 模型都有自己的 Load 来触发 ajax 调用。

self.ViewOrders = function () {
  self.Content("Orders");
  self.ContentVM(new AdminOrdersViewModel());
  self.ContentVM().Load();
}

目前只有大约 9 个不同的"template",我们已尽最大努力对它们进行标准化,但它们很可能会增长。绑定(bind)只会阻止每个"template"向控制台抛出错误。

最佳答案

使用您提到的 fadeIn/fadeOut 示例,我尝试创建一个对元素执行淡入淡出的绑定(bind),然后通过将该内容包装在新的 div 中来初始化元素内部内容的“if”绑定(bind)。然后,if 绑定(bind)会传递一个新的可观察属性,该属性使用 jQuery 的 fade 函数的回调进行设置。它感觉有点老套,并且可能不适用于过于复杂的场景,但也许您或 SO 社区可以对其进行改进。

var viewModel = function(){
    var self = this;
    
    self.showContent = ko.observable(false);
    self.content = ko.observable("content goes here");    
}

//Uses the IF binding to remove the element's content from the DOM, but also fades before/after.
ko.bindingHandlers.fadedIf = {
    init: function (element, valueAccessor, allBindingsAccessor, data, bindingContext) {
        // Initially set the element to be instantly visible/hidden depending on the value
        var value = valueAccessor();
        //If the value is a normal function make it a computed so that it updates properly
        if (!ko.isObservable(value)) {
            value = ko.computed({ read: valueAccessor });
        }
        //attach our observable property to the accessor so that it can be used in the update function
        valueAccessor.domShown = ko.observable(ko.unwrap(value));

        //Wrap any contents of the element in a new div, and then bind that div using the "if" binding.
        //This way the element and its event hooks for fading in/out never leaves the dom, but all content does.
        //it also prevents applying multiple bindings to the same element.
        var contentWrapper = $(element).children().wrapAll(document.createElement("div")).parent()[0];
        ko.applyBindingAccessorsToNode(contentWrapper, { 'if': function () { return valueAccessor.domShown } }, bindingContext);  
    },
    update: function (element, valueAccessor) {
        // Whenever the value subsequently changes, slowly fade the element in or out
        var value = valueAccessor();

        if (ko.unwrap(value)) {
            valueAccessor.domShown(true); //restore the element to the DOM
            $(element).fadeIn();
        } else {
            $(element).fadeOut({
                complete: function () {
                    valueAccessor.domShown(false); //remove the element from the DOM
                }
            });
        }
    }
};
  
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div style="border: 1px solid blue; width:600px; margin:auto; padding: 32px; text-align:center;">
  Show Content<input type="checkbox" data-bind="checked: showContent">
  <br/>
  
  <div data-bind="fadedIf: showContent">
    <div style="background-color: silver; padding: 20px;">
      <h3 data-bind="text: content"></h3>
    </div>
  </div>
  
</div>

关于javascript - 如何为 Knockout.js 的 If 绑定(bind)添加动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43352138/

相关文章:

javascript - jquery 编辑帖子不起作用

javascript - 为 jQuery 位置变量获取未定义

javascript - UIkit CSS 拖放文件上传组件

javascript - JQuery 添加链接到文本

javascript - 将 knockout.simpleGrid.3.0.js 与 Require.js 结合使用

javascript - 基本了解javascript中的函数和声明

javascript - 当 ViewModel 的属性重命名时 Knockout.js 绑定(bind)被破坏

javascript - jQuery 滚动到可滚动 div 中元素的顶部卡住循环

javascript - 在加载完整页面之前使用 JavaScript 获取浏览器记住的滚动位置

javascript - 什么时候需要重新初始化 jQuery 元素