Hovercard没有在knockoutJS中显示带绑定

时间:2015-03-08 15:17:25

标签: javascript jquery css knockout.js

我有这张悬停卡,我想在子菜单中显示它。它在标题中起作用,但不知何故,当在子菜单“with:$ root.chosenMenu”-bindings中时,悬停效果不起作用。

这是我的代码:

HTML:

<div>
    <span class="previewCard">    
        <label class="hovercardName" data-bind="text: displayName"></label>
        <span class="hovercardDetails">     
            <span data-bind="text: miniBio"></span>.<br/>
            <a data-bind="attr: { href: webpage, title: webpage }, text: webpage">My blog</a>
        </span>
    </span> 
    <br/><br/>
    <div class="wysClear wysLeft buttonRow">
        <a href="#pid1" data-bind="click: function(){$root.chosenMenu('a');return false;}">Panel A</a>
        <a href="#pid2" data-bind="click: function(){$root.chosenMenu('b');return false;}">Panel B</a>
    </div>
</div>
<hr/>
<div data-bind="with: $root.chosenMenu">
    <div id="pid1" data-bind="visible: $root.chosenMenu() === 'a'">
        panel A: <br/><br/>
        <span class="previewCard">    
            <label class="hovercardName" data-bind="text: $root.displayName"></label>
            <span class="hovercardDetails">     
                <span data-bind="text: $root.miniBio"></span>.<br/>
                <a data-bind="attr: { href: $root.webpage, title: $root.webpage }, text: $root.webpage">My blog</a>
            </span>
        </span> 
    </div>
    <div id="pid2" data-bind="visible: $root.chosenMenu() === 'b'">
        panel B: <br/><br/>
        <span class="previewCard">    
            <label class="hovercardName" data-bind="text: $root.displayName"></label>
            <span class="hovercardDetails">     
                <span data-bind="text: $root.miniBio"></span>.<br/>
                <a data-bind="attr: { href: $root.webpage, title: $root.webpage }, text: $root.webpage">My blog</a>
            </span>
        </span> 
    </div>
</div>

使用Javascript:

viewModel = function(){
    var self = this;

    self.chosenMenu = ko.observable();
    self.displayName = ko.observable("Asle G");
    self.miniBio = ko.observable("Everywhere we go - there you are!");
    self.webpage = ko.observable("http://blog.a-changing.com")
};

ko.applyBindings( new viewModel() );

// hovercard
$(".previewCard").hover(function() {
    $(this).find(".hovercardDetails").stop(true, true).fadeIn();
}, function() {
    $(this).find(".hovercardDetails").stop(true, true).fadeOut();
});

CSS:

.previewCard {
    position:relative;            
}
.hovercardName {    
    font-weight:bold;    
    position:relative;    
    z-index:100; /*greater than details, to still appear in card*/
}
.hovercardDetails {            
    background:#fff ;    
    border:solid 1px #ddd;      
    position:absolute ;
    width:300px;
    left:-10px;
    top:-10px;
    z-index:50; /*less than name*/
    padding:2em 10px 10px; /*leave enough padding on top for the name*/   
    display:none;
}

小提琴:http://jsfiddle.net/AsleG/jb6b61oh/

2 个答案:

答案 0 :(得分:3)

您有一个经典的jQuery问题:事件处理程序仅附加到<​​em>存在的元素。

这会将hover(mouseenter / mouseleave)事件处理程序附加到唯一的.previewCard

$(".previewCard").hover(function() {
    $(this).find(".hovercardDetails").stop(true, true).fadeIn();
}, function() {
    $(this).find(".hovercardDetails").stop(true, true).fadeOut();
});

但是如果knockout动态地创建了一些,他们就不会有任何事件处理程序。因此,您必须委派事件处理到层次结构中较高的节点。

$(document).on("mouseenter", ".previewCard", function() {
    $(this).find(".hovercardDetails").stop(true, true).fadeIn();
}).on("mouseleave", ".previewCard", function() {
    $(this).find(".hovercardDetails").stop(true, true).fadeOut();
});

这仍然不是解决问题的 clean 方法。为什么不创建一个hovercard绑定处理程序并完全摆脱视图模型中的jQuery代码?

ko.bindingHandlers.hovercard = {
    init: function (element) {
        $(element).hover(function() {
            $(this).find(".hovercardDetails").stop(true, true).fadeIn();
        }, function() {
            $(this).find(".hovercardDetails").stop(true, true).fadeOut();
        });
    }
};

用作:

<span class="previewCard" data-bind="hovercard: true">

http://jsfiddle.net/jb6b61oh/6/

答案 1 :(得分:2)

我认为问题出在你的with绑定中。您正在设置一个当前未定义的observable的上下文,因此删除了任何后代元素。见knockout docs

  

with binding将动态添加或删除后代元素,具体取决于相关值是否为null / undefined或``

这意味着在jQuery运行时,您的元素不在DOM中,因此它们不会绑定到悬停事件。所以,如果你改变了这个:

data-bind="with: $root.chosenMenu">

到此:

<div data-bind="with: $root">

您的问题已修复。也就是说,你真的应该使用自定义绑定处理程序。

&#13;
&#13;
viewModel = function(){
    var self = this;

    self.chosenMenu = ko.observable();
    self.displayName = ko.observable("Asle G");
    self.miniBio = ko.observable("Everywhere we go - there you are!");
    self.webpage = ko.observable("http://blog.a-changing.com")
};

ko.applyBindings( new viewModel() );

// hovercard
$(".previewCard").hover(function() {
    $(this).find(".hovercardDetails").stop(true, true).fadeIn();
}, function() {
    $(this).find(".hovercardDetails").stop(true, true).fadeOut();
});
&#13;
.previewCard {
    position:relative;            
}
.hovercardName {    
    font-weight:bold;    
    position:relative;    
    z-index:100; /*greater than details, to still appear in card*/
}
.hovercardDetails {            
    background:#fff ;    
    border:solid 1px #ddd;      
    position:absolute ;
    width:300px;
    left:-10px;
    top:-10px;
    z-index:50; /*less than name*/
    padding:2em 10px 10px; /*leave enough padding on top for the name*/   
    display:none;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div>
    <span class="previewCard">    
        <label class="hovercardName" data-bind="text: displayName"></label>
        <span class="hovercardDetails">     
            <span data-bind="text: miniBio"></span>.<br/>
            <a data-bind="attr: { href: webpage, title: webpage }, text: webpage">My blog</a>
        </span>
    </span> 
    <br/><br/>
    <div class="wysClear wysLeft buttonRow">
        <a href="#pid1" data-bind="click: function(){$root.chosenMenu('a');return false;}">Panel A</a>
        <a href="#pid2" data-bind="click: function(){$root.chosenMenu('b');return false;}">Panel B</a>
    </div>
</div>
<hr/>
<div data-bind="with: $root">
    <div id="pid1" data-bind="visible: chosenMenu() === 'a'">
        panel A: <br/><br/>
        <span class="previewCard">    
            <label class="hovercardName" data-bind="text: displayName"></label>
            <span class="hovercardDetails">     
                <span data-bind="text: miniBio"></span>.<br/>
                <a data-bind="attr: { href: webpage, title: webpage }, text: webpage">My blog</a>
            </span>
        </span> 
    </div>
    <div id="pid2" data-bind="visible: chosenMenu() === 'b'">
        panel B: <br/><br/>
        <span class="previewCard">    
            <label class="hovercardName" data-bind="text: displayName"></label>
            <span class="hovercardDetails">     
                <span data-bind="text: miniBio"></span>.<br/>
                <a data-bind="attr: { href: webpage, title: webpage }, text: webpage">My blog</a>
            </span>
        </span> 
    </div>
</div>
&#13;
&#13;
&#13;