Создание методов на лету - PullRequest
10 голосов
/ 26 июня 2010

Здравствуйте, я пытаюсь создать плагин 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
        }
    }
}

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

РЕДАКТИРОВАТЬ:

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

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

$(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) отсортирует все элементы по заданному ключу
и т. д.

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

Ответы [ 3 ]

2 голосов
/ 27 июня 2010

Если вы хотите, чтобы эти методы были доступны для любого объекта 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();
2 голосов
/ 27 июня 2010

Я нашел это решение здесь: 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) и т. д. Это прекрасно работает.

0 голосов
/ 26 июня 2010

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

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

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


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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...