Vue.js로 수동으로 만든 RangeSlider

15746 단어 JavaScriptVue.js

완성


나는 그것을 해 보았다.

왜 하고 싶으세요?


나는 평소에 리액션을 쓴다.React도 Component 이외의 마우스 조작으로 화면을 업데이트하고 싶을 때가 있다.이 경우 바디 등addEventListener의 이벤트 설정에 대해refDOM에서left와width를 받아state를 업데이트합니다.
Vue.제이스에서는 어떤 느낌일까요?

이루어지다

<template>
  <div class="range_slider" :style="{width: width + 'px'}">
    <div class="range_wrapper" ref="range" @mousedown="mousedown">
      <div class="range" :style="{'background-color': color}"></div>
    </div>
    <div class="circle" :style="circleStyle" @mousedown="mousedown"></div>
  </div>
</template>

<script>
  export default {
    name: 'RangeSlider',
    props: {
      color: {type: String, default: '#eee'},
      width: {type: Number, default: 200},
      value: {type: Number, default: 0},
      max: {type: Number, default: 100},
      min: {type: Number, default: 0}
    },
    data () {
      return {
        isMoving: false
      }
    },
    methods: {
      moveCircle (e) {
        const width = this.$refs.range.getBoundingClientRect().width
        const rangeLeft = this.$refs.range.getBoundingClientRect().left
        const eventLeft = e.clientX
        const left = eventLeft - rangeLeft

        if (left <= 0) {
          this.$emit('update:value', this.min)
        }
        if (width <= left) {
          this.$emit('update:value', this.max)
        }
        if (left >= 0 && left <= width) {
          const ratio = left / width
          const value = (this.max - this.min) * ratio + this.min
          this.$emit('update:value', Math.round(value))
        }
      },
      mousedown (e) {
        this.isMoving = true
        this.moveCircle(e)
        // mousedownしたタイミングでマウス操作に対するイベントを設定
        document.body.addEventListener('mousemove', this.mousemove)
        document.body.addEventListener('mouseup', this.mouseup)
      },
      mousemove (e) {
        if (this.isMoving) {
          this.moveCircle(e)
        }
      },
      mouseup () {
        this.isMoving = false
        // ドラッグ操作が終わったタイミングでイベントを削除
        document.body.removeEventListener('mousemove', this.mousemove)
        document.body.removeEventListener('mouseup', this.mouseup)
      }
    },
    computed: {
      circleStyle () {
        const ratio = (this.value - this.min) / (this.max - this.min)
        const left = this.width * ratio
        return {
          left: `${left - 10}px`
        }
      }
    }
  }
</script>

<style scoped>
  .range_slider {
    height: 20px;
    margin: 0 auto;
    position: relative;
    display: inline-block;
  }

  .range_wrapper {
    position: relative;
    height: 100%;
    width: 100%;
  }

  .range {
    height: 4px;
    width: 100%;
    background-color: #eee;
    position: absolute;
    top: calc(50% - 2px);
    border-radius: 3px;
  }

  .circle {
    width: 0;
    height: 0;
    top: 0;
    border: 10px solid #DDD;
    border-radius: 50%;
    position: absolute;
  }
</style>

보태다


리액트와 다른 점은 사용this.$refs이라는 점인가.리액트에서도 this.refs 얻는 방법이 있다고 생각하지만 리액트에서는 추천하지 않을 거예요.
여기까지 이룬 아이디어는 HTML5를 사용하는 input의 range도 이런 점을 이룰 수 있을지도 모른다는 것이다.만약 위에 input의range보다 동그란 원을 덮어 이렇게 실현한다면 마우스 조작에 신경 쓸 필요가 없을 수도 있다.

좋은 웹페이지 즐겨찾기