Держите кнопку наведения изображения при нажатии с помощью jQuery - PullRequest
4 голосов
/ 04 октября 2011

У меня есть следующий код для обеспечения эффекта наведения при наведении курсора на изображение кнопки:

 $("img.hoverImage")
    .mouseover(function () {
        var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png";
        $(this).attr("src", src);
    })
    .mouseout(function () {
        var src = $(this).attr("src").replace("_hover", "");
        $(this).attr("src", src);
    });

Это прекрасно работает.Теперь у меня есть дополнительное требование:

У меня есть три кнопки подряд, которые все имеют class = "hoverImage".

<a class="imageLink" href=""><img class="hoverImage" src="/Content/Images/1.png"/></a>
<a class="imageLink" href=""><img class="hoverImage" src="/Content/Images/2.png"/></a>
<a class="imageLink" href=""><img class="hoverImage" src="/Content/Images/3.png"/></a>

Я все еще хочу сохранить этот эффект при наведении, но теперь я также хочу изменить его, чтобы при щелчке по изображению оно оставляло отображаемое изображение при наведении (даже при наведении указателя мыши на это изображение).Когда я нажимаю на другую кнопку, она должна удалить указатель мыши на других кнопках.

ПРИМЕЧАНИЕ : нажатие на ссылки с изображениями НЕ перенаправляет на новую страницу (они просто вызывают некоторый ajaxиз файла js)

Какой лучший способ расширить приведенный ниже код для поддержки этого с помощью jQuery?Кажется, мне нужно отключить обработчик мышки после щелчка по элементу, но я пытаюсь избежать сложного решения.

Ответы [ 10 ]

10 голосов
/ 15 октября 2011

Вы можете отслеживать активное состояние кликаемого изображения одним из классов / data / attr, что-то вроде этого сделает эту работу.

$("img.hoverImage").mouseover(function(){
  if ($(this).is('.activeImage')) return;
  var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png";
  $(this).attr("src", src);
}).mouseout(function(){
  if ($(this).is('.activeImage')) return; // Skip mouseout for active image
  var src = $(this).attr("src").replace("_hover", "");
  $(this).attr("src", src);
}).click(function(){
  // remove previous active state
  $('.activeImage').not(this).removeClass('activeImage').trigger('mouseout');
  // set new active state
  $(this).addClass('activeImage');
  return false;
});
3 голосов
/ 04 октября 2011
$("img.hoverImage").click(function() {
    $(this).removeClass("hoverImage").addClass("keepImage");
    $(this).siblings("img.keepImage").removeClass("keepImage").addClass("hoverImage");
});

По сути, вы удаляете класс hoverimage и его функциональные возможности по щелчку, чтобы при отключении мыши не происходило событие отключения мыши. Он также восстанавливает класс hoverImage для всех братьев и сестер.

Возможно, вам все еще может понадобиться восстановить изображение, не относящееся к наведению на братьях и сестрах, в моем обработчике кликов.

Редактировать: я сделал вас JSFiddle, и я выбрал другой подход:

http://jsfiddle.net/jqWJN/2/

По сути, вы создаете несколько ссылок с помощью класса hoverImage, например:

<a class="hoverImage"> </a>

Затем вы объявляете их встроенными блоками, ширина и высота которых соответствуют размеру вашего изображения, и предоставляете им фоновое изображение по вашему выбору:

a.hoverImage {
    display: inline-block;
    width: 100px; height: 100px;
    background-image: url(http://placekitten.com/g/100/100);
}

Затем вы создаете свойство CSS, которое дает им новое фоновое изображение, когда они находятся и когда у них есть класс «keepImage»:

a.hoverImage:hover, a.hoverImage.keepImage {
    background-image: url(http://placekitten.com/100/100);
}

Естественно, вам нужно будет создать уникальную ссылку для каждой ссылки, если вы хотите разные картинки.

Наконец, вы создаете небольшой фрагмент JQuery, который добавляет класс keepImage к ним при нажатии и удаляет класс из всех братьев и сестер, у которых он есть:

$("a.hoverImage").click(function() {
    $(this).siblings(".keepImage").removeClass("keepImage");
    $(this).addClass("keepImage");
});

Если вы хотите, чтобы это работало в более широком масштабе, чем просто один набор братьев и сестер, как, например, по всей странице, просто замените это:

$(this).siblings(".keepImage")

с этим:

$(".keepImage")

Удачи!

2 голосов
/ 15 октября 2011

Я бы лично внес немало изменений:

Во-первых, я бы не зависел от логики обмена кусками имен файлов. Возможно, вы захотите позже изменить свои условные обозначения, и вам не нужно будет просматривать свои корректирующие файлы JavaScript. Я бы сделал что-то вроде следующего:

<img src="/Content/Images/1.png"
     data-active-image="/Content/Images/1_hover.png" />

Если в будущем вы захотите расширить это, пределом будет небо:

<img src="/Content/Images/1.png"
     data-active-image="/Content/Images/1_hover.png"
     data-hover-image="/Content/Images/1_hover.png"
     data-disabled-image="/Content/Images/1_hover.png" />

Во-вторых, я бы все испортил. Я хотел бы иметь код события, а затем код выбора изображения. Вот что я собрал для кода выбора изображения:

$.fn.updateImage = function(hovering) {
    return this.each(function() {
        var $el = $(this);
        var active = (hovering || $el.hasClass('active'));

        var image = active ? 'activeImage' : 'inactiveImage';

        if(!$el.data('inactiveImage'))
            $el.data('inactiveImage', $el.attr('src'));

        $el.attr('src', $el.data(image));
    });
};

Он принимает логическое значение из кода события, чтобы сказать, наведена ли мышь или нет. Он проверяет, имеет ли элемент активный класс или нет. Если он имеет активный класс или находится в процессе зависания, то это true. Мы используем это, чтобы выбрать, какой источник использовать. Следующий бит используется для кэширования исходного источника в атрибуте data-inactive-image. Наконец, мы устанавливаем источник.

Далее у нас есть код события. Поскольку мы имеем дело со своего рода группировкой в ​​стиле переключателей, я бы остановился на этом, чтобы у вас было несколько групп изображений на странице. При щелчке мы отключаем все изображения из исходного селектора и активируем текущее изображение, используя класс active, упомянутый ранее:

$.fn.makeHoverGroup = function() {
    var $group = this;

    return this
        .mouseover(function() {
            $(this).updateImage(true);
        })
        .mouseout(function() {
            $(this).updateImage(false);
        })
        .click(function() {
            $group.not(this).removeClass('active').updateImage(false);
            $(this).addClass('active').updateImage(true);
        });
};

Чтобы связать все это вместе, у нас осталась всего одна строка:

$('.hoverImage').makeHoverGroup();

В качестве дополнительного бонуса CSS знает все, что делает JavaScript. Для скрытых изображений имеется селектор .hoverImage:hover (a:hover .hoverImage для поддержки IE6), а для активных изображений - селектор .hoverImage.active.

Вы можете увидеть пример здесь: http://fiddle.jshell.net/nDdzA/1/

Обновление Исправлено удаление / повторное добавление при клике.

2 голосов
/ 04 октября 2011

Я думаю, что будет проще, если вы используете "div" с изображением в качестве фона.Укажите ширину и высоту div, чтобы они были такими же, как background-image, и примените их.Это особенно применимо в вашем случае, когда вы используете эти изображения только в качестве заполнителя для того, чтобы кто-то щелкнул по нему.

Как только это будет изменено, укажите: hover CSS fix.Новое требование, которое у вас есть, связано с идентификацией активного в данный момент изображения.Для этого

     $("<<placeholder - selector>>").click(function(){
           $(this).addClass("active").siblings().removeClass("active");

     });

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

1 голос
/ 13 октября 2011

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

При щелчке мыши функция находит изображение с src currentImage, сбрасывает переменную currentImage после того, как она была найдена (что позволяет функции mouseout работать правильно), и вручную выполняет указание мыши. После этого он устанавливает переменную currentImage для изображения src (как упомянуто выше).

Это решение также удобно, поскольку оно вписывается в вашу очередь и оказывает минимальное влияние на JS и не влияет на CSS и HTML.

Проверьте код ниже и дайте мне знать, если у вас есть какие-либо вопросы:)

var currentImage = "0";

$("img.hoverImage")
.click(function(){
    $("img.hoverImage").each(function() {
        if($(this).attr("src")==currentImage){
            currentImage = "0";
            $(this).mouseout();
        }
    });
    currentImage = $(this).attr("src");
})
.mouseover(function () {
    var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png";
    $(this).attr("src", src);
})
.mouseout(function () {
    if($(this).attr("src") != currentImage){
        var src = $(this).attr("src").replace("_hover", "");
        $(this).attr("src", src);
    }
});

Спасибо! :)

1 голос
/ 11 октября 2011

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

Когда элемент щелкается, он получает класс isClicked, остальные удаляются. Все соответствующие элементы передаются в функцию unHover. Функция unHover та же, что и у вашего обработчика мышки, за исключением того, что она работает только с элементами, в которых отсутствует класс isClicked.

$("img.hoverImage")
    .mouseover(function () {
        makeHoverImage(this);
    })
    .mouseout(function () {
        unHoverImage(this);
    })
    .click(function(){
        makeActive(elem);
    });

function makeActive(elem){
    $("img.hoverImage").removeClass("isClicked");
    $(elem).addClass("isClicked");
    $("img.hoverImage").each(function(index,elem){
        unHoverImage(elem);
    });
}

function makeHoverImage(elem){
    var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png";
    $(this).attr("src", src);
}

function unHoverImage(elem){
    if (!$(elem).hasClass("isClicked")){
        var src = $(this).attr("src").replace("_hover", "");
        $(this).attr("src", src);
    }
}
1 голос
/ 10 октября 2011

Вот пример кода о том, как добиться того, что вы хотите: http://jsfiddle.net/wCL2g/

Код JavaScript:

$("img.hoverImage").mouseover(function() {

    var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png";
    $(this).attr("src", src);

    // add class to state the element is hovered
    $(this).addClass('hover');
}).mouseout(function() {
    // don't trigger this function if element has clicked state
    if ($(this).hasClass('click')) {
        return;
    }

    var src = $(this).attr("src").replace("_hover", "");
    $(this).attr("src", src);

    // remove hover class
    $(this).removeClass('hover');
}).click(function(e) {
    // disable the default click event
    e.preventDefault();

    $(this).parent()              // from the parent element
           .siblings()            // find all the siblings elements <a>'s
           .find('img')           // find <img> inside each sibling
           .removeClass('hover')  // remove hover class
           .removeClass('click'); // remove click class

    // trigger the mouse over event for the image tag
    $(this).addClass('click').trigger('mouseover');
});

Надеюсь, это поможет

0 голосов
/ 15 октября 2011

Многие люди предлагают использовать для этого атрибуты jQuery и обработку метаданных.Здесь я просто предлагаю использовать глобальную переменную.Однако есть несколько проблем, с которыми вы, вероятно, сталкивались, поэтому позвольте мне объяснить решения:

(1).Если вы поместите переменную global , остерегайтесь href = "" в ваших якорях.Если вы запустите перезагрузку страницы, вы вернетесь в квадрат ноль, что не очень хорошо.Поэтому я удалил это.

(2).Вы хотите проверить глобальную переменную в mouseover и mouseout, чтобы сделать что-то вроде

if <triggered from current> return;   // disabling check    

Проблема в том, что в функции щелчка вы хотите сделать что-то вроде

if <there is a current> current.trigger('mouseout');
<set new current>
current.trigger('mouseover')

, но, как мыотключение mouseout и mouseover с помощью проверки отключения , затем запуск этих не работает.

У вас есть два варианта: a) вы можете установить current в null, вызвать эти два события, а затемустановить текущее на одно нажатие;б) Или вы можете изолировать эффект наведения / выхода из триггера, чтобы вызвать его в двух местах.

Параметр (а) представляет собой более сложный обработчик щелчков, но более простой обработчик мыши.Вариант (b) требует немного больше рефакторинга, но если вы предпочитаете идти по пути использования других функций jQuery, это, вероятно, хорошая идея.

(3).Поскольку я не использую идиомы jQuery, а ваш подход, нужно быть осторожным с регулярным выражением, чтобы оно соответствовало тому, что должно быть.Я сделал это с.

(4).Приведенный ниже код прикрепляет щелчок к якорям, как вы упомянули (хотя в некоторых решениях упоминаются сами изображения). Проблема заключается в том, как вы связываете объект, по которому щелкнули, с соответствующим изображением.В приведенном ниже коде jQuery find () является ключом.

(5).В jQuery лучше не использовать глобальные переменные, то есть переменные на уровне объекта окна.Вы все еще можете получить тот же результат, объявив переменную над соответствующими замыканиями, как показано ниже.Также людям нравится использовать $ для переменных, содержащих обернутые объекты jQuery, и я так и сделал.

(6).Наконец, остерегайтесь сравнения объектов.Приведенный ниже код гарантирует, что мы сравниваем объекты DOM, поэтому используйте jQuery get () .

Итак, это исправленный HTML-код (удаленный href):

<a id="anchor1" class="imageLink" ><img class="hoverImage" src="images/1.png"/></a>
<a id="anchor2" class="imageLink" ><img class="hoverImage" src="images/2.png"/></a>
<a id="anchor3" class="imageLink" ><img class="hoverImage" src="images/3.png"/></a>

(извините, URL-адреса изображений не такие, как у вас, на самом деле я тестировал приведенный ниже код)

Подход (a):

<script type="text/javascript">
$(function() {
    var clickedImg = null; // this is common to all closures below
    $("img.hoverImage")
        .mouseover(function () {
            var $img = $(this);
            if ($img.get(0) == clickedImg) return;
            // note the improved matching !
            var src = $img.attr("src").match(/[^_\.]+/) + "_hover.png"; 
            $img.attr("src", src);
        })
        .mouseout(function () {
            var $img = $(this);
            if ($img.get(0) == clickedImg) return;
            var src = $img.attr("src").replace("_hover","");
            $img.attr("src", src);
        });
         $("a.imageLink").click(function() {
            var oldClicked = clickedImg;
            clickedImg = null;                         // set to null to trigger events
            if (oldClicked) $(oldClicked).mouseout();
            var newClicked = $(this).find('img').get(0);
            $(newClicked).mouseover();
            clickedImg = newClicked;                   // redefine at the end

            alert($(this).attr('id') + " clicked"); // ajax call here
            });
});
</script>

и подход (b):

<script type="text/javascript">
$(function() {
   var clickedImg = null; // same global
   // refactor the mouse over/out - you could use other jQuery ways here
   function doOver($img) {
       var src = $img.attr("src").match(/[^_\.]+/) + "_hover.png";
       $img.attr("src", src);
   }
   function doOut($img) {
       var src = $img.attr("src").replace("_hover","");
       $img.attr("src", src);
   }
   $("img.hoverImage")
        .mouseover(function () {
                var $img = $(this);
                if ($img.get(0) == clickedImg) return;
                doOver($img);
        })
        .mouseout(function () {
                var $img = $(this);
                if ($img.get(0) == clickedImg) return;
                doOut($img);
        });
   $("a.imageLink").click(function() {
        if (clickedImg) doOut($(clickedImg));
        clickedImg = $(this).find('img').get(0);
        doOver($(clickedImg));
        alert($(this).attr('id') + " clicked"); // presumably your ajax call here
   });
});
</script>

Вариант (а) сохраняет вашу структуру, но я думаю, что вариант (б) должен быть вашим следующим шагом, и это мое предпочтение.

0 голосов
/ 04 октября 2011

Если ваши ссылки не меняют расположение окна, вы можете продолжить с ответом Андреаса или чем-то подобным.Если они это сделают, это больше похоже на работу сценария на стороне сервера.Я не знаю, какой вы используете, поэтому я опубликую пример в php.

<?php foreach ($links as $i => $link): ?>
<a class="imageLink" href="<?php echo $link ?>">
  <img class="hoverImage" src="/Content/Images/<?php echo ($i == $selected) ? $i . "_hover" : $i ?>.png"/>
</a>
<?php endforeach ?>
0 голосов
/ 04 октября 2011

Использовать jquery mousedown & mouseup .

$("img.hoverImage")
.mouseenter(function () {
    var src = $(this).attr("src").match(/[^\.]+/) + "_hover.png";
    $(this).attr("src", src);
})
.mouseleave(function () {
    var src = $(this).attr("src").replace("_hover", "");
    $(this).attr("src", src);
});
.mousedown(function () {
   $(this).trigger('mouseleave');
})
.mouseup(function () {
     $(this).trigger('mouseenter');
});
...