Я работаю над страницей редактирования фотографий. Цель состоит в том, чтобы пользователи могли настраивать такие параметры, как оттенок, насыщенность, яркость, загружая изображения, а затем редактируя их с помощью ползунков диапазона. Чтобы программа хорошо работала в мобильных браузерах, я решил использовать библиотеку rangelider.js. После того, как я получил начальный слайдер и поработал, я решил попробовать более продвинутый дизайн. Я нашел этот дизайн в Интернете, и мне он понравился. Моя цель сейчас - иметь несколько ползунков, каждый из которых отображает свое значение, как связанный ползунок. У меня проблемы с этим. Для простоты я сейчас форматирую свой слайдер с помощью стандартного CSS из rangelider.js. Я могу создать один слайдер, который ведет себя как слайдер в связанном дизайне, но теперь я хочу обобщить это на несколько слайдеров, и именно здесь у меня возникли проблемы. В единой конструкции код, относящийся к созданию ползунка диапазонов, выглядит следующим образом:

//custom slider javascript
var $element = $('input[type="range"]');
var $handle;


$element
  .rangeslider({
    polyfill: false,
    onInit: function() {
      $handle = $('.rangeslider__handle', this.$range);
      updateHandle($handle[0], this.value);
    }
  })
  .on('input', function() {
    updateHandle($handle[0], this.value);
  });

function updateHandle(el, val) {
  el.textContent = " " + "$" + val + " ";
}

$(document).ready(function(){
  
  //when slider changes, hide start message
$("input").on("change", function() {
  $("#helper").fadeOut("slow");
});

//promo-box
$("#js-promo-box").hide();
$("#promo-link").on("click", function(){
  $("#js-promo-box").slideToggle();
  return false;
});
  
});    

Если я оставлю эту функцию без изменений при объявлении нескольких ползунков диапазона в html-коде, то ошибок не будет, но только вход диапазона, который был объявлен последним, будет иметь метку, отображающую его значение. Но все ползунки смогут изменить это значение. Я сузил эту проблему до того факта, что существует только одна переменная $ handle. Чтобы исправить это, я создал код ниже

<script>
        
        //custom slider javascript
      
        var $element = $('input[type="range"]'); // Gets all the elements of type range
        var $handle = new Array($element.length);
    
        console.log($element);
        for(i=0; i<$element.length;i++){
            console.log($element[i]);
            var $temp = $($element[i]);
            $temp.rangeslider({
                polyfill: false,
                onInit: function() {
                    $handle[i] =  $('.rangeslider__handle', this.$range);
                    updateHandle($handle[i][0], this.value);
                }
            })
            .on('input',function() {
                updateHandle($handle[i][0], this.value);
            });
        }

        function updateHandle(el, val) {
          console.log(el);
          el.textContent = " " + "$" + val + " ";
        }
        
        $(document).ready(function(){  
            //when slider changes, hide start message
            $("input").on("change", function() {
              $("#helper").fadeOut("slow");
            });

            //promo-box
            $("#js-promo-box").hide();
            $("#promo-link").on("click", function(){
              $("#js-promo-box").slideToggle();
              return false;
            });  
        });
    </script>

Теперь $ handler - это массив, в котором столько записей, сколько входов диапазона. При запуске все инициализируется нормально, и начальные значения ползунков отображаются должным образом. Несмотря на это, когда я меняю ползунок, я получаю сообщение об ошибке «Uncaught TypeError: не удается получить доступ к свойству 0, $ handle [i] не определен». Это происходит в

.on('input',function() {
                    updateHandle($handle[i][0], this.value);
                });

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

Спасибо

1
Cole Harlow 14 Май 2021 в 07:04

1 ответ

Лучший ответ

Оказывается, это скорее проблема с переменной областью видимости. Невероятно полезный ресурс для объяснения этой проблемы и ее решения - "Переменная обратных вызовов JavaScript Проблема масштаба » Итая Грудева.

По сути, поскольку переменная обратного вызова создается в цикле for, использование переменной i (переменная цикла) не является хорошей идеей. Это связано с тем, что при последующих вызовах значение i не известно функции обратного вызова, поскольку оно выходит за пределы ее области. Есть несколько способов исправить это, как описано Итаем Грудевым. Самый простой - поменять

for(var i=0; i<$element.length;i++){ ...

Into for (let i = 0; i <$ element.length; i ++) {...

Но я считаю, что это поддерживается не всеми браузерами. Вместо этого я создал встроенное закрытие. Это позволяет мне создать переменную внутри замыкания, которая содержит значение i для определенного ползунка. Таким образом, каждый обратный вызов может знать, какому ползунку он соответствует, и соответствующим образом реагировать. Мой последний код ниже

for(var i=0; i<$element.length;i++){
            console.log($element[i]);
            var $temp = $($element[i]);
            $temp.rangeslider({
                polyfill: false,
                onInit: function() {
                    //On init this is fine I don't need a separate definition of i
                    $handle[i] =  $('.rangeslider__handle', this.$range);
                    updateHandle($handle[i][0], this.value);
                }
            })
            .on('input', (function() {
                var j = i;
                return function() {
                    updateHandle($handle[j][0], this.value);
                }
            })() );

Теперь вместо вызова функции для настройки значений ползунка этот скрипт создает функцию для создания новой функции, а затем вызывает эту функцию. Созданная функция имеет доступ к переменной j, чего раньше не хватало.

0
Cole Harlow 17 Май 2021 в 14:51