Rate.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. rateProps: () => rateProps
  22. });
  23. module.exports = __toCommonJS(stdin_exports);
  24. var import_vue = require("vue");
  25. var import_vue2 = require("vue");
  26. var import_utils = require("../utils");
  27. var import_use = require("@vant/use");
  28. var import_use_refs = require("../composables/use-refs");
  29. var import_use_touch = require("../composables/use-touch");
  30. var import_icon = require("../icon");
  31. const [name, bem] = (0, import_utils.createNamespace)("rate");
  32. function getRateStatus(value, index, allowHalf, readonly) {
  33. if (value >= index) {
  34. return {
  35. status: "full",
  36. value: 1
  37. };
  38. }
  39. if (value + 0.5 >= index && allowHalf && !readonly) {
  40. return {
  41. status: "half",
  42. value: 0.5
  43. };
  44. }
  45. if (value + 1 >= index && allowHalf && readonly) {
  46. const cardinal = 10 ** 10;
  47. return {
  48. status: "half",
  49. value: Math.round((value - index + 1) * cardinal) / cardinal
  50. };
  51. }
  52. return {
  53. status: "void",
  54. value: 0
  55. };
  56. }
  57. const rateProps = {
  58. size: import_utils.numericProp,
  59. icon: (0, import_utils.makeStringProp)("star"),
  60. color: String,
  61. count: (0, import_utils.makeNumericProp)(5),
  62. gutter: import_utils.numericProp,
  63. readonly: Boolean,
  64. disabled: Boolean,
  65. voidIcon: (0, import_utils.makeStringProp)("star-o"),
  66. allowHalf: Boolean,
  67. voidColor: String,
  68. touchable: import_utils.truthProp,
  69. iconPrefix: String,
  70. modelValue: (0, import_utils.makeNumberProp)(0),
  71. disabledColor: String
  72. };
  73. var stdin_default = (0, import_vue2.defineComponent)({
  74. name,
  75. props: rateProps,
  76. emits: ["change", "update:modelValue"],
  77. setup(props, {
  78. emit
  79. }) {
  80. const touch = (0, import_use_touch.useTouch)();
  81. const [itemRefs, setItemRefs] = (0, import_use_refs.useRefs)();
  82. const groupRef = (0, import_vue2.ref)();
  83. const untouchable = () => props.readonly || props.disabled || !props.touchable;
  84. const list = (0, import_vue2.computed)(() => Array(+props.count).fill("").map((_, i) => getRateStatus(props.modelValue, i + 1, props.allowHalf, props.readonly)));
  85. let ranges;
  86. let groupRefRect;
  87. let minRectTop = Number.MAX_SAFE_INTEGER;
  88. let maxRectTop = Number.MIN_SAFE_INTEGER;
  89. const updateRanges = () => {
  90. groupRefRect = (0, import_use.useRect)(groupRef);
  91. const rects = itemRefs.value.map(import_use.useRect);
  92. ranges = [];
  93. rects.forEach((rect, index) => {
  94. minRectTop = Math.min(rect.top, minRectTop);
  95. maxRectTop = Math.max(rect.top, maxRectTop);
  96. if (props.allowHalf) {
  97. ranges.push({
  98. score: index + 0.5,
  99. left: rect.left,
  100. top: rect.top,
  101. height: rect.height
  102. }, {
  103. score: index + 1,
  104. left: rect.left + rect.width / 2,
  105. top: rect.top,
  106. height: rect.height
  107. });
  108. } else {
  109. ranges.push({
  110. score: index + 1,
  111. left: rect.left,
  112. top: rect.top,
  113. height: rect.height
  114. });
  115. }
  116. });
  117. };
  118. const getScoreByPosition = (x, y) => {
  119. for (let i = ranges.length - 1; i > 0; i--) {
  120. if (y >= groupRefRect.top && y <= groupRefRect.bottom) {
  121. if (x > ranges[i].left && y >= ranges[i].top && y <= ranges[i].top + ranges[i].height) {
  122. return ranges[i].score;
  123. }
  124. } else {
  125. const curTop = y < groupRefRect.top ? minRectTop : maxRectTop;
  126. if (x > ranges[i].left && ranges[i].top === curTop) {
  127. return ranges[i].score;
  128. }
  129. }
  130. }
  131. return props.allowHalf ? 0.5 : 1;
  132. };
  133. const select = (index) => {
  134. if (!props.disabled && !props.readonly && index !== props.modelValue) {
  135. emit("update:modelValue", index);
  136. emit("change", index);
  137. }
  138. };
  139. const onTouchStart = (event) => {
  140. if (untouchable()) {
  141. return;
  142. }
  143. touch.start(event);
  144. updateRanges();
  145. };
  146. const onTouchMove = (event) => {
  147. if (untouchable()) {
  148. return;
  149. }
  150. touch.move(event);
  151. if (touch.isHorizontal()) {
  152. const {
  153. clientX,
  154. clientY
  155. } = event.touches[0];
  156. (0, import_utils.preventDefault)(event);
  157. select(getScoreByPosition(clientX, clientY));
  158. }
  159. };
  160. const renderStar = (item, index) => {
  161. const {
  162. icon,
  163. size,
  164. color,
  165. count,
  166. gutter,
  167. voidIcon,
  168. disabled,
  169. voidColor,
  170. allowHalf,
  171. iconPrefix,
  172. disabledColor
  173. } = props;
  174. const score = index + 1;
  175. const isFull = item.status === "full";
  176. const isVoid = item.status === "void";
  177. const renderHalf = allowHalf && item.value > 0 && item.value < 1;
  178. let style;
  179. if (gutter && score !== +count) {
  180. style = {
  181. paddingRight: (0, import_utils.addUnit)(gutter)
  182. };
  183. }
  184. const onClickItem = (event) => {
  185. updateRanges();
  186. select(allowHalf ? getScoreByPosition(event.clientX, event.clientY) : score);
  187. };
  188. return (0, import_vue.createVNode)("div", {
  189. "key": index,
  190. "ref": setItemRefs(index),
  191. "role": "radio",
  192. "style": style,
  193. "class": bem("item"),
  194. "tabindex": disabled ? void 0 : 0,
  195. "aria-setsize": count,
  196. "aria-posinset": score,
  197. "aria-checked": !isVoid,
  198. "onClick": onClickItem
  199. }, [(0, import_vue.createVNode)(import_icon.Icon, {
  200. "size": size,
  201. "name": isFull ? icon : voidIcon,
  202. "class": bem("icon", {
  203. disabled,
  204. full: isFull
  205. }),
  206. "color": disabled ? disabledColor : isFull ? color : voidColor,
  207. "classPrefix": iconPrefix
  208. }, null), renderHalf && (0, import_vue.createVNode)(import_icon.Icon, {
  209. "size": size,
  210. "style": {
  211. width: item.value + "em"
  212. },
  213. "name": isVoid ? voidIcon : icon,
  214. "class": bem("icon", ["half", {
  215. disabled,
  216. full: !isVoid
  217. }]),
  218. "color": disabled ? disabledColor : isVoid ? voidColor : color,
  219. "classPrefix": iconPrefix
  220. }, null)]);
  221. };
  222. (0, import_use.useCustomFieldValue)(() => props.modelValue);
  223. (0, import_use.useEventListener)("touchmove", onTouchMove, {
  224. target: groupRef
  225. });
  226. return () => (0, import_vue.createVNode)("div", {
  227. "ref": groupRef,
  228. "role": "radiogroup",
  229. "class": bem({
  230. readonly: props.readonly,
  231. disabled: props.disabled
  232. }),
  233. "tabindex": props.disabled ? void 0 : 0,
  234. "aria-disabled": props.disabled,
  235. "aria-readonly": props.readonly,
  236. "onTouchstartPassive": onTouchStart
  237. }, [list.value.map(renderStar)]);
  238. }
  239. });