У меня есть обработчики событий, которые работают в FF, а не в Safari. Проще говоря, у меня есть список друзей, некоторые жестко запрограммированы, некоторые взяты из базы данных. При нажатии на друга открывается окно чата ... это очень похоже на систему чата Facebook.

Так что в Firefox все работает нормально и как положено. В Safari щелчок по жестко запрограммированным друзьям работает нормально, но щелчок по друзьям, извлеченным из базы данных, не открывает окно чата.

<script type="text/javascript" src="js/jQuery.js"></script>
<script type="text/javascript" src="js/chat.js"></script>
<script type="text/javascript" src="js/ChatBar.js"></script>
<script type="text/javascript" src="js/settings.js"></script>
<script type="text/javascript">
    var chat = new Chat();
    var from = <?php echo "'" .$_SESSION['userid'] . "'"; ?>;
    chat.getUsers(<?php echo "'" .$_SESSION['userid'] . "'"; ?>);
</script>

Поэтому я загружаю всех своих приятелей chat.getUsers. Эта функция:

// get list of friends 
function getBuddyList(userName) {
    userNameID = userName;

    $.ajax({
        type: "GET",
        url: "buddyList.php",
        data: {
            'userName': userName,
            'current': numOfUsers
        },
        dataType: "json",
        cache: false,
        success: function(data) {
            if (numOfUsers != data.numOfUsers) {
                numOfUsers = data.numOfUsers;
                var list = "<li><span>Agents</span></li>";
                for (var i = 0; i < data.friendlist.length; i++) {  
                    list += "<li><a class=\"buddy\" href=\"#\"><img alt=\"\" src=\"images/chat-thumb.gif\">"+ data.friendlist[i] +"</a></li>";
                }
                $('#friend-list ul').append($(list));
            }
            setTimeout('getBuddyList(userNameID)', 1000);
        }
    });
}

BuddyList.php просто извлекает пользователей из базы данных и возвращает массив с именами пользователей. Итак, jQuery для щелчка по приятелю:

// click on buddy in #friends-panel
$('#friends-panel a.buddy').click(function() {
    alert("Loaded");    
    // close #friends-panel
    $('.subpanel').hide();
    $('#friends-panel a.chat').removeClass('active');

    // if a chat window is already active, close it and deactivate
    $('#mainpanel li[class="active-buddy-tab"] div').not('#chat-box').removeAttr('id');
    $('#mainpanel li[class="active-buddy-tab"]').removeClass('active-buddy-tab').addClass('buddy-tab');

    // create active buddy chat window
    $('#mainpanel').append('<li class="active-buddy-tab"><a class="buddy-tab" href="#"></a><div id="chat-window"><h3><p id="to"></p></h3></div></li>');

    // create name and close/minimize buttons
    $('.active-buddy-tab div h3 p#to').text($(this).text());
    $('.active-buddy-tab div h3').append('<span class="close"> X </span><span class="minimize"> &ndash; </span>');
    $('.active-buddy-tab').append('<span class="close"> X </span>');

    // create chat area
    $('.active-buddy-tab div').append('<div id="chat-box"></div><form id="chat-message"><textarea id="message" maxlength="100"></textarea></form>');

    // put curser in chat window
    $('.active-buddy-tab #message').focus();

    // create a chat relationship
    return false;
});

... и основная структура HTML:

<div id="footpanel">
  <ul id="mainpanel">
    <li id="friends-panel">
      <a href="#" class="chat">Friends (<strong>18</strong>) </a>
      <div id="friend-list" class="subpanel">
        <h3><span> &ndash; </span>Friends Online</h3>
        <ul>
          <li><span>Family Members</span></li>
          <!-- Hard coded buddies -->
          <li><a href="#" class="buddy"><img src="images/chat-thumb.gif" alt="" /> Your Friend 1</a></li>
          <li><a href="#" class="buddy"><img src="images/chat-thumb.gif" alt="" /> Your Friend </a></li>
          <!-- buddies will be added in dynamically here -->
        </ul>
      </div>
    </li>
  </ul>
</div>

Я не совсем уверен, с чего начать решение этой проблемы. Я подумал, что это может быть ошибка рендеринга или что-то в этом роде с DOM, но я весь день смотрел на этот код и застрял. Есть идеи, почему он работает в FF, а не в Safari? кстати ... тестирую на Snow Leopard.

Спасибо Христо

РЕДАКТИРОВАТЬ: Я попытался создать событие jQuery с помощью .live () и .delegate (), и произошло то же самое ... FF ломается, а Safari остается сломанным. Таким образом, функциональность теперь та же, и это хорошо, но событие щелчка не работает. Есть другие идеи?

1
Hristo 18 Июн 2010 в 00:59

2 ответа

Лучший ответ

Попробуй это:

$('#friends-panel').delegate( 'a.buddy', 'click', function() {
    alert("Loaded");    
    // ...your code
});

... вместо $('#friends-panel a.buddy').click(function() {...

http://api.jquery.com/delegate/

Когда вы звоните .click(function...), вы фактически звоните .bind('click', function...).

Если он настроен на запуск после загрузки DOM, он назначает обработчик кликов существующим элементам.

Элементы, динамически добавляемые после загрузки DOM, от этого не выигрывают.

Использование .delegate() помещает обработчик кликов на #friends-panel и отслеживает щелчки, которые происходят сбоку от него. Когда это происходит, он проверяет, было ли это снова a.buddy, и если да, запускает обработчик.

Другой вариант - просто привязать click() в обратном вызове success до (или после) добавления к #friends-panel.


Чтобы привязать обработчик кликов к обратному вызову success, сначала переместите функцию в переменную:

var myfunc = function() {
    alert("Loaded");    
    // close #friends-panel
    $('.subpanel').hide();
    $('#friends-panel a.chat').removeClass('active');

    // ...and so on
}

... тогда вместо текущего click сделайте следующее:

$('#friends-panel a.buddy').click( myfunc );

... затем в обратном вызове success сделайте следующее:

success: function(data) {
            if (numOfUsers != data.numOfUsers) {
                numOfUsers = data.numOfUsers;
                var list = "<li><span>Agents</span></li>";
                for (var i = 0; i < data.friendlist.length; i++) {  
                    list += "<li><a class=\"buddy\" href=\"#\"><img alt=\"\" src=\"images/chat-thumb.gif\">"+ data.friendlist[i] +"</a></li>";
                }

                   // new version
                $(list).click( myfunc ).appendTo('#friend-list ul'); 

                // old version
// off-topic, no need to create jQuery object-----v
                // $('#friend-list ul').append($(list)); 

            }
            setTimeout('getBuddyList(userNameID)', 1000);
        }

РЕДАКТИРОВАТЬ: Чтобы назначить функцию, требующую параметра, обработчику кликов, один из способов - поместить вызов функции внутри функции обратного вызова.

Итак, вместо этого:

$('#friends-panel a.buddy').click( buddyClick );

Ты сделаешь это:

// Set up a handler that calls your function------v
$('#friends-panel a.buddy').click( function() { buddyClick(parameters) } );

Другой метод заключается в том, чтобы ваш buddyClick возвращал функцию, которая использует переданные параметры, например:

// Calling buddyClick actually returns a function
//   that can use the parameters you passed in
var buddyClick = function(parameters) {
    return function() {
       alert("Loaded");
       // do something with the parameters  
       // ...and so on
    };
};

// Calling buddyClick returns the function
$('#friends-panel a.buddy').click( buddyClick('some_parameter') );

Таким образом, вы можете вызвать buddyClick, и он вернет функцию, которая принимает параметры, которые будут использоваться для обработчика.

Возможно, немного более запутанный, но действительный подход. Выбирайте. : o)

3
user113716 19 Июн 2010 в 06:36
Я пробовал это с вашим предложением, но он действительно сломал его в FF, и он все еще не работает в Safari. По крайней мере, функциональность одинакова в обоих браузерах, но все равно не работает. Есть другие идеи?
 – 
Hristo
18 Июн 2010 в 17:08
- Не знаю, почему delegate() не работает. Вы пробовали мое последнее предложение, где привязать обработчик в обратном вызове success? Если вы переместите функцию из click() в ее собственную переменную, вы можете повторно использовать ее в обоих местах. Я обновлю свой ответ, чтобы лучше понять, что я имею в виду.
 – 
user113716
18 Июн 2010 в 17:38
Прошу прощения ... Я еще не пробовал ваше последнее предложение. Я пойду кодировать прямо сейчас. Спасибо за вашу помощь!
 – 
Hristo
18 Июн 2010 в 17:43
- Я обновил свой ответ. Но у меня такое чувство, что что-то не так. У вас не должно быть разного поведения между FF и Safari. Я вернусь через пару часов.
 – 
user113716
18 Июн 2010 в 17:50
@patrick ... Спасибо за обновление. Кажется, теперь это работает в FF, и это имеет смысл в моей голове. Однако консоль ошибок Safari сообщает мне «ReferenceError: не удается найти переменную: buddyClick», а buddyClick - это переменная. Также ... ваша единственная строка $(list).click(buddyClick).appendTo('#friend-list ul'); не добавляет список ни в одном браузере.
 – 
Hristo
18 Июн 2010 в 17:59

Как я обычно это делаю:

$('#friends-panel a.buddy').live('click',function() { ... });

Вместо того:

$('#friends-panel a.buddy').click(function() { ... });

.live позволяет привязать обработчики событий к элементам, загруженным AJAX (после готовности DOM).


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

Пример использования console.log () для отладки вашей проблемы:

// get list of friends 
function getBuddyList(userName) {
    userNameID = userName;
    console.log('userNameID: '+ userNameID); //make sure a userNameID is being passed.

    $.ajax({
        type: "GET",
        url: "buddyList.php",
        data: {
            'userName': userName,
            'current': numOfUsers
        },
        dataType: "json",
        cache: false,
        success: function(data) {
            console.log(data); //dump the returned data into the console.log
            if (numOfUsers != data.numOfUsers) {
                numOfUsers = data.numOfUsers;
                var list = "<li><span>Agents</span></li>";
                for (var i = 0; i < data.friendlist.length; i++) {  
                    list += "<li><a class=\"buddy\" href=\"#\"><img alt=\"\" src=\"images/chat-thumb.gif\">"+ data.friendlist[i] +"</a></li>";
                    console.log(list); //dump each iteration to the console but also show each addition on each iteration.
                }
                $('#friend-list ul').append($(list));
            }
            setTimeout('getBuddyList(userNameID)', 1000);
        }
    });
}

А также // щелкаем по приятелю на # панели друзей $ ('# friends-panel a.buddy'). click (function () { alert ("Загружено");
// закрыть # панель друзей $ ('. подпанель'). hide (); $ ('# панель друзей a.chat'). removeClass ('active');

// if a chat window is already active, close it and deactivate
$('#mainpanel li[class="active-buddy-tab"] div').not('#chat-box').removeAttr('id');
$('#mainpanel li[class="active-buddy-tab"]').removeClass('active-buddy-tab').addClass('buddy-tab');

// create active buddy chat window
$('#mainpanel').append('<li class="active-buddy-tab"><a class="buddy-tab" href="#"></a><div id="chat-window"><h3><p id="to"></p></h3></div></li>');

// create name and close/minimize buttons
$('.active-buddy-tab div h3 p#to').text($(this).text());
$('.active-buddy-tab div h3').append('<span class="close"> X </span><span class="minimize"> &ndash; </span>');
$('.active-buddy-tab').append('<span class="close"> X </span>');

// create chat area
$('.active-buddy-tab div').append('<div id="chat-box"></div><form id="chat-message"><textarea id="message" maxlength="100"></textarea></form>');

// put curser in chat window
$('.active-buddy-tab #message').focus();

// create a chat relationship
return false;

});

Это может дать вам некоторое представление о том, где он ломается и почему. Вы также должны добавить console.log () во все функции события щелчка.

0
Jubair 21 Июн 2010 в 22:15
На самом деле я использую live для других событий щелчка, но когда я попробовал это с этим конкретным событием, он не работал ни в FF, ни в Safari.
 – 
Hristo
18 Июн 2010 в 17:02
Странно, не могли бы выложить код? также у вас установлен firebug? в противном случае это необходимо для любой разработки AJAX (помимо прочего, AJAX тоже работает).
 – 
Jubair
18 Июн 2010 в 19:05
Конечно, у меня установлен Firebug :) Какой именно код вы хотите, чтобы я опубликовал? Если вы читаете другой ответ здесь ... Я прокомментировал изменения, которые я сделал, используя его код.
 – 
Hristo
18 Июн 2010 в 20:11
Все, о чем я могу думать, - это скобка, которая где-то не закрывается, или теги внутри файла .js (что не будет ошибкой в ​​firefox, но будет в сафари). имея firebug, это то, что я бы сделал. проверьте, где происходит сбой события, поместив: console.log ('test complete'); в качестве примера я бы сначала вставил это сразу после .click (function () {, а затем, если он там работает, переместите его дальше вниз и продолжайте, пока не найдете, где он сломан. Также поместите его в свои функции. I неукоснительно используйте console.log () с firebug, я вам говорю, это спасение жизни!
 – 
Jubair
21 Июн 2010 в 07:07
Console.log () также позволяет передавать ему практически все, что угодно. попробуйте, если вы не использовали его раньше, это ОБЯЗАТЕЛЬНО нужно при отладке.
 – 
Jubair
21 Июн 2010 в 07:08