Создание методов на лету

Привет, Я пытаюсь создать jQuery-плагин, и мне нужно, чтобы методы были доступны для элементов после их инициализации как такого типа объектов, например:
$('.list').list({some options}); //This initializes .list as a list

//now I want it to have certain methods like:
$('.list').find('List item'); //does some logic that I need

Я пробовал с помощью

$.fn.list = function (options) {
    return this.each(function() {
        // some code here
        this.find = function(test) {
            //function logic
        }
    }
}

и несколько других попыток, я просто не могу понять, как это сделать.

EDIT:

Я попытаюсь объяснить это лучше.

Я пытаюсь превратить таблицу в список, в основном как список на компьютере с заголовками столбцов и сортируемыми элементами и все между ними. Вы запускаете таблицу с помощью команды типа

$(this).list({
    data: [{id: 1, name:'My First List Item', date:'2010/06/26'}, {id:2, name:'Second', date:'2010/05/20'}]
});

.list сделает сортировку <tbody> и выполнит несколько других начальных задач, а затем добавит следующие элементы к элементу:
.findItem(condition) позволит вам найти определенный элемент по условию (например, findItem('name == "Second"')
.list(condition) отобразит все элементы, соответствующие данному условию
.sort(key) сортирует все элементы по заданному ключу
и др.

Какой лучший способ сделать это?

Ответ 1

Я нашел это решение здесь: http://www.virgentech.com/blog/2009/10/building-object-oriented-jquery-plugin.html

Это похоже на то, что мне нужно.

(function($) {
    var TaskList = function(element, options)
    {
        var $elem = $(element);
        var options = $.extend({
            tasks: [],
            folders: []
        }, options || {});

        this.changed = false;
        this.selected = {};

        $elem.sortable({
            revert: true,
            opacity: 0.5
        });

        this.findTask = function(test, look) {
            var results = [];

            for (var i = 0,l = options.tasks.length; i < l; i++)
            {
                var t = options['tasks'][i];
                if (eval(test))
                {
                    results.push(options.tasks[i]);
                }
            }
            return results;
        }

        var debug = function(msg) {
            if (window.console) {
                console.log(msg);
            }
        }
    }

    $.fn.taskList = function(options)
    {
        return this.each(function() {
            var element = $(this);

            if (element.data('taskList')) { return; }

            var taskList = new TaskList(this, options);

            element.data('taskList', taskList);

        });
    }

})(jQuery);

Тогда у меня есть

    $('.task-list-table').taskList({
        tasks: eval('(<?php echo mysql_real_escape_string(json_encode($tasks)); ?>)'),
        folders: eval('(<?php echo mysql_real_escape_string(json_encode($folders)); ?>)')
    });
    var taskList = $('.task-list-table').data('taskList');

и я могу использовать taskList.findTask(condition);

И поскольку конструктор имеет $elem, я также могу отредактировать экземпляр jQuery для таких методов, как list(condition) и т.д. Это отлично работает.

Ответ 2

Если вы хотите, чтобы эти методы были доступны для любого объекта jQuery, вам нужно будет добавить каждый из них в прототип jQuery. Причина в том, что каждый раз, когда вы вызываете $(".list"), создается новый новый объект, и любые методы, которые вы привязали к предыдущему подобному объекту, будут потеряны.

Назначьте каждый метод прототипу jQuery следующим образом:

jQuery.fn.extend({
    list: function() { .. },
    findItem: function() { .. },
    sort: function() { .. }
});

Метод list здесь особенный, поскольку он может быть вызван в двух случаях. Во-первых, при инициализации списка, а во-вторых, при поиске определенных элементов по условию. Вам нужно было бы провести различие между этими двумя случаями - либо по типу аргумента, либо по другому параметру.

Вы также можете использовать API data для генерирования исключения, если эти методы вызывают для объекта, который не был инициализирован плагином списка. Когда ('xyz').list({ .. }) сначала вызывается, сохраните некоторую переменную состояния в кэше данных для этого объекта. Когда какой-либо из других методов - "list", "findItem" или "sort" вызывается позже, проверьте, содержит ли объект эту переменную состояния в кэше данных.

Лучшим подходом было бы пространство имен для вашего плагина, чтобы list() вернул расширенный объект. Три расширенных метода можно вызвать по возвращаемому значению. Интерфейс будет выглядеть следующим образом:

$('selector').list({ ... });
$('selector').list().findOne(..);
$('selector').list().findAll(..);
$('selector').list().sort();

Или сохранить ссылку на возвращенный объект в первый раз и сразу вызвать методы.

var myList = $('selector').list({ ... });
myList.findOne(..);
myList.findAll(..);
myList.sort();

Ответ 3

this.each не требуется. Это должно сделать:

$.fn.list = function (options) {
    this.find = function(test) {
        //function logic
    };
    return this;
};

Обратите внимание, что вы должны перезаписать собственный метод find jQuery, и делать это не рекомендуется.


Кроме того, для чего это стоит, я не думаю, что это хорошая идея. Предполагается, что экземпляры jQuery имеют только методы, унаследованные от объекта прототипа jQuery, и поэтому я чувствую, что вы хотите, чтобы это не соответствовало общепринятому поведению jQuery-плагина, т.е. возвращать объект this (экземпляр jQuery) без изменений.