StarRating.vue 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. <template>
  2. <span
  3. class="star-rating"
  4. :class="sizeClass"
  5. :style="{ cursor: disabled ? 'default' : 'pointer' }"
  6. @click="handleClick"
  7. >
  8. <i v-for="i in max" :key="i" class="star" :class="starClass(i)"></i>
  9. </span>
  10. </template>
  11. <script setup>
  12. import { ref, watch, computed } from 'vue';
  13. const props = defineProps({
  14. value: { type: Number, default: 0 },
  15. max: { type: Number, default: 5 },
  16. step: { type: Number, default: 1 },
  17. disabled: { type: Boolean, default: false },
  18. size: { type: String, default: 'md' }
  19. });
  20. const emit = defineEmits(['change']);
  21. const value = ref(props.value);
  22. watch(() => props.value, (newValue) => { value.value = newValue; });
  23. const sizeClass = computed(() => ({
  24. 'xs': 'fa-xs',
  25. 'sm': 'fa-sm',
  26. 'md': '',
  27. 'lg': 'fa-lg',
  28. 'xl': 'fa-xl',
  29. '2x': 'fa-2x',
  30. '3x': 'fa-3x'
  31. }[props.size] || ''));
  32. function starClass(index) {
  33. const faStar = 'fa-star';
  34. if (props.step === 0.5) {
  35. if (value.value >= index) {
  36. return `fa-solid ${faStar}`;
  37. }
  38. if (value.value >= index - 0.5) {
  39. return `fa-solid ${faStar}-half-stroke`;
  40. }
  41. return `fa-regular ${faStar}`;
  42. }
  43. return value.value >= index ? `fa-solid ${faStar}` : `fa-regular ${faStar}`;
  44. }
  45. function handleClick(event) {
  46. if (props.disabled) return;
  47. const clickedStar = event.target.closest('.star');
  48. if (!clickedStar) return;
  49. const stars = Array.from(event.currentTarget.querySelectorAll('.star'));
  50. const starValue = stars.indexOf(clickedStar) + 1;
  51. if (props.step === 0.5) {
  52. const rect = clickedStar.getBoundingClientRect();
  53. const clickX = event.clientX - rect.left;
  54. value.value = clickX < rect.width / 2 ? starValue - 0.5 : starValue;
  55. } else {
  56. value.value = starValue;
  57. }
  58. emit('change', value.value);
  59. event.currentTarget.dispatchEvent(new CustomEvent('change', {
  60. bubbles: true,
  61. detail: { value: value.value }
  62. }));
  63. }
  64. </script>