Javascript 在HTML中替换数据绑定中的值而不丢失事件
为了提高网站的可用性,我想用Greasemonkey(JavaScript)更改以下内容: 到 试过Javascript 在HTML中替换数据绑定中的值而不丢失事件,javascript,html,greasemonkey,tampermonkey,Javascript,Html,Greasemonkey,Tampermonkey,为了提高网站的可用性,我想用Greasemonkey(JavaScript)更改以下内容: 到 试过 document.body.innerHTML = document.body.innerHTML.replace(text_to_find, text_to_replace) 但是页面会丢失事件,并且不会加载任何数据:“Price”不会加载任何内容并保持为空 然后我发现: 到 有没有办法让它在不损失活动的情况下工作 更新: <div class="row"> <di
document.body.innerHTML = document.body.innerHTML.replace(text_to_find, text_to_replace)
但是页面会丢失事件,并且不会加载任何数据:“Price”不会加载任何内容并保持为空
然后我发现:
到
有没有办法让它在不损失活动的情况下工作
更新:
<div class="row">
<div class="col-md-5">
<h5 data-bind="text: 'Price: ' + db.totalpr().toFixed(2) + ' GBP'" style="margin-left:7px"></h5>
</div>
</div>
这条线看起来是一个“X Y问题”。看下面的折叠
这个问题意味着替换属性,而不是文本。(并且,只需修改属性,这样就不会破坏ajax驱动的页面。) 因为它是ajax驱动的,所以需要类似于
MutationObserver
或waitforkyelments
的东西
下面的脚本演示了如何替换这些类型的属性:
// ==UserScript==
// @name _Dynamically replace JS-coded attributes
// @match *://YOUR_SERVER.COM/YOUR_PATH/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant GM_addStyle
// @grant GM.openInTab
// ==/UserScript==
//- The @grant directives are needed to restore the proper sandbox.
var current_exchange_rate = 1.41; // Hard coded for demo purposes only.
waitForKeyElements ("[data-bind]", ReplacePriceAttributes);
function ReplacePriceAttributes (jNode) {
// Following could alternatively could use `.data("bind")` since attribute is of `data-` type.
var oldBind = jNode.attr ("data-bind");
if (/Price:/.test (oldBind) ) {
let newBind = oldBind.replace ("db.totalpr().toFixed(2)", `( db.totalpr() * ${current_exchange_rate} ).toFixed(2)`);
jNode.attr ("data-bind", newBind)
}
}
当前汇率在脚本中是硬编码的。获取实时值超出了这个问题的范围,无论如何
真正的问题是:
替换这些属性值不太可能达到您真正想要的效果(以美元显示价格)。如果页面是由Knockout.js驱动的(看起来是这样的),这一点尤其正确
要更改您看到的显示价格,请使用与
如果页面使用knockout.js,我建议如下
注意:这仅在应用绑定后才起作用。如果在此之前应用js代码,则只需替换绑定即可。就像你已经做过的一样,但是要注意“.toFixed(2)”问题(参见Mike McCaughan的评论)。如果这就是它无法工作的原因,那么您还应该在控制台日志中看到错误
$(文档).ready(函数(){
//他们的代码。只是为了演示。
var viewModel={
db:{
totalpr:新的可观测ko(123.1234)
}
};
应用绑定(视图模型);
//您的Greasemonkey代码从这里开始:
var current\u exchange\u rate=1.41;//硬编码仅用于演示目的。
var priceElements=$(“h5[数据绑定*='db.totalpr().toFixed(2)'”)
$.each(价格元素、函数(索引、值){
var数据=ko.dataFor(值);
//将您的新值添加到他们的模型中。使用ko.pureComputed确保其在totalpr更改时立即更改。
data.db.modifiedTotalPr=ko.pureComputed(函数(){
返回data.db.totalpr()*当前汇率;
});
//更新数据绑定属性。
$(value).attr(“数据绑定”,“文本:'Price:'+db.modifiedTotalPr().toFixed(2)+'USD')
//应用绑定。
ko.cleanNode(值)
ko.应用绑定(数据、值);
});
});代码>
更改innerHTML会抹去一切,唯一的方法是直接调整元素,但如果页面在脚本到达之前使用了属性,您就无能为力了。例如,当我将“Price”更改为“PriceUSD”时,它会在加载数据之前显示一秒钟,然后再次更改为“Price”.i18n有一些非常好的资源。你不必重新发明这个轮子:你不能将一个字符串(toFixed()
的结果是一个字符串)乘以一个数字。您可能需要(data.totalpr()*当前汇率)。toFixed(2)
。但是,我相信@epascarello的意思是,您可能无法像那样更改属性中的值。等到值被呈现到DOM中,然后将该值解析为一个数字并在那里应用更改。如果我认为该页面使用knockout.js,我是否正确?我不确定这是否有效。如果是knockout.js:knockout绑定通常在初始化时应用,之后只在内部处理。若要更改该绑定,您需要清除该节点,并使用相应的数据重新应用该绑定到该节点。@Paul,GTK。你有没有一个页面可以使用类似于db.totalpr()
的东西供我使用?试试看:我会同时检查是否有淘汰方案。:)我想您的代码现在可以工作了。:)直到现在我才知道,但我喜欢这个主意。唯一的注释问题可能是,在本例中,您需要解析数据中的值。@BrockAdams谢谢您的代码!我已经测试了它好几个小时,试图找出它为什么不改变值——不幸的是,它无法工作,我做了一些调试:它找到了正确的数据绑定,更改了应该更改的内容,但Firefox没有更新我屏幕上的内容——例如,我想将“Price”更改为“PriceUSD”:oldBind显示“Price”,newBind显示“PriceUSD”,我在屏幕上看到的是“Price”,而不是“PriceUSD”。我们快到了!有趣的是,看看OP是否对此做出了回应。以及当价格上涨时是否有副作用。(这似乎改变了演示文稿和数据。?)如果他们的代码写得很好,他们可能在提交时使用了db.totalpr()
。代码不会影响其现有数据。它只是添加了一个自定义字段。如果出现任何问题,也可以编写一个自定义的小视图模型,只显示修改后的totalpr,并让数据保持原样。@Paul感谢您的代码!不幸的是,无法使其工作:priceElements数组中有许多“垃圾”元素,代码以@$开头。在我的情况下,每个(priceElements、函数(索引、值)从未执行过……priceElements数组只能在选择器$(“h5[data bind*='db.totalpr().toFixed(2)]”的情况下包含垃圾(所有h5,都有一个包含db.totalpr().toFixed(2)的数据绑定)应用于许多元素。是这样吗?你有控制台错误吗?@Paul实际上每页有1-5个h5数据绑定。我应该得到什么错误?
function replaceTextOnPage(from, to){
getAllTextNodes().forEach(function(node){
node.nodeValue = node.nodeValue.replace(new RegExp(quote(from), 'g'), to);
});
function getAllTextNodes(){
var result = [];
(function scanSubTree(node){
if(node.childNodes.length)
for(var i = 0; i < node.childNodes.length; i++)
scanSubTree(node.childNodes[i]);
else if(node.nodeType == Node.TEXT_NODE)
result.push(node);
})(document);
return result;
}
function quote(str){
return (str+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
}
}
db.totalpr().toFixed(2)
"db.totalpr().toFixed(2)*current_exchange_rate"
<div class="row">
<div class="col-md-5">
<h5 data-bind="text: 'Price: ' + db.totalpr().toFixed(2) + ' GBP'" style="margin-left:7px"></h5>
</div>
</div>
// ==UserScript==
// @name _Dynamically replace JS-coded attributes
// @match *://YOUR_SERVER.COM/YOUR_PATH/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant GM_addStyle
// @grant GM.openInTab
// ==/UserScript==
//- The @grant directives are needed to restore the proper sandbox.
var current_exchange_rate = 1.41; // Hard coded for demo purposes only.
waitForKeyElements ("[data-bind]", ReplacePriceAttributes);
function ReplacePriceAttributes (jNode) {
// Following could alternatively could use `.data("bind")` since attribute is of `data-` type.
var oldBind = jNode.attr ("data-bind");
if (/Price:/.test (oldBind) ) {
let newBind = oldBind.replace ("db.totalpr().toFixed(2)", `( db.totalpr() * ${current_exchange_rate} ).toFixed(2)`);
jNode.attr ("data-bind", newBind)
}
}
waitForKeyElements ("[data-bind]", ReplacePriceText);
function ReplacePriceText (jNode) {
var oldPriceTxt = jNode.text ();
/* Appropriate HTML not provided by question asker, but convert price text
as shown in linked answer, setting newPriceTxt
*/
jNode.text (newPriceTxt);
}