JQuery UI (ядро эффектов) addClass / removeClass для одного элемента с несколькими селекторами, но есть одна загвоздка

Спасибо, что посмотрели. Я пытаюсь использовать методы jQ UI addClass / remove Class, чтобы развернуть элемент hr при нажатии на предыдущие одноуровневые div. Ядро эффектов пользовательского интерфейса jQ обеспечивает плавный анимированный переход между двумя классами: http://jqueryui.com/demos/removeClass/. Кроме того, hr необходимо динамически добавлять с помощью $, чтобы добиться более широкого дизайна сайта.

Вот кусочки головоломки:

  1. Мой код отображает строки из четырех одноуровневых div размером 100x100 пикселей. У этих div нет классов, но СВОБОДНО ДОБАВЛЯЙТЕ ИХ, ЕСЛИ ЭТО ПОМОЖЕТ - каждый div в конечном итоге будет иметь уникальный класс. После каждого 4-го div динамически добавляется hr.
  2. При щелчке по любому заданному элементу div, следующий сразу же hr должен переключиться на класс «open», что приведет к расширению строки. Если затем щелкнуть этот div еще раз, он должен переключить / удалить класс «open» из hr, в результате чего hr сжимается до исходного размера.
  3. Если щелкнуть один div, чтобы развернуть hr, а затем щелкнуть другой div, должны быть запущены две анимации: сначала должен быть удален "открытый" класс, в результате чего строка снова уменьшится, и ЗАТЕМ класс необходимо повторно добавить чтобы снова открыть строку. Однако, если, например, щелкнули div, чтобы открыть вторую строку, а затем щелкнули второй div, предшествующий первому hr, это действие должно сначала закрыть второй hr, а затем открыть соответствующий hr второго div.

Я застрял. Я пробовал несколько комбинаций функций jQ, но результаты ужасны. То, что вы видите, является самым близким, что я получил. Спасибо, что дали шанс этому. Не стесняйтесь добавлять в код, но вы можете заставить это работать.

<!--HTML...the children divs of ".main" can have their own unique classes if that helps-->
<div class="main">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>

/*CSS-some of this creates other events not mentioned above. These are simplified versions of what I need for my final site design*/

.main  {
    width: 450px;
}
.main div {
    height: 100px;
    width: 100px;
    background-color: #000;
    margin: 3px;
    float:left;
}
div.select   {
    background-color: #f00;
    border: 2px solid #00F;
    margin: 3px;
    float:left;
    display: block;
}
div.active   {
    background-color: #f00;
    margin: 3px;
    float:left;
    display: block;
}
hr  {
    background-color: #FF0;
    float: left;
    display: block;
    height: 20px;
    width: 450px;
}
hr.open {
    float: left;
    display: block;
    height: 300px;
    width: 450px;

}

/*the JS - sorry about the double quotes.  I'm using Dreamweaver, which seems to add them to everything*/

$(document).ready(function() {
//dynamcally adds the <hr> after every 4th div.
    $(".main div:nth-child(4n)").after('<hr class="closed"></hr>');
//puts a blue border on the squares
    $('.main div').hover(function()  {
        $(this).addClass('select');
    },
    function() {
        $(this).removeClass('select')
    });
//changes the color of the active square to red and "deactivates" the previous one.
    $('.main div').click(function()  {
        $(this).toggleClass('active').siblings().removeClass('active');
    });
//here in lies the problem...???
    $('.main div').click(function()  {
        $('hr').removeClass('open', 1000);
        $(this).toggle
        (function() {
            $(this).nextAll("hr").first().addClass('open', 500);
        },
        function()  {
            $(this).nextAll("hr").first().removeClass('open', 500)
        });

    });
});

person Earl1234    schedule 19.09.2012    source источник
comment
К вашему сведению, это jQuery, а не jQuery UI. jQuery UI - это набор плагинов пользовательского интерфейса, таких как Autocomplete, Tabs и т. д.   -  person Barmar    schedule 19.09.2012
comment
эй, Бармар. Обратите внимание, что аргументы addClass и removeClass включают компонент продолжительности - это анимирует переходные классы b / t и возможно только с использованием ядра эффектов пользовательского интерфейса. jqueryui.com/demos/toggleClass. Если бы для этого мне не требовалась последовательная анимация, моя дилемма была бы легко разрешима.   -  person Earl1234    schedule 19.09.2012
comment
Вы пробовали использовать какой-либо элемент, кроме HR? Я понимаю, что использование простого div забивает много другого кода; может быть, попробуйте span и задайте стиль display: block. Я действительно чувствую, что стилизация HR не так хорошо поддерживается во многих браузерах и может легко стать корнем вашей проблемы, но я должен признать, что прошло много времени с тех пор, как я смотрел на использование таких HR.   -  person Patrick M    schedule 19.09.2012
comment
Я создал jsfiddle из ваших материалов: jsfiddle.net/Bv57T/1 Кажется, работает достаточно хорошо . Есть некоторые особенности, связанные с тем, где можно, а где нельзя щелкать. Я попробую поиграть с ним и посмотрю, получится ли что-нибудь более плавное.   -  person Patrick M    schedule 19.09.2012


Ответы (2)


Я почти уверен, что это именно то, что вам нужно. Я скопировал общий HTML-макет с http://makr.com (вы упомянул, что это было то, что вы хотели):

Демо: http://jsfiddle.net/SO_AMK/xm7Sk/

jQuery:

$(".main article:nth-child(4n)").after('<hr class="split"></hr>');
$(".main > article .slidedown").click(function(e) {
        e.stopPropagation();
}); // If you click on the slidedown, it won't collapse

var canAnimate = true,
    slideIsOpen = false,
    animateSpeed = 1000;

$(".main > article").hover(function() {
    $(this).addClass("hover");
}, function() {
    $(this).removeClass("hover");
}).click(function() {
    if (canAnimate) {
        canAnimate = false;
        var article = $(this),
            isThisOpen = article.hasClass("active");
        if (isThisOpen) {
            $(".main").queue(function () {
                hideSlide($(this))
            });
        }
        else {
            if (slideIsOpen) {
                $(".main").queue(function () {
                    hideSlide($(this));
                }).queue(function () {
                    positionPage(article, $(this));
                }).queue(function () {
                    showSlide(article, $(this));
                }).queue(function () {
                    positionPage(article, $(this));
                });
            }
            else {
                $(".main").queue(function () {
                    positionPage(article, $(this));
                }).queue(function () {
                    showSlide(article, $(this));
                }).queue(function () {
                    positionPage(article, $(this));
                });
            }
        }
    }
});

function showSlide(elm, main) {
        canAnimate = false;
        slideIsOpen = true;
        elm.nextAll("hr.split").first().addClass("active", animateSpeed);

        elm.children(".slidedown").css("top", (elm.offset().top + 114)).addClass("active").slideToggle(animateSpeed);

        elm.addClass("active");
        main.dequeue();
        canAnimate = true;
}

function hideSlide(main) {
        canAnimate = false;
        $(".main article.active").nextAll("hr.split.active").removeClass("active", animateSpeed);

        $(".main article.active").children(".slidedown").removeClass("active").slideToggle(animateSpeed);

        $(".main article.active").removeClass("active");
        $(main).dequeue();
        canAnimate = true;
        slideIsOpen = false;
}

function positionPage(elm, main) {
    canAnimate = false;
    var body;
    if ($.browser.safari) {
        body = $("body");
    }
    else {
        body = $("html");
    }
    var elmTop = elm.offset().top,
        bodyScroll = body.scrollTop();
    if (bodyScroll - elmTop == 0) {
        var speed = 0;
    }
    else {
        var speed = animateSpeed;
    }
    body.animate({
        scrollTop: elmTop
    }, speed, function () {
        main.dequeue();
        canAnimate = true;
    })
}​

Это может показаться большим сценарием для чего-то настолько маленького, но в нем есть некоторые средства защиты от сбоев. Единственная ошибка в том, что если вы начинаете быстро нажимать во время переходов, иногда очереди оказываются в неправильном порядке. Но средний пользователь не щелкает быстро во время анимации: D

person A.M.K    schedule 20.09.2012
comment
A.M.K., это великолепно! Спасибо чувак!! Теперь я попытаюсь понять, что все это означает и делает. Идеально. - person Earl1234; 20.09.2012
comment
A.M.K., возился с этим кодом. Во-первых, строки должны быть скрыты, пока не будет нажата статья. Причина в том, что когда продуктовая линейка фильтруется, все часы удаляются, а затем снова добавляются. Я сделал это с помощью этого фрагмента: $ (article: visible: odd: odd) .after ('‹hr class = split› ‹/hr›'); не может этого сделать с nth-child, так как он также считает скрытые элементы. Если hr.split изначально не скрыт, это вызывает рывок при динамическом добавлении. Но мне пока не удалось получить ваш код со скрытыми строками. Пожалуйста, дайте мне знать, если у вас есть исправления. - person Earl1234; 21.09.2012
comment
понял - это так же просто, как возиться с маржей и elm.offset (). top + xxx .... еще раз спасибо !!! - person Earl1234; 21.09.2012

Примерьте это для увеличения размера: http://jsfiddle.net/Bv57T/3/

Основные изменения:

  1. У вас было 2 привязки .click к одному и тому же селектору $('.main div'). Я считаю, что это технически поддерживается, но для этого нет причин, и это усложняет отслеживание вашего кода.
  2. .toggle() не принимает функции в качестве параметров. Проверьте его в документации; это не похоже на hover().
  3. Нет причин иметь отдельные функции для добавления и удаления. Вы также дважды удаляете классы. Вы хотели, чтобы следующий HR был открытым и оставался открытым? Или хотите, чтобы она открывалась и закрывалась немедленно? В последнем случае для этой строки $('hr').removeClass('open', 1000); нет причин. В первом случае нет причин для второй функции () с $(this).nextAll("hr").first().removeClass('open', 500).

Вот javascript, который я использовал в скрипке

$(document).ready(function() {
    //dynamcally adds the <hr> after every 4th div.
    $(".main div:nth-child(4n)").after('<hr class="closed"></hr>');
    //puts a blue border on the squares
    $('.main div').hover(
        function()  {
            $(this).addClass('select');
        },
        function() {
            $(this).removeClass('select')
    });
    //changes the color of the active square to red and "deactivates" the previous one.
    $('.main div').click(function()  {
        $('hr.open').removeClass('open', 1000);
        if(!$(this).hasClass('active')) {
           $(this).nextAll("hr").first().addClass('open', 500);
        }
        $(this).toggleClass('active').siblings().removeClass('active');
    });
});​

Если это не совсем то, что вы хотите и не можете понять отсюда, продолжайте и отправляйте ответ, и я могу еще раз взяться за это.

Изменить Новая и улучшенная версия: http://jsfiddle.net/Bv57T/4/ Также обновлен js выше.

По-прежнему можно подделать это, если вы нажмете второй div во время анимации. Вы можете обойти это, установив для (global) bool значение true на время анимации и проверяя его перед запуском следующей анимации.

Но корень проблемы в том, что вы пытаетесь дублировать состояние пользовательского интерфейса (другими словами, DOM) как состояние приложения. Это может стать непростым делом даже с простыми операциями (как вы сами видели). Я предпочитаю использовать библиотеку, которая отделяет пользовательский интерфейс от приложения. Их обычно называют MVC (модель-представление-контроллер) или MVVM (модель-представление-модель просмотра - прозвище, которое я ненавижу, потому что оно намеренно сбивает с толку). Мне больше всего нравится knockout.js. Он полностью совместим с jQuery и jQuery UI; посмотрите этот пример: анимированные переходы.

Таких библиотек больше. Backbone.js - один, knockback.js сочетает в себе нокаут и backbone. Я знаю, что забываю некоторые другие популярные и хорошие ...

person Patrick M    schedule 19.09.2012
comment
Спасибо, Патик М. Проблема в том, что когда вы дважды щелкаете один и тот же div, он ДОЛЖЕН закрыть hr. Как и в вашей скрипке, дважды щелкнув один и тот же div, сначала закрывается, а затем снова открывается соответствующий hr. Это была моя первоначальная проблема. Может быть, мы можем что-то сделать с активным классом div, на который вы нажимаете. Когда щелкают по div, он становится активным. Так что, возможно, нажатие div.active закроет только hr, а нажатие любого неактивного div закроет любой hr, а затем откроет следующий ?? не совсем уверен, как это реализовать. Вот что я пробовал, но не работает: - person Earl1234; 19.09.2012
comment
$ ('. основной div.active'). click (function () {$ ('hr'). removeClass ('open', 250);}); $ ('. main div'). not ('. active'). click (function () {$ ('hr'). removeClass ('open', 250); $ (this) .nextAll (hr) .first () .addClass ('открытый', 1000);}); }); - person Earl1234; 19.09.2012
comment
Ах, теперь я понимаю. Да, вам нужно будет провести некоторую проверку классов для jQuery, чтобы увидеть разницу. Я ожидаю, что проблема с привязками вашего примера заключается в том, что они привязываются в начале, когда нет активного элемента. Таким образом, вам придется повторно привязать их после каждого события. Возможно, но я отправлю ответ позже сегодня с некоторыми другими идеями. - person Patrick M; 19.09.2012
comment
все еще та же проблема - щелчок по тому же div дважды не закрывает hr. - person Earl1234; 19.09.2012
comment
Ты мужчина. этот проект завис (по крайней мере, в его текущем макете) до тех пор, пока эта проблема не будет решена. - person Earl1234; 19.09.2012
comment
Отредактировано с модификацией. Я думаю, что он делает то, что вы хотите, более внимательно. высмотри и дай мне знать. - person Patrick M; 19.09.2012
comment
Так намного лучше. В идеале первый час закроется раньше, чем откроется второй. Есть ли способ выполнить обратный вызов, который включает оператор IF, чтобы достичь этого? Мне нужно многому научиться - я кодировал 2 недели. На самом деле я пытаюсь создать сайт, похожий на makr.com. Я разрезал движущиеся части в firebug. когда вы нажимаете на продукт, динамически добавляемый hr под продуктом расширяется одновременно с наложением отдельного абсолютно позиционированного div ... этот движок великолепен. Смогу ли я с легкостью разработать что-то подобное в одном из упомянутых вами MVC? - person Earl1234; 19.09.2012
comment
кстати, похоже, что дизайнер сайта makr использовал прототип для большей части кода. - person Earl1234; 19.09.2012
comment
.toggle() имеет форму, которая принимает параметры функции, см. api.jquery.com/toggle-event - person Barmar; 19.09.2012