【问题标题】:Does afterRender work with Knockout components?afterRender 是否适用于 Knockout 组件?
【发布时间】:2014-12-02 08:06:03
【问题描述】:

afterRender 与模板绑定一起使用,但是在将我的模板转换为组件后,似乎没有任何方法可以使用afterRender。我尝试寻找使用afterRender 的组件示例,但找不到任何东西。

【问题讨论】:

  • 请提供源代码,可能在 JSFiddle 中
  • 查看源代码,看起来不像。它不使用模板引擎来渲染组件,它只是将组件模型应用于组件模板。
  • 好的,我并不感到惊讶,组件是相当新的,因为我必须升级到最新版本的 Knockout 才能让它们工作。我看起来可能必须了解 createViewModel(params, componentInfo) 的工作原理。
  • 抱歉,我不是故意要投反对票的,不知道这是怎么回事...

标签: knockout.js knockout-components


【解决方案1】:

我无法按照上述帖子使用该方法。但是我在 git issue list 上找到了一个解决方法,它不需要自定义 KO 绑定。

在您的组件模板 html 或代码字符串中添加以下行。

 <span data-bind="template: { afterRender: init }"></span>

然后在你的模块/viewModel中创建一个init函数:

 this.init = function() {
   Do cool DOM stuff here.
}

或取决于您的 viewModel 结构:

viewModel: function(params) {
    return {
        init: function () {

        }
    };
},

像魅力一样工作。它的工作示例在这里

http://jsfiddle.net/gLcfxkv6/1/

这里的淘汰赛 git 线程: https://github.com/knockout/knockout/issues/1533

感谢 git 上的 vamps 解决方法。

【讨论】:

  • 谢谢...这暂时有效...看起来 Knockout 将在 v3.3 中添加此功能
  • 请注意嵌套组件不要按预期调用 afterRender。
  • 谢谢...在我的用例中,我只想在最顶层的组件完成后运行一个进程。
【解决方案2】:

这里的秘密是http://knockoutjs.com/documentation/custom-bindings.html

ko.bindingHandlers.myCustomBinding = {
  init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    // This will be called when the binding is first applied to an element
    // Set up any initial state, event handlers, etc. here
    if (bindingContext.$data.init) bindingContext.$data.init(element, valueAccessor, allBindings, viewModel, bindingContext);
  },
  update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    // This will be called once when the binding is first applied to an element,
    // and again whenever any observables/computeds that are accessed change
    // Update the DOM element based on the supplied values here.
    if (bindingContext.$data.update) bindingContext.$data.update(element, valueAccessor, allBindings, viewModel, bindingContext);
  }
};

所以在我的组件模板中我做了类似的事情

<div class="row-fluid" data-bind="myCustomBinding: 'someValue'">

在组件 viewModel 上我只是实现了初始化和/或更新,例如:

constructor.prototype.init = function(element, valueAccessor, allBindings, viewModel, bindingContext) {
  // All the buttons in the buttons group need the same name,
  // but they all need distinct ids. We use timestamps because
  // as components, the names and ids should be distinct across
  // multiple instances of each component.
  var timeStamp = new Date().getTime();
  $('input:radio').attr('name', timeStamp).button();
  $('input:radio:eq(0)').attr('id', timeStamp+1);
  $('input:radio:eq(1)').attr('id', timeStamp+2);
  $('input:radio:eq(2)').attr('id', timeStamp+3);

  // Initialize the number-picker
  $('input[name="number-picker"]').TouchSpin();
};

指出这个非常有用的案例可以改进 Knockout 文档。此外,这是一个非常有用的绑定,应该有一个标准的 'init' 和 'update' 绑定,例如

<div data-bind="init: 'someValue'">

【讨论】:

  • 嗨,我尝试使用它,但无法正常工作。我可以看到代码正在执行,但它根本不会影响 dom 元素......所以我无法获取例如要执行的电话号码选择器:(
【解决方案3】:

我们需要在不同组件之间切换后访问组件中的 DOM 元素。我们本来希望在组件上使用不存在的“afterRender”绑定。

我们使用 Javascript setTimeout 解决了这个问题,让 KO 先进行渲染,然后实际上将我们的代码排队。

HTML:

<div data-bind="component: compName"></div>

切换组件的代码:

var compName = ko.observable();

//...

compName(switchToComponent);
setTimeout(function(){
    // this code is queued until after the component is rendered.
}, 0);

【讨论】:

    【解决方案4】:

    从淘汰赛 3.5.1 开始,您可以向您的 viewModel 添加一个 koDescendantsComplete 函数,该函数将在渲染完成后触发

    var viewModel = {
        koDescendantsComplete: element => {
            console.log( 'Rendered!', element );
        }
    }
    

    见:https://github.com/knockout/knockout/blob/2db9f7f79939ed289621de72340ab048362ed76b/src/components/componentBinding.js#L73

    【讨论】:

    • 这是(从 3.5.1 开始)迄今为止最适合组件的解决方案。作为奖励,组件绑定到的 dom 节点作为第一个参数传递。允许方便的听众注册等。
    【解决方案5】:

    创建一个新的绑定,像这样

    ko.bindingHandlers.initBinding = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        debugger
        if (valueAccessor() && valueAccessor().afterRender && bindingContext.$data) {
            valueAccessor().afterRender(bindingContext.$data);
        }
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        }
    };
    
    export default ko.bindingHandlers.initBinding
    

    如果您不使用 ES6(babel 等),则不需要导出。

    然后在你的组件html中,你可以做这样的事情

    <div class="staff-directory" data-bind="initBinding: {afterRender: afterRender }">
        <p>Loaded</p>
    </div>
    

    在你的组件模型中

    class staffDirectory {
    
        constructor() {
            console.log('staff directory loaded');
        }
    
        afterRender() {
            console.log('afterRender called');
        }
    
    }
    
    export default staffDirectory;
    

    【讨论】:

      猜你喜欢
      • 2014-05-03
      • 2017-07-11
      • 2023-03-22
      • 1970-01-01
      • 2017-02-25
      • 1970-01-01
      • 2022-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多