123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- <template>
- <div :class="classes" @mouseleave="handleMouseleave">
- <div
- v-for="item in count"
- :key="item"
- :class="starCls(item)"
- @mousemove="handleMousemove(item, $event)"
- @click="handleClick(item)">
- <span class="iconfont favorite" v-if="!character && !icon">
- <span class="iconfont favorite-half" type="half"></span>
- </span>
- <template v-if="character">
- <span class="m-rate-star-first" type="half">{{ character }}</span>
- <span class="m-rate-star-second">{{ character }}</span>
- </template>
- <i class="iconfont other-icon" :class="['icon-'+ icon]" v-if="icon">
- <i class="iconfont other-icon-half" :class="['icon-'+ icon]" type="half"></i>
- </i>
- </div>
- <div class="m-rate-text" v-if="showText && currentValue > 0">
- <slot>{{currentValue}} 星</slot>
- </div>
- </div>
- </template>
- <script>
- export default {
- name: "mRate"
- };
- </script>
- <script setup>
- import { computed, reactive, toRefs, watch } from 'vue-demi';
- const emits = defineEmits(['update:modelValue','on-change'])
- const props = defineProps({
- count: {
- type: Number,
- default: 5
- },
- modelValue: {
- type: Number,
- default: 0
- },
- allowHalf: {
- type: Boolean,
- default: false
- },
- showText: {
- type: Boolean,
- default: false
- },
- disabled: {
- type: Boolean,
- default: false
- },
- clearable: {
- type: Boolean,
- default: false
- },
- character: {
- type: String,
- default: ''
- },
- icon: {
- type: String,
- default: ''
- },
- })
- const state = reactive({
- hoverIndex: -1,
- isHover: false,
- currentValue: props.modelValue,
- isHalf: props.allowHalf && props.modelValue.toString().indexOf('.') > -1,
- })
- watch(() => props.modelValue,(newVal) => {
- state.currentValue = newVal
- },{immediate:true})
- const classes = computed(() => {
- return [
- 'm-rate',
- {
- 'm-rate-disabled': props.disabled
- }
- ]
- })
- const starCls = (value) => {
- const currentIndex = state.isHover ? state.hoverIndex : state.currentValue;
- let full = false;
- let isLast = false;
- if (currentIndex >= value) full = true;
- if (state.isHover) {
- isLast = currentIndex === value;
- } else {
- isLast = Math.ceil(state.currentValue) === value;
- }
- return [
- 'm-rate-star',
- {
- 'm-rate-star-full': (!isLast && full) || (isLast && !state.isHalf),
- 'm-rate-star-zero': !full,
- 'm-rate-star-half': isLast && state.isHalf,
- }
- ]
- }
- const handleMousemove = (value, event) => {
- if (props.disabled) return;
- state.isHover = true;
- if (props.allowHalf) {
- const type = event.target.getAttribute('type') || false;
- state.isHalf = type === 'half';
- } else {
- state.isHalf = false;
- }
- // hoverIndex 为整
- state.hoverIndex = value;
- }
- const handleMouseleave = () => {
- if (props.disabled) return;
- state.isHover = false;
- setHalf(state.currentValue);
- state.hoverIndex = -1;
- }
- const setHalf = (val) => {
- state.isHalf = props.allowHalf && val.toString().indexOf('.') > -1;
- }
- const handleClick = (value) => {
- if (props.disabled) return;
- if (state.isHalf) value -= 0.5;
- if(props.clearable && Math.abs(value - state.currentValue) < 0.01) {
- value = 0
- }
- state.currentValue = value;
- emits('update:modelValue',value)
- emits('on-change',value)
- }
- const { currentValue } = toRefs(state);
- </script>
- <style lang="scss" scoped>
- @import '../../styles/components/rate.scss';
- </style>
|