import React, { Component } from 'react'
import PropTypes from 'prop-types'
import assign from 'object-assign'
import _ from 'lodash'
import CX from 'classnames' import './index.less' /**
* ProgressBar
* vertical 设置进度条是否垂直显示
* trackHover trackHover事件
* onSlide 事件函数获取percent值
* percent 设置滑块位置,0~100之间
* style 最外层div的样式
* slidedStyle 滑块左侧划过部分的样式
* trackStyle 滑块右侧未划过部分的样式
* ballStyle 滑块的样式
* showHoverStyle 是否设置hover时的样式
* hoverStyle 最外层div的样式
* hoverSlidedStyle 滑块左侧划过部分的样式
* hoverTrackStyle 滑块右侧未划过部分的样式
* hoverBallStyle 滑块的样式
* dragInfo 滑动滑块时显示在滑块上方的提示信息,默认没有提示信息
* dragInfoWrapStyle 滑块提示信息父级元素的样式,可用于调整提示信息的位置
* previewInfo 指针在进度条内时显示的指针位置进度提示信息
* previewInfoWrapStyle previewInfo 提示信息父级元素的样式,可用于调整提示信息的位置
* onCursorSlide 事件函数获取当前指针处的percent 可用于更新previewInfo
*/ class ProgressBar extends Component {
static propTypes = {
vertical: PropTypes.bool,
onSlide: PropTypes.func,
style: PropTypes.object,
slidedStyle: PropTypes.object,
trackStyle: PropTypes.object,
ballStyle: PropTypes.object,
showHoverStyle: PropTypes.bool,
hoverStyle: PropTypes.object,
hoverSlidedStyle: PropTypes.object,
hoverTrackStyle: PropTypes.object,
hoverBallStyle: PropTypes.object,
percent: PropTypes.number,
dragInfo: PropTypes.element,
dragInfoWrapStyle: PropTypes.object,
previewInfo: PropTypes.element,
previewInfoWrapStyle: PropTypes.object,
onCursorSlide: PropTypes.func,
disableSlide: PropTypes.bool,
} static defaultProps = {
vertical: false,
onSlide: _.noop,
style: {},
slidedStyle: {},
trackStyle: {},
ballStyle: {},
showHoverStyle: false,
hoverStyle: {},
hoverSlidedStyle: {},
hoverTrackStyle: {},
hoverBallStyle: {},
percent: 0,
dragInfo: null,
dragInfoWrapStyle: {},
previewInfo: null,
previewInfoWrapStyle: {},
onCursorSlide: _.noop,
disableSlide: false,
} state = {
percent: this.props.percent,
cursorPercent: 0,
moveFlag: false,
cursorInSlideBall: false,
cursorInComponent: false,
} componentDidMount() {
this.rangeSlideElem.addEventListener('mousedown', this.onWrapElemMouseDown)
this.rangeSlideElem.addEventListener('mouseenter', this.onWrapElemMouseEnter)
this.rangeSlideElem.addEventListener('mousemove', this.onWrapElemMouseMove)
this.rangeSlideElem.addEventListener('mouseleave', this.onWrapElemMouseLeave)
this.rangeSlideElem.addEventListener('click', this.handleSlide) document.body.addEventListener('mousemove', this.onBodyMouseMove)
document.body.addEventListener('mouseup', this.onBodyMouseUp)
document.body.addEventListener('mouseleave', this.onBodyMouseLeave)
} componentWillReceiveProps(nextProps) {
if (nextProps.percent !== this.props.percent) {
this.setState({
percent: nextProps.percent,
})
}
} componentWillUnmount() {
document.body.removeEventListener('mousemove', this.onBodyMouseMove)
document.body.removeEventListener('mouseup', this.onBodyMouseUp)
document.body.removeEventListener('mouseleave', this.onBodyMouseLeave)
} getPercent = (e) => {
let percentage
if (this.props.vertical === false) {
const offsetLeft = this.rangeSlideElem.getBoundingClientRect().x
const { offsetWidth } = this.rangeSlideElem
percentage = Math.round(((e.pageX - offsetLeft) / offsetWidth) * 100)
} else {
const offsetTop = this.rangeSlideElem.getBoundingClientRect().y
const { offsetHeight } = this.rangeSlideElem
percentage = Math.round((1 - (e.pageY - offsetTop) / offsetHeight) * 100)
}
percentage = Math.max(Math.min(percentage, 100), 0) return percentage
} onWrapElemMouseDown = () => {
this.setState({
moveFlag: true,
})
} onBodyMouseMove = _.throttle((e) => {
if (this.state.moveFlag) {
this.handleSlide(e)
}
}, 30) onBodyMouseUp = () => {
this.setState({
moveFlag: false,
})
} onBodyMouseLeave = this.onBodyMouseUp handleSlide = (e) => {
if (this.props.disableSlide === true) {
return
}
const percent = this.getPercent(e)
this.props.onSlide(percent)
this.setState({
percent,
})
} onSlideBallMouseEnter = () => {
this.setState({
cursorInSlideBall: true,
})
} onSlideBallMouseLeave = () => {
this.setState({
cursorInSlideBall: false,
})
} onWrapElemMouseEnter = (e) => {
const cursorPercent = this.getPercent(e)
this.props.onCursorSlide(cursorPercent)
this.setState({
cursorInComponent: true,
cursorPercent,
})
} onWrapElemMouseMove = (e) => {
const cursorPercent = this.getPercent(e)
this.props.onCursorSlide(cursorPercent)
this.setState({
cursorPercent,
})
} onWrapElemMouseLeave = () => {
this.setState({
cursorInComponent: false,
})
} rangeSlideElem activeBarElem render() {
const { cursorInComponent } = this.state
const showHoverStyle = cursorInComponent && this.props.showHoverStyle
const wrapStyles = assign({}, showHoverStyle ? this.props.hoverStyle : this.props.style)
let slideTrackStyles
if (this.props.vertical === true) {
slideTrackStyles = assign({}, showHoverStyle ? this.props.hoverTrackStyle : this.props.trackStyle, {
height: `${100 - this.state.percent}%`,
})
} else {
slideTrackStyles = assign({}, showHoverStyle ? this.props.hoverTrackStyle : this.props.trackStyle, {
width: `${100 - this.state.percent}%`,
})
}
const activeBarStyles = assign({}, showHoverStyle ? this.props.hoverSlidedStyle : this.props.slidedStyle)
const slideBallStyles = assign({}, showHoverStyle ? this.props.hoverBallStyle : this.props.ballStyle)
const dragInfoWrapStyle = assign({}, this.props.dragInfoWrapStyle)
const previewInfoWrapStyle = assign({}, this.props.previewInfoWrapStyle, {
left: `${this.state.cursorPercent}%`,
})
const showDragInfo = this.state.cursorInSlideBall || this.state.moveFlag
const showPreviewInfo = showDragInfo === false && this.state.cursorInComponent return (
<div
className={CX({
'horizontal-progress-bar-component-wrap': this.props.vertical === false,
'vertical-progress-bar-component-wrap': this.props.vertical === true,
})}
style={wrapStyles}
ref={(r) => {
this.rangeSlideElem = r
}}
>
<div className="active-bar" style={activeBarStyles} />
<div
className="slide-track"
ref={(r) => {
this.activeBarElem = r
}}
style={slideTrackStyles}
>
<div
className="slide-ball"
style={slideBallStyles}
onMouseEnter={this.onSlideBallMouseEnter}
onMouseLeave={this.onSlideBallMouseLeave}
/>
{
showDragInfo && (
<div
className="drag-info-element-wrap"
style={dragInfoWrapStyle}
>
{this.props.dragInfo}
</div>
)
}
</div>
{
showPreviewInfo && (
<div
className="preview-info-element-wrap"
style={previewInfoWrapStyle}
>
{this.props.previewInfo}
</div>
)
}
</div>
)
}
} export default ProgressBar

样式如下:

.horizontal-progress-bar-component-wrap {
width: 100%;
height: 12px;
margin:;
position:relative;
cursor: pointer; .active-bar {
position:absolute;
top: 50%;
left:;
margin-top: -2px;
width: 100%;
height: 4px;
border-radius: 4px;
background: linear-gradient(to right, #81d5fa, #3977f6);
}
.slide-track {
width: 50%;
height: 4px;
position:absolute;
top: 50%;
right:;
margin-top: -2px;
border-radius: 4px;
background: #fff; .slide-ball {
width: 12px;
height: 12px;
position: absolute;
left: -6px;
top: -4px;
border-radius: 50%;
cursor: pointer;
background: url('~ROOT/shared/assets/image/vn-circle-blue-42-42.png') no-repeat center;
background-size: 12px;
}
.drag-info-element-wrap {
position: absolute;
left: -24px;
top: -46px;
}
} .preview-info-element-wrap {
position: absolute;
top: -32px;
margin-left: -24px;
}
} .vertical-progress-bar-component-wrap {
width: 12px;
height: 100%;
margin:;
position: relative;
cursor: pointer; .active-bar {
position:absolute;
bottom:;
left: 50%;
margin-left: -2px;
height: 100%;
width: 4px;
border-radius: 4px;
background: linear-gradient(to top, #81d5fa, #3977f6);
}
.slide-track {
position:absolute;
height: 50%;
width: 4px;
right: 50%;
top: -2px;
margin-right: -2px;
border-radius: 4px;
background: #fff; .slide-ball {
width: 12px;
height: 12px;
position: absolute;
left: -4px;
bottom: -6px;
border-radius: 50%;
cursor: pointer;
background: url('~ROOT/shared/assets/image/vn-circle-blue-42-42.png') no-repeat center;
background-size: 12px;
}
.drag-info-element-wrap {
position: absolute;
left: -46px;
bottom: -24px;
}
} .preview-info-element-wrap {
position: absolute;
left: -32px;
margin-bottom: -24px;
}
}

音量调节条-封装通用的ProgressBar组件的更多相关文章

  1. 【Ubuntu日常技巧】【解决】Ubuntu 16 右上角的音量调节通知框不停地闪烁问题

    一. 先上干货 解决问题 1.1 安装工具alsa-tools-gui sudo apt-get install alsa-tools-gui 1.2 通过hdajackretask设置 直接执行命令 ...

  2. 如何通过 Vue+Webpack 来做通用的前端组件化架构设计

    目录:   1. 架构选型     2. 架构目录介绍     3. 架构说明     4. 招聘消息 目前如果要说比较流行的前端架构哪家强,屈指可数:reactjs.angularjs.emberj ...

  3. 第二百四十一节,Bootstrap进度条媒体对象和 Well 组件

    第二百四十一节,Bootstrap进度条媒体对象和 Well 组件 学习要点: 1.Well 组件 2.进度条组件 3.媒体对象组件 本节课我们主要学习一下 Bootstrap 的三个组件功能:Wel ...

  4. Android、iOS平台RTMP/RTSP播放器实时音量调节

    介绍移动端RTMP.RTSP播放器实时音量调节之前,我们之前也写过,为什么windows播放端加这样的接口,windows端播放器在多窗口大屏显示的场景下尤其需要,尽管我们老早就有了实时静音接口,相对 ...

  5. Windows平台RTMP/RTSP播放器实现实时音量调节

    为什么要做实时音量调节 RTMP或RTSP直播播放音量调节,主要用于多实例(多窗口)播放场景下,比如同时播放4路RTMP或RTSP流,如果音频全部打开,几路audio同时打开,可能会影响用户体验,我们 ...

  6. C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper(三:附源码)

    前言:之前的两篇封装了一些基础的表单组件,这篇继续来封装几个基于bootstrap的其他组件.和上篇不同的是,这篇的有几个组件需要某些js文件的支持. 本文原创地址:http://www.cnblog ...

  7. C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper

    前言:之前学习过很多的Bootstrap组件,博主就在脑海里构思:是否可以封装一套自己Bootstrap组件库呢.再加上看到MVC的Razor语法里面直接通过后台方法输出前端控件的方式,于是打算仿照H ...

  8. JS组件系列——封装自己的JS组件,你也可以

    前言:之前分享了那么多bootstrap组件的使用经验,这篇博主打算研究下JS组件的扩展和封装,我们来感受下JQuery为我们提供$.Extend的神奇,看看我们怎么自定义自己的组件,比如我们想扩展一 ...

  9. JS组件系列——分享自己封装的Bootstrap树形组件:jqTree

    前言:之前的一篇介绍了下如何封装自己的组件,这篇再次来体验下自己封装组件的乐趣.看过博主博客的园友应该记得之前分享过一篇树形菜单的使用JS组件系列——Bootstrap 树控件使用经验分享,这篇里面第 ...

随机推荐

  1. 如何登陆Tomcat的控制台

    当我们成功安装启动Tomcat服务后,在浏览器输入http://localhost:8080(8080是Tomcat的默认端口,可自行修改)回车 右上角可以看到三个控制台:Server Status. ...

  2. TensorFlow DeepLab教程初稿-tensorflow gpu安装教程

    TensorFlow DeepLab教程初稿-tensorflow gpu安装教程 商务合作,科技咨询,版权转让:向日葵,135-4855__4328,xiexiaokui#qq.com Summar ...

  3. Linux防火墙白名单设置

    在linux系统中安装yum install iptables-services 然后 vi /etc/sysconfig/iptables # Generated by iptables-save ...

  4. openresty开发系列10--openresty的简单介绍及安装

    openresty开发系列10--openresty的简单介绍及安装 一.Nginx优点 十几年前,互联网没有这么火,软件外包开发,信息化建设,帮助企业做无纸化办公,收银系统,工厂erp,c/s架构偏 ...

  5. iframe子页面无法返回上一页的问题

    本文讨论的场景是ipad终端. 如题,因业务需要,需要使用iframe嵌套子页面.让外层始终保持一个socket连接,避免socket每跳转一个页面都要重新关闭建立连接的问题.但是这样问题来了,上线后 ...

  6. Flutter Navigator&Router(导航与路由)

    参考地址:https://www.jianshu.com/p/b9d6ec92926f 在我们Flutter中,页面之间的跳转与数据传递使用的是Navigator.push和Navigator.pop ...

  7. Android开发之高仿微信图片选择器

    记得刚开始做Andriod项目那会,经常会碰到一些上传图片的功能需求,特别是社交类的app,比如用户头像,说说配图,商品配图等功能都需要让我们到系统相册去选取图片,但官方却没有提供可以选取多张图片的相 ...

  8. pipline中执行shell脚本推送镜像并且部署

    实验架构: 192.168.0.96 gitlab 192.168.0.97 jenkins 192.168.0.98 harbor.docker集群 说明:下面代码编译镜像那一步的代码必须靠左,目的 ...

  9. web端自动化——Selenium3+python自动化(3.7版本)-chrome67环境搭建

    前言 目前selenium版本已经升级到3.0了,网上的大部分教程是基于2.0写的,所以在学习前先要弄清楚版本号,这点非常重要.本系列依然以selenium3为基础. 一.selenium简介 Sel ...

  10. git 获取线上代码并合并到本地

    //查询当前远程的版本 $ git remote -v //获取最新代码到本地(本地当前分支为[branch],获取的远端的分支为[origin/branch]) $ git fetch origin ...