jQuery 不要・noUiSliderレンジスライダーを使ってみよう

jQuery 不要・noUiSliderレンジスライダーを使ってみよう

JavaScripthtml

HTMLでもレンジスライダー用のタグが数年前から使えるようになりましたね。

しかし、ブラウザで見た目がマチマチだし値は1パーツに一個しか付与できず、とても使い勝手が悪いです。レンジスライダー(つまみのある範囲の選べるフォーム)のJSライブラリ・noUiSliderの使い方についてメモしました。

導入の仕方やレンジスライダーを使った動的フォームの実装方法などのコードサンプルを中心に詳しく解説します。

この記事を書いた人

かみーゆ/フロントエンドエンジニア

資金ゼロからフィリピンで起業した海外ノマドエンジニア。IT業界10年以上でテクニカルディレクター(技術責任者)・エンジニア講師・ブリッジSEを経てLenzTechnologies Inc.を設立し、代表を務める。CMS concreteCMSエバンジェリスト。テックブログ以外も「磨耗しない人生」や「海外ノマド」のライフスタイルについて発信。好きなものは肉とハイボール。

この記事の対象者はこんな方です。
  • JavaScript の基礎は分かる
  • レンジスライダーを実装したい
  • 2個以上の値をレンジで実装する必要がある
  • 範囲内で直感的に使えるフォームを実装したい
  • jQueryを使いたくない

レンジスライダーとは?

レンジスライダーとは範囲(レンジ)内で値を選択できるフォームの一種です。

HTMLでもレンジスライダーのフォームパーツはあります。

HTML
<input type="range" min="0" max="100">

が、ご覧の通り、見た目がマチマチです。

HTMLだと、ブラウザで見た目がマチマチ
かみーゆ
かみーゆ

今回はサクッとJavaScriptのライブラリで解決します。

noUiSlider 導入方法

早速、noUiSliderの導入方法をご紹介します。

noUiSlider

noUiSlider公式サイト

noUiSlider はよくjQueryと紹介されてますが、実際にはjQueryなしで実装可能です。

基本の導入方法

もっとも簡単な noUiSlider 導入方法は JavaScript とCSSのソースを読み込む方法です。ソースは GitHub にありますが、今回はお気軽にCDNを読み込む方法をご紹介します。

オプション について解説はこの記事の一番最後にまとめています。

noUiSlider
HTML
<!-- css -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/15.6.1/nouislider.css">
<!-- js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/15.6.1/nouislider.min.js"></script>
HTML
<div class="range-wrapper">
  <div id="range"></div>
</div>
CSS
#range {
  height: 10px;
}
.range-wrapper {
  width: 800px;
  margin: 0 auto;
  padding: 50px;
}
JavaScript
const range = document.getElementById('range');
noUiSlider.create(range, {

    range: {
        'min': 0,
        'max': 10
    },
    step: 1,
    start: [2, 4],
    connect: true,
    behaviour: 'tap-drag',
    pips: {
        mode: 'steps',
        stepped: true,
        density: 10
    }
});

オプションのpipsでメモリと数字が表示されます。

小数点をつけたくない場合は pips の詳細オプションを density10 にします。

オプション について解説はこの記事の一番最後にまとめています。

コードサンプル noUiSlider Basic | CodePen

noUiSlider Tooltip

上のスクショのように、ツールチップ(つまみの上の数字)を表示したい時は、オプション tooltipstrue にします。

JavaScript
const rangeSlider = document.getElementById('values-slider');
noUiSlider.create(range, {
  range: {
      'min': 0,
      'max': 10
    },
    step: 1,
    start: [2, 4],
    connect: true,
    behaviour: 'tap-drag',
    tooltips: true,
    pips: {
      mode: 'steps',
      stepped: true,
      density: 10,
    }
});
noUiSlider Tooltip メモリやツールチップ(つまみの上の数字)を任意の数字にしたい場合はメモリを配列で値を自作します。

オプション について解説はこの記事の一番最後にまとめています。

JavaScript
const rangeSlider = document.getElementById('range');
const valuesForSlider = [0,1,2,3,4, 5,6,7,8,9,10]

const format = {
    to: function(value) {
        return valuesForSlider[Math.round(value)];
    },
    from: function (value) {
        return valuesForSlider.indexOf(Number(value));
    }
};

noUiSlider.create(rangeSlider, {
    start: [4, 8],
    range: { min: 0, max: valuesForSlider.length - 1 },
    step: 1,
    connect: true,
    tooltips: true,
    format: format,
    behaviour: 'tap-drag',
    pips: {
      mode: 'steps',
      stepped: true,
      density: 10,
      format: format,
    }
});

コードサンプル noUiSlider Tooltip | CodePen

Events:動的に値やオプションなどを変更する

noUiSliderでは、スライダーの変化やオプションの書き換えなどができるメソッドが用意されています。

スライダーが更新されたら、フォームの値を変更

noUiSliderのイベントを利用して、スライダーの変化を受け取ることができます。

noUiSlider.on() メソッドを使って、フォームの値をリアルタイムでレンダリングさせます。

noUiSlider Tooltip
HTML
<div class="range-wrapper">
  <div class="range-num">
    <input type="number" min="0" max="10" id="num-min" step="1" value="5" readonly> ~
    <input type="number" min="0" max="10" id="num-max" step="1" value="8" readonly>
  </div>
  <div id="range"></div>
</div>
CSS
#range {
  height: 10px;
}
.range-wrapper {
  width: 800px;
  margin: 0 auto;
  padding: 50px;
}
.range-num {
  margin-bottom: 40px;
}
.range-num input{
  border: 2px solid #ccc;
  height: 32px;
  padding-left: 5px;
  width: 50px;
  font-size: 16px;
}
JavaScript
const range = document.getElementById('range');
const min = document.getElementById('num-min');
const max = document.getElementById('num-max');
noUiSlider.create(range, {
    range: {
        'min': 0,
        'max': 10
    },
    step: 1,
    start: [min.value, max.value],
    connect: true,
    behaviour: 'tap-drag',
    pips: {
        mode: 'steps',
        stepped: true,
        density: 10
    }
});

range.noUiSlider.on('update', function( values, handle ) {
  min.value = Math.trunc(values[0])
  max.value = Math.trunc(values[1])
})

セットできるイベントは
‘start’、‘slide’、‘drag’、‘update’、‘change’、‘set’、‘end’ の7つです。

最大値、最小値の場合値自体を表示しない処理も可能

最大値、最小値の場合値自体を表示しない処理も可能です。分かりづらいので値がない場合の placeholder 属性を追加します。

JavaScript
<input type="number" min="0" max="10" id="num-min" step="1" value="5" readonly placeholder="最大値"> ~
<input type="number" min="0" max="10" id="num-max" step="1" value="8" readonly placeholder="最大値">
JavaScript
range.noUiSlider.on('update', function( values, handle ) {
  min.value = Math.trunc(values[0]) === 0 ? '' : Math.trunc(values[0])
  max.value = Math.trunc(values[1]) === 10 ? '' : Math.trunc(values[1])
})

コードサンプル noUiSlider Update | CodePen

オプションを変更する

noUiSlider では、オプションの変更もあとから可能です。

たとえば、チェックボックスの値が変更されたタイミングでレンジの最大値を変えるなども可能です。

noUiSlider オプションの変更
HTML
<div class="range-wrapper">
  <div class="range-num">
    <label><input type="radio" name="gender" value="male" checked>男性</label>
    <label><input type="radio" name="gender" value="female">女性</label>
  </div>
  <div id="range"></div>
</div>
JavaScript
const valuesSlider = document.getElementById('values-slider');
const genders = document.querySelectorAll('input[name=gender]');

noUiSlider.create(range, {
    range: {
        'min': 0,
        'max': 10
    },
    step: 1,
    start: [5, 8],
    connect: true,
    behaviour: 'tap-drag',
    pips: {
        mode: 'steps',
        stepped: true,
        density: 10
    }
});

genders.forEach(function(item){
  item.addEventListener('change', function(){
    let maxLevel = item.value === 'female' ? 15 : 10
    range.noUiSlider.updateOptions({
      range: {
        'min': 0,
        'max': maxLevel
      },
    });
  }, false);
}, false);

コードサンプル noUiSlider UpdateOption | CodePen

まとめ

たまたま見つけて使ってみたのですが、公式サイトを見ると全くjQueryじゃない上に高機能で感動したのがきっかけでご紹介させていたきました。

この記事が皆さんのコーディングライフの一助となれば幸いです。

最後までお読みいただきありがとうございました。

おまけ・オプション

オプションです。

オプション名説明・使用用途
range範囲の最小値と最大値の指定。デフォ値なし-range: {min: 0, max: 10}
range: {min: [0], max: [10]}
(0~8が選ばれた状態)
start初期値。デフォ値なし-start: [0, 8](0~8が選ばれた状態)
connectバーに色を付けるか否か。lowerが手前で、upperがつまみより後にバーに色がつく。2点以上つまみがある場合はtrue。複数ある場合は配列で指定。。デフォ値false。-lower, upper,true, false, 配列内に入れ子
margin2つのハンドルの最大の間隔。デフォ値なし。numbermargin: 302間の値は30以下にはならない。
limit2つのハンドルの最小の間隔。デフォ値なし。numberlimit: 302間の値は30以上にはならない。
paddingスライダーのそれぞれの端からの値。デフォ値は0。スライダーを端まで動かしたくない等の場合。number,array[number],array[number, number]padding: [10, 15]最小値が0の場合は10以上下げらず、最大値が100の場合は85以上には増やせない。
stepステップスライダーの1ステップあたりの移動範囲。デフォ値なし。numberstep: 1010ずつ増減できる。
orientationスライダーの方向。デフォはhorizontal“vertical”, “horizontal”orientation: 'vertical'縦方向。
directionスライダーの方向。デフォはltr(左から右、もしくは上から下)“ltr”, “rtl”direction: 'rtl'右から左に動かすと数値が増える。
tooltipsツールチップを表示するか否か。デフォはfalse。removeTooltips() メソッドで削除可能。false, true, formattertooltips: 'true'
animateスライダーをアニメーションさせるか否かです。初期値はtrueです。クリックイベントなどとセットで使います。アニメーションの間隔(duration)を調整したい場合はCSSの調整が必要です。false, trueanimate: true,
handleAttributesaria-label等、ハンドル(つまみ)に属性を付与できますfalse, truehandleAttributes: [{ 'aria-label': 'lower' },{ 'aria-label': 'upper' }]

その他、キーボードサポートなどのオプションもありますが、きりがないのでOption | noUiSliderをご確認ください。

おまけ・スライダーの挙動

オプションの中でも、スライダーの挙動のみ詳しく説明します。

behaviour: "drag"
スライダーの挙動
drag範囲をドラック可能でいつもつまみをドラッグできる
drag-fixed範囲をドラック可能。範囲を変えることができないので、ツマミのみを動かす。
tapスライダーをタップすると近くにハンドルが動く。
tap-dragタップしたところにハンドルが動く。
hoverバーの上をペンやカーソルを当てるとホバーでイベント発火。
unconstrained-tapハンドルが互いに通りすぎることができる
none基本の挙動を除いて、他はすべてオフ

お読みいただきありがとうございます。
「銀ねこアトリエ」をより良いブログにするために是非応援してください!

銀ねこアトリエを応援する