You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
3.8 KiB

5 months ago
  1. /**
  2. * 使用普通的js方案实现slider
  3. */
  4. export default {
  5. watch: {
  6. value(n) {
  7. // 只有在非滑动状态时,才可以通过value更新滑块值,这里监听,是为了让用户触发
  8. if (this.status === 'end') {
  9. this.updateSliderPlacement(n, true)
  10. }
  11. }
  12. },
  13. mounted() {
  14. this.init()
  15. },
  16. methods: {
  17. init() {
  18. this.getSliderRect()
  19. },
  20. // 获取slider尺寸
  21. getSliderRect() {
  22. // 获取滑块条的尺寸信息
  23. setTimeout(() => {
  24. this.$uGetRect('.u-slider').then((rect) => {
  25. this.sliderRect = rect
  26. this.updateSliderPlacement(this.value, true)
  27. })
  28. }, 10)
  29. },
  30. // 是否可以操作
  31. canNotDo() {
  32. return this.disabled
  33. },
  34. // 获取当前手势点的X轴位移值
  35. getTouchX(e) {
  36. return e.touches[0].clientX
  37. },
  38. formatStep(value) {
  39. // 移动点占总长度的百分比
  40. return Math.round(Math.max(this.min, Math.min(value, this.max)) / this.step) * this.step
  41. },
  42. // 发出事件
  43. emitEvent(event, value) {
  44. this.$emit(event, value || this.value)
  45. },
  46. // 标记当前手势的状态
  47. setTouchStatus(status) {
  48. this.status = status
  49. },
  50. onTouchStart(e) {
  51. if (this.canNotDo()) {
  52. return
  53. }
  54. // 标示当前的状态为开始触摸滑动
  55. this.emitEvent('start')
  56. this.setTouchStatus('start')
  57. },
  58. onTouchMove(e) {
  59. if (this.canNotDo()) {
  60. return
  61. }
  62. // 滑块的左边不一定跟屏幕左边接壤,所以需要减去最外层父元素的左边值
  63. const x = this.getTouchX(e)
  64. const { left, width } = this.sliderRect
  65. const distanceX = x - left
  66. // 获得移动距离对整个滑块的百分比值,此为带有多位小数的值,不能用此更新视图
  67. // 否则造成通信阻塞,需要每改变一个step值时修改一次视图
  68. const percent = (distanceX / width) * 100
  69. this.setTouchStatus('moving')
  70. this.updateSliderPlacement(percent, true, 'moving')
  71. },
  72. onTouchEnd() {
  73. if (this.canNotDo()) {
  74. return
  75. }
  76. this.emitEvent('end')
  77. this.setTouchStatus('end')
  78. },
  79. // 设置滑点的位置
  80. updateSliderPlacement(value, drag, event) {
  81. // 去掉小数部分,同时也是对step步进的处理
  82. const { width } = this.sliderRect
  83. const percent = this.formatStep(value)
  84. // 设置移动的值
  85. const barStyle = {
  86. width: `${percent / 100 * width}px`
  87. }
  88. // 移动期间无需过渡动画
  89. if (drag === true) {
  90. barStyle.transition = 'none'
  91. } else {
  92. // 非移动期间,删掉对过渡为空的声明,让css中的声明起效
  93. delete barStyle.transition
  94. }
  95. // 修改value值
  96. this.$emit('input', percent)
  97. // 事件的名称
  98. if (event) {
  99. this.emitEvent(event, percent)
  100. }
  101. this.barStyle = barStyle
  102. },
  103. onClick(e) {
  104. if (this.canNotDo()) {
  105. return
  106. }
  107. // 直接点击滑块的情况,计算方式与onTouchMove方法相同
  108. const { left, width } = this.sliderRect
  109. const value = ((e.detail.x - left) / width) * 100
  110. this.updateSliderPlacement(value, false, 'click')
  111. }
  112. }
  113. }