Skip to content

Commit

Permalink
releases 4.2.14
Browse files Browse the repository at this point in the history
  • Loading branch information
xuliangzhan committed Oct 5, 2024
1 parent d952281 commit ea9fc17
Show file tree
Hide file tree
Showing 10 changed files with 436 additions and 19 deletions.
3 changes: 2 additions & 1 deletion examples/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ const navList = ref<VxeMenuPropTypes.Options>([
{ name: 'ResultTest', routerLink: { name: 'ResultTest' } },
{ name: 'WatermarkTest', routerLink: { name: 'WatermarkTest' } },
{ name: 'BadgeTest', routerLink: { name: 'BadgeTest' } },
{ name: 'AvatarTest', routerLink: { name: 'AvatarTest' } }
{ name: 'AvatarTest', routerLink: { name: 'AvatarTest' } },
{ name: 'SliderTest', routerLink: { name: 'SliderTest' } }
])
const theme = ref((localStorage.getItem('VXE_THEME') as 'light' | 'dark') || 'light')
Expand Down
5 changes: 5 additions & 0 deletions examples/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,11 @@ const routes: Array<RouteRecordRaw> = [
path: '/component/avatar',
name: 'AvatarTest',
component: () => import('../views/avatar/AvatarTest.vue')
},
{
path: '/component/slider',
name: 'SliderTest',
component: () => import('../views/slider/SliderTest.vue')
}
]

Expand Down
19 changes: 19 additions & 0 deletions examples/views/slider/SliderTest.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template>
<div>
<vxe-slider v-model="val1"></vxe-slider>
<vxe-slider v-model="val3" min="20" max="180"></vxe-slider>
<vxe-slider v-model="val2" range></vxe-slider>
<vxe-slider v-model="val4" readonly></vxe-slider>
<vxe-slider v-model="val5" disabled></vxe-slider>
</div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
const val1 = ref(40)
const val2 = ref([30, 60])
const val3 = ref(50)
const val4 = ref(40)
const val5 = ref(40)
</script>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vxe-pc-ui",
"version": "4.2.13",
"version": "4.2.14",
"description": "A vue based PC component library",
"scripts": {
"update": "npm install --legacy-peer-deps",
Expand Down
241 changes: 236 additions & 5 deletions packages/slider/src/slider.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,102 @@
import { defineComponent, ref, h, reactive } from 'vue'
import { defineComponent, ref, h, reactive, PropType, watch, computed, inject, onMounted } from 'vue'
import XEUtils from 'xe-utils'
import { createEvent } from '../../ui'
import { getConfig, createEvent, renderEmptyElement, useSize } from '../../ui'

import type { SliderReactData, VxeSliderEmits, SliderMethods, SliderPrivateMethods, ValueOf, SliderPrivateRef, VxeSliderPrivateComputed, VxeSliderConstructor, VxeSliderPrivateMethods } from '../../../types'
import type { SliderReactData, VxeSliderEmits, VxeSliderPropTypes, SliderMethods, VxeFormDefines, VxeFormConstructor, VxeFormPrivateMethods, SliderPrivateMethods, ValueOf, SliderPrivateRef, VxeSliderPrivateComputed, VxeSliderConstructor, VxeSliderPrivateMethods } from '../../../types'

export default defineComponent({
name: 'VxeSlider',
props: {
modelValue: [String, Number, Array] as PropType<VxeSliderPropTypes.ModelValue>,
vertical: Boolean as PropType<VxeSliderPropTypes.Vertical>,
max: {
type: [String, Number] as PropType<VxeSliderPropTypes.Max>,
default: () => getConfig().slider.max
},
min: {
type: [String, Number] as PropType<VxeSliderPropTypes.Min>,
default: () => getConfig().slider.min
},
step: {
type: [String, Number] as PropType<VxeSliderPropTypes.Step>,
default: () => getConfig().slider.step
},
size: {
type: String as PropType<VxeSliderPropTypes.Size>,
default: () => getConfig().slider.size || getConfig().size
},
range: {
type: Boolean as PropType<VxeSliderPropTypes.Range>,
default: () => getConfig().slider.range
},
readonly: {
type: Boolean as PropType<VxeSliderPropTypes.Readonly>,
default: null
},
disabled: {
type: Boolean as PropType<VxeSliderPropTypes.Disabled>,
default: null
}
},
emits: [
'update:modelValue',
'change'
] as VxeSliderEmits,
setup (props, context) {
const { emit } = context

const $xeForm = inject<VxeFormConstructor & VxeFormPrivateMethods | null>('$xeForm', null)
const formItemInfo = inject<VxeFormDefines.ProvideItemInfo | null>('xeFormItemInfo', null)

const xID = XEUtils.uniqueId()

const { computeSize } = useSize(props)

const refElem = ref<HTMLDivElement>()
const refBarElem = ref<HTMLDivElement>()
const refTrackElem = ref<HTMLDivElement>()
const refStartBtnElem = ref<HTMLDivElement>()
const refEndBtnElem = ref<HTMLDivElement>()

const reactData = reactive<SliderReactData>({
startValue: 0,
endValue: 0
})

const refMaps: SliderPrivateRef = {
refElem
}

const computeFormReadonly = computed(() => {
const { readonly } = props
if (readonly === null) {
if ($xeForm) {
return $xeForm.props.readonly
}
return false
}
return readonly
})

const computeIsDisabled = computed(() => {
const { disabled } = props
if (disabled === null) {
if ($xeForm) {
return $xeForm.props.disabled
}
return false
}
return disabled
})

const computeMaxNum = computed(() => {
return XEUtils.toNumber(props.max || 0)
})

const computeMinNum = computed(() => {
return XEUtils.toNumber(props.min || 0)
})

const computeMaps: VxeSliderPrivateComputed = {
}

Expand All @@ -37,6 +110,10 @@ export default defineComponent({
getComputeMaps: () => computeMaps
} as unknown as VxeSliderConstructor & VxeSliderPrivateMethods

const emitModel = (value: any) => {
emit('update:modelValue', value)
}

const dispatchEvent = (type: ValueOf<VxeSliderEmits>, params: Record<string, any>, evnt: Event | null) => {
emit(type, createEvent(evnt, { $slider: $xeSlider }, params))
}
Expand All @@ -45,18 +122,172 @@ export default defineComponent({
dispatchEvent
}

const getStartPercent = (startValue: number) => {
const { range } = props
const maxNum = computeMaxNum.value
const minNum = computeMinNum.value
return range ? XEUtils.floor((startValue - minNum) / XEUtils.toNumber(maxNum - minNum) * 100) : 0
}

const getEndPercent = (startValue: number, endValue: number) => {
const { range } = props
const maxNum = computeMaxNum.value
const minNum = computeMinNum.value
return XEUtils.floor((endValue - (range ? startValue : 0) - minNum) / XEUtils.toNumber(maxNum - minNum) * 100)
}

const updateModel = () => {
const { modelValue } = props
if (XEUtils.isArray(modelValue)) {
const [sVal, eVal] = XEUtils.clone(modelValue, true).sort()
reactData.startValue = XEUtils.floor(XEUtils.toNumber(sVal || 0))
reactData.endValue = XEUtils.floor(XEUtils.toNumber(eVal || 0))
} else {
reactData.startValue = 0
reactData.endValue = XEUtils.floor(XEUtils.toNumber(modelValue || 0))
}
}

const updateBarStyle = () => {
const { startValue, endValue } = reactData
const trackElem = refTrackElem.value
const startBtnElem = refStartBtnElem.value
const endBtnElem = refEndBtnElem.value
let startPercent = 0
let endPercent = 0
if (startValue > endValue) {
startPercent = getStartPercent(endValue)
endPercent = getEndPercent(endValue, startValue)
} else {
startPercent = getStartPercent(startValue)
endPercent = getEndPercent(startValue, endValue)
}
if (trackElem) {
trackElem.style.left = `${startPercent}%`
trackElem.style.width = `${endPercent}%`
}
if (startBtnElem) {
startBtnElem.style.left = `${startPercent}%`
}
if (endBtnElem) {
endBtnElem.style.left = `${XEUtils.floor(startPercent + endPercent)}%`
}
}

const changeEvent = (evnt: MouseEvent) => {
const { range } = props
const { startValue, endValue } = reactData
const value = range ? [startValue, endValue].sort() : endValue
emitModel(value)
dispatchEvent('change', { value }, evnt)
// 自动更新校验状态
if ($xeForm && formItemInfo) {
$xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, value)
}
}

const handleMousedownEvent = (evnt: MouseEvent, isEnd: boolean) => {
const formReadonly = computeFormReadonly.value
const isDisabled = computeIsDisabled.value
const maxNum = computeMaxNum.value
const minNum = computeMinNum.value
if (!(formReadonly || isDisabled)) {
evnt.preventDefault()
const domMousemove = document.onmousemove
const domMouseup = document.onmouseup
document.onmousemove = evnt => {
evnt.preventDefault()
const barElem = refBarElem.value
if (barElem) {
const barRect = barElem.getBoundingClientRect()
const trackWidth = (evnt.clientX - barRect.left) / 914
if (isEnd) {
reactData.endValue = XEUtils.floor(Math.max(minNum, Math.min(maxNum, trackWidth * (maxNum - minNum) + minNum)))
} else {
reactData.startValue = XEUtils.floor(Math.max(minNum, Math.min(maxNum, trackWidth * (maxNum - minNum))))
}
}
updateBarStyle()
}
document.onmouseup = (evnt: MouseEvent) => {
document.onmousemove = domMousemove
document.onmouseup = domMouseup
changeEvent(evnt)
updateBarStyle()
}
}
}

const handleStartMousedownEvent = (evnt: MouseEvent) => {
const endBtnElem = refEndBtnElem.value
const startBtnElem = evnt.currentTarget as HTMLDivElement
handleMousedownEvent(evnt, endBtnElem ? endBtnElem.offsetLeft < startBtnElem.offsetLeft : false)
}

const handleEndMousedownEvent = (evnt: MouseEvent) => {
const startBtnElem = refStartBtnElem.value
const endBtnElem = evnt.currentTarget as HTMLDivElement
handleMousedownEvent(evnt, startBtnElem ? endBtnElem.offsetLeft > startBtnElem.offsetLeft : true)
}

const collapsePanePrivateMethods: SliderPrivateMethods = {
}

Object.assign($xeSlider, collapsePaneMethods, collapsePanePrivateMethods)

const renderVN = () => {
const { vertical, range } = props
const vSize = computeSize.value
const formReadonly = computeFormReadonly.value
const isDisabled = computeIsDisabled.value
return h('div', {
ref: refElem,
class: 'vxe-slider'
}, [])
class: ['vxe-slider', {
[`size--${vSize}`]: vSize,
'is--vertical': vertical,
'is--readonly': formReadonly,
'is--disabled': isDisabled
}]
}, [
h('div', {
class: 'vxe-slider--inner'
}, [
h('div', {
ref: refBarElem,
class: 'vxe-slider--bar-wrapper'
}),
h('div', {
ref: refTrackElem,
class: 'vxe-slider--bar-track'
}),
formReadonly || !range
? renderEmptyElement($xeSlider)
: h('div', {
ref: refStartBtnElem,
class: 'vxe-slider--bar-btn vxe-slider--start-btn',
onMousedown: handleStartMousedownEvent
}),
formReadonly
? renderEmptyElement($xeSlider)
: h('div', {
ref: refEndBtnElem,
class: 'vxe-slider--bar-btn vxe-slider--end-btn',
onMousedown: handleEndMousedownEvent
})
])
])
}

watch(() => props.modelValue, () => {
updateModel()
})

onMounted(() => {
updateBarStyle()
})

updateModel()

$xeSlider.renderVN = renderVN

return $xeSlider
Expand Down
5 changes: 4 additions & 1 deletion packages/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,10 @@ setConfig({
select: {
multiCharOverflow: 8
},
slider: {},
slider: {
max: 100,
min: 0
},
steps: {},
switch: {},
tabPane: {},
Expand Down
11 changes: 3 additions & 8 deletions styles/components/avatar.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$btnThemeList: (
$avatarThemeList: (
(
name: "primary",
textColor: var(--vxe-ui-font-primary-color),
Expand Down Expand Up @@ -28,11 +28,6 @@ $btnThemeList: (
name: "error",
textColor: var(--vxe-ui-status-error-color),
btnColor: #fff,
),
(
name: "perfect",
textColor: var(--vxe-ui-table-header-background-color),
btnColor: var(--vxe-ui-font-color),
)
);

Expand Down Expand Up @@ -64,8 +59,8 @@ $btnThemeList: (
z-index: 1;
}
}
@for $index from 0 to length($btnThemeList) {
$item: nth($btnThemeList, $index + 1);
@for $index from 0 to length($avatarThemeList) {
$item: nth($avatarThemeList, $index + 1);
$textColor: map-get($item, textColor);
$btnColor: map-get($item, btnColor);
&.theme--#{map-get($item, name)} {
Expand Down
Loading

0 comments on commit ea9fc17

Please sign in to comment.