jQuery,将自定义函数绑定到DOM元素

17

我的应用程序中有两个div,我希望它们具有相同签名的自定义函数,但具有不同的操作,这样我就可以将“当前”div存储在变量中,只需调用类似以下代码:

myCurrentDiv.theFunction(someEventData);

并触发对应的方法。

如何使用jQuery实现这一点?

我尝试了以下方式:

$("#myFirstDiv").theFunction = function() {
    alert("theFunction on firstDiv");
}
$("#mySecondDiv").theFunction = function() {
    alert("theFunction on secondDiv");
}
6个回答

47

jQuery的哲学与您想要的相反:jQuery不会使用新属性或方法扩展任何现有类型/对象;它将所有这些都实现在自己内部。

但是,如果您想要使用jQuery来实现它,有几种不同的方式:

  1. JavaScript方式:

    $("#mySecondDiv")[0].theFunction = function(a, b) { /* ... */ }
    
  2. jQuery.data:

    该函数可以绑定和获取存储在DOM元素上的数据,也可以处理私有数据。
  3. $("#mySecondDiv").data({ theFunction: function(a, b) { /* ... */ } });
    $("#mySecondDiv").data("theFunction")(1, 2)
    
  4. 自定义事件:

  5. $("#mySecondDiv").bind('my-event', function(event, a ,b) { /* ... */ });
    $("#mySecondDiv").trigger('my-event', [1, 2]);
    

谢谢回复。但是有没有一种使用“真正的”jQuery哲学来做我想做的事情(即将不同的逻辑绑定到具有相同签名的函数)的方法?换句话说,我应该编写一个插件,来引入我的<code><pre>.myMethod()</pre><code> 方法,然后以某种方式将操作绑定到我的<divs>,类似于这样: <code><pre> $("div_one").myMethod(someEventData, function(){/* */}); </pre></code> - Ibolit
是的,有真正的jQuery方式(甚至有两种):简单插件开发指南UI插件开发指南 - Rost
JavaScript的方式被认为是不好的实践吗?如果是,原因是什么?谢谢。 - Jinghui Niu

3
你可以使用jQuery.data来存储与特定元素关联的数据。
例如:
var div = $("#myFirstDiv")[0];
jQuery.data(div, "theFunction", function() {
    alert("theFunction on firstDiv");
});

3

看起来你需要在 jQuery 中创建一个自定义事件...

$('#myFirstDiv').bind('theFunction', function(e) {
  alert('theFunction on firstDiv');
});

$('#mySecondDiv').bind('theFunction', function(e) {
  alert('theFunction on firstDiv');
});

$('#myFirstDiv').trigger('theFunction');

这是一个可以展示例子的有效fiddle链接: http://jsfiddle.net/XkutP/

你不能从事件中返回值;这不是同一件事。 - gss

1
你也可以尝试这个,它有点丑,但它有效 :)
自定义对象:
$.fn.epicModule = function (pMessage) {

    var object = $(this)[0];

    object.__construct = function (pMessage) {
        //TODO
        this.message = pMessage;
    }

    object.callMeDirectly = function () {
        alert(this.message);
    }

    object.__construct(pMessage);
}

初始化模块:

$(".myHtmlEl").epicModule("Hallo World");

调用函数:

$(".myHtmlEl")[0].callMeDirectly();

0

构建一个超级jQuery对象

您也可以使用$.fn.extend()一次绑定多个方法(函数)……如果您真的想深入了解,您可以使用$.fn.extend()重新创建jQuery元素,使其成为功能强大的自定义对象,然后用于自动化和管理逻辑上/虚拟上属于同一对象或工具的DOM元素。(附注:我编造了“超级jQuery”这个词语——那不是真正的行话……好吧,现在也许是了。)

我现在正在开发一个Excel文件上传器。我将在此处重新创建/复制其中一些内容,以便让您有一个想法:


HTML

<div id="uploader" class="uploader">

            <div class="uploader-item-title uploader-item title">
                <span class="title-item-value title-item value">
                    Excel File Uploader
                </span>                
            </div>
            <div class="uploader-item-subtitle uploader-item subtitle">
                <span class="subtitle-item-value subtitle-item value">
                    Uploads Excel files
                </span>
            </div>

            <div id="formatError" style="width:100%;">
                <div class="error-message">
                    <!-- General-purpose error-message container (registered on server-side) -->
                </div>
            </div>

            <div id="messagebox" class="uploader-item-messagebox uploader-item messagebox hidden" style="width:100%;">
                <span class="messagebox-item-value messagebox-item value">
                    <!-- Enter any messages/alerts here that you would like to display to the user -->
                </span>
            </div>

            <div id="dropzone" dropzone="copy f:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" class="uploader-item-dropzone uploader-item dropzone">
                <span class="dropzone-item-notes dropzone-item notes">
                    Drag and drop your Excel file(s) here to begin the upload process.
                </span>

                <div id="fileSummaryTable" class="dropzone-item-filesummary dropzone-item filesummary hidden">
                    <table class="filesummary-item-table filesummary-item table">
                        <!-- Display excel file information here. -->
                    </table>
                </div>

                <div id="pbar" class="dropzone-item-pbar dropzone-item pbar hidden">
                    <div class="pbar-item-filler pbar-item filler">
                    </div>
                </div>
            </div>
    <div id="fallbackUploader" class="uploader-item-fallbackuploader uploader-item fallbackuploader invisible">
                <!-- some asp code you don't need to see :) -->
            </div>
</div>

Javascript

var oUploader = (function () {

    function oUploader(opts) { // primary object constructor

            var primaryOpts = opts || {}; // Optional arguments
            var superObj_primary = $('#uploader'); // primary super object
            var that = this;

            var superObj_secondary = (function () { 
                function superObj_secondary(secondaryOpts) { // secondary object constructor

                    // =================================================================================
                    // step 10 = get the default options' values
                    // =================================================================================
                    var self = this,
                        o = secondaryOpts || {},
                        title_val = o.title || 'Excel File Uploader',
                        subtitle_val = o.subtitle || 'Uploads Excel files',
                        notes_val = o.notes || 'Drag and drop your Excel file(s) here to begin the upload process.';

                    // =================================================================================
                    // step 20 = create your public properties and children here.
                    // =================================================================================
                    self.dropzone = $('.uploader-item-dropzone');
                    self.dropzone.pbar = $('.dropzone-item-pbar');
                    self.dropzone.fileSummaryTable = $('#fileSummaryTable');
                    self.fallbackUploader = $('#fallbackUploader');
                    self.messagebox = $('.uploader-item-messagebox');


                    // =================================================================================
                    // step 30 = create your private properties and children here.
                    // =================================================================================
                    var progress_ele = self.dropzone.pbar.children('.pbar-item-filler'), // inner-progressbar element
                        fileSummaryTable_table_ele = self.dropzone.fileSummaryTable.children('table.filesummary-item-table'), // inner table for the file summary table
                        title_ele = $('.uploader-item-title'), // title container for the main uploader object
                        title_value_ele = title_ele.children('.title-item-value'), // inner value object for the title
                        subtitle_ele = $('.uploader-item-subtitle'), // subtitle container for the main uploader object
                        subtitle_value_ele = subtitle_ele.children('subtitle-item-value'), // inner value object for the subtitle
                        notes_value_ele = self.dropzone.children('.dropzone-item-notes'), // element containing the notes text
                        messagebox_ele = $('.uploader-item-messagebox'), // element containing the message/alert container
                        messagebox_value_ele = messagebox_ele.children('.messagebox-item-value'); // element containing the message/alert text

                    // =================================================================================
                    // step 30 = create your public get/set functions for private properties
                    // =================================================================================
                    // ------------------------------------------------------------
                    // get/set function for private properties of uploader
                    // ------------------------------------------------------------
                    Object.defineProperties(superObj_primary,
                        {
                            // gets or sets the title of the uploader
                            'title': {  
                                'get': function () { return title_value_ele.text(); },
                                'set': function (val) { title_value_ele.text(val); }
                            },
                            // gets or sets the sub-title of the uploader
                            'subtitle': { 
                                'get': function () { return subtitle_value_ele.text(); },
                                'set': function (val) { subtitle_value_ele.text(val); }
                            },
                            // either (1) gets the msg value, (2) sets the msg and grows 
                            //      in the container, or (3) clears the msg value and 
                            //      shrinks out the container.
                            'msg': {
                                'get': function () { return messagebox_value_ele.text(); },
                                'set': function (val) {
                                    if (val.length) {
                                        messagebox_value_ele.text(val);
                                        messagebox_ele.xGrowIn(null,null,function () { // fadeObj = custom jQuery plugin created elsewhere
                                            messagebox_value_ele.fadeObj('show',100); // fadeObj = custom jQuery plugin created elsewhere
                                        });
                                    } else {
                                        messagebox_value_ele.fadeObj('invisible',100, function () {
                                            messagebox_ele.xShrinkOut(null,function () {
                                                messagebox_value_ele.text('.');
                                            });
                                        });
                                    }
                                }
                            }
                        });


                    // ------------------------------------------------------------
                    // get/set function for progressbar object
                    // ------------------------------------------------------------
                    Object.defineProperties(self.dropzone.pbar,
                        {
                            // gets or sets the width and data-progress attribute of the inner progress bar.
                            'progress': { 
                                'get': function () { return (parseInt(Math.round(progress_ele.attr('aria-valuenow'))) || 0); },
                                'set': function (val) { progress_ele.progressbar({ value: Math.round(val) }); }
                            }
                        });


                    // =================================================================================
                    // step 40 = create your public methods here.
                    // =================================================================================
                    // ------------------------------------------------------------
                    // hide all of the primary uploader elements and show the fallback elements.
                    // ------------------------------------------------------------
                    self.switchToFallback = function () {
                        // hide the primary uploader elements
                        self.dropzone.addClass('hidden');
                        self.dropzone.fileSummaryTable.addClass('hidden');
                        self.dropzone.pbar.addClass('hidden');
                        // show the fallback uploader elements
                        self.fallbackUploader.removeClass('invisible');
                    };

                    // ------------------------------------------------------------
                    // show the primary dropzone and add the necessary event listeners
                    // ------------------------------------------------------------
                    self.enableDropzone = function () {
                        self.dropzone.removeClass('hidden');
                        // init event handlers
                        self.dropzone.addEventListener("dragenter", dragEnter, false);
                        self.dropzone.addEventListener("dragexit", dragExit, false);
                        self.dropzone.addEventListener("dragleave", dragExit, false);
                        self.dropzone.addEventListener("dragover", dragOver, false);
                        self.dropzone.addEventListener("drop", drop, false);

                        // define drag and drop events
                        function dragEnter(evt) {
                            evt.stopPropagation();
                            evt.preventDefault();
                        }
                        function dragExit(evt) {
                            evt.stopPropagation();
                            evt.preventDefault();
                            self.dropzone.removeClass("active-dropzone");
                        }
                        function dragOver(evt) {
                            evt.stopPropagation();
                            evt.preventDefault();
                            self.dropzone.addClass("active-dropzone");
                        };
                        function drop(evt) {
                            evt.stopPropagation();
                            evt.preventDefault();

                            self.dropzone.removeClass("active-dropzone");
                            superObj_primary.msg = ''; // hide any messages.
                            var files = evt.dataTransfer.files;
                            var count = files.length;

                            // Only call the handler if 1 file was dropped.
                            if (count == 1) {
                                handleFiles(files);
                            }
                            else if (count > 1) {
                                // still working on this part :-/
                            }
                        }

                    };

                    // ------------------------------------------------------------
                    // Method to fill the pbar to the max value (i.e., 100%)
                    // ------------------------------------------------------------
                    self.dropzone.pbar.complete = function () {
                        progress_ele.progressbar({ value: 100 });
                    };

                    // ------------------------------------------------------------
                    // Check if FileAPI and XmlHttpRequest.upload are supported.
                    // ------------------------------------------------------------
                    self.hasDndSupport = function () {
                        return (window.File && window.FileReader && window.FileList && window.Blob && new XMLHttpRequest().upload);
                    };
                };

                return superObj_secondary;
            })();

            return $.fn.extend(superObj_primary, new superObj_secondary());


        };

        return oUploader;
    })();

    var uploader = new oUploader(); // now we just init the new object and there we go. You can go to your console and try out the commands.
// **Note: If you are doing this in JsFiddle, you'll have to change the scope of the browser console from "<top frame>" to "result( fiddle.jshell.net/)". 

额外自动化

只要我构建相应的HTML对象,这个对象就可以工作。但通常当我完成构建它们时,我会添加一个额外的部分,在其中通过javascript在对象的构建过程中创建所有的HTML组件。这样做的目的,当然是为了使工具更容易部署。


如果您在同一页上有几个这样的组件,如果您想要使用外部触发器(按钮点击)来访问特定实例的uUploader并操作其数据,会发生什么? - AaA
哦,天啊。我有一段时间没有看过这个了。现在可能有更好的方法来完成文件加载器,但是为了回答你的问题,我会说你需要以某种方式封装引用。也许通过填充选择器或容器对象来定义DOM中元素的范围。 - Ross Brasseaux

0
使用 .bind 和自定义函数,然后 .trigger 调用该函数。

抱歉,我忘了提到。我尝试过使用 .bind 和 .live,但出于某种原因,我无法传递 eventdata。也就是说,我希望能够调用 .theFunction(eventData) 并且能够在函数体中访问该对象。 - Ibolit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接