更新:登录功能
This commit is contained in:
25
uni_modules/wot-design-uni/components/wd-rate/index.scss
Normal file
25
uni_modules/wot-design-uni/components/wd-rate/index.scss
Normal file
@@ -0,0 +1,25 @@
|
||||
@import './../common/abstracts/_mixin.scss';
|
||||
@import './../common/abstracts/variable.scss';
|
||||
|
||||
@include b(rate) {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
line-height: 1;
|
||||
|
||||
@include e(item) {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
touch-action: none; // 禁用默认触摸行为
|
||||
}
|
||||
@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%;
|
||||
}
|
||||
}
|
||||
103
uni_modules/wot-design-uni/components/wd-rate/types.ts
Normal file
103
uni_modules/wot-design-uni/components/wd-rate/types.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import type { PropType } from 'vue'
|
||||
import { baseProps, makeBooleanProp, makeNumberProp, makeStringProp } from '../common/props'
|
||||
|
||||
export const rateProps = {
|
||||
...baseProps,
|
||||
|
||||
/**
|
||||
* 评分最大值
|
||||
* 类型: number
|
||||
* 默认值: 5
|
||||
*/
|
||||
num: makeNumberProp(5),
|
||||
|
||||
/**
|
||||
* 当前分数,使用v-model进行双向绑定
|
||||
* 类型: string | number | null
|
||||
* 默认值: null
|
||||
*/
|
||||
modelValue: {
|
||||
type: [String, Number, null] as PropType<string | number | null>,
|
||||
default: null
|
||||
},
|
||||
|
||||
/**
|
||||
* 是否只读
|
||||
* 类型: boolean
|
||||
* 默认值: false
|
||||
*/
|
||||
readonly: makeBooleanProp(false),
|
||||
|
||||
/**
|
||||
* 图标大小
|
||||
* 类型: string
|
||||
* 默认值: '16px'
|
||||
*/
|
||||
size: makeStringProp('16px'),
|
||||
|
||||
/**
|
||||
* 图标间距
|
||||
* 类型: string
|
||||
* 默认值: '4px'
|
||||
*/
|
||||
space: makeStringProp('4px'),
|
||||
|
||||
/**
|
||||
* 未选中的图标颜色
|
||||
* 类型: string
|
||||
* 默认值: '#E8E8E8'
|
||||
*/
|
||||
color: makeStringProp('#E8E8E8'),
|
||||
|
||||
/**
|
||||
* 选中的图标颜色,支持传颜色数组(用于分段颜色)
|
||||
* 类型: string | Array<string>
|
||||
* 默认值: 'linear-gradient(180deg, rgba(255,238,0,1) 0%,rgba(250,176,21,1) 100%)'
|
||||
*/
|
||||
activeColor: {
|
||||
type: [String, Array] as PropType<string | Array<string>>,
|
||||
default: 'linear-gradient(180deg, rgba(255,238,0,1) 0%,rgba(250,176,21,1) 100%)'
|
||||
},
|
||||
|
||||
/**
|
||||
* 未选中的图标类名
|
||||
* 类型: string
|
||||
* 默认值: 'star-on'
|
||||
*/
|
||||
icon: makeStringProp('star-on'),
|
||||
|
||||
/**
|
||||
* 选中的图标类名
|
||||
* 类型: string
|
||||
* 默认值: 'star-on'
|
||||
*/
|
||||
activeIcon: makeStringProp('star-on'),
|
||||
|
||||
/**
|
||||
* 是否禁用
|
||||
* 类型: boolean
|
||||
* 默认值: false
|
||||
*/
|
||||
disabled: makeBooleanProp(false),
|
||||
|
||||
/**
|
||||
* 禁用的图标颜色
|
||||
* 类型: 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%)'),
|
||||
|
||||
/**
|
||||
* 是否允许半选
|
||||
* 类型: boolean
|
||||
* 默认值: false
|
||||
*/
|
||||
allowHalf: makeBooleanProp(false),
|
||||
|
||||
/**
|
||||
* 当 clearable 属性设置为 true,再次点击相同的值时,可以将值重置为 0。
|
||||
* 类型: boolean
|
||||
* 默认值: false
|
||||
*/
|
||||
clearable: makeBooleanProp(false)
|
||||
}
|
||||
178
uni_modules/wot-design-uni/components/wd-rate/wd-rate.vue
Normal file
178
uni_modules/wot-design-uni/components/wd-rate/wd-rate.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<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"
|
||||
>
|
||||
<wd-icon
|
||||
custom-class="wd-rate__item-star"
|
||||
:name="isActive(rate) ? activeIcon : icon"
|
||||
:size="size"
|
||||
:custom-style="rate === '100%' ? iconActiveStyle : iconStyle"
|
||||
@click="handleClick(index, false)"
|
||||
/>
|
||||
<view v-if="props.allowHalf" class="wd-rate__item-half" @click.stop="handleClick(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>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-rate',
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
styleIsolation: 'shared'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import wdIcon from '../wd-icon/wd-icon.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'])
|
||||
|
||||
const rateList = ref<Array<string>>([])
|
||||
const activeValue = ref<string>('')
|
||||
|
||||
const iconStyle = computed(() => {
|
||||
return `background:${props.color};`
|
||||
})
|
||||
|
||||
const iconActiveStyle = computed(() => {
|
||||
return `background:${props.disabled ? props.disabledColor : activeValue.value};`
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.activeColor,
|
||||
(newVal) => {
|
||||
if (Array.isArray(newVal) && !newVal.length) {
|
||||
console.error('activeColor cannot be an empty array')
|
||||
}
|
||||
computeActiveValue()
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
[() => props.num, () => props.modelValue],
|
||||
() => {
|
||||
computeRateList()
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
)
|
||||
|
||||
// 当前选项是否为激活状态
|
||||
const isActive = (rate: string) => {
|
||||
return rate !== '0'
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 计算当前应当展示的rate数量
|
||||
*/
|
||||
function computeRateList() {
|
||||
const { modelValue, num, allowHalf } = props
|
||||
// value和num都准备好才能计算
|
||||
if (modelValue === null || !num) return
|
||||
if (typeof modelValue !== 'number') {
|
||||
console.error('[wot ui] error(wd-rate): the value of wd-rate should be a number')
|
||||
return
|
||||
}
|
||||
const tempRateList: string[] = []
|
||||
const fullLength = Math.floor(modelValue)
|
||||
for (let i = 0; i < num; i++) {
|
||||
if (i < fullLength) {
|
||||
tempRateList.push('100%')
|
||||
} else if (i === fullLength && allowHalf && modelValue % 1 !== 0) {
|
||||
tempRateList.push('50%')
|
||||
} else {
|
||||
tempRateList.push('0')
|
||||
}
|
||||
}
|
||||
rateList.value = tempRateList
|
||||
computeActiveValue()
|
||||
}
|
||||
/**
|
||||
* @description 计算当前应当展示的rate颜色
|
||||
*/
|
||||
function computeActiveValue() {
|
||||
const { activeColor, modelValue, num } = props
|
||||
let tempActiveValue: string = ''
|
||||
if (Array.isArray(activeColor) && activeColor.length) {
|
||||
tempActiveValue = Number(modelValue) <= num * 0.6 || !activeColor[1] ? activeColor[0] : activeColor[1]
|
||||
} else {
|
||||
tempActiveValue = activeColor as string
|
||||
}
|
||||
activeValue.value = tempActiveValue
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 处理点击事件
|
||||
* @param index 点击的索引
|
||||
* @param isHalf 是否为半星
|
||||
*/
|
||||
function handleClick(index: number, isHalf: boolean) {
|
||||
const { readonly, disabled, clearable, allowHalf, modelValue } = props
|
||||
if (readonly || disabled) return
|
||||
let value = isHalf ? index + 0.5 : index + 1
|
||||
// 点击清空逻辑:当点击的值与当前modelValue相等且等于最小值时允许清空
|
||||
if (clearable) {
|
||||
const minValue = allowHalf ? 0.5 : 1
|
||||
if (value === modelValue && value === minValue) {
|
||||
value = 0
|
||||
}
|
||||
}
|
||||
updateValue(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 设置评分值并触发事件
|
||||
*/
|
||||
function updateValue(value: number) {
|
||||
emit('update:modelValue', value)
|
||||
emit('change', {
|
||||
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) {
|
||||
const value = isHalf ? targetIndex + 0.5 : targetIndex + 1
|
||||
updateValue(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user