简体   繁体   English

将jQuery与OOP JS一起使用是否有效?如果可以,如何在类函数之间创建状态更改菜单?

[英]Is it effective/efficient to use jQuery with OOP JS, and if so, how do I create a changing-state menu across class functions?

I'm trying to write a JavaScript widget in object-oriented JavaScript, or at least what I understand JS' near-equivalent of classes to be. 我试图用面向对象的JavaScript编写JavaScript widget ,或者至少我理解JS几乎等同于类的东西。

All I'm trying to achieve is a menu which changes state. 我想要实现的只是一个更改状态的菜单。 In pseudo;

  • Upon widget load, populate #nav with a <ul> menu containing year group <li> s. 加载小部件后,使用包含年份组 <li><ul>菜单填充#nav
  • Upon clicking a year group <li> , empty #nav ul of its <li> and re-populate it with tutor group <li> s in that year, as well as appending a return link. 单击年份组<li> ,将其<li> #nav ul清空,并在该年份中将其与导师组 <li>一起重新填充,并附加一个return链接。
  • Upon clicking the return link, empty #nav and re-populate it with the original year group <ul> menu whilst being able to utilise all of the above functionality. 单击return链接后,清空#nav并使用原始的年组 <ul>菜单重新填充它,同时能够使用上述所有功能。

Historically , ie to date, I've used "embedded" functions to try and keep everything within the same DOM layer/timing. 从历史上讲 (即迄今为止),我曾使用“嵌入式”功能来尝试将所有内容保持在同一DOM层/定时内。 I don't really understand how any of this works, or if this is an appropriate thing to do, but the code itself seemed to work. 我真的不明白这是如何工作的,或者这是否合适,但是代码本身似乎可以工作。

Here's an example of the way I've done it previously: 这是我之前做过的一个例子:

var GroupsDisplayHTML = '<h2>Tutor Groups</h2>' +
    '<ul><li><a class="year" href="javascript:void(0);" title="Year 9" id="9">Year 9</a></li>' +
    '<li><a class="year" href="javascript:void(0);" title="Year 10" id="10">Year 10</a></li>' +
    '<li><a class="year" href="javascript:void(0);" title="Year 11" id="11">Year 11</a></li>' +
    '<li><a class="year" href="javascript:void(0);" title="Year 12" id="12">Year 12</a></li>' +
    '<li><a class="year" href="javascript:void(0);" title="Year 13" id="13">Year 13</a></li></ul>';

$("div#groups").html(GroupsDisplayHTML);

$('a.year').click( function() {
    var Groups;
    var Groups_Sorted = [];

    Frog.API.get('groups.getAll',
    {
        'onSuccess': function (data) { Groups = data; },
        'onError': function(err) { alert(err); }
    });

    for (var i = 0; i < Groups.length; i++) {
        var Year = $(this).attr("id");

        if (Groups[i].name.indexOf(Year) == 0 && Groups[i].name.indexOf('/Tp') != -1) {
            var arrayToPush = { 'id': Groups[i].id, 'name': Groups[i].name };
            Groups_Sorted.push(arrayToPush);
        }
    }

    GroupsDisplayHTML = '<h2>Year ' + Year + '</h2><ul>';

    for(var i = 0; i < Groups_Sorted.length; i++){
        GroupsDisplayHTML += '<li><a class="group" href="javascript:void(0);" title="' + Groups_Sorted[i].id + '" id="' + Groups_Sorted[i].id + '">' + 
            Groups_Sorted[i].name + ' <span style="font-size:10px;color:#bbb;">(' + Groups_Sorted[i].name + ')</span></a></li>';
    }

    GroupsDisplayHTML += '<li><a class="return" href="javascript:void(0);">&lt;- Back to Year Groups</a></li></ul>';

    $("div#groups").html(GroupsDisplayHTML);

    $('a.group').click( function() {
        var Group_ID = $(this).attr("id");
        AssignPoints.getUsers(Group_ID);
    });

    $('a.return').click( function() {
        AssignPoints.displayGroups(data);
    });
});

However, now, I'm wondering if the better way to do it is to use jQuery's on function. 但是,现在,我想知道是否更好的方法是使用jQuery的on函数。 Here's the code I'm currently writing (*just to try and achieve the changing-state menu): 这是我当前正在编写的代码(*仅用于尝试实现状态更改菜单):

var TutorGroupPoints = {
    URL: 'http://staff.curriculum.local/frog/rewards.php',
    currentUser: UWA.Environment.user.id,
    groupsObject: { },
    sortedArray: [ ],
    navHTML: '<h2>Tutor Groups</h2>' +
        '<ul>' +
            '<li><a class="year" title="Year 9" id="9">Year 9</a></li>' +
            '<li><a class="year" title="Year 10" id="10">Year 10</a></li>' +
            '<li><a class="year" title="Year 11" id="11">Year 11</a></li>' +
            '<li><a class="year" title="Year 12" id="12">Year 12</a></li>' +
            '<li><a class="year" title="Year 13" id="13">Year 13</a></li>' +
        '</ul>',

    init: function() {
        /* caching outer this -> AJAX scope problems */
        var that = this;

        /* retrieve all of the user groups from Frog VLE and store them in an object-level variable */
        Frog.API.get('groups.getAll',
        {
            'onSuccess': function (data) { that.groupsObject = data; },
            'onError': function(err) { alert(err); }
        });

        /* populate the div#nav with our year group UL */
        $('#nav').append(this.navHTML);

        /* using "on" because the LIs have been created in the DOM? */
        $('#nav ul').on("click", "li a", function(e) {
            e.preventDefault();
            that.yearClick( $(this).attr("id") );
        });
    },

    yearClick: function(year) {
        /* run through groupsObject and pull out any tutor groups found in the year we've clicked on
           then put those into our sortedArray */
        for (var i = 0; i < this.groupsObject.length; i++) {
            if (this.groupsObject[i].name.indexOf(year) == 0 && this.groupsObject[i].name.indexOf('/Tp') != -1) {
                /* all we need is name and id */
                var arrayToPush = { 'id': this.groupsObject[i].id, 'name': this.groupsObject[i].name };
                this.sortedArray.push(arrayToPush);
            }
        }

        /* clear the existing UL from div#nav */
        $('#nav ul').empty();

        /* populate div#nav's UL with LIs of our tutor groups (label being name, attr="id" being id) and
           clickable links for each */
        for (var i = 0; i < this.sortedArray.length; i++) {
            $('#nav ul').append('<li><a class="tutor" id="' + this.sortedArray[i].id + '">' + this.sortedArray[i].name + '</a></li>');
        }

        /* add a "return" link to view other years' tutor groups */
        $('#nav ul').append('<li><a id="return">&lt;- Return</a></li>');

        /* upon clicking the return link, empty #nav ul then re-append our navHTML from earlier */
        $('#nav ul').on("click", "a#return", function(e) {
            e.preventDefault();
            $('#nav ul').empty();
            $('#nav').append(this.navHTML);
        });

        /* upon clicking any of our tutor group LIs, display that link's id so that we can use it in
           another function to actually display some content */
        $('#nav ul').on("click", "a.tutor", function(e) {
            e.preventDefault();
            alert( $(this).attr("id") );
        });
    }

};

widget.onLoad = function(){
    /* run our "class" */
    TutorGroupPoints.init();
}

And the HTML: 和HTML:

<div id="wrapper">
    <div id="nav">

    </div>
    <div id="content">

    </div>
</div>

I've created a jsFiddle here , which is a slight manipulation of the code (ie I've removed the inaccessible Frog API calls and replaced them with a fixed object). 我在这里创建了一个jsFiddle ,它是对代码的轻微操纵(即,我删除了无法访问的Frog API调用,并用固定对象替换了它们)。 Hopefully this works adequately. 希望这可以正常工作。

The problem here is that once I click the return button, nothing happens . 这里的问题是,一旦我单击返回按钮,就什么也没有发生 In addition, I suspect that fixing the return button would then provide me with some links which, when clicked upon, would do nothing. 此外,我怀疑固定返回按钮会为我提供一些链接,这些链接在单击时将无济于事。

Ideally , as per the bottom end of the code, I would like to run another function within my TutorGroupPoints class when the user clicks on a specific tutor group. 理想情况下 ,根据代码的最底端,当用户单击特定的导师组时,我想在TutorGroupPoints类中运行另一个函数 How will this affect my return button, etc? 这将如何影响我的返回按钮等? Will they then stop working because they aren't being run from the "current" function? 他们会因为没有从“当前”功能运行而停止工作吗?

More than "just" an answer to my code problems, I'd quite like some direction , ie is the recent code I've written better than the older stuff? 我不仅仅要“解决”我的代码问题,还需要提供一些指导 ,即,我编写的最新代码是否比旧版本要好? Should I be using on or should I be using embedded jQuery functions and communicative class functions? 我应该使用on还是应该使用嵌入式jQuery函数和可通信类函数?

Thanks in advance, 提前致谢,

Short answer: http://jsfiddle.net/byzgv/4/ 简短答案: http : //jsfiddle.net/byzgv/4/

I'm not sure about the OOP aspect, but this seems to be your scenario: 我不确定OOP方面,但这似乎是您的情况:

  1. when the page is loaded, you insert a list into a div. 加载页面时,您将一个列表插入div。
  2. you add some event handlers to this list 您将一些事件处理程序添加到此列表中
  3. you click a list item, your event handlers run, and change the list items. 您单击一个列表项,您的事件处理程序运行,并更改列表项。
  4. the "Return" list item "does nothing" when you click it. 单击它时,“返回”列表项“不执行任何操作”。

In your fiddle, clicking the "Return" list item does do something, it empties this list. 在您的小提琴中,单击“返回”列表项执行某些操作,从而清空此列表。 This is partly what you asked it to do: 这部分是您要求它执行的操作:

$('#nav').on("click", "ul a#return", function(e) {
    e.preventDefault();
    $('#nav ul').empty();
    $('#nav').append(this.navHTML);
});

So this event handler has fired, and the first two instructions have worked. 因此,此事件处理程序已触发,并且前两个指令已起作用。 The call to append doesn't work because you're in a different context - this does not refer to the TutorGroupPoints object. append调用不起作用,因为您处于不同的上下文中- this不引用TutorGroupPoints对象。 So you can fix this by referring to your object explicitly: 因此,您可以通过显式引用对象来解决此问题:

$('#nav').on("click", "ul a#return", function(e) {
    e.preventDefault();
    $('#nav ul').empty();
    $('#nav').append(TutorGroupPoints.navHTML);
});

(by the way, you're appending a whole new list, so you need to do $('#nav').empty(); instead of $('#nav ul').empty(); ) (顺便说一句,您要追加一个全新的列表,因此需要执行$('#nav').empty();而不是$('#nav ul').empty();

Then, as you guessed, clicking the "Return" item gives you a new list which doesn't respond to click events. 然后,正如您所猜测的,单击“返回”项将为您提供一个新列表,该列表不响应单击事件。 This is because of how you're calling the on function. 这是因为您如何调用on函数。 The jQuery object you call on on must exist when the event handler is being set up. 你叫jQuery对象on时,正在建立的事件处理程序上必须存在。 In your init function, the list does exist when you set up the event handlers, as you're appending it to the div before calling on . 在您的init函数中,列表在设置事件处理程序时确实存在,因为您需要在调用之前将其追加到div on But later, you trash this list and replace it. 但是,稍后,您将其丢弃,然后将其替换。

To get your event handlers working on all lists rather than just the first one, you need to attach your event handlers to an element that exists from the start and doesn't change, ie the #nav div. 为了使事件处理程序能够在所有列表上而不是仅在第一个列表上运行,您需要将事件处理程序附加到从一开始就存在且不会更改的元素,即#nav div。 So 所以

$('#nav ul').on("click", "li a", function(e) {

can become 可以变成

$('#nav').on("click", "ul li a", function(e) {

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM