DEV Community

Cover image for VueJS: Double range slider component
Andrés Baamonde Lozano
Andrés Baamonde Lozano

Posted on

VueJS: Double range slider component

Yesterday i built an advanced search component. For that component, we needed to implement a range search between two numbers. I didnt need something really complex and i had no plans to add a new library to the project. After a couple dumb searches like ' range slider double' and 'doublerange slinder'. I found this amazing codepen. So frist the acknowledgments, if you are reading that post, Thank you Kristof Friess.

This guy has a cool codepen with vanilla JS of that i was looking for, and it works perfectly :)
Gif codepen

So today i will create a vue component based in that codepen and make a small contribution.

First, i will move the javascript code to a independt file, called ZbRangeSlider.js, and i will import it to my component. On the following steps i would like to migrate code to the component. But as a first aprroach it will work .And also, having the code on a different file enables us to use another double range implementation. We only will need changing our import and adapting html.

I will use $emit to update my model parameters. I am not happy at all with that solution, if you know a better one please leave a comment below.

Implementation

<template>
<div class="content">
  <div id="my-slider" :se-min="minThreshold" :se-step="step" :se-min-value="min" :se-max-value="max" :se-max="maxThreshold" class="slider">
    <div class="slider-touch-left">
      <span></span>
    </div>
    <div class="slider-touch-right">
      <span></span>
    </div>
    <div class="slider-line">
      <span></span>
    </div>
  </div>
</div>
</template>

<script>
import ZbRangeSlider from './ZbRangeSlider'

export default {
  props: {
    minThreshold: {
      type: Number,
      default: -100
    },
    maxThreshold: {
      type: Number,
      default: 100
    },
    step: {
      type: Number,
      default: 1
    },
    min: {
      type: Number,
      required: true
    },
    max: {
      type: Number,
      required: true
    }
  },
  data: function () {
    return {
      instance: undefined
    }
  },
  mounted: function () {
    this.instance = new ZbRangeSlider('my-slider')
    this.instance.onChange = (min, max) => this.updateValues(min, max)
  },
  destroyed: function () {

  },
  methods: {
    updateValues: function (min, max) {
      this.$emit('update:min', min)
      this.$emit('update:max', max)
    }
  }
}
</script>

<style>
.slider {
  display: block;
  position: relative;
  height: 36px;
  width: 100%;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
}
.slider .slider-touch-left,
.slider .slider-touch-right {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  display: block;
  position: absolute;
  height: 36px;
  width: 36px;
  padding: 6px;
  z-index: 2;
}
.slider .slider-touch-left span,
.slider .slider-touch-right span {
  display: block;
  width: 100%;
  height: 100%;
  background: #f0f0f0;
  border: 1px solid #a4a4a4;
  border-radius: 50%;
}
.slider .slider-line {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  position: absolute;
  width: calc(100% - 36px);
  left: 18px;
  top: 16px;
  height: 4px;
  border-radius: 4px;
  background: #f0f0f0;
  z-index: 0;
  overflow: hidden;
}
.slider .slider-line span {
  display: block;
  height: 100%;
  width: 0%;
  background: orange;
}
</style>

Enter fullscreen mode Exit fullscreen mode

Using the component

On the component´s demo i will add some inputs to see the value change event.

<template>
  <DoubleRangeSlider :min="min" :max="max" @update:min="value => min = value" @update:max="value => max = value"></DoubleRangeSlider>
</template>

    <label>Min</label><input type="text" v-model="min">
    <label>Max</label><input type="text" v-model="max">
<script>

import RatingComponent from '@/components/shared/rating/stars'
import ScrollTopArrow from '@/components/shared/blog/ScrollTopArrow'
import DoubleRangeSlider from '@/components/shared/slider/DoubleRangeSlider'

export default {
  data () {
    return {
      min: 0,
      max: 10
    }
  },
  components: {
    DoubleRangeSlider
  },
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

Result

Demo component

References

Github
CodePen
zebresel Code Pen
StackOverflow - jquery ui :S
Multiple bindings

Top comments (2)

Collapse
 
phumbie profile image
Phumbie

The problem I had with this is that, when I bind it to an input, it's not reactive to that input whenever I put in a value

Collapse
 
sadewole profile image
Samador • Edited

Great work!.