Передайте функцию javascript как атрибут data- * и выполните

Мы знаем такие синтаксисы, как указано ниже, при определении атрибута value для onClick:

<button type="submit" onclick="alert('hi');"></button>
<button type="submit" onclick="doWork"></button> <!-- This one doesn't work -->
<button type="submit" onclick="doWork()"></button>
<button type="submit" onclick="doWork('Mike', 2)"></button>

Я заинтересован в том, чтобы определить пользовательский data-attribute и выполнить значение следующим образом:

<button type="submit" data-callback="alert('hi');"      class="marker"></button>
<button type="submit" data-callback="doWork"            class="marker"></button>
<button type="submit" data-callback="doWork()"          class="marker"></button>
<button type="submit" data-callback="doWork('Mike', 2)" class="marker"></button>

<script type="text/javascript">
    jQuery("body").on("click","button.marker", function(e) {
        var callback = jQuery(e.currentTarget).data("callback");

        // Now I need to execute the callback no matter of the format
        // 1. Execute as function body
        // 2. Or by function 'name'
        // 3. Or by function 'name' with 0 parameters
        // 4. Or by function 'name' with n parameters
    })

    function doWork(name, nr){
        var personName = name || "Unnamed";
        var personNr = nr || 0;
        alert("Name is: " + personName + " Nr: " + personNr);
    }
</script>

Я вставил образец в jsBin

Как выполнить такое же поведение с использованием пользовательских атрибутов данных?

Ответы

Ответ 1

Один из способов - использовать eval()

jQuery(".container").on("click", "button.marker", function (e) {
    var callback = jQuery(e.currentTarget).data("callback");

    var x = eval(callback)
    if (typeof x == 'function') {
        x()
    }
});

Демо: Fiddle

Примечание. Убедитесь, что он безопасен в вашей среде, то есть нет возможности впрыска script из-за плохого ввода от пользователей

Ответ 2

Я думаю, что лучшей идеей было бы динамическое связывание событий и их запуск. Если вы хотите, чтобы их знали только другие коды, вы можете использовать пользовательские события.

<button type="submit" class="marker marker1"></button>
<button type="submit" class="marker marker2"></button>
<button type="submit" class="marker marker3"></button>
<button type="submit" class="marker marker4"></button>

<script>
    var $markers = $('.marker');
    $markers.filter('.marker1').bind('customCallback', function(){ alert("hi"); });
    $markers.filter('.marker2').bind('customCallback', function(){ doWork(); });
</script>

Затем ваши другие компоненты могли бы вызывать их с помощью $(selector).trigger('customCallback');

Ответ 3

Просто с помощью

 $("body").on("click","button.marker", function(e) {
     eval($(this).data("callback"));
 })

Ответ 4

Если вы действительно хотели передавать функции (с или без параметров) из одной вещи в другую, не связывая их как события, вы могли бы сделать это таким образом (я начал с ответа @Taplar)

<button type="submit" class="marker marker1"></button>
<button type="submit" class="marker marker2"></button>
<button type="submit" class="marker marker3"></button>
<button type="submit" class="marker marker4"></button>

<script>
  var $markers = $('.marker');
  $markers.filter('.marker1').get(0).customCallback =  doWork;
  $markers.filter('.marker2').get(0).customCallback = function(){ 
    doWork(arg0,arg1); 
  };
</script>

Затем вы можете получить доступ к ним в своем другом компоненте как:

<script>
  $('.marker').each(function(){
    var  thisFunction = $(this).get(0).customCallback;
    //do something useful with thisFunction
  });
</script>

Ответ 5

Вы можете просто связать функцию как атрибут данных

const ele = $('button');

ele.data('onClick', evt => {
    alert('bye');
})

ele.click(evt => {
    const ele = $(evt.target);
    ele.data('onClick')(evt);
})

Ответ 6

Другой способ - использовать window[func](args).

Аналогично eval(), но вам придется хранить имя функции и аргумент отдельно в атрибуте HTML.

Вот быстрый пример... CodePen

<button type="submit" data-func="Angel" data-args='use me instead of evil()' class="marker">TEST</button>

<script type="text/javascript">

    //=== The Listener =====
    $(".marker").on("click",function(){

        // Get the function name and arguments
        let func = $(this).attr("data-func");
        let args = $(this).attr("data-args");

        // Call the function
        window[func](args);
    })


    //=== The Function =====
    function Angel(msg){
        alert(arguments.callee.name + " said : " + msg);
    }
</script>