index.js 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { VantComponent } from '../common/component';
  2. import { touch } from '../mixins/touch';
  3. import { canIUseModel } from '../common/version';
  4. import { getRect } from '../common/utils';
  5. VantComponent({
  6. mixins: [touch],
  7. props: {
  8. range: Boolean,
  9. disabled: Boolean,
  10. useButtonSlot: Boolean,
  11. activeColor: String,
  12. inactiveColor: String,
  13. max: {
  14. type: Number,
  15. value: 100,
  16. },
  17. min: {
  18. type: Number,
  19. value: 0,
  20. },
  21. step: {
  22. type: Number,
  23. value: 1,
  24. },
  25. value: {
  26. type: null,
  27. value: 0,
  28. observer(val) {
  29. if (val !== this.value) {
  30. this.updateValue(val);
  31. }
  32. },
  33. },
  34. barHeight: null,
  35. },
  36. created() {
  37. this.updateValue(this.data.value);
  38. },
  39. methods: {
  40. onTouchStart(event) {
  41. if (this.data.disabled)
  42. return;
  43. const { index } = event.currentTarget.dataset;
  44. if (typeof index === 'number') {
  45. this.buttonIndex = index;
  46. }
  47. this.touchStart(event);
  48. this.startValue = this.format(this.value);
  49. this.newValue = this.value;
  50. if (this.isRange(this.newValue)) {
  51. this.startValue = this.newValue.map((val) => this.format(val));
  52. }
  53. else {
  54. this.startValue = this.format(this.newValue);
  55. }
  56. this.dragStatus = 'start';
  57. },
  58. onTouchMove(event) {
  59. if (this.data.disabled)
  60. return;
  61. if (this.dragStatus === 'start') {
  62. this.$emit('drag-start');
  63. }
  64. this.touchMove(event);
  65. this.dragStatus = 'draging';
  66. getRect(this, '.van-slider').then((rect) => {
  67. const diff = (this.deltaX / rect.width) * this.getRange();
  68. if (this.isRange(this.startValue)) {
  69. this.newValue[this.buttonIndex] =
  70. this.startValue[this.buttonIndex] + diff;
  71. }
  72. else {
  73. this.newValue = this.startValue + diff;
  74. }
  75. this.updateValue(this.newValue, false, true);
  76. });
  77. },
  78. onTouchEnd() {
  79. if (this.data.disabled)
  80. return;
  81. if (this.dragStatus === 'draging') {
  82. this.updateValue(this.newValue, true);
  83. this.$emit('drag-end');
  84. }
  85. },
  86. onClick(event) {
  87. if (this.data.disabled)
  88. return;
  89. const { min } = this.data;
  90. getRect(this, '.van-slider').then((rect) => {
  91. const value = ((event.detail.x - rect.left) / rect.width) * this.getRange() + min;
  92. if (this.isRange(this.value)) {
  93. const [left, right] = this.value;
  94. const middle = (left + right) / 2;
  95. if (value <= middle) {
  96. this.updateValue([value, right], true);
  97. }
  98. else {
  99. this.updateValue([left, value], true);
  100. }
  101. }
  102. else {
  103. this.updateValue(value, true);
  104. }
  105. });
  106. },
  107. isRange(val) {
  108. const { range } = this.data;
  109. return range && Array.isArray(val);
  110. },
  111. handleOverlap(value) {
  112. if (value[0] > value[1]) {
  113. return value.slice(0).reverse();
  114. }
  115. return value;
  116. },
  117. updateValue(value, end, drag) {
  118. if (this.isRange(value)) {
  119. value = this.handleOverlap(value).map((val) => this.format(val));
  120. }
  121. else {
  122. value = this.format(value);
  123. }
  124. this.value = value;
  125. this.setData({
  126. barStyle: `
  127. width: ${this.calcMainAxis()};
  128. left: ${this.isRange(value) ? `${value[0]}%` : 0};
  129. ${drag ? 'transition: none;' : ''}
  130. `,
  131. });
  132. if (drag) {
  133. this.$emit('drag', { value });
  134. }
  135. if (end) {
  136. this.$emit('change', value);
  137. }
  138. if ((drag || end) && canIUseModel()) {
  139. this.setData({ value });
  140. }
  141. },
  142. getScope() {
  143. return Number(this.data.max) - Number(this.data.min);
  144. },
  145. getRange() {
  146. const { max, min } = this.data;
  147. return max - min;
  148. },
  149. // 计算选中条的长度百分比
  150. calcMainAxis() {
  151. const { value } = this;
  152. const { min } = this.data;
  153. const scope = this.getScope();
  154. if (this.isRange(value)) {
  155. return `${((value[1] - value[0]) * 100) / scope}%`;
  156. }
  157. return `${((value - Number(min)) * 100) / scope}%`;
  158. },
  159. format(value) {
  160. const { max, min, step } = this.data;
  161. return Math.round(Math.max(min, Math.min(value, max)) / step) * step;
  162. },
  163. },
  164. });