Rate.js 7.4 KB

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