bing-progress.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. <template>
  2. <view class="bing-progress" :style="{width:bpWidth,height:bpHeight,borderRadius:borderRadius,
  3. backgroundColor:backgroundColor,flexDirection:direction!='vertical'?'row':'column'}">
  4. <!-- 进度 -->
  5. <!-- #ifdef APP-NVUE -->
  6. <div class="bp-bar_max"
  7. :style="{width:barMaxWidth,height:barMaxHeight,backgroundColor:noActiveColor,
  8. flexDirection:direction!='vertical'?'row':'column',left:barMaxLeft,borderRadius:barBorderRadius}">
  9. <div class="bp-bar_sub_active"
  10. :style="{width:barSubActiveWidth,height:barSubActiveHeight,backgroundColor:subActiveColor,
  11. top:subActiveTop,bottom:subActiveBottom,left:subActiveLeft,right:subActiveRight,borderRadius:isActiveCircular?barBorderRadius:0}"></div>
  12. <div class="bp-bar_active"
  13. :style="{width:barActiveWidth,height:barActiveHeight,backgroundColor:activeColor,
  14. top:activeTop,bottom:activeBottom,left:activeLeft,right:activeRight,borderRadius:isActiveCircular?barBorderRadius:0}"></div>
  15. </div>
  16. <!-- #endif -->
  17. <!-- #ifndef APP-NVUE -->
  18. <view class="bp-bar_max"
  19. :style="{width:barMaxWidth,height:barMaxHeight,backgroundColor:noActiveColor,borderRadius:barBorderRadius,
  20. flexDirection:direction!='vertical'?'row':'column',left:barMaxLeft}">
  21. <view class="bp-bar_sub_active"
  22. :style="{width:barSubActiveWidth,height:barSubActiveHeight,backgroundColor:subActiveColor,
  23. top:subActiveTop,bottom:subActiveBottom,left:subActiveLeft,right:subActiveRight,borderRadius:isActiveCircular?barBorderRadius:0}"></view>
  24. <view class="bp-bar_active"
  25. :style="{width:barActiveWidth,height:barActiveHeight,backgroundColor:activeColor,
  26. top:activeTop,bottom:activeBottom,left:activeLeft,right:activeRight,borderRadius:isActiveCircular?barBorderRadius:0}"></view>
  27. </view>
  28. <!-- #endif -->
  29. <movable-area id="bp-marea" class="bp-marea" @touchmove.stop.prevent="touchmove" @touchstart.stop.prevent="touchstart" @touchcancel="touchend" @touchend="touchend"
  30. :style="{width:mareaWidth,height:mareaHeight,left:mareaLeft}">
  31. <!-- 拖柄 -->
  32. <movable-view id="bp-mview" class="bp-mview" :direction="direction=='vertical'?'vertical':'horizontal'" :animation="false"
  33. :disabled="true" :x="handleX" :y="handleY" friction="10" damping="100"
  34. :style="{width:mhandleWidth,height:mhandleHeight,backgroundColor:handleColor,
  35. borderRadius:handleBorderRadius,fontSize:infoFontSize,top:mhandleTop}">
  36. <view id="bp-handle" class="bp-handle" :style="{fontSize:infoFontSize,width:mhandleWidth,height:mhandleHeight,borderRadius:handleBorderRadius}">
  37. <image class="bp-handle-img" :src="handleImgUrl" v-if="handleImgUrl"
  38. :style="{fontSize:infoFontSize,width:mhandleWidth,height:mhandleHeight,borderRadius:handleBorderRadius}"></image>
  39. <!-- 进度值 -->
  40. <text class="bp-handle-text" v-if="handleImgUrl=='' && infoAlign=='handle' && showInfo"
  41. :style="{fontSize:infoFontSize,color:infoColor,width:mhandleWidth,height:textHeight,borderRadius:'20px'}">{{ infoContent=='subValue'?msubValue:showValue }}{{ infoEndText }}</text>
  42. <!-- 挂件 -->
  43. <!-- #ifndef APP-NVUE -->
  44. <!-- 图片挂件 -->
  45. <image v-if="widgetPos=='top' && widgetUrl" class="bp-handle-widget" :src="widgetUrl" :style="{flexDirection: 'column',borderRadius:mwidgetBorderRadius, bottom: moffset,width:mwidgetWidth,height:mwidgetHeight,opacity:widgetOpacity,transform: mwidgetAngle}"></image>
  46. <image v-if="widgetPos=='right' && widgetUrl" class="bp-handle-widget" :src="widgetUrl" :style="{flexDirection: 'row',borderRadius:mwidgetBorderRadius,left: moffset,width:mwidgetWidth,height:mwidgetHeight,opacity:widgetOpacity,transform: mwidgetAngle}"></image>
  47. <image v-if="widgetPos=='bottom' && widgetUrl" class="bp-handle-widget" :src="widgetUrl" :style="{flexDirection: 'column',borderRadius:mwidgetBorderRadius,top: moffset,width:mwidgetWidth,height:mwidgetHeight,opacity:widgetOpacity,transform: mwidgetAngle}"></image>
  48. <image v-if="widgetPos=='left' && widgetUrl" class="bp-handle-widget" :src="widgetUrl" :style="{flexDirection: 'row',borderRadius:mwidgetBorderRadius,right: moffset,width:mwidgetWidth,height:mwidgetHeight,opacity:widgetOpacity,transform: mwidgetAngle}"></image>
  49. <!-- 自定义元素挂件 -->
  50. <view v-if="widgetPos=='top' && widgetUrl==''" class="bp-handle-widget" :style="{flexDirection: 'column',borderRadius:mwidgetBorderRadius,bottom: moffset,width:mwidgetWidth,height:mwidgetHeight,opacity:widgetOpacity,transform: mwidgetAngle}">
  51. <slot/>
  52. </view>
  53. <view v-if="widgetPos=='right' && widgetUrl==''" class="bp-handle-widget" :style="{flexDirection: 'row',borderRadius:mwidgetBorderRadius,left: moffset,width:mwidgetWidth,height:mwidgetHeight,opacity:widgetOpacity,transform: mwidgetAngle}">
  54. <slot/>
  55. </view>
  56. <view v-if="widgetPos=='bottom' && widgetUrl==''" class="bp-handle-widget" :style="{flexDirection: 'column',borderRadius:mwidgetBorderRadius,top: moffset,width:mwidgetWidth,height:mwidgetHeight,opacity:widgetOpacity,transform: mwidgetAngle}">
  57. <slot/>
  58. </view>
  59. <view v-if="widgetPos=='left' && widgetUrl==''" class="bp-handle-widget" :style="{flexDirection: 'row',borderRadius:mwidgetBorderRadius,right: moffset,width:mwidgetWidth,height:mwidgetHeight,opacity:widgetOpacity,transform: mwidgetAngle}">
  60. <slot/>
  61. </view>
  62. <!-- #endif -->
  63. </view>
  64. </movable-view>
  65. </movable-area>
  66. <!-- 进度值 -->
  67. <text class="bp-value" v-if="showValueState() || (infoAlign=='center'&&direction!='vertical' && showInfo)"
  68. :style="{color:infoColor,fontSize:infoFontSize,left:valueLeft,width:valueWidth()+'px'}">{{ infoContent=='subValue'?msubValue:showValue }}{{ infoEndText }}</text>
  69. </view>
  70. </template>
  71. <script>
  72. /**
  73. * 进度条,副进度条
  74. */
  75. export default {
  76. created() {
  77. /**
  78. * 获取系统屏幕信息,用于后续单位换算
  79. */
  80. const systemInfo = uni.getSystemInfoSync()
  81. this.px2rpx = 750 / systemInfo.screenWidth
  82. this.screenWidth = systemInfo.screenWidth
  83. this.screenHeight = systemInfo.screenHeight
  84. },
  85. mounted() {
  86. // #ifndef APP-NVUE
  87. /**
  88. * 非NVUE movable-area 滑动事件获取到的位置是相对于文档的,获取组件位置,用于计算滑块位置
  89. */
  90. this.updateRect()
  91. // #endif
  92. this.mmax = this.valueFormat(this.max,false)
  93. this.percent = Math.abs((this.valueFormat(this.value) - this.min) / (this.mmax - this.min))
  94. this.subPercent = Math.abs((this.valueFormat(this.subValue,true) - this.min) / (this.mmax - this.min))
  95. if(this.reverse) {
  96. if(this.direction!='vertical') {
  97. this.handleX = (1 - this.percent) * this.barMaxLength
  98. }
  99. else {
  100. this.handleY = this.percent * this.barMaxLength
  101. }
  102. }
  103. else {
  104. if(this.direction!='vertical') {
  105. this.handleX = this.percent * this.barMaxLength
  106. }
  107. else {
  108. this.handleY = (1 - this.percent) * this.barMaxLength
  109. }
  110. }
  111. if(this.bpname=='test') {
  112. console.log(this.mainInfo)
  113. }
  114. },
  115. /**
  116. * sub表示副进度条属性
  117. */
  118. props: {
  119. // 组件名字
  120. bpname: {
  121. type: String,
  122. default: ''
  123. },
  124. width: {
  125. type: String,
  126. default: '300px'
  127. },
  128. strokeWidth: {
  129. type: String,
  130. default: '30px'
  131. },
  132. backgroundColor: {
  133. type: String,
  134. default: 'rgba(0,0,0,0)'
  135. },
  136. noActiveColor: {
  137. type: String,
  138. default: "#00ffff"
  139. },
  140. activeColor: {
  141. type: String,
  142. default: "#0000ff"
  143. },
  144. subActiveColor: {
  145. type: String,
  146. default: "#ffaaaa"
  147. },
  148. handleColor: {
  149. type: String,
  150. default: "#ffff00"
  151. },
  152. infoColor: {
  153. type: String,
  154. default: "#000000"
  155. },
  156. // 整个进度条的外边界圆角半径
  157. borderRadius: {
  158. type: String,
  159. default: '5px'
  160. },
  161. // 进度条内部滑轨圆角半径
  162. barBorderRadius: {
  163. type: String,
  164. default: '5px'
  165. },
  166. // active and subActive 是否显示圆角 NVUE默认true,其他默认false
  167. // #ifdef APP-NVUE
  168. isActiveCircular: {
  169. type: Boolean,
  170. default: true
  171. },
  172. // #endif
  173. // #ifndef APP-NVUE
  174. isActiveCircular: {
  175. type: Boolean,
  176. default: false
  177. },
  178. // #endif
  179. handleWidth: {
  180. type: String,
  181. default: '50px'
  182. },
  183. handleHeight: {
  184. type: String,
  185. default: '40px'
  186. },
  187. handleBorderRadius: {
  188. type: String,
  189. default: '5px'
  190. },
  191. handleImgUrl: {
  192. type: String,
  193. default: ''
  194. },
  195. disabled: {
  196. type: Boolean,
  197. default: false
  198. },
  199. direction: {
  200. type: String,
  201. default: 'horizontal'
  202. },
  203. infoEndText: {
  204. type: String,
  205. default: ""
  206. },
  207. infoFontSize: {
  208. type: String,
  209. default: '18px'
  210. },
  211. showInfo: {
  212. type: Boolean,
  213. default: true
  214. },
  215. // 进度值显示value还是subValue
  216. infoContent: {
  217. type: String,
  218. default: 'value'
  219. },
  220. // 进度值显示位置 left, right, center, handle
  221. infoAlign: {
  222. type: String,
  223. default: 'right'
  224. },
  225. max: {
  226. type: Number,
  227. default: 100
  228. },
  229. min: {
  230. type: Number,
  231. default: 0
  232. },
  233. value: {
  234. type: Number,
  235. default: 0
  236. },
  237. subValue: {
  238. type: Number,
  239. default: 0
  240. },
  241. step: {
  242. type: Number,
  243. default: 1
  244. },
  245. // 副进度条步长
  246. subStep: {
  247. type: Number,
  248. default: 1
  249. },
  250. // true连续滑动,false步进,即以step的间隔变化
  251. continuous: {
  252. type: Boolean,
  253. default: true
  254. },
  255. // 副进度条continuous
  256. subContinuous: {
  257. type: Boolean,
  258. default: true
  259. },
  260. reverse: {
  261. type: Boolean,
  262. default: false
  263. },
  264. // 挂件位置 top, right, bottom, left
  265. widgetPos: {
  266. type: String,
  267. default: "top"
  268. },
  269. widgetHeight: {
  270. type: [String,Number],
  271. default: '40px'
  272. },
  273. widgetWidth: {
  274. type: [String,Number],
  275. default: '50px'
  276. },
  277. widgetBorderRadius: {
  278. type: [String,Number],
  279. default: '5px'
  280. },
  281. // 挂件不透明度 0完全透明 1不透明
  282. widgetOpacity: {
  283. type: [String,Number],
  284. default: 1
  285. },
  286. // 挂件距离组件的偏移量,正数原理组件,负数靠近组件
  287. widgetOffset: {
  288. type: [String,Number],
  289. default: '0px'
  290. },
  291. // 挂件图片
  292. widgetUrl: {
  293. type: String,
  294. default: ''
  295. },
  296. // 挂件旋转角度
  297. widgetAngle: {
  298. type: [String,Number],
  299. default: 0
  300. }
  301. },
  302. data() {
  303. return {
  304. handleX: 50,
  305. handleY: 0,
  306. px2rpx: 1,
  307. percent: 0, // 0-1
  308. subPercent: 0, // 0-1
  309. mainInfo: {
  310. left: 0,
  311. top: 0,
  312. bottom: 0,
  313. right: 0
  314. },
  315. touchState: false,
  316. screenHeight: 0,
  317. screenWidth: 0,
  318. msubValue: 0,
  319. moveable: true,
  320. lastTouchTime: 0,
  321. mmax: 100
  322. }
  323. },
  324. watch: {
  325. /**
  326. * @param {Object} newValue
  327. * @param {Object} oldValue
  328. */
  329. value(newValue, oldValue) {
  330. if(!this.touchState) {
  331. newValue = this.valueSetBoundary(newValue)
  332. this.percent = Math.abs((newValue - this.min) / (this.mmax - this.min))
  333. }
  334. },
  335. showValue(newValue, oldValue) {
  336. // 步进
  337. if(!this.continuous) {
  338. let percent
  339. if(this.reverse) {
  340. if(this.direction!='vertical') {
  341. percent = Math.abs(1 - (newValue - this.min) / (this.mmax - this.min))
  342. this.handleX = percent * this.barMaxLength
  343. }
  344. else {
  345. percent = Math.abs((newValue - this.min) / (this.mmax - this.min))
  346. this.handleY = percent * this.barMaxLength
  347. }
  348. }
  349. else {
  350. if(this.direction!='vertical') {
  351. percent = Math.abs((newValue - this.min) / (this.mmax - this.min))
  352. this.handleX = percent * this.barMaxLength
  353. }
  354. else {
  355. percent = (1 - Math.abs((newValue - this.min) / (this.mmax - this.min)))
  356. this.handleY = percent * this.barMaxLength
  357. }
  358. }
  359. }
  360. this.$emit("change", {bpname: this.bpname,type: 'change',value:this.showValue,subValue:this.msubValue})
  361. this.$emit("valuechange", {bpname: this.bpname,type: 'valuechange',value:this.showValue,subValue:this.msubValue})
  362. },
  363. percent(newValue, oldValue) {
  364. // 连续
  365. if(this.continuous) {
  366. if(this.reverse) {
  367. if(this.direction!='vertical') {
  368. this.handleX = (1 - newValue) * this.barMaxLength
  369. }
  370. else {
  371. this.handleY = newValue * this.barMaxLength
  372. }
  373. }
  374. else {
  375. if(this.direction!='vertical') {
  376. this.handleX = newValue * this.barMaxLength
  377. }
  378. else {
  379. this.handleY = (1 - newValue) * this.barMaxLength
  380. }
  381. }
  382. }
  383. },
  384. subValue(newValue, oldValue) {
  385. newValue = this.valueSetBoundary(newValue)
  386. if(this.subContinuous) {
  387. this.msubValue = newValue
  388. }
  389. else {
  390. this.msubValue = this.valueFormat(newValue, true)
  391. }
  392. this.subPercent = Math.abs((newValue - this.min) / (this.mmax - this.min))
  393. this.$emit("change", {bpname: this.bpname,type: 'change',value:this.showValue,subValue:this.msubValue})
  394. this.$emit("subvaluechange", {bpname: this.bpname,type: 'subvaluechange',value:this.showValue,subValue:this.msubValue})
  395. },
  396. max(newValue,oldValue) {
  397. this.mmax = this.valueFormat(newValue,false)
  398. }
  399. },
  400. computed: {
  401. bpWidth() {
  402. if(this.direction=="vertical") {
  403. return this.maxHeight()[2]
  404. }
  405. return this.sizeDeal(this.width)[2]
  406. },
  407. bpHeight() {
  408. if(this.direction=="vertical") {
  409. return this.sizeDeal(this.width)[2]
  410. }
  411. return this.maxHeight()[2]
  412. },
  413. mareaWidth() {
  414. if(this.direction=="vertical") {
  415. return this.maxHeight()[2]
  416. }
  417. let width = this.sizeDeal(this.width)[0]
  418. return (width - this.textWidth()) + 'px'
  419. },
  420. mareaHeight() {
  421. if(this.direction=="vertical") {
  422. let width = this.sizeDeal(this.width)[0]
  423. return (width - this.textWidth()) + 'px'
  424. }
  425. return this.maxHeight()[2]
  426. },
  427. mareaLeft() {
  428. if(this.showValueState()) {
  429. if(this.infoAlign == 'left') {
  430. return this.textWidth() + 'px'
  431. }
  432. }
  433. return 0
  434. },
  435. barMaxHeight() {
  436. if(this.direction=="vertical") {
  437. let width = this.sizeDeal(this.width)[0]
  438. let handleWidth = this.sizeDeal(this.handleWidth)
  439. return (width - this.textWidth() - handleWidth[0]) + 'px'
  440. }
  441. return this.sizeDeal(this.strokeWidth)[2]
  442. },
  443. barMaxWidth() {
  444. if(this.direction=="vertical") {
  445. return this.sizeDeal(this.strokeWidth)[2]
  446. }
  447. let width = this.sizeDeal(this.width)[0]
  448. let handleWidth = this.sizeDeal(this.handleWidth)
  449. return (width - this.textWidth() - handleWidth[0]) + 'px'
  450. },
  451. barMaxLeft() {
  452. if(this.showValueState()) {
  453. if(this.infoAlign == 'left') {
  454. return this.textWidth() + this.sizeDeal(this.handleWidth)[0] / 2 + 'px'
  455. }
  456. }
  457. if(this.direction != 'vertical') {
  458. return this.sizeDeal(this.handleWidth)[0] / 2 + 'px'
  459. }
  460. // vertical
  461. return (this.maxHeight()[0] - this.sizeDeal(this.strokeWidth)[0]) / 2 + 'px'
  462. },
  463. activeRight() {
  464. if(this.reverse) {
  465. return 0
  466. }
  467. return 'unset'
  468. },
  469. activeLeft() {
  470. if(this.reverse) {
  471. return 'unset'
  472. }
  473. return 0
  474. },
  475. activeTop() {
  476. if(this.reverse) {
  477. return 0
  478. }
  479. return 'unset'
  480. },
  481. activeBottom() {
  482. if(this.reverse) {
  483. return 'unset'
  484. }
  485. return 0
  486. },
  487. barActiveWidth() {
  488. if(this.direction=="vertical") {
  489. return this.sizeDeal(this.strokeWidth)[2]
  490. }
  491. let percent
  492. if(this.continuous) {
  493. percent = this.percent
  494. }
  495. else {
  496. percent = Math.abs((this.showValue - this.min) / (this.mmax - this.min))
  497. }
  498. return this.barMaxLength * percent + 'px'
  499. },
  500. barActiveHeight() {
  501. if(this.direction=="vertical") {
  502. let percent
  503. if(this.continuous) {
  504. percent = this.percent
  505. }
  506. else {
  507. percent = Math.abs((this.showValue - this.min) / (this.mmax - this.min))
  508. }
  509. return this.barMaxLength * percent + 'px'
  510. }
  511. return this.sizeDeal(this.strokeWidth)[2]
  512. },
  513. subActiveTop() {
  514. if(this.reverse) {
  515. return 0
  516. }
  517. return 'unset'
  518. },
  519. subActiveBottom() {
  520. if(this.reverse) {
  521. return 'unset'
  522. }
  523. return 0
  524. },
  525. subActiveRight() {
  526. if(this.reverse) {
  527. return 0
  528. }
  529. return 'unset'
  530. },
  531. subActiveLeft() {
  532. if(this.reverse) {
  533. return 'unset'
  534. }
  535. return 0
  536. },
  537. barSubActiveWidth() {
  538. if(this.direction == "vertical") {
  539. return this.sizeDeal(this.strokeWidth)[2]
  540. }
  541. if(this.subContinuous) {
  542. return this.barMaxLength * this.subPercent + 'px'
  543. }
  544. else {
  545. return this.barMaxLength * Math.abs((this.msubValue - this.min) / (this.mmax - this.min)) + 'px'
  546. }
  547. },
  548. barSubActiveHeight() {
  549. if(this.direction == "vertical") {
  550. if(this.subContinuous) {
  551. return this.barMaxLength * this.subPercent + 'px'
  552. }
  553. else {
  554. this.barMaxLength * Math.abs((this.msubValue - this.min) / (this.mmax - this.min)) + 'px'
  555. }
  556. }
  557. return this.sizeDeal(this.strokeWidth)[2]
  558. },
  559. mhandleWidth() {
  560. if(this.direction == "vertical") {
  561. return this.sizeDeal(this.handleHeight)[2]
  562. }
  563. return this.sizeDeal(this.handleWidth)[2]
  564. },
  565. mhandleHeight() {
  566. if(this.direction == "vertical") {
  567. return this.sizeDeal(this.handleWidth)[2]
  568. }
  569. return this.sizeDeal(this.handleHeight)[2]
  570. },
  571. mhandleTop() {
  572. if(this.direction == 'vertical') {
  573. return 0
  574. }
  575. else {
  576. // 拖柄垂直居中
  577. let handle = this.sizeDeal(this.handleHeight)[0]
  578. let top = this.maxHeight()[0] / 2 - handle / 2 + 'px'
  579. return top
  580. }
  581. },
  582. showValue() {
  583. return this.valueFormat(this.percent * (this.mmax - this.min) + this.min)
  584. },
  585. textHeight() {
  586. let infoSize = this.sizeDeal(this.infoFontSize)
  587. return infoSize[0]*1.2 + infoSize[1]
  588. },
  589. valueLeft() {
  590. if(this.infoAlign=='left') {
  591. return 0
  592. }
  593. else if(this.infoAlign == 'center') {
  594. let width = this.sizeDeal(this.width)
  595. return width[0]/2 - this.valueWidth()/2 + 'px'
  596. }
  597. else if(this.infoAlign=='right'){
  598. let width = this.sizeDeal(this.width)
  599. return width[0] - this.textWidth() + 'px'
  600. }
  601. return 0
  602. },
  603. barMaxLength() {
  604. let width = this.sizeDeal(this.width)[0]
  605. let handleWidth = this.sizeDeal(this.handleWidth)
  606. return width - this.textWidth() - handleWidth[0]
  607. },
  608. mwidgetWidth() {
  609. return this.sizeDeal(this.widgetWidth)[2];
  610. },
  611. mwidgetHeight() {
  612. return this.sizeDeal(this.widgetHeight)[2];
  613. },
  614. moffset() {
  615. let off = this.sizeDeal(this.widgetOffset);
  616. // console.log(off)
  617. switch(this.widgetPos) {
  618. case 'top':
  619. return this.sizeDeal(this.mhandleHeight)[0] + off[0] + 'px'
  620. case 'right':
  621. return this.sizeDeal(this.mhandleWidth)[0] + off[0] + 'px'
  622. case 'bottom':
  623. return this.sizeDeal(this.mhandleHeight)[0] + off[0] + 'px'
  624. case 'left':
  625. return this.sizeDeal(this.mhandleWidth)[0] + off[0] + 'px'
  626. }
  627. return 0
  628. },
  629. mwidgetBorderRadius() {
  630. return this.sizeDeal(this.widgetBorderRadius)[2];
  631. },
  632. mwidgetAngle() {
  633. return "rotate("+Number(this.widgetAngle)+"deg)"
  634. }
  635. },
  636. methods: {
  637. prevent(e) {
  638. console.log(1)
  639. },
  640. updateRect() {
  641. // #ifndef APP-NVUE
  642. /**
  643. * 非NVUE movable-area 滑动事件获取到的位置是相对于文档的,获取组件位置,用于计算滑块位置
  644. */
  645. let query = uni.createSelectorQuery().in(this)
  646. query.select('.bing-progress').boundingClientRect(data => {
  647. this.mainInfo.top = data.top
  648. this.mainInfo.left = data.left
  649. this.mainInfo.bottom = data.bottom
  650. this.mainInfo.right = data.right
  651. }).exec()
  652. // #endif
  653. },
  654. touchstart(e) {
  655. if(!this.disabled) {
  656. // #ifdef APP-NVUE
  657. e.stopPropagation()
  658. e.target.attr.preventGesture = true
  659. if(this.direction == 'vertical' && e.target.attr.id != 'bp-mview' && (e.timestamp - this.lastTouchTime > 100)) {
  660. this.moveable = false
  661. }
  662. this.lastTouchTime = e.timestamp
  663. // #endif
  664. // #ifndef APP-NVUE
  665. /**
  666. * 防止组件在文档流中的位置被修改,导致组件进度值异常
  667. */
  668. this.updateRect()
  669. // #endif
  670. // 阻止组件信息异常情况下的进度值修改
  671. if(this.mainInfo.top > this.screenHeight) {
  672. this.$emit("dragstart", {bpname: this.bpname,type: 'dragstart',value:this.showValue,subValue:this.msubValue})
  673. return
  674. }
  675. this.touchState = true
  676. let detail = e.changedTouches[0]
  677. this.handleMove(detail)
  678. this.$emit("dragstart", {bpname: this.bpname,type: 'dragstart',value:this.showValue,subValue:this.msubValue})
  679. }
  680. },
  681. touchmove(e) {
  682. if(!this.disabled) {
  683. let detail = e.changedTouches[0]
  684. this.handleMove(detail)
  685. this.$emit("dragging", {bpname: this.bpname,type: 'dragging',value:this.showValue,subValue:this.msubValue})
  686. }
  687. },
  688. touchend(e) {
  689. if(!this.disabled) {
  690. // #ifdef APP-NVUE
  691. if(!this.moveable) {
  692. this.moveable = true
  693. return
  694. }
  695. // #endif
  696. let detail = e.changedTouches[0]
  697. this.handleMove(detail)
  698. this.touchState = false
  699. this.$emit("dragend", {bpname: this.bpname,type: 'dragend',value:this.showValue,subValue:this.msubValue})
  700. }
  701. },
  702. handleMove(detail) {
  703. let width = this.sizeDeal(this.width)[0]
  704. let handleWidth = this.sizeDeal(this.handleWidth)
  705. let percent
  706. if(this.direction!='vertical') {
  707. if(this.infoAlign=='left') {
  708. // #ifndef APP-NVUE
  709. percent = (detail.pageX - this.mainInfo.left - this.textWidth() - handleWidth[0]/2)/ this.barMaxLength
  710. // #endif
  711. // #ifdef APP-NVUE
  712. percent = (detail.pageX - handleWidth[0]/2)/ this.barMaxLength
  713. // #endif
  714. }
  715. else {
  716. // #ifndef APP-NVUE
  717. percent = (detail.pageX - this.mainInfo.left - handleWidth[0]/2)/ this.barMaxLength
  718. // #endif
  719. // #ifdef APP-NVUE
  720. percent = (detail.pageX - handleWidth[0]/2)/ this.barMaxLength
  721. // #endif
  722. }
  723. }
  724. else {
  725. // #ifdef APP-NVUE
  726. percent = 1 - (detail.pageY - handleWidth[0]/2- 1) / this.barMaxLength
  727. // #endif
  728. // #ifndef APP-NVUE
  729. percent = 1 - (detail.clientY - this.mainInfo.top - handleWidth[0]/2)/ this.barMaxLength
  730. // #endif
  731. }
  732. percent = percent > 0 ? percent : 0
  733. percent = percent < 1 ? percent : 1
  734. if(this.reverse) {
  735. this.percent = 1 - percent
  736. }
  737. else {
  738. this.percent = percent
  739. }
  740. },
  741. showValueState() {
  742. if(this.direction != 'vertical' && this.showInfo && (this.infoAlign=='left' || this.infoAlign=='right')) {
  743. return true
  744. }
  745. return false
  746. },
  747. valueSetBoundary(value) {
  748. // 控制value在合法范围内
  749. if(this.mmax > this.min) {
  750. value = value < this.mmax ? value : this.mmax
  751. value = value > this.min ? value : this.min
  752. }
  753. else {
  754. value = value > this.mmax ? value : this.mmax
  755. value = value < this.min ? value : this.min
  756. }
  757. return value
  758. },
  759. /**
  760. * @param {Object} v
  761. * @param {Object} isSub 是否是副副进度条
  762. */
  763. valueFormat (v,isSub){
  764. // set step
  765. v = this.valueSetBoundary(v)
  766. let stepInfo = this.stepInfo(isSub)
  767. v = Number(v - this.min).toFixed(stepInfo[1])
  768. let step = stepInfo[0] * 10 ** stepInfo[1]
  769. let valueE = v * 10 ** stepInfo[1]
  770. let remainder = valueE % step
  771. let remainderInt = Math.floor(remainder)
  772. // 对余数四舍五入0-1
  773. let sub = Math.round(remainder / step)
  774. let value = (Math.floor(valueE) - remainderInt + sub*step) / (10 ** stepInfo[1])
  775. value = Number((value + this.min).toFixed(stepInfo[1]))
  776. return value
  777. },
  778. /**
  779. * @param {Object} v
  780. * @param {Object} isSub 是否是副副进度条
  781. */
  782. stepInfo(isSub) {
  783. // return step, decimal位数
  784. let step
  785. if(isSub) {
  786. step = Number(this.subStep)
  787. }
  788. else {
  789. step = Number(this.step)
  790. }
  791. if (step <= 0 || !step){
  792. return [1, 0]
  793. }
  794. else{
  795. let steps = step.toString().split('.')
  796. if (steps.length == 1){
  797. return [step,0]
  798. }
  799. else {
  800. return [step,steps[1].length]
  801. }
  802. }
  803. },
  804. textWidth() {
  805. if(this.showValueState()) {
  806. let numWidth = this.mmax.toString().length> this.min.toString().length? this.mmax.toString().length: this.min.toString().length
  807. let textWidth = ((numWidth + this.stepInfo()[1]) * 0.7 + this.infoEndText.length) * this.sizeDeal(this.infoFontSize)[0]
  808. return Number(textWidth.toFixed(2))
  809. }
  810. return 0
  811. },
  812. valueWidth() {
  813. let numWidth = this.mmax.toString().length> this.min.toString().length? this.mmax.toString().length: this.min.toString().length
  814. let textWidth = ((numWidth + this.stepInfo()[1]) * 0.7 + this.infoEndText.length) * this.sizeDeal(this.infoFontSize)[0]
  815. return Number(textWidth.toFixed(2))
  816. },
  817. maxHeight() {
  818. let h = []
  819. if (this.direction!='vertical'){ // direction 为 vertical 时不显示info
  820. let subt = this.infoEndText.match(/[^\x00-\xff]/g)
  821. if (subt){
  822. h.push(this.sizeDeal(this.infoFontSize)[0] * 1.1)
  823. }
  824. else{
  825. h.push(this.sizeDeal(this.infoFontSize)[0])
  826. }
  827. }
  828. h.push(this.sizeDeal(this.strokeWidth)[0])
  829. h.push(this.sizeDeal(this.handleHeight)[0])
  830. h.sort(function(a, b) {
  831. return b - a
  832. }) // 降序
  833. return [h[0], 'px', h[0] + 'px']
  834. },
  835. sizeDeal(size) {
  836. // 分离字体大小和单位,rpx 转 px
  837. let s = Number.isNaN(parseFloat(size)) ? 0 : parseFloat(size)
  838. let u = size.toString().replace(/[0-9\.]/g, '')
  839. if (u == 'rpx') {
  840. s /= this.px2rpx
  841. u = 'px'
  842. }else if (u == 'vw') {
  843. u = 'px'
  844. s = s / 100 * this.screenWidth
  845. } else if(u == 'vh') {
  846. u = 'px'
  847. s = s / 100 * this.screenHeight
  848. } else{
  849. u = 'px'
  850. }
  851. return [s, u, s + u]
  852. },
  853. }
  854. }
  855. </script>
  856. <style scoped>
  857. @import "bing-progress.css"
  858. </style>