简体   繁体   English

如何将动画添加到Knockout.js的If绑定中?

[英]How to add animation to Knockout.js' If binding?

I want to use the Knockout.js If binding but include animation. 我想使用Knockout.js If绑定,但要包含动画。 I am using a single view model container to allow for a large number of separate views to be loaded into the same container. 我正在使用单个视图模型容器,以允许将大量单独的视图加载到同一容器中。 If I use the visibility binding on the "template" the bindings are hidden and all throw errors since their view model is not currently loaded. 如果我在“模板”上使用visibility绑定,则这些绑定将被隐藏,并且由于当前未加载其视图模型,因此所有抛出错误。 I am fearful these view models will begin to slowdown the page if everything is loaded. 我担心如果加载了所有这些视图模型将开始降低页面速度。

From the knockout If documentation: 从淘汰赛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. 但是,if绑定实际上会添加或删除DOM中包含的标记,并且仅在表达式为true时才将绑定应用于子代。

The knockout animated transitions documentation creates a custom binding using jQuery's Show/Hide functions. 剔除动画过渡文档使用jQuery的Show / Hide函数创建自定义绑定。 However, these also hide/show the DOM elements. 但是,这些也会隐藏/显示DOM元素。

In short I am trying to learn one of two things. 简而言之,我正在尝试学习两件事之一。

What would be the appropriate way to remove/add DOM elements in jQuery so that it may be used in a custom binding? 什么是在jQuery中删除/添加DOM元素以便可以在自定义绑定中使用的适当方法?

Or 要么

How does the if binding in knockout work, so that I may reverse engineer it? 剔除中的if绑定如何工作,以便我可以对其进行反向工程?

Clarifying Edit: 澄清编辑:

To clarify more how the code is setup. 为了进一步阐明代码的设置方式。 The admin section of the site that raised this question will contain a place to edit all of the standard content pages, and access reports for the business. 提出此问题的网站的管理员部分将包含一个位置,用于编辑所有标准内容页面,并访问业务报告。

Html "templates" are stored as such (To be clear, these are not knockout templates, but rather html files that contain data-bindings. This could be changed with a compelling reason.) HTML“模板”是这样存储的(要清楚的是,这些不是敲除模板,而是包含数据绑定的html文件。出于令人信服的原因,可以对其进行更改。)

Admin
  Page Edit
  User Edit
  etc
Reports 
  Product
  User
  etc

Our javascript is similar to this 我们的javascript与此类似

BaseViewModel.js: 
  Content view model 

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

AdminReportsViewModels.js
  [similar to above]

When a link is clicked the main page content view model is loaded into the Base view model and is made visible by the binding that inspired this question. 单击链接后,会将主页内容视图模型加载到基本视图模型中,并通过启发该问题的绑定使其可见。 Then each view model has it's own Load to trigger the ajax calls. 然后,每个视图模型都有其自己的Load来触发ajax调用。

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

Right now there are only about 9 different "templates" and we have normalized them the best we can, but it is likely they will grow. 目前只有大约9个不同的“模板”,我们已经尽力将它们标准化,但是它们可能会增长。 The binding would just prevent each "template" from throwing errors into the console. 绑定只会阻止每个“模板”向控制台抛出错误。

If you are using a template for your separated views, then you could get the afterRender callback by using a factory function to initialize the template. 如果将模板用于分离的视图,则可以通过使用工厂函数初始化模板来获取afterRender回调。

Here is a simply stub for that purpose: 这是为此目的的一个简单存根:

ko.components.register("ItemTemplate", {
    viewModel:  function(params) {
        function Item(params) {
            var self = this;
            // observables
            self.enhance = function(elements) {
                // enhance/animate here the DOM elements
            };
        }
        Item.prototype.dispose = function() {
            // dispose what has been created inside here
        };
        var item = new Item(params);
        return item;
    },
    template: '<div data-bind="template: {afterRender: enhance}">'+
            // component markup
            '</div>',
    synchronous: true
});

Using the fadeIn/fadeOut example you mentioned I tried to create a binding that performs fading on the element, and then initializes an "if" binding on the element's inner content by wrapping that content in a new div. 使用您提到的fadeIn / fadeOut示例,我尝试创建一个对元素执行淡入淡出的绑定,然后通过将内容包装在新的div中来初始化该元素的内部内容上的“ if”绑定。 The if binding is then passed a new observable property that gets set using the callback from jQuery's fade function. 然后将if绑定传递给一个新的observable属性,该属性使用jQuery的fade函数的回调进行设置。 It feels a little hacky and probably doesn't work in overly complex scenarios, but perhaps you or the SO community can improve upon it. 感觉有些棘手,在过于复杂的情况下可能无法正常工作,但也许您或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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM