Hovercard 未在 knockoutJS 中显示 with-binding
Hovercard not displaying in knockoutJS with-binding
我得到了这张悬停卡片,我想在 sub-menu 中显示它。它在 header 中工作,但在 sub-menu "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;
}
您有一个典型的 jQuery 问题:事件处理程序仅附加到当时 存在 的元素。
这会将 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();
});
这仍然不是解决问题的干净方法。为什么不创建一个 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">
我认为问题出在您的 with
绑定中。您正在为一个当时未定义的可观察对象设置上下文,因此任何后代元素都将被删除。见 knockout docs:
The with binding will dynamically add or remove descendant elements depending on whether the associated value is null/undefined or not``
这意味着在 jQuery 运行时,您的元素不在 DOM 中,因此它们未绑定到悬停事件。所以,如果你改变这个:
data-bind="with: $root.chosenMenu">
对此:
<div data-bind="with: $root">
您的问题已解决。也就是说,您确实应该为此使用自定义绑定处理程序。
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();
});
.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;
}
<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>
我得到了这张悬停卡片,我想在 sub-menu 中显示它。它在 header 中工作,但在 sub-menu "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;
}
您有一个典型的 jQuery 问题:事件处理程序仅附加到当时 存在 的元素。
这会将 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();
});
这仍然不是解决问题的干净方法。为什么不创建一个 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">
我认为问题出在您的 with
绑定中。您正在为一个当时未定义的可观察对象设置上下文,因此任何后代元素都将被删除。见 knockout docs:
The with binding will dynamically add or remove descendant elements depending on whether the associated value is null/undefined or not``
这意味着在 jQuery 运行时,您的元素不在 DOM 中,因此它们未绑定到悬停事件。所以,如果你改变这个:
data-bind="with: $root.chosenMenu">
对此:
<div data-bind="with: $root">
您的问题已解决。也就是说,您确实应该为此使用自定义绑定处理程序。
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();
});
.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;
}
<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>