11<template >
2- <view :class =" `wd-rate ${customClass}`" :style =" customStyle" >
2+ <view :class =" `wd-rate ${customClass}`" :style =" customStyle" @touchmove = " onTouchMove " >
33 <view
44 v-for =" (rate, index) in rateList"
55 :key =" index"
66 :data-index =" index"
77 :style =" { 'margin-right': index == rateList.length - 1 ? 0 : space }"
88 class =" wd-rate__item"
9- @click =" changeRate(index)"
109 >
11- <view class =" wd-rate__item-star" :style =" { width: size, height: size }" >
12- <wd-icon :name =" icon" :size =" size" :custom-style =" iconStyle" />
13- </view >
14- <view class =" wd-rate__item-star wd-rate__item-star--active" :style =" { width: rate, height: size }" >
15- <wd-icon :name =" activeIcon" :size =" size" :custom-style =" iconActiveStyle" />
10+ <wd-icon
11+ custom-class =" wd-rate__item-star"
12+ :name =" isActive(rate) ? activeIcon : icon"
13+ :size =" size"
14+ :custom-style =" rate === '100%' ? iconActiveStyle : iconStyle"
15+ @click =" changeRate(index, false)"
16+ />
17+ <view v-if =" props.allowHalf" class =" wd-rate__item-half" @click.stop =" changeRate(index, true)" >
18+ <wd-icon
19+ custom-class =" wd-rate__item-star"
20+ :name =" isActive(rate) ? activeIcon : icon"
21+ :size =" size"
22+ :custom-style =" rate !== '0' ? iconActiveStyle : iconStyle"
23+ />
1624 </view >
1725 </view >
1826 </view >
@@ -30,8 +38,10 @@ export default {
3038 </script >
3139<script lang="ts" setup>
3240import wdIcon from ' ../wd-icon/wd-icon.vue'
33- import { computed , ref , watch } from ' vue'
41+ import { computed , getCurrentInstance , ref , watch } from ' vue'
3442import { rateProps } from ' ./types'
43+ import { getRect } from ' ../common/util'
44+ const { proxy } = getCurrentInstance () as any
3545
3646const props = defineProps (rateProps )
3747const emit = defineEmits ([' update:modelValue' , ' change' ])
@@ -40,11 +50,11 @@ const rateList = ref<Array<string>>([])
4050const activeValue = ref <string >(' ' )
4151
4252const iconStyle = computed (() => {
43- return ` background:${props .color }; -webkit-background-clip: text; color: transparent `
53+ return ` background:${props .color }; `
4454})
4555
4656const iconActiveStyle = computed (() => {
47- return ` background:${props .disabled ? props .disabledColor : activeValue .value }; -webkit-background-clip: text; color: transparent `
57+ return ` background:${props .disabled ? props .disabledColor : activeValue .value }; `
4858})
4959
5060watch (
@@ -72,25 +82,29 @@ watch(
7282 }
7383)
7484
85+ // 当前选项是否为激活状态
86+ const isActive = (rate : string ) => {
87+ return rate !== ' 0'
88+ }
89+
7590/**
7691 * @description 计算当前应当展示的rate数量
7792 */
7893function computeRateList() {
79- const { modelValue, num } = props
94+ const { modelValue, num, allowHalf } = props
8095 // value和num都准备好才能计算
8196 if (modelValue === null || ! num ) return
8297 if (typeof modelValue !== ' number' ) {
8398 console .error (' [Wot Design] error(wd-rate): the value of wd-rate should be a number' )
8499 return
85100 }
86101 const tempRateList: string [] = []
87- const fullLength = Math .ceil (modelValue ) - 1
102+ const fullLength = Math .floor (modelValue )
88103 for (let i = 0 ; i < num ; i ++ ) {
89104 if (i < fullLength ) {
90105 tempRateList .push (' 100%' )
91- } else if (i === fullLength ) {
92- const rate = modelValue - fullLength > 0.5 ? 1 : 0.5
93- tempRateList .push (rate * 100 + ' %' )
106+ } else if (i === fullLength && allowHalf && modelValue % 1 !== 0 ) {
107+ tempRateList .push (' 50%' )
94108 } else {
95109 tempRateList .push (' 0' )
96110 }
@@ -113,14 +127,31 @@ function computeActiveValue() {
113127}
114128/**
115129 * @description 点击icon触发组件的change事件
116- * @param Event
117130 */
118- function changeRate(index : number ) {
131+ function changeRate(index : number , isHalf : boolean ) {
119132 if (props .readonly || props .disabled ) return
120- emit (' update:modelValue' , index + 1 )
133+ const value = isHalf ? index + 0.5 : index + 1
134+ emit (' update:modelValue' , value )
121135 emit (' change' , {
122- value: index + 1
136+ value
137+ })
138+ }
139+
140+ async function onTouchMove(event : TouchEvent ) {
141+ const { clientX } = event .touches [0 ]
142+ const rateItems = await getRect (' .wd-rate__item' , true , proxy )
143+ const targetIndex = Array .from (rateItems ).findIndex ((rect ) => {
144+ return clientX >= rect .left ! && clientX <= rect .right !
123145 })
146+ if (targetIndex !== - 1 ) {
147+ const target = rateItems [targetIndex ]
148+ const itemWidth = target .width !
149+ const isHalf = props .allowHalf && clientX - target .left ! < itemWidth / 2
150+ const value = isHalf ? targetIndex + 0.5 : targetIndex + 1
151+ if (value >= 0.5 ) {
152+ changeRate (targetIndex , isHalf )
153+ }
154+ }
124155}
125156 </script >
126157<style lang="scss" scoped>
0 commit comments