【问题标题】:Can you set a javascript function name as an html attribute?您可以将 javascript 函数名称设置为 html 属性吗?
【发布时间】:2014-12-12 16:19:08
【问题描述】:

是否可以编写一个 html 属性来存储 javascript 函数的名称,然后提取该 val() 并执行该函数?示例:

<button id="example" data-function-name="showAllElements()">

然后在 js/jq 中

fn = $('#example').data('function-name');

fn;

【问题讨论】:

标签: javascript jquery html


【解决方案1】:

可以,是的。你是否应该完全是另一个问题,答案几乎肯定是“否”(就执行字符串而言;就下面显示的替代方案而言,有时它很有用)。

您评估该 sn-p 代码的方式(您所拥有的只是一个函数名称,因为 ())将使用可怕的 eval

eval(fn);

几乎总有比使用eval 更好的选择。 (见下文。)

eval 示例:

$("#example").on("click", function() {
  var fn = $("#example").attr("data-function-name");
  eval(fn);
});

function showAllElements() {
  alert("showAllElements was called");
}
<button type="button" id="example" data-function-name="showAllElements()">Click Me</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

一个更好的选择是将函数引用作为属性存储在对象上,然后使用括号表示法根据函数名称获取函数引用:

例子:

var functions = {
  showAllElements: function() {
    alert("showAllElements was called");
  }
};

$("#example").on("click", function() {
  var fn = $("#example").attr("data-function-name");
  functions[fn]();
});
<button type="button" id="example" data-function-name="showAllElements">Click Me</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

请注意,我只是存储函数名称,而不是任意代码。

更新:如果您将函数嵌套在对象中,请参阅canon's answer 以了解处理它的巧妙方法,例如mumble.foo.doSomething,使用reduce。 (reduce 是一个 ES5 特性,但它是可填充的。)


旁注:除非您所做的不仅仅是检索data-* 属性的值,否则不要使用data,使用attrdata 为元素初始化数据缓存,读入该元素的所有data-* 属性,并将它们复制到缓存中。如果您不使用它,则没有理由这样做。使用data 访问data-* 属性的想法是一种常见的误解。

【讨论】:

  • 谢谢我真的很喜欢你的建议!另外,你能向我解释一下你会使用 .data() 的情况吗?
  • 我很遗憾地误用了 jQuery 的 data() 有一段时间......认为它是 dataset 的包装器/polyfill。
  • @canon:你和其他很多人。 :-) 我一直在想,在另一个宇宙中,API 是如何让这一点更清楚的,因为人们会被它误导。但是我什么都没想出来,反正现在猫已经出局了……
【解决方案2】:

当然……假设 showAllElements 是全局的……

function showAllElements() {
  console.log("test!");
}
document.querySelector("button").addEventListener("click", function(e) {
  var functionName = this.getAttribute("data-function-name");
  window[functionName]();
});
&lt;button id="example" data-function-name="showAllElements"&gt;x&lt;/button&gt;

现在,假设您的属性实际上是更复杂的东西,例如:foo.bar.showAllElements...

var foo = {
  bar: {
    showAllElements: function() {
      console.log("test!");
    }
  }
};

document.querySelector("button").addEventListener("click", function(e){
    var functionName = this.getAttribute("data-function-name");
    // Split by "." and resolve each segment starting at the window. Invoke with ()
    functionName.split(".").reduce((o,n) => o[n], window)();
});
&lt;button id="example" data-function-name="foo.bar.showAllElements"&gt;x&lt;/button&gt;

【讨论】:

  • 不错,没想到!
  • 当然,只适用于全局函数,而全局函数和所有全局函数一样,是个坏主意。
  • @T.J.Crowder - 不,只要您有对它的引用,它就适用于任何对象。它只是通过名称查找函数,然后调用它。没有什么神奇的。也可以很简单:({ foo: function(){ console.log('bar'); } })['foo']();。那里没有全局函数。
  • 我意识到我把它作为热门帖子遗漏了。没有看到其他答案。你的很可能在那里,但这不是我添加它的原因。我刚刚意识到我犯了告诉 OP 如何使用eval 来做这件事,告诉他们他们可能不应该这样做,并且不给他们选择! :-)
  • 哦,+1 巧妙地使用reduce
【解决方案3】:

虽然我不认为您可以直接使用 HTML 属性执行此操作(除了上面提到的全局函数),如果您可以在页面加载时使用 javascript 添加数据元素,您可以直接执行此操作。正如这里所说,jquery 的$.data()data-* 属性不同。根据jQuery docs,使用.data()存储的值“新的数据值;这可以是除了未定义的任何Javascript类型。”

所以你可以直接使用存储一个函数

function my_func(){
   // Do stuff
}
$(function(){
   $('#foo').data('func', my_func);
});

后来

var func = $('#foo').data('func');
if( $.isFunction( func ) ) {
   func.call( $('#foo'), somearg );
}

我有an example as a fiddle

这样做的好处是,只要将它们添加到同一个外壳范围内的元素中,就可以拥有外壳等中的功能。

【讨论】:

    猜你喜欢
    • 2010-11-24
    • 2021-06-01
    • 2013-09-25
    • 2023-02-09
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多