mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat(Rate): 当使用 readonly 和 allow-half 时支持 modelValue 设置小数 (#8528)
* feat(Rate): 当使用readonly和allow-half时支持modelValue设置小数 * docs(Rate): 完善文档 * docs(Rate): update snapshot * docs(Rate): add description of decimal value Co-authored-by: neverland <chenjiahan@buaa.edu.cn>
This commit is contained in:
parent
8e4e6d54a6
commit
8fb3560f39
@ -88,6 +88,23 @@ export default {
|
|||||||
<van-rate v-model="value" readonly />
|
<van-rate v-model="value" readonly />
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Readonly Half Star
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-rate v-model="value" readonly />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const value = ref(3.3);
|
||||||
|
return { value };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### Change Event
|
### Change Event
|
||||||
|
|
||||||
```html
|
```html
|
||||||
|
@ -88,6 +88,25 @@ export default {
|
|||||||
<van-rate v-model="value" readonly />
|
<van-rate v-model="value" readonly />
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 只读状态显示小数
|
||||||
|
|
||||||
|
设置 `readonly` 和 `allow-half` 属性后,Rate 组件可以展示任意小数结果。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-rate v-model="value" readonly allow-half />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const value = ref(3.3);
|
||||||
|
return { value };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### 监听 change 事件
|
### 监听 change 事件
|
||||||
|
|
||||||
```html
|
```html
|
||||||
|
@ -15,18 +15,34 @@ const [name, bem] = createNamespace('rate');
|
|||||||
|
|
||||||
type RateStatus = 'full' | 'half' | 'void';
|
type RateStatus = 'full' | 'half' | 'void';
|
||||||
|
|
||||||
|
type RateListItem = {
|
||||||
|
status: RateStatus;
|
||||||
|
value: number;
|
||||||
|
};
|
||||||
|
|
||||||
function getRateStatus(
|
function getRateStatus(
|
||||||
value: number,
|
value: number,
|
||||||
index: number,
|
index: number,
|
||||||
allowHalf: boolean
|
allowHalf: boolean,
|
||||||
): RateStatus {
|
readonly: boolean
|
||||||
|
): RateListItem {
|
||||||
if (value >= index) {
|
if (value >= index) {
|
||||||
return 'full';
|
return { status: 'full', value: 1 };
|
||||||
}
|
}
|
||||||
if (value + 0.5 >= index && allowHalf) {
|
|
||||||
return 'half';
|
if (value + 0.5 >= index && allowHalf && !readonly) {
|
||||||
|
return { status: 'half', value: 0.5 };
|
||||||
}
|
}
|
||||||
return 'void';
|
|
||||||
|
if (value + 1 >= index && allowHalf && readonly) {
|
||||||
|
const cardinal = 10 ** 10;
|
||||||
|
return {
|
||||||
|
status: 'half',
|
||||||
|
value: Math.round((value - index + 1) * cardinal) / cardinal,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { status: 'void', value: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -72,10 +88,17 @@ export default defineComponent({
|
|||||||
const untouchable = () =>
|
const untouchable = () =>
|
||||||
props.readonly || props.disabled || !props.touchable;
|
props.readonly || props.disabled || !props.touchable;
|
||||||
|
|
||||||
const list = computed<RateStatus[]>(() =>
|
const list = computed<RateListItem[]>(() =>
|
||||||
Array(props.count)
|
Array(props.count)
|
||||||
.fill('')
|
.fill('')
|
||||||
.map((_, i) => getRateStatus(props.modelValue, i + 1, props.allowHalf))
|
.map((_, i) =>
|
||||||
|
getRateStatus(
|
||||||
|
props.modelValue,
|
||||||
|
i + 1,
|
||||||
|
props.allowHalf,
|
||||||
|
props.readonly
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const select = (index: number) => {
|
const select = (index: number) => {
|
||||||
@ -130,7 +153,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderStar = (status: RateStatus, index: number) => {
|
const renderStar = (item: RateListItem, index: number) => {
|
||||||
const {
|
const {
|
||||||
icon,
|
icon,
|
||||||
size,
|
size,
|
||||||
@ -145,8 +168,8 @@ export default defineComponent({
|
|||||||
disabledColor,
|
disabledColor,
|
||||||
} = props;
|
} = props;
|
||||||
const score = index + 1;
|
const score = index + 1;
|
||||||
const isFull = status === 'full';
|
const isFull = item.status === 'full';
|
||||||
const isVoid = status === 'void';
|
const isVoid = item.status === 'void';
|
||||||
|
|
||||||
let style;
|
let style;
|
||||||
if (gutter && score !== +count) {
|
if (gutter && score !== +count) {
|
||||||
@ -181,6 +204,7 @@ export default defineComponent({
|
|||||||
{allowHalf && (
|
{allowHalf && (
|
||||||
<Icon
|
<Icon
|
||||||
size={size}
|
size={size}
|
||||||
|
style={{ width: item.value + 'em' }}
|
||||||
name={isVoid ? voidIcon : icon}
|
name={isVoid ? voidIcon : icon}
|
||||||
class={bem('icon', ['half', { disabled, full: !isVoid }])}
|
class={bem('icon', ['half', { disabled, full: !isVoid }])}
|
||||||
color={disabled ? disabledColor : isVoid ? voidColor : color}
|
color={disabled ? disabledColor : isVoid ? voidColor : color}
|
||||||
|
@ -39,8 +39,12 @@
|
|||||||
<van-rate v-model="value6" readonly />
|
<van-rate v-model="value6" readonly />
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
|
<demo-block :title="t('readonlyHalfStar')">
|
||||||
|
<van-rate v-model="value7" readonly allow-half />
|
||||||
|
</demo-block>
|
||||||
|
|
||||||
<demo-block v-if="!isWeapp" :title="t('changeEvent')">
|
<demo-block v-if="!isWeapp" :title="t('changeEvent')">
|
||||||
<van-rate v-model="value7" @change="onChange" />
|
<van-rate v-model="value8" @change="onChange" />
|
||||||
</demo-block>
|
</demo-block>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -57,6 +61,7 @@ const i18n = {
|
|||||||
customStyle: '自定义样式',
|
customStyle: '自定义样式',
|
||||||
customCount: '自定义数量',
|
customCount: '自定义数量',
|
||||||
readonly: '只读状态',
|
readonly: '只读状态',
|
||||||
|
readonlyHalfStar: '只读状态小数显示',
|
||||||
changeEvent: '监听 change 事件',
|
changeEvent: '监听 change 事件',
|
||||||
toastContent: (value: number) => `当前值:${value}`,
|
toastContent: (value: number) => `当前值:${value}`,
|
||||||
},
|
},
|
||||||
@ -67,6 +72,7 @@ const i18n = {
|
|||||||
customStyle: 'Custom Style',
|
customStyle: 'Custom Style',
|
||||||
customCount: 'Custom Count',
|
customCount: 'Custom Count',
|
||||||
readonly: 'Readonly',
|
readonly: 'Readonly',
|
||||||
|
readonlyHalfStar: 'Readonly Half Star',
|
||||||
changeEvent: 'Change Event',
|
changeEvent: 'Change Event',
|
||||||
toastContent: (value: number) => `current value:${value}`,
|
toastContent: (value: number) => `current value:${value}`,
|
||||||
},
|
},
|
||||||
@ -82,7 +88,8 @@ export default {
|
|||||||
value4: 2.5,
|
value4: 2.5,
|
||||||
value5: 4,
|
value5: 4,
|
||||||
value6: 3,
|
value6: 3,
|
||||||
value7: 2,
|
value7: 3.3,
|
||||||
|
value8: 2,
|
||||||
});
|
});
|
||||||
|
|
||||||
const onChange = (value: number) => Toast(t('toastContent', value));
|
const onChange = (value: number) => Toast(t('toastContent', value));
|
||||||
|
@ -225,7 +225,7 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
</i>
|
</i>
|
||||||
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half van-rate__icon--full"
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half van-rate__icon--full"
|
||||||
style="font-size: 25px;"
|
style="font-size: 25px; width: 1em;"
|
||||||
data-score="0.5"
|
data-score="0.5"
|
||||||
>
|
>
|
||||||
</i>
|
</i>
|
||||||
@ -243,7 +243,7 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
</i>
|
</i>
|
||||||
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half van-rate__icon--full"
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half van-rate__icon--full"
|
||||||
style="font-size: 25px;"
|
style="font-size: 25px; width: 1em;"
|
||||||
data-score="1.5"
|
data-score="1.5"
|
||||||
>
|
>
|
||||||
</i>
|
</i>
|
||||||
@ -261,7 +261,7 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
</i>
|
</i>
|
||||||
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half van-rate__icon--full"
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half van-rate__icon--full"
|
||||||
style="font-size: 25px;"
|
style="font-size: 25px; width: 0.5em;"
|
||||||
data-score="2.5"
|
data-score="2.5"
|
||||||
>
|
>
|
||||||
</i>
|
</i>
|
||||||
@ -279,7 +279,7 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
</i>
|
</i>
|
||||||
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half"
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half"
|
||||||
style="color: rgb(238, 238, 238); font-size: 25px;"
|
style="color: rgb(238, 238, 238); font-size: 25px; width: 0em;"
|
||||||
data-score="3.5"
|
data-score="3.5"
|
||||||
>
|
>
|
||||||
</i>
|
</i>
|
||||||
@ -297,7 +297,7 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
</i>
|
</i>
|
||||||
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half"
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half"
|
||||||
style="color: rgb(238, 238, 238); font-size: 25px;"
|
style="color: rgb(238, 238, 238); font-size: 25px; width: 0em;"
|
||||||
data-score="4.5"
|
data-score="4.5"
|
||||||
>
|
>
|
||||||
</i>
|
</i>
|
||||||
@ -517,6 +517,98 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<div role="radiogroup"
|
||||||
|
class="van-rate van-rate--readonly"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div role="radio"
|
||||||
|
class="van-rate__item"
|
||||||
|
tabindex="0"
|
||||||
|
aria-setsize="5"
|
||||||
|
aria-posinset="1"
|
||||||
|
aria-checked="true"
|
||||||
|
>
|
||||||
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--full"
|
||||||
|
data-score="1"
|
||||||
|
>
|
||||||
|
</i>
|
||||||
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half van-rate__icon--full"
|
||||||
|
style="width: 1em;"
|
||||||
|
data-score="0.5"
|
||||||
|
>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
<div role="radio"
|
||||||
|
class="van-rate__item"
|
||||||
|
tabindex="0"
|
||||||
|
aria-setsize="5"
|
||||||
|
aria-posinset="2"
|
||||||
|
aria-checked="true"
|
||||||
|
>
|
||||||
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--full"
|
||||||
|
data-score="2"
|
||||||
|
>
|
||||||
|
</i>
|
||||||
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half van-rate__icon--full"
|
||||||
|
style="width: 1em;"
|
||||||
|
data-score="1.5"
|
||||||
|
>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
<div role="radio"
|
||||||
|
class="van-rate__item"
|
||||||
|
tabindex="0"
|
||||||
|
aria-setsize="5"
|
||||||
|
aria-posinset="3"
|
||||||
|
aria-checked="true"
|
||||||
|
>
|
||||||
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--full"
|
||||||
|
data-score="3"
|
||||||
|
>
|
||||||
|
</i>
|
||||||
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half van-rate__icon--full"
|
||||||
|
style="width: 1em;"
|
||||||
|
data-score="2.5"
|
||||||
|
>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
<div role="radio"
|
||||||
|
class="van-rate__item"
|
||||||
|
tabindex="0"
|
||||||
|
aria-setsize="5"
|
||||||
|
aria-posinset="4"
|
||||||
|
aria-checked="true"
|
||||||
|
>
|
||||||
|
<i class="van-badge__wrapper van-icon van-icon-star-o van-rate__icon"
|
||||||
|
data-score="4"
|
||||||
|
>
|
||||||
|
</i>
|
||||||
|
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--half van-rate__icon--full"
|
||||||
|
style="width: 0.3em;"
|
||||||
|
data-score="3.5"
|
||||||
|
>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
<div role="radio"
|
||||||
|
class="van-rate__item"
|
||||||
|
tabindex="0"
|
||||||
|
aria-setsize="5"
|
||||||
|
aria-posinset="5"
|
||||||
|
aria-checked="false"
|
||||||
|
>
|
||||||
|
<i class="van-badge__wrapper van-icon van-icon-star-o van-rate__icon"
|
||||||
|
data-score="5"
|
||||||
|
>
|
||||||
|
</i>
|
||||||
|
<i class="van-badge__wrapper van-icon van-icon-star-o van-rate__icon van-rate__icon--half"
|
||||||
|
style="width: 0em;"
|
||||||
|
data-score="4.5"
|
||||||
|
>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div role="radiogroup"
|
<div role="radiogroup"
|
||||||
class="van-rate"
|
class="van-rate"
|
||||||
|
@ -127,3 +127,16 @@ test('should not emit change event when untouchable rate is touchmoved', () => {
|
|||||||
triggerDrag(wrapper, 100, 0);
|
triggerDrag(wrapper, 100, 0);
|
||||||
expect(wrapper.emitted('change')).toBeFalsy();
|
expect(wrapper.emitted('change')).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should get decimal when using allow-half and readonly prop', () => {
|
||||||
|
const wrapper = mount(Rate, {
|
||||||
|
props: {
|
||||||
|
allowHalf: true,
|
||||||
|
readonly: true,
|
||||||
|
modelValue: 3.3,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const item4 = wrapper.findAll('.van-rate__icon--half')[3];
|
||||||
|
expect(item4.style.width).toEqual('0.3em');
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user