为什么警报框在此代码中显示两次?

时间:2015-09-23 21:00:49

标签: javascript jquery knockout.js

这是一些简单的代码来演示"后现代"淘汰模板的功能。当我点击按钮时,警告框会显示两次,而它应该只显示一次。

您可以在下面找到完整的代码。知道警报框出现两次的原因吗?

<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js"></script>

</head>

<body>

<div data-bind="component: {name : 'foo-component', params: {onLoad: fooLoadedCallback}}"></div>

<!--foo-component params="onLoad: fooLoadedCallback"></foo-component-->


<script type="text/javascript">
ko.components.register('foo-component', {
    //inner view model, only for this component in the template below.
    viewModel: function(params) {
        return {
            status: ko.observable('Constructed'),

            //this is called only after the template is rendered. This is called due to a statement in template.
            componentLoaded: function () {

                if (params.onLoad) {
                    params.onLoad(this);
                }
                $('button').click(function(){
                    alert("Rendered.");
                });

            }
        };
    },
    template: '<h1>Hello</h1><br><button>Click me</button><br><span data-bind="text: status">Template</span>'
       +'<span data-bind="template: { afterRender: componentLoaded() }"></span>',
});

//outer view model, for the div element.
var outerViewModel = {
    fooLoadedCallback: function(viewModel) {
        viewModel.status('Rendered!');
    },
};

ko.applyBindings(outerViewModel);
</script>
</body>
</html>

2 个答案:

答案 0 :(得分:2)

您收到两个警报,因为您的componentLoaded方法被调用两次,将多个侦听器附加到该按钮。

我相信你的问题出在<span data-bind="template: { afterRender: componentLoaded() }"></span>部分。

例如,如果您使用template更改with,则代码可以正常运行。有一个例子:

template: '<h1>Hello</h1><br><button>Click me</button>'
+ '<br><span data-bind="text: status">Template</span>'
+ '<span data-bind="with: { afterRender: componentLoaded() }"></span>'

但是,请记住,我从未使用过Knockout,并且无法告诉您这是否正确。我只是指出发生了什么。

答案 1 :(得分:2)

当异步加载组件时,

afterRender总是被调用两次。一次是占位符元素,一次是真实的东西。使用once之类的内容可以防止它被调用两次,或者可以安全地多次调用componentLoaded

此外,$('button')将为您提供DOM中当前的每个按钮。如果你有多个,它会将点击添加到所有这些。