Почему мое 'this' не меняет контекст внутри внутреннего цикла jQuery? - PullRequest
1 голос
/ 14 декабря 2011

Идея состоит в том, что я хочу пройтись по этим объектам и построить структуру HTML, которая будет добавлена ​​на страницу.Я думал, что было бы чище делать все это в цепочке, но, видимо, я не понимаю что-то о контексте this, поскольку он развивается через внутренние циклы.Я немного посмотрел на jQuery.proxy(), но я не уверен, что понимаю, как применить его здесь.Может быть, есть и другой способ сделать то, что я пытаюсь сделать здесь ...

var obj = [
    {"id":1213854620001,"name":"item 1","URL":"1213897576001.jpg"},
    {"id":1213854619001,"name":"item 2","URL":"1213890384001.jpg"},
    {"id":1213854618001,"name":"item 3","URL":"1213890378001.jpg"},
    {"id":1213854616001,"name":"item 4","URL":"1213897663001.jpg"},
    {"id":1213854615001,"name":"item 5","URL":"1213897554001.jpg"}
];
$(function() {
    if(obj.length) {
        $("<ul/>",{id:"myID"}).append(function(){
            var that = document.createDocumentFragment();
            $.each(obj,function(index,dataObj){
                $("<li/>",{data:{dataID:dataObj.id},text:dataObj.name}) // this === obj[index] === dataObj, shouldn't it be the [object HTMLLIElement]
                    .live("click",function(event) {
                        openVideo($(event.target).data(dataID));
                    })
                    .append(function() {
                        return $("<img/>",{src:dataObj.thumbnailURL})[0];
                    })
                    .appendTo(that);
            });
            return that;
        }).appendTo("body");
    }
});

function openVideo(str) {
    //console.log(str);
}

Неявный вопрос: почему that пусто после моего цикла?и как я могу построить эту структуру HTML с помощью вложенных циклов?

Используя предложения из комментариев и ответов, я построил это, которое, кажется, работает точно так, как должно, читает немного чище и позволяет jQuery делатьвесь javascript (например, documentFragment создание, манипулирование и т. д.):

$(function() {
    if(obj.length) {
        $("<ul/>",{id:"myID"})
        .delegate("li","click",function(){openVideo($(this).data("dataID"));})
        .append(function() {
            var that = $(this);
            $.each(obj,function(index,dataObj) {
                $("<li/>",{data:{dataID:dataObj.id},text:dataObj.name}).each(function() {                   
                    $("<img/>",{src:dataObj.URL}).appendTo(this);
                    that.append(this);
                })
            });
        }).appendTo("body");
    }
});

Ответы [ 3 ]

4 голосов
/ 14 декабря 2011

this меняет значение при переходе к новым вложенным функциям. не меняет значение, когда вы вызываете $() для создания нового элемента.

Так что сразу внутри

$.each(obj, function(index, dataObj) {

this - текущий объект, над которым вы зацикливаетесь. Как только вы получите здесь:

.live("click",function(event) {  // <------  inside of nested function 
    openVideo($(event.target).data(dataID));
})

this - это элемент, по которому вы щелкнули.

Но звонит

    $("<li/>",{data:{dataID:dataObj.id},text:dataObj.name}) 

для создания нового li элемента не устанавливает this для вновь созданного элемента.


Кроме того, если вы хотите сохранить значение this даже внутри вложенных функций, стандартным способом является сохранение его в новой переменной.

$.each(obj, function() {
    var self = this;

Теперь self можно использовать вместо this в качестве элемента, который вы в данный момент «включили» в любом месте цикла, даже в обработчиках вложенных функций. Или вы можете передать index и dataObjects каждой функции - тот же эффект.

EDIT

Как отмечено в комментарии, вы используете live неправильно. Если вы используете jQuery 1.7, вам нужно:

$(document).on("click", "li", function(event) {
      openVideo($(this).data(dataID));
});

в вашем document.ready обработчике. Если все li, которые будут нажаты, будут в определенном div, тогда выберите вместо этого document. Если вы не хотите, чтобы этот обработчик кликов применялся ко всем li, но только к некоторым, то украсьте все ли, к которым вы хотите применить этот обработчик кликов, с помощью класса css, а затем вместо передачи фильтра "li" в on ты бы сдал li.yourClass

1 голос
/ 14 декабря 2011

$.each устанавливает this для внутренней итерируемой функции элемента (и да, this - одна из сложных вещей в Javascript, но ваш комментарий можно объяснить, просто сославшись на поведение each).

0 голосов
/ 14 декабря 2011

Дело в том, что в основанных на прототипах языках, где javascript - один, функции - это объекты, а объекты имеют свойства. Поэтому, когда вы используете ключевое слово this, оно возвращается к области действия текущего прототипа. Внутри «встроенной функции» (которая на самом деле не является понятием в javascript, поскольку функции являются просто объектами), это относится к функции.

...