Knockout js:有条件地绑定title属性
Posted
技术标签:
【中文标题】Knockout js:有条件地绑定title属性【英文标题】:Knockout js: Conditionally bind title attribute 【发布时间】:2021-09-28 17:12:22 【问题描述】:我在屏幕顶部有几个选项卡,可将用户导航到程序的多个部分。 如果程序的某个部分有紧急通知给用户,那么现在应该突出显示其中一个选项卡。
我在#main-header 中添加了一个“通知”属性,它是整个顶部 div 的 id。
只有 css 的项目正在相应地改变,到目前为止一切都很好。
但是,只有在有用户通知时,我才需要在标题 attr 中添加文本。 如果有任何通知,它会每 10 分钟检查一次。
这个顶部菜单是在循环中创建的,在 html 中看起来像这样:
<ul id="navigationMenuTop" class="nav navbar-nav" data-bind="foreach: getRoutes">
<li data-bind="css: active: isActive() , attr: title: hash === '#url/location' ? setNotificationTitle : '' ">
<a data-bind="attr: href: hash , html: displayName"></a>
在视图模型中:
var self = this;
self.setNotificationTitle = ko.computed(function ()
var attr = $("#main-header").attr("notifications");
if (typeof attr !== 'undefined' && attr !== false)
return "NotificationAlert";
else
return "";
);
这是在此帮助下创建的:Knockout.js: conditionally bind title attribute of div
问题是使用 setNotificationTitle 导致我在顶部看不到任何选项卡。 当我在 html 中简单地对文本进行硬编码时,会显示顶部菜单并且工具提示会起作用。
我错过了什么?
编辑: 现在的视图如下所示:
<ul id="navigationMenuTop" class="nav navbar-nav" data-bind="foreach: getRoutes">
<li data-bind="css: active: isActive() , attr: title: hash === '#url/location' ? notificationTitle : '' ">
<a data-bind="attr: href: hash , html: displayName"></a>
还有视图模型:
var self = this;
self.notificationTitle = ko.observable("");
self.setNotificationTitle = ko.computed(function ()
var attr = $("#main-header").attr("notifications");
if (typeof attr !== 'undefined' && attr !== false)
self.notificationTitle("NotificationAlert");
else
self.notificationTitle("");
);
只要检查是否有任何通知,就会调用 setNotificationTitle。 这也给了我同样的结果。
编辑: 不确定它是否重要,但在视图模型的底部,它会返回 NavigationViewModel 之类的
return NavigationViewModel;
将其更改为我在淘汰赛 js 文档中看到的内容
return NavigationViewModel =
notificationTitle: this.notificationTitle
;
在系统内容中导致浏览器出现错误,因为 notificationTitle 未定义,它不是...
【问题讨论】:
如果hash
是可观察的,你应该使用hash()
。如果setNotificationTitle
是可观察的(或返回字符串的函数),则必须调用它:setNotificationTitle()
。
我可以读取哈希值,if 语句适用于硬编码文本。在 setNotificationTitle 中添加括号会给我同样的结果。
啊,我看到您实际上在您的问题中包含了setNotificationTitle
。对于那个很抱歉。我认为问题在于您正在从计算中的 DOM 中读取数据。 Knockout 永远不会知道何时必须重新检查 main-header 属性。它不会自动观察您的文档是否有更改。解决方案是在您的定期更新运行时翻转一个可观察的属性,而不仅仅是在您的标题上设置一个属性。
我添加了一个编辑,以便您可以看到我所做的更改。现在在检查完成时调用 setNotificationTitle 是否有任何通知。不幸的是,我得到了相同的结果
css 无法读取 observable 属性。 Css 读取此标头并相应地更改 css 可以自行更改的内容。 (背景颜色、字体颜色、警告图像是否可见)如果我通过代码执行此操作,那么我需要设置超时,因为代码到达此处时未加载选项卡。
【参考方案1】:
问题在于您正在使用和更新 DOM 来存储状态。淘汰赛无法知道您何时修改该状态。
假设你的页面上有一个元素:
<div id="stateEl" data-state="1">...</div>
您可以编写一个可以正常工作的淘汰赛测试绑定:
<div data-bind="text: document.getElementById('stateEl').dataset.state"></div>
当您调用ko.applyBindings
时,该元素将向页面呈现“1”。
然而,如果您在调用ko.applyBindings
之后更改了第一个元素的属性,则knockout 的文本绑定将不会更新。数据绑定依赖ko.observable
属性;淘汰赛没有提供订阅 DOM 更改的机制。
所以每当你这样做时:
document.getElementById("stateEl").dataset.state = 2;
剔除元素仍将呈现“1”。
可能的解决方案
有许多可能的解决方案,有些解决方案比其他解决方案更激进。我会按照我个人喜好的顺序列出一些:
仅坚持使用 knockout.js。 不要通过 jQuery 或任何其他 javascript 代码直接访问或修改 DOM。即:通过淘汰视图模型运行您的定期更新,并使用在淘汰赛中运行良好的模式来共享您想要显示的数据。 确保您的视图模型实例可供外界访问,并确保更新代码通知它任何新信息。 在视图模型中实现额外的定时更新,每 x 秒从 DOM 读取一次这是第二种解决方案的示例:
// Viewmodel
const vm =
notificationCount: ko.observable(0)
// Apply bindings
ko.applyBindings(vm, document.getElementById("app"));
// Periodic updates
let i = 0;
setInterval(() =>
const newCount = i++;
// Update the attribute
const header = document.getElementById("header");
header.dataset.count = newCount;
// Update the knockout vm explicitly
vm.notificationCount(header.dataset.count);
, 500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<!-- HTML not bound to knockout -->
<div id="header" data-count="0"></div>
<!-- HTML bound to a viewmodel in knockout -->
<div id="app" data-bind="text: notificationCount"></div>
【讨论】:
【参考方案2】:最终通过添加这个 observable 和这个在检查是否有任何通知时调用的函数来解决这个问题。
self.notificationTitle = ko.observable("");
self.setNotificationTitle = function ()
var attr = $("#main-header").attr("notifications");
if (typeof attr !== 'undefined' && attr !== false)
self.notificationTitle("NotificationAlert");
else
self.notificationTitle("");
;
并像这样添加:
<li data-bind="css: active: (isActive() , attr: title: $parent.notificationTitle ">
【讨论】:
以上是关于Knockout js:有条件地绑定title属性的主要内容,如果未能解决你的问题,请参考以下文章