index.vue 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <template>
  2. <uni-shadow-root class="vant-dist-slider-index"><view :class="'custom-class '+(utils.bem('slider', { disabled }))" :style="style({ background: inactiveColor, height: utils.addUnit(barHeight) })" @click="onClick">
  3. <view :class="utils.bem('slider__bar')" :style="(barStyle)+'; '+(style({ backgroundColor: activeColor }))">
  4. <view v-if="range" :class="utils.bem('slider__button-wrapper-left')" :data-index="0" @touchstart="onTouchStart" @touchmove.stop.prevent="onTouchMove" @touchend="onTouchEnd" @touchcancel="onTouchEnd">
  5. <slot v-if="useButtonSlot" name="left-button"></slot>
  6. <view v-else :class="utils.bem('slider__button')"></view>
  7. </view>
  8. <view v-if="range" :class="utils.bem('slider__button-wrapper-right')" :data-index="1" @touchstart="onTouchStart" @touchmove.stop.prevent="onTouchMove" @touchend="onTouchEnd" @touchcancel="onTouchEnd">
  9. <slot v-if="useButtonSlot" name="right-button"></slot>
  10. <view v-else :class="utils.bem('slider__button')"></view>
  11. </view>
  12. <view v-if="(!range)" :class="utils.bem('slider__button-wrapper')" @touchstart="onTouchStart" @touchmove.stop.prevent="onTouchMove" @touchend="onTouchEnd" @touchcancel="onTouchEnd">
  13. <slot v-if="useButtonSlot" name="button"></slot>
  14. <view v-else :class="utils.bem('slider__button')"></view>
  15. </view>
  16. </view>
  17. </view></uni-shadow-root>
  18. </template>
  19. <wxs src="../wxs/utils.wxs" module="utils"></wxs><wxs src="../wxs/style.wxs" module="style"></wxs>
  20. <script>
  21. global['__wxRoute'] = 'vant/dist/slider/index'
  22. import { VantComponent } from '../common/component';
  23. import { touch } from '../mixins/touch';
  24. import { canIUseModel } from '../common/version';
  25. import { getRect } from '../common/utils';
  26. VantComponent({
  27. mixins: [touch],
  28. props: {
  29. range: Boolean,
  30. disabled: Boolean,
  31. useButtonSlot: Boolean,
  32. activeColor: String,
  33. inactiveColor: String,
  34. max: {
  35. type: Number,
  36. value: 100,
  37. },
  38. min: {
  39. type: Number,
  40. value: 0,
  41. },
  42. step: {
  43. type: Number,
  44. value: 1,
  45. },
  46. value: {
  47. type: null,
  48. value: 0,
  49. observer(val) {
  50. if (val !== this.value) {
  51. this.updateValue(val);
  52. }
  53. },
  54. },
  55. barHeight: null,
  56. },
  57. created() {
  58. this.updateValue(this.data.value);
  59. },
  60. methods: {
  61. onTouchStart(event) {
  62. if (this.data.disabled)
  63. return;
  64. const { index } = event.currentTarget.dataset;
  65. if (typeof index === 'number') {
  66. this.buttonIndex = index;
  67. }
  68. this.touchStart(event);
  69. this.startValue = this.format(this.value);
  70. this.newValue = this.value;
  71. if (this.isRange(this.newValue)) {
  72. this.startValue = this.newValue.map((val) => this.format(val));
  73. }
  74. else {
  75. this.startValue = this.format(this.newValue);
  76. }
  77. this.dragStatus = 'start';
  78. },
  79. onTouchMove(event) {
  80. if (this.data.disabled)
  81. return;
  82. if (this.dragStatus === 'start') {
  83. this.$emit('drag-start');
  84. }
  85. this.touchMove(event);
  86. this.dragStatus = 'draging';
  87. getRect(this, '.van-slider').then((rect) => {
  88. const diff = (this.deltaX / rect.width) * this.getRange();
  89. if (this.isRange(this.startValue)) {
  90. this.newValue[this.buttonIndex] =
  91. this.startValue[this.buttonIndex] + diff;
  92. }
  93. else {
  94. this.newValue = this.startValue + diff;
  95. }
  96. this.updateValue(this.newValue, false, true);
  97. });
  98. },
  99. onTouchEnd() {
  100. if (this.data.disabled)
  101. return;
  102. if (this.dragStatus === 'draging') {
  103. this.updateValue(this.newValue, true);
  104. this.$emit('drag-end');
  105. }
  106. },
  107. onClick(event) {
  108. if (this.data.disabled)
  109. return;
  110. const { min } = this.data;
  111. getRect(this, '.van-slider').then((rect) => {
  112. const value = ((event.detail.x - rect.left) / rect.width) * this.getRange() + min;
  113. if (this.isRange(this.value)) {
  114. const [left, right] = this.value;
  115. const middle = (left + right) / 2;
  116. if (value <= middle) {
  117. this.updateValue([value, right], true);
  118. }
  119. else {
  120. this.updateValue([left, value], true);
  121. }
  122. }
  123. else {
  124. this.updateValue(value, true);
  125. }
  126. });
  127. },
  128. isRange(val) {
  129. const { range } = this.data;
  130. return range && Array.isArray(val);
  131. },
  132. handleOverlap(value) {
  133. if (value[0] > value[1]) {
  134. return value.slice(0).reverse();
  135. }
  136. return value;
  137. },
  138. updateValue(value, end, drag) {
  139. if (this.isRange(value)) {
  140. value = this.handleOverlap(value).map((val) => this.format(val));
  141. }
  142. else {
  143. value = this.format(value);
  144. }
  145. this.value = value;
  146. this.setData({
  147. barStyle: `
  148. width: ${this.calcMainAxis()};
  149. left: ${this.isRange(value) ? `${value[0]}%` : 0};
  150. ${drag ? 'transition: none;' : ''}
  151. `,
  152. });
  153. if (drag) {
  154. this.$emit('drag', { value });
  155. }
  156. if (end) {
  157. this.$emit('change', value);
  158. }
  159. if ((drag || end) && canIUseModel()) {
  160. this.setData({ value });
  161. }
  162. },
  163. getScope() {
  164. return Number(this.data.max) - Number(this.data.min);
  165. },
  166. getRange() {
  167. const { max, min } = this.data;
  168. return max - min;
  169. },
  170. // 计算选中条的长度百分比
  171. calcMainAxis() {
  172. const { value } = this;
  173. const { min } = this.data;
  174. const scope = this.getScope();
  175. if (this.isRange(value)) {
  176. return `${((value[1] - value[0]) * 100) / scope}%`;
  177. }
  178. return `${((value - Number(min)) * 100) / scope}%`;
  179. },
  180. format(value) {
  181. const { max, min, step } = this.data;
  182. return Math.round(Math.max(min, Math.min(value, max)) / step) * step;
  183. },
  184. },
  185. });
  186. export default global['__wxComponents']['vant/dist/slider/index']
  187. </script>
  188. <style platform="mp-weixin">
  189. @import '../common/index.css';.van-slider{position:relative;height:2px;height:var(--slider-bar-height,2px);border-radius:999px;border-radius:var(--border-radius-max,999px);background-color:#ebedf0;background-color:var(--slider-inactive-background-color,#ebedf0)}.van-slider:before{position:absolute;right:0;left:0;content:"";top:-8px;top:-var(--padding-xs,8px);bottom:-8px;bottom:-var(--padding-xs,8px)}.van-slider__bar{position:relative;width:100%;height:100%;background-color:#1989fa;background-color:var(--slider-active-background-color,#1989fa);border-radius:inherit;transition:all .2s;transition:all var(--animation-duration-fast,.2s)}.van-slider__button{width:24px;width:var(--slider-button-width,24px);height:24px;height:var(--slider-button-height,24px);border-radius:50%;border-radius:var(--slider-button-border-radius,50%);box-shadow:0 1px 2px rgba(0,0,0,.5);box-shadow:var(--slider-button-box-shadow,0 1px 2px rgba(0,0,0,.5));background-color:#fff;background-color:var(--slider-button-background-color,#fff)}.van-slider__button-wrapper,.van-slider__button-wrapper-right{position:absolute;top:50%;right:0;transform:translate3d(50%,-50%,0)}.van-slider__button-wrapper-left{position:absolute;top:50%;left:0;transform:translate3d(-50%,-50%,0)}.van-slider--disabled{opacity:.5;opacity:var(--slider-disabled-opacity,.5)}
  190. </style>