Slider.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. var __defProp = Object.defineProperty;
  2. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  3. var __getOwnPropNames = Object.getOwnPropertyNames;
  4. var __hasOwnProp = Object.prototype.hasOwnProperty;
  5. var __export = (target, all) => {
  6. for (var name2 in all)
  7. __defProp(target, name2, { get: all[name2], enumerable: true });
  8. };
  9. var __copyProps = (to, from, except, desc) => {
  10. if (from && typeof from === "object" || typeof from === "function") {
  11. for (let key of __getOwnPropNames(from))
  12. if (!__hasOwnProp.call(to, key) && key !== except)
  13. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  14. }
  15. return to;
  16. };
  17. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  18. var stdin_exports = {};
  19. __export(stdin_exports, {
  20. default: () => stdin_default,
  21. sliderProps: () => sliderProps
  22. });
  23. module.exports = __toCommonJS(stdin_exports);
  24. var import_vue = require("vue");
  25. var import_utils = require("../utils");
  26. var import_use = require("@vant/use");
  27. var import_use_touch = require("../composables/use-touch");
  28. const [name, bem] = (0, import_utils.createNamespace)("slider");
  29. const sliderProps = {
  30. min: (0, import_utils.makeNumericProp)(0),
  31. max: (0, import_utils.makeNumericProp)(100),
  32. step: (0, import_utils.makeNumericProp)(1),
  33. range: Boolean,
  34. reverse: Boolean,
  35. disabled: Boolean,
  36. readonly: Boolean,
  37. vertical: Boolean,
  38. barHeight: import_utils.numericProp,
  39. buttonSize: import_utils.numericProp,
  40. activeColor: String,
  41. inactiveColor: String,
  42. modelValue: {
  43. type: [Number, Array],
  44. default: 0
  45. }
  46. };
  47. var stdin_default = (0, import_vue.defineComponent)({
  48. name,
  49. props: sliderProps,
  50. emits: ["change", "dragEnd", "dragStart", "update:modelValue"],
  51. setup(props, {
  52. emit,
  53. slots
  54. }) {
  55. let buttonIndex;
  56. let current;
  57. let startValue;
  58. const root = (0, import_vue.ref)();
  59. const slider = [(0, import_vue.ref)(), (0, import_vue.ref)()];
  60. const dragStatus = (0, import_vue.ref)();
  61. const touch = (0, import_use_touch.useTouch)();
  62. const scope = (0, import_vue.computed)(() => Number(props.max) - Number(props.min));
  63. const wrapperStyle = (0, import_vue.computed)(() => {
  64. const crossAxis = props.vertical ? "width" : "height";
  65. return {
  66. background: props.inactiveColor,
  67. [crossAxis]: (0, import_utils.addUnit)(props.barHeight)
  68. };
  69. });
  70. const isRange = (val) => props.range && Array.isArray(val);
  71. const calcMainAxis = () => {
  72. const {
  73. modelValue,
  74. min
  75. } = props;
  76. if (isRange(modelValue)) {
  77. return `${(modelValue[1] - modelValue[0]) * 100 / scope.value}%`;
  78. }
  79. return `${(modelValue - Number(min)) * 100 / scope.value}%`;
  80. };
  81. const calcOffset = () => {
  82. const {
  83. modelValue,
  84. min
  85. } = props;
  86. if (isRange(modelValue)) {
  87. return `${(modelValue[0] - Number(min)) * 100 / scope.value}%`;
  88. }
  89. return "0%";
  90. };
  91. const barStyle = (0, import_vue.computed)(() => {
  92. const mainAxis = props.vertical ? "height" : "width";
  93. const style = {
  94. [mainAxis]: calcMainAxis(),
  95. background: props.activeColor
  96. };
  97. if (dragStatus.value) {
  98. style.transition = "none";
  99. }
  100. const getPositionKey = () => {
  101. if (props.vertical) {
  102. return props.reverse ? "bottom" : "top";
  103. }
  104. return props.reverse ? "right" : "left";
  105. };
  106. style[getPositionKey()] = calcOffset();
  107. return style;
  108. });
  109. const format = (value) => {
  110. const min = +props.min;
  111. const max = +props.max;
  112. const step = +props.step;
  113. value = (0, import_utils.clamp)(value, min, max);
  114. const diff = Math.round((value - min) / step) * step;
  115. return (0, import_utils.addNumber)(min, diff);
  116. };
  117. const updateStartValue = () => {
  118. const current2 = props.modelValue;
  119. if (isRange(current2)) {
  120. startValue = current2.map(format);
  121. } else {
  122. startValue = format(current2);
  123. }
  124. };
  125. const handleRangeValue = (value) => {
  126. var _a, _b;
  127. const left = (_a = value[0]) != null ? _a : Number(props.min);
  128. const right = (_b = value[1]) != null ? _b : Number(props.max);
  129. return left > right ? [right, left] : [left, right];
  130. };
  131. const updateValue = (value, end) => {
  132. if (isRange(value)) {
  133. value = handleRangeValue(value).map(format);
  134. } else {
  135. value = format(value);
  136. }
  137. if (!(0, import_utils.isSameValue)(value, props.modelValue)) {
  138. emit("update:modelValue", value);
  139. }
  140. if (end && !(0, import_utils.isSameValue)(value, startValue)) {
  141. emit("change", value);
  142. }
  143. };
  144. const onClick = (event) => {
  145. event.stopPropagation();
  146. if (props.disabled || props.readonly) {
  147. return;
  148. }
  149. updateStartValue();
  150. const {
  151. min,
  152. reverse,
  153. vertical,
  154. modelValue
  155. } = props;
  156. const rect = (0, import_use.useRect)(root);
  157. const getDelta = () => {
  158. if (vertical) {
  159. if (reverse) {
  160. return rect.bottom - event.clientY;
  161. }
  162. return event.clientY - rect.top;
  163. }
  164. if (reverse) {
  165. return rect.right - event.clientX;
  166. }
  167. return event.clientX - rect.left;
  168. };
  169. const total = vertical ? rect.height : rect.width;
  170. const value = Number(min) + getDelta() / total * scope.value;
  171. if (isRange(modelValue)) {
  172. const [left, right] = modelValue;
  173. const middle = (left + right) / 2;
  174. if (value <= middle) {
  175. updateValue([value, right], true);
  176. } else {
  177. updateValue([left, value], true);
  178. }
  179. } else {
  180. updateValue(value, true);
  181. }
  182. };
  183. const onTouchStart = (event) => {
  184. if (props.disabled || props.readonly) {
  185. return;
  186. }
  187. touch.start(event);
  188. current = props.modelValue;
  189. updateStartValue();
  190. dragStatus.value = "start";
  191. };
  192. const onTouchMove = (event) => {
  193. if (props.disabled || props.readonly) {
  194. return;
  195. }
  196. if (dragStatus.value === "start") {
  197. emit("dragStart", event);
  198. }
  199. (0, import_utils.preventDefault)(event, true);
  200. touch.move(event);
  201. dragStatus.value = "dragging";
  202. const rect = (0, import_use.useRect)(root);
  203. const delta = props.vertical ? touch.deltaY.value : touch.deltaX.value;
  204. const total = props.vertical ? rect.height : rect.width;
  205. let diff = delta / total * scope.value;
  206. if (props.reverse) {
  207. diff = -diff;
  208. }
  209. if (isRange(startValue)) {
  210. const index = props.reverse ? 1 - buttonIndex : buttonIndex;
  211. current[index] = startValue[index] + diff;
  212. } else {
  213. current = startValue + diff;
  214. }
  215. updateValue(current);
  216. };
  217. const onTouchEnd = (event) => {
  218. if (props.disabled || props.readonly) {
  219. return;
  220. }
  221. if (dragStatus.value === "dragging") {
  222. updateValue(current, true);
  223. emit("dragEnd", event);
  224. }
  225. dragStatus.value = "";
  226. };
  227. const getButtonClassName = (index) => {
  228. if (typeof index === "number") {
  229. const position = ["left", "right"];
  230. return bem(`button-wrapper`, position[index]);
  231. }
  232. return bem("button-wrapper", props.reverse ? "left" : "right");
  233. };
  234. const renderButtonContent = (value, index) => {
  235. const dragging = dragStatus.value === "dragging";
  236. if (typeof index === "number") {
  237. const slot = slots[index === 0 ? "left-button" : "right-button"];
  238. let dragIndex;
  239. if (dragging && Array.isArray(current)) {
  240. dragIndex = current[0] > current[1] ? buttonIndex ^ 1 : buttonIndex;
  241. }
  242. if (slot) {
  243. return slot({
  244. value,
  245. dragging,
  246. dragIndex
  247. });
  248. }
  249. }
  250. if (slots.button) {
  251. return slots.button({
  252. value,
  253. dragging
  254. });
  255. }
  256. return (0, import_vue.createVNode)("div", {
  257. "class": bem("button"),
  258. "style": (0, import_utils.getSizeStyle)(props.buttonSize)
  259. }, null);
  260. };
  261. const renderButton = (index) => {
  262. const current2 = typeof index === "number" ? props.modelValue[index] : props.modelValue;
  263. return (0, import_vue.createVNode)("div", {
  264. "ref": slider[index != null ? index : 0],
  265. "role": "slider",
  266. "class": getButtonClassName(index),
  267. "tabindex": props.disabled ? void 0 : 0,
  268. "aria-valuemin": props.min,
  269. "aria-valuenow": current2,
  270. "aria-valuemax": props.max,
  271. "aria-disabled": props.disabled || void 0,
  272. "aria-readonly": props.readonly || void 0,
  273. "aria-orientation": props.vertical ? "vertical" : "horizontal",
  274. "onTouchstartPassive": (event) => {
  275. if (typeof index === "number") {
  276. buttonIndex = index;
  277. }
  278. onTouchStart(event);
  279. },
  280. "onTouchend": onTouchEnd,
  281. "onTouchcancel": onTouchEnd,
  282. "onClick": import_utils.stopPropagation
  283. }, [renderButtonContent(current2, index)]);
  284. };
  285. updateValue(props.modelValue);
  286. (0, import_use.useCustomFieldValue)(() => props.modelValue);
  287. slider.forEach((item) => {
  288. (0, import_use.useEventListener)("touchmove", onTouchMove, {
  289. target: item
  290. });
  291. });
  292. return () => (0, import_vue.createVNode)("div", {
  293. "ref": root,
  294. "style": wrapperStyle.value,
  295. "class": bem({
  296. vertical: props.vertical,
  297. disabled: props.disabled
  298. }),
  299. "onClick": onClick
  300. }, [(0, import_vue.createVNode)("div", {
  301. "class": bem("bar"),
  302. "style": barStyle.value
  303. }, [props.range ? [renderButton(0), renderButton(1)] : renderButton()])]);
  304. }
  305. });