Chosen: Выпадающий список внизу страницы ломает макет

Созданный на 5 авг. 2011  ·  60Комментарии  ·  Источник: harvesthq/chosen

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

Feature Request

Самый полезный комментарий

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

Код немного подробен — намеренно так, чтобы вы могли видеть, что происходит.

$('#my-select').on('chosen:showing_dropdown', function(event, params) {
   var chosen_container = $( event.target ).next( '.chosen-container' );
   var dropdown = chosen_container.find( '.chosen-drop' );
   var dropdown_top = dropdown.offset().top - $(window).scrollTop();
   var dropdown_height = dropdown.height();
   var viewport_height = $(window).height();

   if ( dropdown_top + dropdown_height > viewport_height ) {
      chosen_container.addClass( 'chosen-drop-up' );
   }

});
$('#my-select').on('chosen:hiding_dropdown', function(event, params) {
   $( event.target ).next( '.chosen-container' ).removeClass( 'chosen-drop-up' );
});

Я не публиковал никаких CSS, потому что мой собственный, поэтому он никому не поможет. Но вы можете начать с

.chosen-container.chosen-drop-up .chosen-drop{
   top: auto;
   bottom: 100%;
}

... который поместит раскрывающийся список над элементом ввода. Остальное — возиться с границами и так далее.

Надеюсь, это поможет кому-то.

Все 60 Комментарий

+1

+1

+1

+1

Написал в него небольшую функцию, теперь отлично работает для нумерации страниц
http://jsfiddle.net/adamelevate/WFejY/

Мой выведен из класса css в поле выбора, поэтому он все еще не динамичен, простите....

+1

+1

+1

Это обязательная функция

+1

еще не исправили?

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

Я успешно избежал этого, убедившись, что все родительские элементы имеют overflow:visible.

+1
исправлено в моем проекте, как это

 #selectId_chzn .chzn-drop {
    bottom: 20px;
    top: auto !important;
}

но я надеюсь, что вы можете сделать это автоматически

Значит, никто не нашел способ справиться с этим, используя интеллектуальное обнаружение границ? Мой проект не позволяет мне роскошь конкретно идентифицировать элементы Chosen на основе контейнера, который гарантированно вызовет переполнение. Я немного подумал о том, как заставить Избранного распознавать, есть ли место для расширения вниз, а если нет, применить стиль, аналогичный тому, что предложил @coldman333 , и еще не придумал отличный или надежный способ сделать это, . Также потребуется указать выпадающему списку border-top и удалить его border-bottom , чтобы сохранить согласованность стилей. Возможно, вместо этого следует просто применить специальный класс CSS, используя jQuery addClass() для экономии вычислительной мощности.

+1

Хорошо, у меня есть работающее решение, но оно просто как-то взломано в скомпилированном файле javascript. Я вставлю код сюда, если кто-то захочет создать из него запрос на извлечение.

Если он обнаружит, что раскрывающийся список будет простираться ниже окна, он изменит его размер и добавит полосу прокрутки, но все равно опустится вниз. ЕСЛИ между раскрывающимся списком и окном меньше 100 пикселей, тогда он добавит класс chzn-above в раскрывающийся список и покажет его над вводом.

/выбранный/выбранный.jquery.js
[вокруг строки 326]

``` .js
this.search_results = this.container.find('ul.chzn-results').first();
// Запускаем дополнительный код
this.search_results.data('initialMaxHeight', this.search_results.css('max-height'));
// Конец дополнительного кода
this.search_field_scale();

[around line 568]

``` .js
Chosen.prototype.results_show = function() {
  var dd_top;
  if (!this.is_multiple) {
    this.selected_item.addClass("chzn-single-with-drop");
    if (this.result_single_selected) {
      this.result_do_highlight(this.result_single_selected);
    }
  }
  dd_top = this.is_multiple ? this.container.height() : this.container.height() - 1;
  this.dropdown.css({
    "top": dd_top + "px",
    "left": 0
  });

  // Start additional code
  this.search_results.css('max-height', 'none');

  var windowHeight = $(window).height() + $('html').scrollTop(),
      dropdownHeight = this.dropdown.height(),
      dropdownTop    = Math.ceil(this.dropdown.offset().top),
      totalHeight    = dropdownHeight + dropdownTop;

  if (totalHeight > windowHeight) {
    var difference = totalHeight - windowHeight,
        height     = dropdownHeight - difference;

    if (height > 100) {
      this.search_results.css('max-height', height);
    } else {
      this.dropdown.addClass('chzn-above');
      this.search_results.css('max-height', this.search_results.data('initialMaxHeight'));
    }
  } else {
    this.search_results.css('max-height', this.search_results.data('initialMaxHeight'));
  }
  // End additional code

  this.results_showing = true;
  this.search_field.focus();
  this.search_field.val(this.search_field.val());
  return this.winnow_results();
};

/выбранный/выбранный.css

.css /* Add this rule */ .chzn-container .chzn-drop.chzn-above { top:auto !important; bottom:29px; border:solid #aaa; border-width:1px 1px 0 1px; }

Потрясающий

+1

Привет,
Эта проблема исправлена. Но в случае с chzn-select-deselect опция не работает для этой функции. Пожалуйста, проверьте это.

Спасибо,
Сатиш Бабу

+1

Я не вижу исправления в примерах…

Я хотел, чтобы мой выпадающий список «выпадал». Я исправил свою проблему, изменив top на .chzn-drop на отрицательное значение max-height на chzn-results . Также изменено max-height просто на height , иначе он создает пустое место, если в выпадающем списке недостаточно результатов. Я знаю, что это уродливое решение, но оно сработало для меня.

ps Требуется немного изменить стиль. Например: граница будет отсутствовать вверху и должна быть удалена внизу выпадающего списка.

Пожалуйста, работайте над #1330, чтобы решить эту проблему! Столкнулись с этой серьезной ошибкой в ​​нашем приложении — selected просто не работает, когда находится у нижнего края экрана.

+1

много +1

+1

+1

+1
у кого-нибудь есть рабочее решение?

+1

ребята, кажется, огромный спрос, как дела?

Привет!

Добавьте это в файл CSS:

.chosen-container-active.chosen-with-dropup .chosen-single{
  -moz-border-radius-topright: 0 !important;
  border-top-right-radius: 0 !important;
  -moz-border-radius-topleft: 0 !important;
  border-top-left-radius: 0 !important;
}

.chosen-dropup {
  top: auto !important;
  bottom: 23px;
  border: solid #aaa;
  border-width: 1px 1px 0 1px;
  margin-top: -1px;
  border-radius: 4px 4px 0px 0px !important;
}

Затем измените файл JS:

Найдите Chosen.prototype.results_hide = function() и добавьте это:

this.container.removeClass("chosen-with-drop");
//Added by Fenistil
this.container.removeClass("chosen-with-dropup");
//End
this.form_field_jq.trigger("chosen:hiding_dropdown", {

Найдите Chosen.prototype.close_field = function() и добавьте это:

this.container.removeClass("chosen-container-active");
//Added by Fenistil
this.container.removeClass("chosen-with-dropup");
//End
this.clear_backstroke();

Найдите Chosen.prototype.activate_field = function() и добавьте это:

this.container.addClass("chosen-container-active");
//Added by Fenistil
var windowHeight = $(window).height() + $('html').scrollTop(),
  totalHeight  = this.dropdown.height() + Math.ceil(this.dropdown.offset().top);

if (totalHeight > windowHeight) {
  this.container.addClass("chosen-with-dropup");
  this.dropdown.addClass('chosen-dropup');
}
//End
this.active_field = true;

Найдите Chosen.prototype.results_show = function() и добавьте это:

this.container.addClass("chosen-with-drop");
//Added by Fenistil
var windowHeight = $(window).height() + $('html').scrollTop(),
      totalHeight  = this.dropdown.height() + Math.ceil(this.dropdown.offset().top);

if (totalHeight > windowHeight) {
  this.container.addClass("chosen-with-dropup");
  this.dropdown.addClass('chosen-dropup');
}
//End
this.results_showing = true;
this.search_field.focus();

Привет!

PS.: Спасибо coreyworrell, это основано на его коде.

ОБНОВИТЬ:

Эй, спасибо за это решение @fenisteel. Это работает хорошо только с одним небольшим исключением. Он рассчитывает, нужно ли опускаться вверх или вниз, на основе высоты окна, а не положения прокрутки. Он не является динамическим, как выбор начальной загрузки. Например, при загрузке страницы пользователь находится в верхней части страницы, выбранный в нижней части страницы будет выпадающим. Но если пользователь прокручивает страницу вниз, что в конечном итоге создает больше места для выбранной нижней части, она должна опускаться, как обычно.

http://silviomoreto.github.io/bootstrap-select/

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

Спасибо @fenisteel. Приятно видеть, что спустя три года есть достойное решение.

Почему спустя столько лет нет динамичных решений? Мне очень нравится управление, кроме этой проблемы.

Спасибо @fenisteel. Ваше решение отлично работает и очень четкие инструкции о том, что нужно изменить.

@fenisteel , можете ли вы отправить PR со своими изменениями?

+1 к пиару от @fenisteel. Я использую Chosen через Bower в производстве и не могу редактировать файлы библиотеки в репозитории.

+1 хотелось бы, чтобы это могло выйти как можно скорее в версии 1.3.1

Я превратил изменения @fenisteel в PR, см . https://github.com/harvesthq/chosen/pull/2312.

Это работает для меня

jQuery('.chosen-single').click(function() {
        var $chosePosition = this.getBoundingClientRect(),
            $choseDropListHeight = $(this).next().outerHeight();
        if($(this).hasClass('above')) $(this).removeClass('above');
        if (($chosePosition.bottom + $choseDropListHeight + 10) > $(window).height() && ($chosePosition.top - $choseDropListHeight) > 10) {
            $(this).next().addClass("above");
            $(this).addClass("above");
        }
        else {
            $(this).next().removeClass("above");
            $(this).removeClass("above");
        }
        $chosensingle = $(this);
        $chosenvar = this;
        $(window).bind('mousewheel DOMMouseScroll', function(event){
            $chosePosition = $chosenvar.getBoundingClientRect(),
                $choseDropListHeight = $chosensingle.next().outerHeight();
            console.log($chosePosition.bottom + $choseDropListHeight + 10, '-',$(window).height(), '-',$chosePosition.top - $choseDropListHeight);
            if (($chosePosition.bottom + $choseDropListHeight + 10) > $(window).height() && ($chosePosition.top - $choseDropListHeight) > 10) {
                $chosensingle.next().addClass("above");
                $chosensingle.addClass("above");
            }
            else {
                $chosensingle.next().removeClass("above");
                $chosensingle.removeClass("above");
            }
        });
    });

@peimn у меня это не сработало

Это было открыто, как давно? почему это не было приоритетом для исправления?

+1...

+1

+1

Есть ETA по этому поводу? Очень нужная функция. В настоящее время я использую решение выше, но мне нужно взломать его. Было бы здорово, если бы это было частью исходного кода.

+1 - это был невыполненный запрос в течение 4 лет. Есть ли шанс попасть туда?

+1

+1

Я бы порекомендовал использовать Tether.js для позиционирования раскрывающегося списка, это гораздо лучший способ, потому что он помещает его в тело, а не туда, где находится сам элемент select , поэтому любой overflow:hidden на родительском элементе элемент не обрезает его. Кроме того, Tether.js очень умен в позиционировании в соответствии с областью просмотра, и вы можете контролировать все.

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

Код немного подробен — намеренно так, чтобы вы могли видеть, что происходит.

$('#my-select').on('chosen:showing_dropdown', function(event, params) {
   var chosen_container = $( event.target ).next( '.chosen-container' );
   var dropdown = chosen_container.find( '.chosen-drop' );
   var dropdown_top = dropdown.offset().top - $(window).scrollTop();
   var dropdown_height = dropdown.height();
   var viewport_height = $(window).height();

   if ( dropdown_top + dropdown_height > viewport_height ) {
      chosen_container.addClass( 'chosen-drop-up' );
   }

});
$('#my-select').on('chosen:hiding_dropdown', function(event, params) {
   $( event.target ).next( '.chosen-container' ).removeClass( 'chosen-drop-up' );
});

Я не публиковал никаких CSS, потому что мой собственный, поэтому он никому не поможет. Но вы можете начать с

.chosen-container.chosen-drop-up .chosen-drop{
   top: auto;
   bottom: 100%;
}

... который поместит раскрывающийся список над элементом ввода. Остальное — возиться с границами и так далее.

Надеюсь, это поможет кому-то.

@Taeon Большое спасибо за ваше решение, оно работает отлично!
Это действительно должно быть объединено.
Не могли бы вы отправить запрос на вытягивание? (еще один из 80, я знаю, но все же...)

@claudio-silva: поскольку автор до сих пор игнорировал все соответствующие PR, я не уверен, что в этом есть большой смысл. И в любом случае, этот код специально НЕ предназначен для слияния с ядром — он предназначен для работы без изменения файлов ядра. Таким образом, он все равно будет работать, даже если я выберу обновление.

+1

Я реализовал решение, предложенное @Taeon (ну, более или менее, вычисления отличаются из-за особенностей приложения)
Вот CSS, который я придумал, чтобы все выглядело нормально. (Здесь не профессионал css)

.chosen-container.chosen-drop-up .chosen-drop {
  border-bottom: 0;
  border-radius: 4px 4px 0 0;
  border-top: 1px solid #aaa;
  bottom: 100%;
  box-shadow: none;
  top: auto;
}

.chosen-container-active.chosen-with-drop.chosen-drop-up .chosen-single {
  background-image: -webkit-gradient(linear,50% 0,50% 100%,color-stop(40%,#eee),color-stop(90%,#fff));
  background-image: -webkit-linear-gradient(#fff 40%,#eee 90%);
  background-image: -moz-linear-gradient(#fff 40%,#eee 90%);
  background-image: -o-linear-gradient(#fff 40%,#eee 90%);
  background-image: linear-gradient(#fff 40%,#eee 90%);
  border-radius: 0 0 4px 4px;
  border-top: 0;
  box-shadow: 0 1px 0 #fff inset;
}

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

JS

$('select').on('chosen:showing_dropdown chosen:hiding_dropdown', function(e){
    var chosen_container = $( e.target ).next( '.chosen-container' ),
        classState = e.type == 'chosen:showing_dropdown' && dropdownExceedsBottomViewport();

    function dropdownExceedsBottomViewport(){
        var dropdown        = chosen_container.find( '.chosen-drop' ),
            dropdown_top    = dropdown.offset().top - document.documentElement.scrollTop,
            dropdown_height = dropdown.height(),
            viewport_height = document.documentElement.clientHeight;

        return dropdown_top + dropdown_height > viewport_height;
    }

    chosen_container.toggleClass( 'chosen-drop-up', classState );
});

СКСС

.chosen-container {
    &.chosen-drop-up .chosen-drop {
        border-bottom: 0;
        border-radius: 4px 4px 0 0;
        border-top: 1px solid #aaa;
        bottom: 100%;
        box-shadow: 0 -4px 5px rgba(#000, .15);
        top: auto;
    }
}

.chosen-container-active {
    &.chosen-with-drop {
            .chosen-single:not(.chosen-drop-up) {
                border: 1px solid #aaa;
                border-bottom-right-radius: 0;
                border-bottom-left-radius: 0;
                //background-image:linear-gradient(#eee 20%, #fff 80%);
                //box-shadow: 0 1px 0 #fff inset;
            }
            &.chosen-drop-up{
                .chosen-drop{
                    display:flex;
                    flex-direction: column-reverse;
                }
                .chosen-single {
                    // background-image: linear-gradient(#FFF 40%, #EEE 90%);
                    border-radius: 0 0 4px 4px;
                    border-top: 0;
                    box-shadow: 0 1px 0 #FFF inset;
                    border-top-right-radius: 0;
                    border-top-left-radius: 0;
                }
            }
        }
    }
}

@Taeon, его решение отлично работает для меня
+1

хорошо, у меня была такая же проблема. Итак, я исправил это, может быть, не самым элегантным, но это сработало для меня. Я только что добавил margin-top: -332px; на .chzn-drop

@Taeon Спасибо за этот код! Это сэкономило мне несколько часов или разочарование :)

@yairEO - Это должно полностью проникнуть в ядро! Работает как шарм!

@yairEO - Хорошее решение, но если у нас есть более одного раскрывающегося списка с этим решением, если один из раскрывающихся списков выбора вызывает перезагрузку ajax, класс «выбранный раскрывающийся список» больше не добавляется в выбранный список.

@Taeon - ваше решение сработало, когда я изменил селектор идентификатора на класс для нескольких выбранных вариантов на странице 👍

Была ли эта страница полезной?
0 / 5 - 0 рейтинги