Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨ Rate 评分新增支持半选和触摸滑动选中 #896

Merged
merged 1 commit into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion docs/component/rate.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
```

```typescript

const value = ref<number>(1)

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

## 允许半选

设置 `allowHalf` 属性。

```html
<wd-rate v-model="value" allow-half />
```

## Attributes

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

## Events

Expand Down
7 changes: 6 additions & 1 deletion src/pages/rate/Index.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!--
* @Author: weisheng
* @Date: 2023-07-29 17:03:39
* @LastEditTime: 2024-03-17 20:19:52
* @LastEditTime: 2025-02-13 23:36:41
* @LastEditors: weisheng
* @Description:
* @FilePath: /wot-design-uni/src/pages/rate/Index.vue
Expand Down Expand Up @@ -41,6 +41,10 @@
<demo-block title="修改size、space">
<wd-rate v-model="value7" space="10px" size="30px" />
</demo-block>

<demo-block title="允许半选">
<wd-rate v-model="value8" allow-half />
</demo-block>
</page-wraper>
</template>
<script lang="ts" setup>
Expand All @@ -53,6 +57,7 @@ const value4 = ref<number>(3)
const value5 = ref<number>(4)
const value6 = ref<number>(3)
const value7 = ref<number>(5)
const value8 = ref<number>(2.5)

function changeValue1({ value }: any) {
console.log(value)
Expand Down
21 changes: 11 additions & 10 deletions src/uni_modules/wot-design-uni/components/wd-rate/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@
@include e(item) {
position: relative;
display: inline-block;
touch-action: none; // 禁用默认触摸行为
}
@include e(item-star) {
display: inline-block;
vertical-align: top;

@include m(active) {
position: absolute;
left: 0;
top: 0;
overflow: hidden;
}
@include edeep(item-star) {
-webkit-background-clip: text !important;
color: transparent;
}
@include e(item-half) {
position: absolute;
left: 0;
top: 0;
overflow: hidden;
width: 50%;
}
}
9 changes: 8 additions & 1 deletion src/uni_modules/wot-design-uni/components/wd-rate/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,12 @@ export const rateProps = {
* 类型: string
* 默认值: 'linear-gradient(315deg, rgba(177,177,177,1) 0%,rgba(199,199,199,1) 100%)'
*/
disabledColor: makeStringProp('linear-gradient(315deg, rgba(177,177,177,1) 0%,rgba(199,199,199,1) 100%)')
disabledColor: makeStringProp('linear-gradient(315deg, rgba(177,177,177,1) 0%,rgba(199,199,199,1) 100%)'),

/**
* 是否允许半选
* 类型: boolean
* 默认值: false
*/
allowHalf: makeBooleanProp(false)
}
69 changes: 50 additions & 19 deletions src/uni_modules/wot-design-uni/components/wd-rate/wd-rate.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
<template>
<view :class="`wd-rate ${customClass}`" :style="customStyle">
<view :class="`wd-rate ${customClass}`" :style="customStyle" @touchmove="onTouchMove">
<view
v-for="(rate, index) in rateList"
:key="index"
:data-index="index"
:style="{ 'margin-right': index == rateList.length - 1 ? 0 : space }"
class="wd-rate__item"
@click="changeRate(index)"
>
<view class="wd-rate__item-star" :style="{ width: size, height: size }">
<wd-icon :name="icon" :size="size" :custom-style="iconStyle" />
</view>
<view class="wd-rate__item-star wd-rate__item-star--active" :style="{ width: rate, height: size }">
<wd-icon :name="activeIcon" :size="size" :custom-style="iconActiveStyle" />
<wd-icon
custom-class="wd-rate__item-star"
:name="isActive(rate) ? activeIcon : icon"
:size="size"
:custom-style="rate === '100%' ? iconActiveStyle : iconStyle"
@click="changeRate(index, false)"
/>
<view v-if="props.allowHalf" class="wd-rate__item-half" @click.stop="changeRate(index, true)">
<wd-icon
custom-class="wd-rate__item-star"
:name="isActive(rate) ? activeIcon : icon"
:size="size"
:custom-style="rate !== '0' ? iconActiveStyle : iconStyle"
/>
</view>
</view>
</view>
Expand All @@ -30,8 +38,10 @@ export default {
</script>
<script lang="ts" setup>
import wdIcon from '../wd-icon/wd-icon.vue'
import { computed, ref, watch } from 'vue'
import { computed, getCurrentInstance, ref, watch } from 'vue'
import { rateProps } from './types'
import { getRect } from '../common/util'
const { proxy } = getCurrentInstance() as any

const props = defineProps(rateProps)
const emit = defineEmits(['update:modelValue', 'change'])
Expand All @@ -40,11 +50,11 @@ const rateList = ref<Array<string>>([])
const activeValue = ref<string>('')

const iconStyle = computed(() => {
return `background:${props.color}; -webkit-background-clip: text; color: transparent`
return `background:${props.color};`
})

const iconActiveStyle = computed(() => {
return `background:${props.disabled ? props.disabledColor : activeValue.value}; -webkit-background-clip: text; color: transparent`
return `background:${props.disabled ? props.disabledColor : activeValue.value};`
})

watch(
Expand Down Expand Up @@ -72,25 +82,29 @@ watch(
}
)

// 当前选项是否为激活状态
const isActive = (rate: string) => {
return rate !== '0'
}

/**
* @description 计算当前应当展示的rate数量
*/
function computeRateList() {
const { modelValue, num } = props
const { modelValue, num, allowHalf } = props
// value和num都准备好才能计算
if (modelValue === null || !num) return
if (typeof modelValue !== 'number') {
console.error('[Wot Design] error(wd-rate): the value of wd-rate should be a number')
return
}
const tempRateList: string[] = []
const fullLength = Math.ceil(modelValue) - 1
const fullLength = Math.floor(modelValue)
for (let i = 0; i < num; i++) {
if (i < fullLength) {
tempRateList.push('100%')
} else if (i === fullLength) {
const rate = modelValue - fullLength > 0.5 ? 1 : 0.5
tempRateList.push(rate * 100 + '%')
} else if (i === fullLength && allowHalf && modelValue % 1 !== 0) {
tempRateList.push('50%')
} else {
tempRateList.push('0')
}
Expand All @@ -113,14 +127,31 @@ function computeActiveValue() {
}
/**
* @description 点击icon触发组件的change事件
* @param Event
*/
function changeRate(index: number) {
function changeRate(index: number, isHalf: boolean) {
if (props.readonly || props.disabled) return
emit('update:modelValue', index + 1)
const value = isHalf ? index + 0.5 : index + 1
emit('update:modelValue', value)
emit('change', {
value: index + 1
value
})
}

async function onTouchMove(event: TouchEvent) {
const { clientX } = event.touches[0]
const rateItems = await getRect('.wd-rate__item', true, proxy)
const targetIndex = Array.from(rateItems).findIndex((rect) => {
return clientX >= rect.left! && clientX <= rect.right!
})
if (targetIndex !== -1) {
const target = rateItems[targetIndex]
const itemWidth = target.width!
const isHalf = props.allowHalf && clientX - target.left! < itemWidth / 2
const value = isHalf ? targetIndex + 0.5 : targetIndex + 1
if (value >= 0.5) {
changeRate(targetIndex, isHalf)
}
}
}
</script>
<style lang="scss" scoped>
Expand Down