先看效果:
要想实现如上图的,进度跳效果,有两种方式,首先介绍第一种:
1、自己用 div 写一个,代码如下
<template> <div class="mfc-slider-runway" ref="runway"> <div class="mfc-slider-bar" :style="{w}"></div> <div class="mfc-slider-button-wrap" :style="{left:w}" ref="thumb"> <div class="mfc-slider-button" ></div> </div> </div> </template> <script> //进度条组件 export default{ props:{ min:{ //最小值 type:Number, default:0 }, max:{ //最大值 type:Number, default:100 }, step:{ //每步的值为多少 type:Number, default:1 }, value:{ // v-model 的初始值 type:Number, default:0 } }, data(){ return { startX:0, moveRun:false, maxWidth:0, left:0 }; }, computed:{ w(){ var maxWidth = this.maxWidth ; if( !maxWidth){ return 0; } if(this.min > this.value){ this.value = this.min; this.$emit("input", this.value); } if(this.max < this.value){ this.value = this.max; this.$emit("input", this.value); } var s = ((this.value - this.step - this.min) / (this.max - this.min))*maxWidth; //上限 var e = ((this.value + this.step- this.min ) / (this.max - this.min))*maxWidth; //下限 var left = this.left; if(left < s || left > e){ //说明value 的值,与 left 容差太大,需要调和,用于外部的 v-model 初始化 console.log("计算容差---"); left = ( (this.value- this.min )/ (this.max - this.min))*maxWidth; } return (left / maxWidth)*100 + "%"; } }, mounted(){ var $thumb = $(this.$refs.thumb); $thumb.on("mousedown",this.mousedown.bind(this)); $(window).on("mouseup",this.mouseup.bind(this)); this.maxWidth = $(this.$refs.runway).width(); //总共要走的 px 像素 var value = this.value if(this.min > value){ value = this.min; } if(this.max < value){ value = this.max; } this.$emit("input", value); }, methods:{ mousedown(e){ e.preventDefault(); e.stopPropagation(); this.startX = e.clientX ; this.moveRun = true; $(window).on("mousemove",this.mousemove.bind(this)) }, mouseup(e){ this.moveRun = false; $(window).off("mousemove",this.mousemove.bind(this)) }, mousemove(e){ e.preventDefault(); e.stopPropagation(); if(this.moveRun){ var x = e.clientX; var startX = this.startX; this.slide(startX,x); this.startX = x; } }, slide(start,end){ var miss = end - start; if(miss == 0){ return ; } var maxWidth = $(this.$refs.runway).width(); if(maxWidth == 0){ return ; } var $thumb = $(this.$refs.thumb); this.offsetLeft = $thumb.offset().left - $thumb.position().left var left = end - this.offsetLeft; this.maxWidth = maxWidth; if(left < 0){ left = 0; } if(left > maxWidth){ left = maxWidth; } this.left = left; //----根据 step 的大小,换算出最终的 value 值 var value = (left / maxWidth) * (this.max - this.min) + this.min; var v = Math.floor(value / this.step); value = v*this.step + Math.ceil(value - v); if(this.min > value){ value = this.min; } if(this.max < value){ value = this.max; } this.$emit("input",value); } }, destroyed(){ $(this.$refs.thumb).off("mousedown",this.mousedown.bind(this)); $(window).on("mouseup",this.mouseup.bind(this)); } } </script> <style lang="less"> div.mfc-slider-runway{ 100%; height: 6px; margin: 10px 0; background-color: #e4e7ed; border-radius: 3px; position: relative; cursor: pointer; vertical-align: middle; div.mfc-slider-bar{ height: 6px; background-color: #409eff; border-top-left-radius: 3px; border-bottom-left-radius: 3px; position: absolute; left: 0; } div.mfc-slider-button-wrap{ height: 36px; 36px; text-align: center; position: absolute; z-index: 1001; top: -15px; transform: translateX(-50%) ; background-color: transparent; text-align: center; user-select: none; line-height: normal; div.mfc-slider-button{ 16px; height: 16px; border: 2px solid #409eff; background-color: #fff; border-radius: 50%; transition: .2s; user-select: none; position: absolute; left: 0; right: 0; top:0; bottom: 0; margin: auto; &:hover{ transform: scale(1.2); cursor: grab; } } } } </style>
使用:
import rangeSlide from "./component/range-slide.vue"; <range-slide v-model="test"></range-slide> <div> {{test}} </div>
2、可以使用 input 的新属性 type=range , 然后通过css修改样式
css:
input[type=range] { box-sizing: border-box; -webkit-appearance: none; -moz-appearance: none; appearance: none; 100%; margin: 0; padding: 0 2px; /* Add some L/R padding to ensure box shadow of handle is shown */ overflow: hidden; border: 0; border-radius: 1px; outline: none; background: -webkit-linear-gradient(#649efd, #649efd) no-repeat center; background: linear-gradient(#649efd, #649efd) no-repeat center; /* Use a linear gradient to generate only the 2px height background */ background-size: 100% 2px; pointer-events: none; vertical-align: middle; } input[type=range]:active, input[type=range]:focus { outline: none; } input[type=range]::-webkit-slider-thumb { height: 18px; 18px; border-radius: 18px; background-color: #fff; position: relative; margin: 5px 0; /* Add some margin to ensure box shadow is shown */ cursor: pointer; -webkit-appearance: none; appearance: none; pointer-events: all; box-shadow: 0 1px 4px 0.5px rgba(0, 0, 0, 0.25); } input[type=range]::-webkit-slider-thumb::before { content: ' '; display: block; position: absolute; top: 13px; left: 100%; 2000px; height: 2px; } .multi-range { position: relative; height: 32px; } .multi-range input[type=range] { position: absolute; } .multi-range input[type=range]:nth-child(1)::-webkit-slider-thumb::before { background-color: red; } .multi-range input[type=range]:nth-child(2) { background: none; } .multi-range input[type=range]:nth-child(2)::-webkit-slider-thumb::before { background-color: grey; }
使用:
<div class="multi-range"> <input type="range"> </div>
小结: 因为 input 的 range属性,兼容不是很好,所以,最好还是自己写,但是自己写会遇见很多坑,比如,value值和step的初始化设置,可能会将 value 设置为一个永远也取不到的值,比如 value初始化为 2 , step又为 5