Skip to content

Commit 9d34f2e

Browse files
feat: ✨ Rate 评分新增支持半选和触摸滑动选中 (#896)
Closes: #669
1 parent 0e31950 commit 9d34f2e

File tree

5 files changed

+84
-32
lines changed

5 files changed

+84
-32
lines changed

docs/component/rate.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
```
1212

1313
```typescript
14-
1514
const value = ref<number>(1)
1615

1716
function changeValue({ value }) {
@@ -60,6 +59,14 @@ function changeValue({ value }) {
6059
<wd-rate v-model="value" size="30px" space="10px"/>
6160
```
6261

62+
## 允许半选
63+
64+
设置 `allowHalf` 属性。
65+
66+
```html
67+
<wd-rate v-model="value" allow-half />
68+
```
69+
6370
## Attributes
6471

6572
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
@@ -75,6 +82,7 @@ function changeValue({ value }) {
7582
| active-icon | 选中的图标类名 | string | - | wd-icon-star-on | - |
7683
| disabled | 是否禁用 | boolean | - | false | - |
7784
| disabled-color | 禁用的图标颜色 | string | - | linear-gradient(315deg, rgba(177,177,177,1) 0%,rgba(199,199,199,1) 100%) | - |
85+
| allow-half | 是否允许半选 | boolean | - | false | $LOWEST_VERSION$ |
7886

7987
## Events
8088

src/pages/rate/Index.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!--
22
* @Author: weisheng
33
* @Date: 2023-07-29 17:03:39
4-
* @LastEditTime: 2024-03-17 20:19:52
4+
* @LastEditTime: 2025-02-13 23:36:41
55
* @LastEditors: weisheng
66
* @Description:
77
* @FilePath: /wot-design-uni/src/pages/rate/Index.vue
@@ -41,6 +41,10 @@
4141
<demo-block title="修改size、space">
4242
<wd-rate v-model="value7" space="10px" size="30px" />
4343
</demo-block>
44+
45+
<demo-block title="允许半选">
46+
<wd-rate v-model="value8" allow-half />
47+
</demo-block>
4448
</page-wraper>
4549
</template>
4650
<script lang="ts" setup>
@@ -53,6 +57,7 @@ const value4 = ref<number>(3)
5357
const value5 = ref<number>(4)
5458
const value6 = ref<number>(3)
5559
const value7 = ref<number>(5)
60+
const value8 = ref<number>(2.5)
5661
5762
function changeValue1({ value }: any) {
5863
console.log(value)

src/uni_modules/wot-design-uni/components/wd-rate/index.scss

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@
99
@include e(item) {
1010
position: relative;
1111
display: inline-block;
12+
touch-action: none; // 禁用默认触摸行为
1213
}
13-
@include e(item-star) {
14-
display: inline-block;
15-
vertical-align: top;
16-
17-
@include m(active) {
18-
position: absolute;
19-
left: 0;
20-
top: 0;
21-
overflow: hidden;
22-
}
14+
@include edeep(item-star) {
15+
-webkit-background-clip: text !important;
16+
color: transparent;
17+
}
18+
@include e(item-half) {
19+
position: absolute;
20+
left: 0;
21+
top: 0;
22+
overflow: hidden;
23+
width: 50%;
2324
}
2425
}

src/uni_modules/wot-design-uni/components/wd-rate/types.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,12 @@ export const rateProps = {
8585
* 类型: string
8686
* 默认值: 'linear-gradient(315deg, rgba(177,177,177,1) 0%,rgba(199,199,199,1) 100%)'
8787
*/
88-
disabledColor: makeStringProp('linear-gradient(315deg, rgba(177,177,177,1) 0%,rgba(199,199,199,1) 100%)')
88+
disabledColor: makeStringProp('linear-gradient(315deg, rgba(177,177,177,1) 0%,rgba(199,199,199,1) 100%)'),
89+
90+
/**
91+
* 是否允许半选
92+
* 类型: boolean
93+
* 默认值: false
94+
*/
95+
allowHalf: makeBooleanProp(false)
8996
}

src/uni_modules/wot-design-uni/components/wd-rate/wd-rate.vue

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
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>
3240
import wdIcon from '../wd-icon/wd-icon.vue'
33-
import { computed, ref, watch } from 'vue'
41+
import { computed, getCurrentInstance, ref, watch } from 'vue'
3442
import { rateProps } from './types'
43+
import { getRect } from '../common/util'
44+
const { proxy } = getCurrentInstance() as any
3545
3646
const props = defineProps(rateProps)
3747
const emit = defineEmits(['update:modelValue', 'change'])
@@ -40,11 +50,11 @@ const rateList = ref<Array<string>>([])
4050
const activeValue = ref<string>('')
4151
4252
const iconStyle = computed(() => {
43-
return `background:${props.color}; -webkit-background-clip: text; color: transparent`
53+
return `background:${props.color};`
4454
})
4555
4656
const 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
5060
watch(
@@ -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
*/
7893
function 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

Comments
 (0)