123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691 |
- <template>
- <view>
- <view class="cu-progress-main" :style="{'border-radius':bgBR,'width': progressMainW,'height':progressMainH,'background-color': backgroundColor}">
- <view class="cu-progress" :style="{'left':areaLeft, 'flex-direction':flexDirection,'width':areaW,height:areaH}">
- <view class="cu-progress-bar" :style="{'bottom':pgBarBottom,'background':pgBarBg,'margin-left':pgBarML, 'margin-bottom':pgBarMB,'width': pgBarW,'height':pgBarH,'border-radius':pgBarBR,'background-color':noActiveColor}"></view>
- <movable-area class="cu-area" :style="{'flex-direction':flexDirection,'width':areaW,height:areaH}" @touchcancel="touchCancel" @touchstart="areaTouchStart"
- @touchmove="areaTouchMove" @touchend="touchEnd">
- <movable-view class="cu-handle" disabled="disabled" :animation="false" :style="{ 'top':handleT, 'width':handleS,'height':handleS,'border-radius': handleBR,'background-color':handleColor}"
- @change="change" :damping="damping" :x="handleX" :y="handleY" :direction="direction == 'vertical' ? 'vertical' : 'horizontal'">
- <text :class="handleIcon" :style="{'backgroundColor':iconColor,'font-size':iconS,'border-radius':iconBR}"></text>
- </movable-view>
- </movable-area>
- </view>
- <text v-if="getShowInfoStatus2view" class="cu-showInfo" :style="{'right':infoRt, 'left':infoLt, 'color':infoColor,'font-size':infoS,width:infoW}">{{showValue}}{{infoEndText}}</text>
- </view>
- </view>
- </template>
- <script>
- export default {
- data() {
- return {
- scale: 1,
- percent: 0, // progress进度
- // pgbw: '10px', // progress-bar width
- showValue: 0, //显示进度
- showVL: 0, // showValue 最大长度
- handleMoveStatus: false,
- handleX: 0, // 拖柄位置
- handleY: 0,
- progressBarInfo: {
- left: 0,
- bottom: 0,
- width: 0,
- height: 0
- },
- area: {
- left: 0,
- bottom: 0,
- width: 0,
- height: 0,
- top: 0
- },
- handle: {
- height: 0
- }
- };
- },
- beforeMount: function() {
- const res = uni.getSystemInfoSync()
- this.scale = 750 / res.windowWidth;
- // 0 为 false
- if (this.maxValue - this.minValue == 0) {
- console.error("min不能等于max:" + this.minValue + "->" + this.maxValue)
- return
- }
- else{
- this.showValue = this.valueFormat(this.value)
- }
- this.percent = Math.abs(this.showValue - this.minValue) / Math.abs(this.maxValue - this.minValue) * 100
- let minl = this.textLength(this.minValue + this.infoEndText)
- let maxl = this.textLength(this.maxValue + this.infoEndText)
- this.showVL = maxl > minl ? maxl : minl
- },
- mounted: function() {
- this.$nextTick(function() {
- const query = uni.createSelectorQuery().in(this)
- query.select(".cu-progress-bar").boundingClientRect(data => {
- this.progressBarInfo.width = data.width
- this.progressBarInfo.left = data.left
- this.progressBarInfo.bottom = data.bottom
- this.progressBarInfo.height = data.height
- if (this.direction == 'vertical'){
- this.handleY = this.progressBarInfo.height * (100 - this.percent) / 100
- }
- else{
- this.handleX = this.progressBarInfo.width * this.percent / 100
- }
- }).exec()
- query.select(".cu-area").boundingClientRect(data => {
- this.area.width = data.width
- this.area.left = data.left
- this.area.height = data.height
- this.area.bottom = data.bottom
- this.area.top = data.top
- }).exec()
- query.select(".cu-handle").boundingClientRect(data => {
- this.handle.height = data.height
- }).exec()
- })
- },
- props: {
- infoAlign: {
- default: 'right',
- type: String
- },
- step: {
- default: 1,
- type: [String, Number]
- },
- direction: {
- default: 'horizontal', //vertical 方向
- type: String
- },
- disabled: {
- default: false,
- type: [String, Boolean]
- },
- bgBorderRadius: {
- default: 0,
- type: [Number, String]
- },
- iconBorderRadius: {
- default: '8px',
- type: [Number, String]
- },
- iconColor: {
- default: 'inherit',
- type: String
- },
- iconSize: {
- default: '8px',
- type: [Number, String]
- },
- handleIcon: {
- default: '',
- type: String
- },
- backgroundColor: {
- default: 'inherit',
- type: String
- },
- max: {
- default: 100,
- type: [String, Number]
- },
- min: {
- default: 0,
- type: [String, Number]
- },
- value: {
- default: null, // 设置进度条进度
- type: [String, Number]
- },
- activeColor: {
- default: '#444444', // 已经过区域颜色
- type: String
- },
- noActiveColor: {
- default: '#888888', // 为经过区域颜色
- type: String
- },
- strokeWidth: {
- default: '3', // 行程宽度
- type: [String, Number]
- },
- damping: {
- default: 100, // 阻尼系数,越大移动越快
- type: [String, Number]
- },
- handleColor: {
- default: '#000000', // 拖柄颜色
- type: String
- },
- handleSize: {
- default: '8px', // 拖柄尺寸
- type: [String, Number]
- },
- handleBorderRadius: {
- default: '8px', // 拖柄圆角半径
- type: [String, Number]
- },
- showInfo: {
- default: false, // 是否在进度条右侧显示百分比
- type: [Boolean, String]
- },
- infoSize: {
- default: '16px', // 百分比显示字体尺寸
- type: [String, Number]
- },
- infoColor: {
- default: '#000000', // 百分比显示字体颜色
- type: String
- },
- infoEndText: {
- default: '',
- type: String
- },
- borderRadius: {
- default: 0, // 进度条圆角半径
- type: [String, Number]
- },
- width: {
- default: '200px', // 进度条总宽,如果显示百分比,则包括百分比在内的宽度
- type: [String, Number]
- },
- },
- computed: {
- getShowInfoStatus2view(){
- if ((this.showInfo == true || this.showInfo == 'true') && this.direction != "vertical"){
- return true
- }
- else{
- return false
- }
- },
- showVLC (){
- let minl = this.textLength(this.minValue.toFixed(0) + this.infoEndText)
- let maxl = this.textLength(this.maxValue.toFixed(0) + this.infoEndText)
-
- let L = maxl > minl ? maxl : minl
- return L
- },
- flexDirection (){
- if (this.direction == 'vertical'){
- return 'column'
- }
- else{
- return 'row'
- }
- },
- pgBarBottom (){
- // progress-
- if (this.direction == 'vertical'){
- return '0px'
- }
- else{
- return 'unset'
- }
- },
- showInfoStatus (){
- if (this.getShowInfoStatus() && this.direction != "vertical"){
- return true
- }
- else{
- return false
- }
- },
- pgBarBg(){
- let bg1
- if (this.direction == 'vertical'){
- bg1 = "linear-gradient(to top," + this.activeColor + ' ' + this.percent + "%," + this.noActiveColor + ' ' + this.percent + "%)"
- }
- else{
- bg1 = "linear-gradient(to right," + this.activeColor + ' ' + this.percent + "%," + this.noActiveColor + ' ' + this.percent + "%)"
- // qq
- let bg2 = "-webkit-linear-gradient(left," + this.activeColor + ' ' + this.percent + "%," + this.noActiveColor + ' ' + this.percent + "%)"
- let bg3 = "-o-linear-gradient(right," + this.activeColor + ' ' + this.percent + "%," + this.noActiveColor + ' ' + this.percent + "%)"
- let bg4 = "-moz-linear-gradient(right," + this.activeColor + ' ' + this.percent + "%," + this.noActiveColor + ' ' + this.percent + "%)"
- }
- return bg1
- },
- pgBarBR(){
- return this.sizeDeal(this.borderRadius)[2]
- },
- bgBR() {
- return this.sizeDeal(this.bgBorderRadius)[2]
- },
- iconBR() {
- return this.sizeDeal(this.iconBorderRadius)[2]
- },
- iconS() {
- return this.sizeDeal(this.iconSize)[2]
- },
- infoW() {
- const s = this.sizeDeal(this.infoSize)
- const size = s[0] * this.showVL + s[1]
- return size
- },
- infoS() {
- return this.sizeDeal(this.infoSize)[2]
- },
- infoRt(){
- // showinfo right
- if (this.infoAlign == 'left' && this.direction != 'vertical'){
- return 'unset'
- }
- else{ return 0 }
- },
- infoLt(){
- if (this.infoAlign == 'left' && this.direction != 'vertical'){
- return 0
- }
- else if (this.infoAlign == 'center' && this.direction != 'vertical'){
- let aw = this.area.width / 2
- const s = this.sizeDeal(this.infoSize)
- const size = aw - (s[0] * this.showVL) / 2 + 'px'
- return size
- }
- else{ return 'unset' }
- },
- areaW: {
- get (){
- if (this.direction == 'vertical'){
- return this.maxHeight(true)[2]
- }
- else{
- const s = this.sizeDeal(this.infoSize)
- const h = this.maxHeight()
- let w
- if (this.getShowInfoStatus()) {
- w = 'calc(' + this.width + ' - ' + s[0] * this.showVL + s[1] + ')'
- } else { w = this.width }
- return w
- }
- },
- set (w){ return w }
-
- },
- areaH: {
- get(){
- if (this.direction == 'vertical'){ return this.width }
- else{ return this.maxHeight()[2] }
- },
- set (v){ return v }
-
- },
- areaLeft() {
- if (this.infoAlign == 'left' && this.direction != 'vertical'){
- const s = this.sizeDeal(this.infoSize)
- const size = s[0] * this.showVL + s[1]
- return size
- }
- else{ return 0 }
- },
- pgBarW() {
- // width
- if (this.direction == 'vertical'){
- return this.sizeDeal(this.strokeWidth)[2]
- }
- else{
- const s = this.sizeDeal(this.infoSize)
- const w = this.sizeDeal(this.width)
- const s2 = this.sizeDeal(this.handleSize)
- let w2
- if (this.getShowInfoStatus()) {
- w2 = 'calc(' + w[2] + ' - ' + s[0] * this.showVL + s[1] + ' - ' + s2[2] + ')'
- } else {
- w2 = 'calc(' + w[2] + ' - ' + s2[2] + ')'
- }
- return w2
- }
- },
- pgBarH() {
- // height
- if (this.direction == 'vertical'){
- const w = this.sizeDeal(this.width)
- const s2 = this.sizeDeal(this.handleSize)
- let w2 = 'calc(' + w[2] + ' - ' + s2[2] + ')'
- return w2
- }
- else{ return this.sizeDeal(this.strokeWidth)[2] }
- },
- pgBarML() {
- // margin-left
- if (this.direction == 'vertical'){
- const s = this.sizeDeal(this.progressBarInfo.width)
- const ah = Number(this.area.width) / 2
- const t = ah - s[0] / 2 + 'px'
- return t
- }
- else{
- const s2 = this.sizeDeal(this.handleSize)
- return s2[0] / 2 + s2[1]
- }
- },
- pgBarMB() {
- // margin-bottom
- if (this.direction == 'vertical'){
- const s2 = this.sizeDeal(this.handleSize)
- return s2[0] / 2 + s2[1]
- }
- else{ return 0 }
- },
- handleS() {
- const s = this.sizeDeal(this.handleSize)
- return s[2]
- },
- handleL (){
- if (this.direction == 'vertical') {
- const s = this.sizeDeal(this.handleSize)
- const ah = Number(this.area.width) / 2
- const t = ah - s[0] / 2 + 'px'
- return t
- }
- else{
- return 'unset'
- }
- },
- handleT() {
- if (this.area.height && this.direction != 'vertical') {
- const s = this.sizeDeal(this.handleSize)
- const ah = Number(this.area.height) / 2
- const t = ah - s[0] / 2 + 'px'
- return t
- }
- else{
- return 'unset'
- }
- },
- handleBR() {
- const r = this.sizeDeal(this.handleBorderRadius)
- return r[2]
- },
- progressMainW() {
- let w
- if (this.direction == 'vertical'){
- w = this.maxHeight(true)[2]
- }
- else{
- w = this.width
- }
- return w
- },
- progressMainH() {
- let h
- if (this.direction == 'vertical'){
- h = this.width
- }
- else{
- h = this.maxHeight()[2]
- }
- return h
- },
- maxValue() {
- let max = Number.isNaN(parseFloat(this.max)) ? 100 : parseFloat(this.max)
- return this.valueFormat(max)
- },
- minValue() {
- let min = Number.isNaN(parseFloat(this.min)) ? 0 : parseFloat(this.min)
- let si = this.getStepInfo()
- return Number(min.toFixed(si[1]))
- // return this.valueFormat(min)
- },
- },
- watch: {
- showVLC (v){
- this.showVL = v
- if (this.direction != 'vertical'){
- const s = this.sizeDeal(this.infoSize)
- const h = this.maxHeight()
- let w
- if (this.getShowInfoStatus()) {
- w = 'calc(' + this.width + ' - ' + s[0] * this.showVL + s[1] + ')'
- } else {
- w = this.width
- }
- this.areaW = w
- this.areaH = h[2]
- }
- this.clientInit()
- },
- value(v) {
- // 当处于拖动状态时,禁止进度条外部触发变化
- if (!this.handleMoveStatus) {
- this.showValue = this.valueFormat(v)
- this.percent = (this.showValue - this.minValue) / Math.abs(this.maxValue - this.minValue) * 100
- if (this.direction == 'vertical'){
- this.handleY = this.progressBarInfo.height * this.percent / 100
- }
- else{
- this.handleX = this.progressBarInfo.width * this.percent / 100
- }
- }
- },
- },
- methods: {
- valueFormat (v){
- // set step
- v = Number(v - this.minValue).toFixed(7)
- let stepInfo = this.getStepInfo()
- let valueE = v * 10 ** stepInfo[1]
- let remainder = valueE % (stepInfo[0] * 10 ** stepInfo[1])
- let remainderInt = Math.floor(remainder)
- let value = (Math.floor(valueE) - remainderInt) / (10 ** stepInfo[1])
- return Number((value + this.minValue).toFixed(6))
- },
- getStepInfo() {
- // return step, decimal位数
- let step = Number(this.step)
- if (step <= 0 || !step){
- return [1, 0]
- }
- else{
- let steps = step.toString().split('.')
- if (steps.length == 1){
- return [step,0]
- }
- else {
- return [step,steps[1].length]
- }
- }
- },
- clientInit() {
- this.$nextTick(function() {
- const query = uni.createSelectorQuery().in(this)
- query.select(".cu-progress-bar").boundingClientRect(data => {
- this.progressBarInfo.width = data.width
- this.progressBarInfo.left = data.left
- this.progressBarInfo.bottom = data.bottom
- this.progressBarInfo.height = data.height
- if (this.direction == 'vertical'){
- this.handleY = this.progressBarInfo.height * this.percent / 100
- }
- else{
- this.handleX = this.progressBarInfo.width * this.percent / 100
- }
- }).exec()
- query.select(".cu-area").boundingClientRect(data => {
- this.area.width = data.width
- this.area.left = data.left
- this.area.height = data.height
- this.area.bottom = data.bottom
- this.area.top = data.top
- }).exec()
- if (this.maxValue - this.minValue == 0) {
- console.error("min不能等于max:" + this.minValue + "->" + this.maxValue)
- }
- else{
- let stepInfo = this.getStepInfo()
- let v = this.percent * (this.maxValue - this.minValue) / 100
- let valueE = v * 10 ** stepInfo[1]
- let remainder = valueE % (stepInfo[0] * 10 ** stepInfo[1])
- let remainderInt = Math.floor(remainder)
- let sv = (Math.floor(valueE) - remainderInt) / (10 ** stepInfo[1])
- this.showValue = sv
- }
- })
- },
- getShowInfoStatus(){
- if ((this.showInfo == true || this.showInfo == 'true') && this.direction != "vertical" && this.infoAlign !== 'center'){
- return true
- }
- else{
- return false
- }
- },
- textLength(t) {
- t = t.toString()
- let int = t.split('.')[0]
- let subt = t.match(/[^\x00-\xff]/g)
- let subl = 0
- if (subt) {
- subl = subt.length
- }
- let l = (int.length - subl + this.getStepInfo()[1]) / 3 * 2 + subl + 0.2
- return Number(l.toFixed(2))
- },
- maxHeight(vertical) {
- let h = []
- if (!vertical){ // direction 为 vertical 时不显示info
- let subt = this.infoEndText.match(/[^\x00-\xff]/g)
- if (subt){
- h.push(this.sizeDeal(this.infoSize)[0] * 1.1)
- }
- else{
- h.push(this.sizeDeal(this.infoSize)[0])
- }
- }
- h.push(this.sizeDeal(this.strokeWidth)[0])
- h.push(this.sizeDeal(this.handleSize)[0])
- h.sort(function(a, b) {
- return b - a
- }) // 降序
- return [h[0], 'px', h[0] + 'px']
- },
- sizeDeal(size) {
- // 分离字体大小和单位,rpx 转 px
- let s = Number.isNaN(parseFloat(size)) ? 0 : parseFloat(size)
- let u = size.toString().replace(/[0-9]/g, '')
- if (u == 'rpx') {
- s /= this.scale
- u = 'px'
- } else if (u == '') {
- u = 'px'
- }else if (u == 'vw') {
- u = 'px'
- s = s / 100 * 750 / this.scale
- }
- return [s, u, s + u]
- },
- change (){
- this.$emit('change', {
- type: 'change',
- value: this.showValue,
- })
- },
- handleMove(x_) {
- let x = x_
- x = x >= 0 ? x : 0
- let s = this.sizeDeal(this.handleSize)
- let cp
- let sv
- if (this.direction == 'vertical'){
- // #ifdef H5
- x = x - s[0] / 2 - this.area.bottom // ?
- cp = x / (this.area.height - s[0] - 1)
- // #endif
- // #ifndef H5
- x = x - this.area.top - s[0] / 2
- cp = x / (this.area.height - s[0] - 1)
- // #endif
- cp = cp <= 1 ? cp : 1
- cp = cp > 0 ? cp : 0
- let value = Number(((1 - cp) * (this.maxValue - this.minValue))) + this.minValue
- this.percent = (1 - cp) * 100
- this.showValue = this.valueFormat(value)
- this.handleY = x
- }
- else{
- cp = x / (this.area.width - s[0] - 1) // 多减 1 避免达不到maxValue
- cp = cp <= 1 ? cp : 1
- cp = cp > 0 ? cp : 0
- let value = Number((cp * (this.maxValue - this.minValue))) + this.minValue
- this.percent = cp * 100
- this.showValue = this.valueFormat(value)
- this.handleX = x
- }
- this.$emit('dragging', {
- type: 'dragging',
- value: this.showValue
- })
- },
- touchEnd() {
- if (!this.disabled){
- this.handleMoveStatus = false
- this.$emit('dragged', {
- type: 'dragged',
- value: this.showValue
- })
- }
- },
- areaTouchStart(e) {
- if (!this.disabled){
- this.handleMoveStatus = true
- let s = this.sizeDeal(this.handleSize)
- let tapX
- if (this.direction == 'vertical'){
- // #ifdef H5
- tapX = this.area.height + e.changedTouches[0].pageY
- // #endif
- // #ifndef H5
- tapX = e.changedTouches[0].pageY
- // #endif
- }
- else{
- tapX = e.changedTouches[0].pageX - this.area.left - s[0] / 2 // 拖柄中心与鼠标箭头一致
- }
- tapX = tapX >= 0 ? tapX : 0
- this.handleMove(tapX)
- this.$emit('dragstart', {
- type: 'dragstart',
- value: this.showValue
- })
- }
- },
- areaTouchMove(e) {
- if (!this.disabled){
- let s = this.sizeDeal(this.handleSize)
- let tapX
- if (this.direction == 'vertical'){
- // #ifdef H5
- tapX = this.area.height + e.changedTouches[0].pageY
- // #endif
- // #ifndef H5
- tapX = e.changedTouches[0].pageY
- // #endif
- }
- else{
- tapX = e.changedTouches[0].pageX - this.area.left - s[0] / 2
- }
- tapX = tapX >= 0 ? tapX : 0
- this.handleMove(tapX)
- }
- },
- touchCancel() {
- if (!this.disabled){
- this.touchEnd()
- this.$emit('dragcancel', {
- type: 'dragcancel',
- value: this.showValue
- })
- }
- },
- }
- }
- </script>
- <style scoped>
- @import 'cu-progress.css'
- </style>
|