您应该更改一些内容以使其正常工作,采用 Jimbo 的答案并添加其他一些内容:
var dict = {
"dataP": "this is my p tag text"
};
$('[data-text]').each(function () {
if ( $(this).data("text") ) {
var dictAttr = $(this).data("text");
if ( dictAttr && dict[dictAttr] ) {
$(this).html( dict[dictAttr] );
}
}
});
您还应该更改标记以使事情变得更容易(特别是如果您只处理一个dict
对象):
<p data-text="dataP"></p>
通过上述更改,您应该可以按预期工作。
http://jsfiddle.net/b2zgw/
基于字符串的对象导航
奇怪的是,正如我们所说,我实际上正在研究基于字符串的对象导航框架。但是,如果代码库过于复杂,无法仅在 stackoverflow 答案的末尾添加。作为我评论的补充,我意识到还有第三种选择可能是两全其美的选择(取决于您的需要)。
:: 评估
我不推荐这种方法,但为了简单起见,不能与之争论——以下是上面代码的片段,应该替换该部分:
var dictNav = $(this).data("text"); /// e.g. say dictNav == 'dict.dataP'
var ref; eval('ref='+dictNav);
if ( ref && red.substr ) {
$(this).html( ref );
}
上面的问题是它eval
会评估任何 JavaScript - 所以攻击者所要做的就是找到一种方法来为data-text
您页面上的某些内容添加属性,他们将能够执行他们喜欢的任何 JavaScript。
:: 基于字符串的导航
以下是一个可以改进的简单功能,但应该会给您一些想法:
function navigate( obj, path ){
var cur = obj, bits = path.split('.');
for ( var i=0, l=bits.length; i<l && cur; i++ ) {
cur = cur[bits[i]];
}
return cur;
}
使用上述内容,您可以导航您的字典结构 - 请注意,因为您以特定的 var 名称开始您的“导航路径”(即dict
),您必须将您的字典放置在您希望遍历的对象的下一级;这就是原因{dict:dict}
。要支持多个字典,您只需要像这样扩展该对象{dict:dict,dict2:dict2}
- 以下是一个片段,应该替换原始代码:
var dictNav = $(this).data("text"); /// e.g. say dictNav == 'dict.dataP.test'
var ref = navigate({dict:dict}, dictNav);
if ( ref && red.substr ) {
$(this).html( ref );
}
:: 第三个选项 - 简化你的字典
第三个选项可能是最理想的,但意味着不能实时修改字典(或至少不容易)。基本上在运行其余代码之前,通过修改其结构的解析函数推送字典:
var dict = {
"dataP": "this is a test",
"forms": {
"inputLabel": "this is a second level"
}
};
function simplifyDict( obj, target, path, subpath ){
if ( !target ) { target = {}; }
if ( !path ) { path = ''; }
for( var i in obj ) {
subpath = (path ? path + '.' : '') + i;
if ( typeof obj[i] == 'object' ) {
simplifyDict( obj[i], target, subpath );
}
else {
target[subpath] = obj[i];
}
}
return target;
}
dict = simplifyDict( dict );
上面的简化函数应该返回如下内容:
{
"dataP" : "this is a test",
"forms.inputLabel" : "this is a second level"
}
然后你需要做的就是在这个答案的顶部使用我的原始代码。您没有将字符串转换为单独的对象属性并导航字典,而是将字典切换为基于字符串的查找......所以现在您可以直接使用字符串,即dict['forms.inputLabel']