| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- <template>
- <span
- class="star-rating"
- :class="sizeClass"
- :style="{ cursor: disabled ? 'default' : 'pointer' }"
- @click="handleClick"
- >
- <i v-for="i in max" :key="i" class="star" :class="starClass(i)"></i>
- </span>
- </template>
- <script setup>
- import { ref, watch, computed } from 'vue';
- const props = defineProps({
- value: { type: Number, default: 0 },
- max: { type: Number, default: 5 },
- step: { type: Number, default: 1 },
- disabled: { type: Boolean, default: false },
- size: { type: String, default: 'md' }
- });
- const emit = defineEmits(['change']);
- const value = ref(props.value);
- watch(() => props.value, (newValue) => { value.value = newValue; });
- const sizeClass = computed(() => ({
- 'xs': 'fa-xs',
- 'sm': 'fa-sm',
- 'md': '',
- 'lg': 'fa-lg',
- 'xl': 'fa-xl',
- '2x': 'fa-2x',
- '3x': 'fa-3x'
- }[props.size] || ''));
- function starClass(index) {
- const faStar = 'fa-star';
- if (props.step === 0.5) {
- if (value.value >= index) {
- return `fa-solid ${faStar}`;
- }
- if (value.value >= index - 0.5) {
- return `fa-solid ${faStar}-half-stroke`;
- }
- return `fa-regular ${faStar}`;
- }
- return value.value >= index ? `fa-solid ${faStar}` : `fa-regular ${faStar}`;
- }
- function handleClick(event) {
- if (props.disabled) return;
- const clickedStar = event.target.closest('.star');
- if (!clickedStar) return;
- const stars = Array.from(event.currentTarget.querySelectorAll('.star'));
- const starValue = stars.indexOf(clickedStar) + 1;
- if (props.step === 0.5) {
- const rect = clickedStar.getBoundingClientRect();
- const clickX = event.clientX - rect.left;
- value.value = clickX < rect.width / 2 ? starValue - 0.5 : starValue;
- } else {
- value.value = starValue;
- }
- emit('change', value.value);
- event.currentTarget.dispatchEvent(new CustomEvent('change', {
- bubbles: true,
- detail: { value: value.value }
- }));
- }
- </script>
|