基于 mithril.js ,javascript ,scss写一个可拖动的滑块组件
问题描述:
需求需要实现一个可拖动的滑块组件,但是又不能用UI框架,只好自己动手写一个了。 废话不多说,直接上代码。技术要求
需要有mithril.js,javascript,scss技术基础。js及页面代码。
var m = require("mithril");
require('./slider.scss');
import slider from './slider';
let obj = {
colorWidth: 0, // 已拖拽长度
clickOpen: false, // 是否开启拖拽
sliderDom: '', // 绑定的灰条dom
colorDom: '', // 绑定的有色条dom
radiusDom: '', // 绑定的圆点dom
moveEmentRect: null, // 获取灰条dom参数
Percentage: 0, // 百分比
minWidth: 0, // 拖动区间下限
maxWidth: 0, // 拖动区间上限
sliderCallback: null, // 参数回调
node: [0, 25, 50, 75, 100], // 节点数及占比
// 初始化数据
initslider:function(){
obj.sliderDom = document.getElementsByClassName('slider-body')[0]; // 允许进行开始拖拽的元素
obj.colorDom = document.getElementsByClassName('slider-section')[0]; // 允许进行开始拖拽的元素
obj.radiusDom = document.getElementsByClassName('slider-radius-body')[0]; // 允许进行开始拖拽的元素
obj.moveEmentRect = obj.sliderDom.getBoundingClientRect(); // 获取拖拽父元素的宽度
obj.maxWidth = obj.moveEmentRect.width;
},
// 处理宽度值域
handleWidth:function(EV){
if (EV <= obj.minWidth) {
return obj.minWidth;
} else if (EV >= obj.maxWidth) {
return obj.maxWidth;
} else {
return EV;
}
},
// 鼠标点击 拖动开始
getMousedown:function(e){
if (e.target === obj.sliderDom || e.target === obj.colorDom || e.target === obj.radiusDom) {
// 判断是否是可点击拖拽的元素
obj.clickOpen = true; // 打开拖拽状态
let Width = e.clientX - obj.moveEmentRect.left; // 计算拖拽距离
obj.colorWidth = this.handleWidth(Width); // 处理拖拽距离转化为长度
console.log(obj.colorWidth, '拖动开始')
this.sliderCallback && this.sliderCallback({
colorWidth : this.getPercentage(), // 将数据回传页面
})
}
},
// 拖动中
getMoveWidth:function(e){
if (obj.clickOpen) {
let moveX = e.clientX - obj.moveEmentRect.left;
obj.colorWidth = this.handleWidth(moveX);
console.log(obj.colorWidth, '拖动中')
this.sliderCallback && this.sliderCallback({
colorWidth : this.getPercentage(), // 将数据回传页面
})
}
},
// 鼠标松开 拖动结束
getmouseUp:function(){
obj.clickOpen = false;
console.log('拖动结束')
},
// 绑定到body上,实现在组件外面可以拖拽
getBodyMouse: function(){
let body = document.querySelector('body');
body.onmousemove = function(e){
obj.getMoveWidth(e); // 在body上拖拽组件
};
body.onmouseup = function(e){
obj.getmouseUp(e); // 在body上拖拽结束时关闭可拖拽状态
obj.onmouseout(); // 在body上结束拖拽时隐藏百分比
}
},
// 计算拖动的百分比
getPercentage: function () {
let _P = (Number(obj.colorWidth) / Number(obj.maxWidth)).toFixed(2);
this.Percentage = Math.floor((Number(_P || 0) * 100));
return Number(_P);
},
// 鼠标移入显示百分比
onmouseover:function(){
let _S = document.getElementsByClassName('slider-percentage')[0];
_S.style.display = 'block';
},
// 鼠标移除隐藏百分比
onmouseout:function(){
let _S = document.getElementsByClassName('slider-percentage')[0];
_S.style.display = 'none';
},
// 清除数据
closemode: function () {
obj.colorWidth = 0; // 已拖拽长度
obj.clickOpen = false; // 是否开启拖拽
obj.sliderDom = ''; // 绑定的灰条dom
obj.colorDom = ''; // 绑定的有色条dom
obj.radiusDom = ''; // 绑定的圆点dom
obj.moveEmentRect = null; // 获取灰条dom参数
obj.Percentage = 0; // 百分比
obj.minWidth = 0;
obj.maxWidth = 0;
obj.sliderCallback = null; // 参数回调
},
// 百分比选择
getNodePer:function () {
return obj.node.map((item) => {
return m('div',{
class:'slider-node', style: `left: ${
item}%`, onclick: function(){
obj.getNodeData(item);
}},[
])
})
},
getNodeData:function(item){
obj.colorWidth = Number(obj.maxWidth) * (item / 100);
this.sliderCallback && this.sliderCallback({
colorWidth : this.getPercentage(), // 将数据回传页面
});
},
}
export default {
oninit: function (vnode) {
},
oncreate: function (vnode) {
obj.sliderCallback = vnode.attrs.cb;
obj.initslider();
obj.onmouseout();
obj.getBodyMouse();
},
view: function (vnode) {
return m('div', {
class: 'slider'}, [
m('div',{
class:"slider-body",onmousedown:function(e){
obj.getMousedown(e);
},onmousemove:function(e){
obj.getMoveWidth(e);
},onmouseup:function(e){
obj.getmouseUp(e);
}},[
m('div',{
class:"slider-section", style:`width: ${
obj.colorWidth}px`},[
m('div',{
class:"slider-radius",onmouseover:function(){
obj.onmouseover();
},onmouseout:function(){
obj.onmouseout();
}},[
m('div',{
class:"slider-radius-body"},[])
]),
m('div',{
class:"slider-percentage" , style: `left: ${
obj.colorWidth - 25}px`},[
obj.Percentage + '%'
]),
]),
obj.getNodePer(),
]),
])
},
onremove: function (vnode) {
obj.closemode();
},
}
scss样式代码。
// 用的是scss预处理样式
// $arrowsSize scss变量
// var(--primary-lighten)用的是全局颜色,可以直接用颜色值代替
// $dark #ligth 为黑夜白天样式,可以不用。
$arrowsSize: 6px; // 三角形 大小
.slider{
width: 100%;
.slider-body{
width: 100%;
height: 6px;
margin: 16px 0;
border-radius: 5px;
position: relative;
cursor: pointer;
.slider-section{
height: 6px;
background-color: var(--primary-lighten);
// width: 30%;
position: absolute;
left: 0;
border-radius: 5px;
.slider-radius{
height: 16px;
width: 16px;
position: absolute;
left: 100%;
z-index: 999;
top: -5px;
transform: translateX(-50%);
background-color: transparent;
text-align: center;
user-select: none;
line-height: normal;
.slider-radius-body{
width: 16px;
height: 16px;
border: 2px solid var(--primary-lighten);
background-color: var(--fontwhite-base);
border-radius: 50%;
transition: .2s;
user-select: none;
&::after {
content: '';
height: 100%;
display: inline-block;
vertical-align: middle;
}
}
}
.slider-percentage{
// display: none;
height: 25px;
width: 50px;
line-height: 25px;
border-radius: 5px;
background-color: var(--mode-darken);
text-align: center;
font-size: 14px;
color: var(--font-darken);
position: absolute;
top: -40px;
// left: 100%;
&::after {
content: '';
display: inline-block;
vertical-align: middle;
width: 0;
height: 0;
position: absolute;
border-top: solid $arrowsSize;
border-left: solid $arrowsSize transparent !important;
border-right: solid $arrowsSize transparent !important;
border-bottom: solid $arrowsSize transparent !important;
top: 25px;
left: 35%;
color: var(--mode-darken);
}
}
}
.slider-node{
position: absolute;
height: 8px;
width: 8px;
border-radius: 100%;
background-color: var(--fontwhite-base);
border: 2px solid var(--primary-lighten);
transform: translateX(-50%);
top: -1px;
}
}
}
#dark .slider-body{
background-color: var(--line-darken3);
}
#light .slider-body{
background-color: var(--line-lighten3);
}
调用
getSlider: function () {
return m(slider, {
cb : function(arg){
console.log(arg,22222)
},
});
},
obj.getSlider(),
说明一下
因为公司项目涉及保密条例,电脑都加了安全限制,无法录制视频或者gif图片,所有只能截图展示了。效果
可以点击圆点拖动,也可以直接点击灰条进行点选然后拖动,也可以点击灰条上的百分比圆点进行拖动,因为单独又把事件绑定到了body上,所以可以在灰条上拖动开始并且在组件外也可以进行拖动,类似Element UI的slider组件效果。
拖动参数的打印
只为分享写代码过程中的一些心得体会,感谢平台!
来源:oschina
链接:https://my.oschina.net/u/4312329/blog/4775995