index.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import { createNamespace, addUnit } from '../utils';
  2. import { deepClone } from '../utils/deep-clone';
  3. import { preventDefault } from '../utils/dom/event';
  4. import { range, addNumber } from '../utils/format/number';
  5. import { TouchMixin } from '../mixins/touch';
  6. import { FieldMixin } from '../mixins/field';
  7. var _createNamespace = createNamespace('slider'),
  8. createComponent = _createNamespace[0],
  9. bem = _createNamespace[1];
  10. var isSameValue = function isSameValue(newValue, oldValue) {
  11. return JSON.stringify(newValue) === JSON.stringify(oldValue);
  12. };
  13. export default createComponent({
  14. mixins: [TouchMixin, FieldMixin],
  15. props: {
  16. disabled: Boolean,
  17. vertical: Boolean,
  18. range: Boolean,
  19. barHeight: [Number, String],
  20. buttonSize: [Number, String],
  21. activeColor: String,
  22. inactiveColor: String,
  23. min: {
  24. type: [Number, String],
  25. default: 0
  26. },
  27. max: {
  28. type: [Number, String],
  29. default: 100
  30. },
  31. step: {
  32. type: [Number, String],
  33. default: 1
  34. },
  35. value: {
  36. type: [Number, Array],
  37. default: 0
  38. }
  39. },
  40. data: function data() {
  41. return {
  42. dragStatus: ''
  43. };
  44. },
  45. computed: {
  46. scope: function scope() {
  47. return this.max - this.min;
  48. },
  49. buttonStyle: function buttonStyle() {
  50. if (this.buttonSize) {
  51. var size = addUnit(this.buttonSize);
  52. return {
  53. width: size,
  54. height: size
  55. };
  56. }
  57. }
  58. },
  59. created: function created() {
  60. // format initial value
  61. this.updateValue(this.value);
  62. },
  63. mounted: function mounted() {
  64. if (this.range) {
  65. this.bindTouchEvent(this.$refs.wrapper0);
  66. this.bindTouchEvent(this.$refs.wrapper1);
  67. } else {
  68. this.bindTouchEvent(this.$refs.wrapper);
  69. }
  70. },
  71. methods: {
  72. onTouchStart: function onTouchStart(event) {
  73. if (this.disabled) {
  74. return;
  75. }
  76. this.touchStart(event);
  77. this.currentValue = this.value;
  78. if (this.range) {
  79. this.startValue = this.value.map(this.format);
  80. } else {
  81. this.startValue = this.format(this.value);
  82. }
  83. this.dragStatus = 'start';
  84. },
  85. onTouchMove: function onTouchMove(event) {
  86. if (this.disabled) {
  87. return;
  88. }
  89. if (this.dragStatus === 'start') {
  90. this.$emit('drag-start');
  91. }
  92. preventDefault(event, true);
  93. this.touchMove(event);
  94. this.dragStatus = 'draging';
  95. var rect = this.$el.getBoundingClientRect();
  96. var delta = this.vertical ? this.deltaY : this.deltaX;
  97. var total = this.vertical ? rect.height : rect.width;
  98. var diff = delta / total * this.scope;
  99. if (this.range) {
  100. this.currentValue[this.index] = this.startValue[this.index] + diff;
  101. } else {
  102. this.currentValue = this.startValue + diff;
  103. }
  104. this.updateValue(this.currentValue);
  105. },
  106. onTouchEnd: function onTouchEnd() {
  107. if (this.disabled) {
  108. return;
  109. }
  110. if (this.dragStatus === 'draging') {
  111. this.updateValue(this.currentValue, true);
  112. this.$emit('drag-end');
  113. }
  114. this.dragStatus = '';
  115. },
  116. onClick: function onClick(event) {
  117. event.stopPropagation();
  118. if (this.disabled) return;
  119. var rect = this.$el.getBoundingClientRect();
  120. var delta = this.vertical ? event.clientY - rect.top : event.clientX - rect.left;
  121. var total = this.vertical ? rect.height : rect.width;
  122. var value = +this.min + delta / total * this.scope;
  123. if (this.range) {
  124. var _this$value = this.value,
  125. left = _this$value[0],
  126. right = _this$value[1];
  127. var middle = (left + right) / 2;
  128. if (value <= middle) {
  129. left = value;
  130. } else {
  131. right = value;
  132. }
  133. value = [left, right];
  134. }
  135. this.startValue = this.value;
  136. this.updateValue(value, true);
  137. },
  138. // 处理两个滑块重叠之后的情况
  139. handleOverlap: function handleOverlap(value) {
  140. if (value[0] > value[1]) {
  141. value = deepClone(value);
  142. return value.reverse();
  143. }
  144. return value;
  145. },
  146. updateValue: function updateValue(value, end) {
  147. if (this.range) {
  148. value = this.handleOverlap(value).map(this.format);
  149. } else {
  150. value = this.format(value);
  151. }
  152. if (!isSameValue(value, this.value)) {
  153. this.$emit('input', value);
  154. }
  155. if (end && !isSameValue(value, this.startValue)) {
  156. this.$emit('change', value);
  157. }
  158. },
  159. format: function format(value) {
  160. var min = +this.min;
  161. var max = +this.max;
  162. var step = +this.step;
  163. value = range(value, min, max);
  164. var diff = Math.round((value - min) / step) * step;
  165. return addNumber(min, diff);
  166. }
  167. },
  168. render: function render() {
  169. var _wrapperStyle,
  170. _this = this,
  171. _barStyle;
  172. var h = arguments[0];
  173. var vertical = this.vertical;
  174. var mainAxis = vertical ? 'height' : 'width';
  175. var crossAxis = vertical ? 'width' : 'height';
  176. var wrapperStyle = (_wrapperStyle = {
  177. background: this.inactiveColor
  178. }, _wrapperStyle[crossAxis] = addUnit(this.barHeight), _wrapperStyle); // 计算选中条的长度百分比
  179. var calcMainAxis = function calcMainAxis() {
  180. var value = _this.value,
  181. min = _this.min,
  182. range = _this.range,
  183. scope = _this.scope;
  184. if (range) {
  185. return (value[1] - value[0]) * 100 / scope + "%";
  186. }
  187. return (value - min) * 100 / scope + "%";
  188. }; // 计算选中条的开始位置的偏移量
  189. var calcOffset = function calcOffset() {
  190. var value = _this.value,
  191. min = _this.min,
  192. range = _this.range,
  193. scope = _this.scope;
  194. if (range) {
  195. return (value[0] - min) * 100 / scope + "%";
  196. }
  197. return null;
  198. };
  199. var barStyle = (_barStyle = {}, _barStyle[mainAxis] = calcMainAxis(), _barStyle.left = this.vertical ? null : calcOffset(), _barStyle.top = this.vertical ? calcOffset() : null, _barStyle.background = this.activeColor, _barStyle);
  200. if (this.dragStatus) {
  201. barStyle.transition = 'none';
  202. }
  203. var renderButton = function renderButton(i) {
  204. var map = ['left', 'right'];
  205. var isNumber = typeof i === 'number';
  206. var current = isNumber ? _this.value[i] : _this.value;
  207. var getClassName = function getClassName() {
  208. if (isNumber) {
  209. return "button-wrapper-" + map[i];
  210. }
  211. return "button-wrapper";
  212. };
  213. var getRefName = function getRefName() {
  214. if (isNumber) {
  215. return "wrapper" + i;
  216. }
  217. return "wrapper";
  218. };
  219. var renderButtonContent = function renderButtonContent() {
  220. if (isNumber) {
  221. var slot = _this.slots(i === 0 ? 'left-button' : 'right-button', {
  222. value: current
  223. });
  224. if (slot) {
  225. return slot;
  226. }
  227. }
  228. if (_this.slots('button')) {
  229. return _this.slots('button');
  230. }
  231. return h("div", {
  232. "class": bem('button'),
  233. "style": _this.buttonStyle
  234. });
  235. };
  236. return h("div", {
  237. "ref": getRefName(),
  238. "attrs": {
  239. "role": "slider",
  240. "tabindex": _this.disabled ? -1 : 0,
  241. "aria-valuemin": _this.min,
  242. "aria-valuenow": _this.value,
  243. "aria-valuemax": _this.max,
  244. "aria-orientation": _this.vertical ? 'vertical' : 'horizontal'
  245. },
  246. "class": bem(getClassName()),
  247. "on": {
  248. "touchstart": function touchstart() {
  249. if (isNumber) {
  250. // 保存当前按钮的索引
  251. _this.index = i;
  252. }
  253. },
  254. "click": function click(e) {
  255. return e.stopPropagation();
  256. }
  257. }
  258. }, [renderButtonContent()]);
  259. };
  260. return h("div", {
  261. "style": wrapperStyle,
  262. "class": bem({
  263. disabled: this.disabled,
  264. vertical: vertical
  265. }),
  266. "on": {
  267. "click": this.onClick
  268. }
  269. }, [h("div", {
  270. "class": bem('bar'),
  271. "style": barStyle
  272. }, [this.range ? [renderButton(0), renderButton(1)] : renderButton()])]);
  273. }
  274. });