HTML5: İki girişli kaydırıcı mümkün mü?


106

Örneğin bir fiyat aralığı seçmek için iki giriş değerine sahip bir HTML5 kaydırıcısı yapmak mümkün müdür? Eğer öyleyse, nasıl yapılabilir?

Yanıtlar:


68

Hayır, HTML5 aralığı girişi yalnızca bir girişi kabul eder. Bu görev için jQuery UI aralığı kaydırıcısı gibi bir şey kullanmanızı tavsiye ederim .


Bağlantı ve bilgi için teşekkürler. Bunu mobil cihazlarda çalıştırıp çalıştıramayacağımı kontrol etmem gerekiyor.
sık

36
Bir süre önce ... ama iki kaydırıcıyı tam olarak üst üste yerleştirerek bir çift kaydırıcıyı "taklit etmeyi" başardım. Biri minimum değerden başlar, diğeri maksimum değerden başlar. Sanırım bu hile ama ... benim için işe yarıyor.
sık

WhatWG en azından uygulamayı tartışıyor: html.spec.whatwg.org/multipage/…
kunambi

7
İonRangeSlider'ı jQuery UI kaydırıcısından biraz daha çok seviyorum
Charlotte

5
Diğer bir yaklaşım, yan yana giriş kontrolleri ile çift kaydırıcıyı "taklit etmektir": simple.gy/blog/range-slider-two-handles
SimplGy

84

Bir süredir hafif, bağımlılık içermeyen bir ikili kaydırıcı arıyordum (sadece bunun için jQuery'yi içe aktarmak çılgınca görünüyordu) ve orada çok fazla görünmüyor. Ben değiştirerek sona erdi Devetabaný koduna @ ve gerçekten de öyle biraz.


Maalesef Android 4.0.4 Mobile Safari 4.0 tarayıcı ile çalışmıyor. :-(
erik

@erik Bu sürümleri test etmek için gerçekten iyi bir yolum yok, ancak bu benim için Safari'nin en son sürümüyle Android 5.0'da çalışıyor (google play 1.2 diyor, bu yüzden 4.0'ınız konusunda kafam karıştı). Eğer çözersen, bilmek isterim.
Gary

1
Bu gerçekten zekice! Sorunu herhangi bir bağımlılık olmadan incelikle çözdüğü için nasıl doğru cevap olarak işaretlenmediğini merak ediyorum. Sadece bunu yapmak için jQuery eklemek kesinlikle abartılı.
zanona

@zanona Teşekkürler ama doğru cevap 4 yıl önce işaretlenmişti, bu yüzden OP'nin başka bir çözüme pek önem verdiğini düşünmüyorum.
Gary

12
Yaklaşımınızı gerçekten beğendim ve kullanım durumuma uyarlamaya çalıştım, ancak sahip olduğum bazı tasarım özelliklerinin (örneğin, aralığın "aktif" bölümünü parçanın geri kalanından farklı bir şekilde renklendirdiğini fark ettiğimde vazgeçmek zorunda kaldım) ) bununla uygulanması mümkün değildir. Bu yüzden başka bir çözüm aradım ve bu gerçekten güzel projeyi buldum: refreshless.com/nouislider Bağımlılık içermez, hoş ve temiz bir API'ye sahiptir, AMD uyumludur ve birçok seçenek sunar. Şimdiye kadar ondan oldukça memnunum.
Felix Wienberg

39

Geç geliyor, ancak noUiSlider , kabul edilen yanıtın sahip olmadığı bir jQuery-ui bağımlılığından kaçınıyor. Tek "uyarı", IE desteğinin IE9 için ve daha yeni olması, eğer eski IE sizin için bir anlaşma kırıcı ise.

Ayrıca ücretsiz, açık kaynaklıdır ve ticari projelerde kısıtlama olmaksızın kullanılabilir.

Kurulum: noUiSlider'ı indirin, CSS ve JS dosyasını site dosya sisteminizde herhangi bir yere çıkarın ve ardından CSS'ye baştan ve gövdeden JS'ye bağlayın:

<!-- In <head> -->
<link href="nouislider.min.css" rel="stylesheet">

<!-- In <body> -->
<script src="nouislider.min.js"></script>

Örnek kullanım: 0'dan 100'e giden ve 20-80'e ayarlanmaya başlayan bir kaydırıcı oluşturur.

HTML:

<div id="slider">
</div>

JS:

var slider = document.getElementById('slider');

noUiSlider.create(slider, {
    start: [20, 80],
    connect: true,
    range: {
        'min': 0,
        'max': 100
    }
});

1
İnanılmaz vay!! Bu tam olarak ihtiyacımız olan şeydi ve harika bir şekilde geliştirildi! WHITOUT jQuery
DavidTaubmann

Yine de bunu kendiniz eklemek ve projeye bir talep göndermek oldukça kolay olmalı?
dario_ramos

3
Kazmadım ama kaydırıcıyı klavyeyle kullanabilirim, bu yüzden şimdi uygulandığını düşünüyorum @ptrin :)
Edu Ruiz

24

Elbette, birbirini kaplayan iki kaydırıcıyı kullanabilir ve seçicilerin minimum / maksimum değerleri (@Garys'de olduğu gibi) aşmadığı bir miktar javascript (aslında en fazla 5 satır) ekleyebilirsiniz.

Ekte, yapabileceklerinizi göstermek için bazı CSS3 stillerini içeren mevcut bir projeden uyarlanmış kısa bir pasaj bulacaksınız (yalnızca webkit). Ayrıca seçilen değerleri görüntülemek için bazı etiketler ekledim.

JQuery kullanıyor ancak bir vanillajs sürümü sihir değil.

    (function() {

        function addSeparator(nStr) {
            nStr += '';
            var x = nStr.split('.');
            var x1 = x[0];
            var x2 = x.length > 1 ? '.' + x[1] : '';
            var rgx = /(\d+)(\d{3})/;
            while (rgx.test(x1)) {
                x1 = x1.replace(rgx, '$1' + '.' + '$2');
            }
            return x1 + x2;
        }

        function rangeInputChangeEventHandler(e){
            var rangeGroup = $(this).attr('name'),
                minBtn = $(this).parent().children('.min'),
                maxBtn = $(this).parent().children('.max'),
                range_min = $(this).parent().children('.range_min'),
                range_max = $(this).parent().children('.range_max'),
                minVal = parseInt($(minBtn).val()),
                maxVal = parseInt($(maxBtn).val()),
                origin = $(this).context.className;

            if(origin === 'min' && minVal > maxVal-5){
                $(minBtn).val(maxVal-5);
            }
            var minVal = parseInt($(minBtn).val());
            $(range_min).html(addSeparator(minVal*1000) + ' €');


            if(origin === 'max' && maxVal-5 < minVal){
                $(maxBtn).val(5+ minVal);
            }
            var maxVal = parseInt($(maxBtn).val());
            $(range_max).html(addSeparator(maxVal*1000) + ' €');
        }

     $('input[type="range"]').on( 'input', rangeInputChangeEventHandler);
})();
body{
font-family: sans-serif;
font-size:14px;
}
input[type='range'] {
  width: 210px;
  height: 30px;
  overflow: hidden;
  cursor: pointer;
    outline: none;
}
input[type='range'],
input[type='range']::-webkit-slider-runnable-track,
input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
    background: none;
}
input[type='range']::-webkit-slider-runnable-track {
  width: 200px;
  height: 1px;
  background: #003D7C;
}

input[type='range']:nth-child(2)::-webkit-slider-runnable-track{
  background: none;
}

input[type='range']::-webkit-slider-thumb {
  position: relative;
  height: 15px;
  width: 15px;
  margin-top: -7px;
  background: #fff;
  border: 1px solid #003D7C;
  border-radius: 25px;
  z-index: 1;
}


input[type='range']:nth-child(1)::-webkit-slider-thumb{
  z-index: 2;
}

.rangeslider{
    position: relative;
    height: 60px;
    width: 210px;
    display: inline-block;
    margin-top: -5px;
    margin-left: 20px;
}
.rangeslider input{
    position: absolute;
}
.rangeslider{
    position: absolute;
}

.rangeslider span{
    position: absolute;
    margin-top: 30px;
    left: 0;
}

.rangeslider .right{
   position: relative;
   float: right;
   margin-right: -5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div class="rangeslider">
                                <input class="min" name="range_1" type="range" min="1" max="100" value="10" />
                                <input class="max" name="range_1" type="range" min="1" max="100" value="90" />
                                <span class="range_min light left">10.000 €</span>
                                <span class="range_max light right">90.000 €</span>
                            </div>


7
Hey harika görünüyor! ancak Firefox'ta çalışmıyor, yalnızca maksimum girişi sürükleyebilirsiniz. Düzeltmeyi başardın mı?
Toni Michel Caubet

6
Oh adamım. Buraya neredeyse aynı şeyi eklemek için geldim! simple.gy/blog/range-slider-two-handles Benim versiyonum, girişleri yan yana koyar, ancak aynı zamanda ikili girişler kullanır.
SimplGy

9

Aslında betiğimi doğrudan html'de kullandım. Ancak javascript'te bu olay için bir girdi olay dinleyicisi eklediğinizde, verileri otomatik olarak verir. Sadece gereksinimlerinize göre değeri atamanız gerekir.

[slider] {
  width: 300px;
  position: relative;
  height: 5px;
  margin: 45px 0 10px 0;
}

[slider] > div {
  position: absolute;
  left: 13px;
  right: 15px;
  height: 5px;
}
[slider] > div > [inverse-left] {
  position: absolute;
  left: 0;
  height: 5px;
  border-radius: 10px;
  background-color: #CCC;
  margin: 0 7px;
}

[slider] > div > [inverse-right] {
  position: absolute;
  right: 0;
  height: 5px;
  border-radius: 10px;
  background-color: #CCC;
  margin: 0 7px;
}


[slider] > div > [range] {
  position: absolute;
  left: 0;
  height: 5px;
  border-radius: 14px;
  background-color: #d02128;
}

[slider] > div > [thumb] {
  position: absolute;
  top: -7px;
  z-index: 2;
  height: 20px;
  width: 20px;
  text-align: left;
  margin-left: -11px;
  cursor: pointer;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
  background-color: #FFF;
  border-radius: 50%;
  outline: none;
}

[slider] > input[type=range] {
  position: absolute;
  pointer-events: none;
  -webkit-appearance: none;
  z-index: 3;
  height: 14px;
  top: -2px;
  width: 100%;
  opacity: 0;
}

div[slider] > input[type=range]:focus::-webkit-slider-runnable-track {
  background: transparent;
  border: transparent;
}

div[slider] > input[type=range]:focus {
  outline: none;
}

div[slider] > input[type=range]::-webkit-slider-thumb {
  pointer-events: all;
  width: 28px;
  height: 28px;
  border-radius: 0px;
  border: 0 none;
  background: red;
  -webkit-appearance: none;
}

div[slider] > input[type=range]::-ms-fill-lower {
  background: transparent;
  border: 0 none;
}

div[slider] > input[type=range]::-ms-fill-upper {
  background: transparent;
  border: 0 none;
}

div[slider] > input[type=range]::-ms-tooltip {
  display: none;
}

[slider] > div > [sign] {
  opacity: 0;
  position: absolute;
  margin-left: -11px;
  top: -39px;
  z-index:3;
  background-color: #d02128;
  color: #fff;
  width: 28px;
  height: 28px;
  border-radius: 28px;
  -webkit-border-radius: 28px;
  align-items: center;
  -webkit-justify-content: center;
  justify-content: center;
  text-align: center;
}

[slider] > div > [sign]:after {
  position: absolute;
  content: '';
  left: 0;
  border-radius: 16px;
  top: 19px;
  border-left: 14px solid transparent;
  border-right: 14px solid transparent;
  border-top-width: 16px;
  border-top-style: solid;
  border-top-color: #d02128;
}

[slider] > div > [sign] > span {
  font-size: 12px;
  font-weight: 700;
  line-height: 28px;
}

[slider]:hover > div > [sign] {
  opacity: 1;
}
<div slider id="slider-distance">
  <div>
    <div inverse-left style="width:70%;"></div>
    <div inverse-right style="width:70%;"></div>
    <div range style="left:0%;right:0%;"></div>
    <span thumb style="left:0%;"></span>
    <span thumb style="left:100%;"></span>
    <div sign style="left:0%;">
      <span id="value">0</span>
    </div>
    <div sign style="left:100%;">
      <span id="value">100</span>
    </div>
  </div>
  <input type="range" value="0" max="100" min="0" step="1" oninput="
  this.value=Math.min(this.value,this.parentNode.childNodes[5].value-1);
  let value = (this.value/parseInt(this.max))*100
  var children = this.parentNode.childNodes[1].childNodes;
  children[1].style.width=value+'%';
  children[5].style.left=value+'%';
  children[7].style.left=value+'%';children[11].style.left=value+'%';
  children[11].childNodes[1].innerHTML=this.value;" />

  <input type="range" value="100" max="100" min="0" step="1" oninput="
  this.value=Math.max(this.value,this.parentNode.childNodes[3].value-(-1));
  let value = (this.value/parseInt(this.max))*100
  var children = this.parentNode.childNodes[1].childNodes;
  children[3].style.width=(100-value)+'%';
  children[5].style.right=(100-value)+'%';
  children[9].style.left=value+'%';children[13].style.left=value+'%';
  children[13].childNodes[1].innerHTML=this.value;" />
</div>


Sen bir dahisin! Bu harika bir fikir ve stiliniz de harika.
Puspam

2

Soru şuydu: "Örneğin bir fiyat aralığı seçmek için iki giriş değerine sahip bir HTML5 kaydırıcısı yapmak mümkün müdür? Öyleyse, nasıl yapılabilir?"

On yıl önce cevap muhtemelen "Hayır" idi. Ancak zaman değişti. In 2020 , bir yaratmak nihayet mümkündür iki parmakla tamamen erişilebilir, yerli olmayan jquery HTML5 kaydırıcı fiyat aralıkları için. Bu çözümü zaten oluşturduktan sonra bu postayı bulursa ve uygulamamı burada paylaşmanın güzel olacağını düşündüm.

Bu uygulama, mobil Chrome ve Firefox (Android) ve Chrome ve Firefox (Linux) üzerinde test edilmiştir. Diğer platformlardan emin değilim ama oldukça iyi olmalı. Geri bildiriminizi almak ve bu çözümü geliştirmek isterim.

Bu çözüm, bir sayfada birden çok örneğe izin verir ve ekran okuyucular için açıklayıcı etiketlere sahip yalnızca iki girişten (her biri) oluşur. Başparmak boyutunu, ızgara etiketlerinin miktarına göre ayarlayabilirsiniz. Ayrıca, kaydırıcıyla etkileşim kurmak için dokunma, klavye ve fareyi kullanabilirsiniz. Değer, 'girişte' olay dinleyicisi nedeniyle ayarlama sırasında güncellenir.

İlk yaklaşımım kaydırıcıları kaplamak ve kırpmaktı. Ancak bu, birçok tarayıcı bağımlılığına sahip karmaşık kodlarla sonuçlandı. Sonra çözümü 'satır içi' olan iki kaydırıcıyla yeniden yarattım. Aşağıda bulacağınız çözüm budur.

var thumbsize = 14;

function draw(slider,splitvalue) {

    /* set function vars */
    var min = slider.querySelector('.min');
    var max = slider.querySelector('.max');
    var lower = slider.querySelector('.lower');
    var upper = slider.querySelector('.upper');
    var legend = slider.querySelector('.legend');
    var thumbsize = parseInt(slider.getAttribute('data-thumbsize'));
    var rangewidth = parseInt(slider.getAttribute('data-rangewidth'));
    var rangemin = parseInt(slider.getAttribute('data-rangemin'));
    var rangemax = parseInt(slider.getAttribute('data-rangemax'));

    /* set min and max attributes */
    min.setAttribute('max',splitvalue);
    max.setAttribute('min',splitvalue);

    /* set css */
    min.style.width = parseInt(thumbsize + ((splitvalue - rangemin)/(rangemax - rangemin))*(rangewidth - (2*thumbsize)))+'px';
    max.style.width = parseInt(thumbsize + ((rangemax - splitvalue)/(rangemax - rangemin))*(rangewidth - (2*thumbsize)))+'px';
    min.style.left = '0px';
    max.style.left = parseInt(min.style.width)+'px';
    min.style.top = lower.offsetHeight+'px';
    max.style.top = lower.offsetHeight+'px';
    legend.style.marginTop = min.offsetHeight+'px';
    slider.style.height = (lower.offsetHeight + min.offsetHeight + legend.offsetHeight)+'px';
    
    /* correct for 1 off at the end */
    if(max.value>(rangemax - 1)) max.setAttribute('data-value',rangemax);

    /* write value and labels */
    max.value = max.getAttribute('data-value'); 
    min.value = min.getAttribute('data-value');
    lower.innerHTML = min.getAttribute('data-value');
    upper.innerHTML = max.getAttribute('data-value');

}

function init(slider) {
    /* set function vars */
    var min = slider.querySelector('.min');
    var max = slider.querySelector('.max');
    var rangemin = parseInt(min.getAttribute('min'));
    var rangemax = parseInt(max.getAttribute('max'));
    var avgvalue = (rangemin + rangemax)/2;
    var legendnum = slider.getAttribute('data-legendnum');

    /* set data-values */
    min.setAttribute('data-value',rangemin);
    max.setAttribute('data-value',rangemax);
    
    /* set data vars */
    slider.setAttribute('data-rangemin',rangemin); 
    slider.setAttribute('data-rangemax',rangemax); 
    slider.setAttribute('data-thumbsize',thumbsize); 
    slider.setAttribute('data-rangewidth',slider.offsetWidth);

    /* write labels */
    var lower = document.createElement('span');
    var upper = document.createElement('span');
    lower.classList.add('lower','value');
    upper.classList.add('upper','value');
    lower.appendChild(document.createTextNode(rangemin));
    upper.appendChild(document.createTextNode(rangemax));
    slider.insertBefore(lower,min.previousElementSibling);
    slider.insertBefore(upper,min.previousElementSibling);
    
    /* write legend */
    var legend = document.createElement('div');
    legend.classList.add('legend');
    var legendvalues = [];
    for (var i = 0; i < legendnum; i++) {
        legendvalues[i] = document.createElement('div');
        var val = Math.round(rangemin+(i/(legendnum-1))*(rangemax - rangemin));
        legendvalues[i].appendChild(document.createTextNode(val));
        legend.appendChild(legendvalues[i]);

    } 
    slider.appendChild(legend);

    /* draw */
    draw(slider,avgvalue);

    /* events */
    min.addEventListener("input", function() {update(min);});
    max.addEventListener("input", function() {update(max);});
}

function update(el){
    /* set function vars */
    var slider = el.parentElement;
    var min = slider.querySelector('#min');
    var max = slider.querySelector('#max');
    var minvalue = Math.floor(min.value);
    var maxvalue = Math.floor(max.value);
    
    /* set inactive values before draw */
    min.setAttribute('data-value',minvalue);
    max.setAttribute('data-value',maxvalue);

    var avgvalue = (minvalue + maxvalue)/2;

    /* draw */
    draw(slider,avgvalue);
}

var sliders = document.querySelectorAll('.min-max-slider');
sliders.forEach( function(slider) {
    init(slider);
});
* {padding: 0; margin: 0;}
body {padding: 40px;}

.min-max-slider {position: relative; width: 200px; text-align: center; margin-bottom: 50px;}
.min-max-slider > label {display: none;}
span.value {height: 1.7em; font-weight: bold; display: inline-block;}
span.value.lower::before {content: "€"; display: inline-block;}
span.value.upper::before {content: "- €"; display: inline-block; margin-left: 0.4em;}
.min-max-slider > .legend {display: flex; justify-content: space-between;}
.min-max-slider > .legend > * {font-size: small; opacity: 0.25;}
.min-max-slider > input {cursor: pointer; position: absolute;}

/* webkit specific styling */
.min-max-slider > input {
  -webkit-appearance: none;
  outline: none!important;
  background: transparent;
  background-image: linear-gradient(to bottom, transparent 0%, transparent 30%, silver 30%, silver 60%, transparent 60%, transparent 100%);
}
.min-max-slider > input::-webkit-slider-thumb {
  -webkit-appearance: none; /* Override default look */
  appearance: none;
  width: 14px; /* Set a specific slider handle width */
  height: 14px; /* Slider handle height */
  background: #eee; /* Green background */
  cursor: pointer; /* Cursor on hover */
  border: 1px solid gray;
  border-radius: 100%;
}
.min-max-slider > input::-webkit-slider-runnable-track {cursor: pointer;}
<div class="min-max-slider" data-legendnum="2">
    <label for="min">Minimum price</label>
    <input id="min" class="min" name="min" type="range" step="1" min="0" max="3000" />
    <label for="max">Maximum price</label>
    <input id="max" class="max" name="max" type="range" step="1" min="0" max="3000" />
</div>

Değerlerin yeniden çizim / yeniden çizim hataları nedeniyle değişmesini önlemek için adım boyutunu 1 olarak tutmanız gerektiğini unutmayın.

Şu adresten çevrimiçi görüntüleyin: https://codepen.io/joosts/pen/rNLdxvK


Teşekkür ederim, çözümü gerçekten beğendim!
Svatopluk Ledl

Yine de yuvarlamayla ilgili sorun yaşadım ( avgvalueXX.5 olabilir). Sonuç olarak, sol kaydırıcıyla minimum boyut 1, sağ kaydırıcıyla 0 aralığı oluşturabilirsiniz. I ile çözdük floor/ ' ceililgili girdi en için max/ min+ koşullu padding-leftböylece her iki taraftan en az büyüklüğü 1 aralığı imkan veren ikinci sürgü için.
Svatopluk Ledl
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.