mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-02-05 13:00:47 +08:00
refactor(slider): use v-binder, remove placeable mixin
This commit is contained in:
parent
271753707b
commit
50ec676e2d
@ -1,7 +1,6 @@
|
||||
export { default as useAsFormItem } from './use-as-form-item'
|
||||
export { default as asFormItem } from './as-form-item'
|
||||
export { default as locale } from './locale'
|
||||
export { default as placeable } from './placeable/index'
|
||||
export { default as themeable } from './themeable'
|
||||
export { default as configurable } from './configurable'
|
||||
export { default as withCssr } from './with-cssr'
|
||||
|
@ -1,137 +0,0 @@
|
||||
const oppositeDirection = {
|
||||
top: 'bottom',
|
||||
bottom: 'top',
|
||||
left: 'right',
|
||||
right: 'left'
|
||||
}
|
||||
|
||||
const lengthToCompare = {
|
||||
top: 'height',
|
||||
bottom: 'height',
|
||||
left: 'width',
|
||||
right: 'width'
|
||||
}
|
||||
|
||||
const placementToTransformOrigin = {
|
||||
'bottom-start': 'top left',
|
||||
bottom: 'top center',
|
||||
'bottom-end': 'top right',
|
||||
'top-start': 'bottom left',
|
||||
top: 'bottom',
|
||||
'top-end': 'bottom right',
|
||||
'right-start': 'top left',
|
||||
right: 'center left',
|
||||
'right-end': 'bottom left',
|
||||
'left-start': 'top right',
|
||||
left: 'center right',
|
||||
'left-end': 'bottom right'
|
||||
}
|
||||
|
||||
const positionDirections = {
|
||||
'bottom-start': 'right',
|
||||
'bottom-end': 'left',
|
||||
'top-start': 'right',
|
||||
'top-end': 'left',
|
||||
'right-start': 'bottom',
|
||||
'right-end': 'top',
|
||||
'left-start': 'bottom',
|
||||
'left-end': 'top'
|
||||
}
|
||||
const oppositePosition = {
|
||||
start: 'end',
|
||||
end: 'start'
|
||||
}
|
||||
|
||||
export function getAdjustedPlacementOfTrackingElement (placement, trackedRect, trackingRect, flip) {
|
||||
if (!flip) {
|
||||
return placement
|
||||
}
|
||||
const [direction, position] = placement.split('-')
|
||||
let adjustedPosition = position
|
||||
if (position) {
|
||||
const adjacentPositionDirection = positionDirections[placement]
|
||||
if (trackingRect[lengthToCompare[adjacentPositionDirection]] > trackedRect[lengthToCompare[adjacentPositionDirection]]) {
|
||||
if (trackedRect[adjacentPositionDirection] + trackedRect[lengthToCompare[adjacentPositionDirection]] <= trackingRect[lengthToCompare[adjacentPositionDirection]]) {
|
||||
adjustedPosition = oppositePosition[position]
|
||||
}
|
||||
} else if (trackingRect[lengthToCompare[adjacentPositionDirection]] < trackedRect[lengthToCompare[adjacentPositionDirection]]) {
|
||||
if (trackedRect[oppositeDirection[adjacentPositionDirection]] < 0 && trackedRect[adjacentPositionDirection] > 0) {
|
||||
adjustedPosition = oppositePosition[position]
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trackedRect[direction] >= trackingRect[lengthToCompare[direction]]) {
|
||||
return adjustedPosition ? (direction + '-' + adjustedPosition) : direction
|
||||
} else if (trackedRect[oppositeDirection[direction]] >= trackingRect[lengthToCompare[direction]]) {
|
||||
return adjustedPosition ? `${oppositeDirection[direction]}-${adjustedPosition}` : oppositeDirection[direction]
|
||||
} else {
|
||||
return adjustedPosition ? (direction + '-' + adjustedPosition) : direction
|
||||
}
|
||||
}
|
||||
|
||||
export function getTransformOriginByPlacement (placement) {
|
||||
return placementToTransformOrigin[placement] || null
|
||||
}
|
||||
|
||||
export function getPosition (placement, offsetContainerRect, trackedRect) {
|
||||
const offset = {
|
||||
top: null,
|
||||
bottom: null,
|
||||
left: null,
|
||||
right: null,
|
||||
transform: null
|
||||
}
|
||||
if (placement === 'bottom-start') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top + trackedRect.height) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left) + 'px'
|
||||
} else if (placement === 'bottom-end') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top + trackedRect.height) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left + trackedRect.width) + 'px'
|
||||
offset.transform = 'translateX(-100%)'
|
||||
} else if (placement === 'top-start') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left) + 'px'
|
||||
offset.transform = 'translateY(-100%)'
|
||||
} else if (placement === 'top-end') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left + trackedRect.width) + 'px'
|
||||
offset.transform = 'translateY(-100%) translateX(-100%)'
|
||||
} else if (placement === 'right-start') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left + trackedRect.width) + 'px'
|
||||
} else if (placement === 'right-end') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top + trackedRect.height) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left + trackedRect.width) + 'px'
|
||||
offset.transform = 'translateY(-100%)'
|
||||
} else if (placement === 'left-start') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left) + 'px'
|
||||
offset.transform = 'translateX(-100%)'
|
||||
} else if (placement === 'left-end') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top + trackedRect.height) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left) + 'px'
|
||||
offset.transform = 'translateX(-100%) translateY(-100%)'
|
||||
} else if (placement === 'top') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left + trackedRect.width / 2) + 'px'
|
||||
offset.transform = 'translateX(-50%) translateY(-100%)'
|
||||
} else if (placement === 'right') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top + trackedRect.height / 2) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left + trackedRect.width) + 'px'
|
||||
offset.transform = 'translateY(-50%)'
|
||||
} else if (placement === 'bottom') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top + trackedRect.height) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left + trackedRect.width / 2) + 'px'
|
||||
offset.transform = 'translateX(-50%)'
|
||||
} else if (placement === 'left') {
|
||||
offset.top = (trackedRect.top - offsetContainerRect.top + trackedRect.height / 2) + 'px'
|
||||
offset.left = (trackedRect.left - offsetContainerRect.left) + 'px'
|
||||
offset.transform = 'translateX(-100%) translateY(-50%)'
|
||||
} else {
|
||||
console.error(
|
||||
'[naive-ui/mixins/placeable]: Placement %s is not supported.',
|
||||
placement
|
||||
)
|
||||
}
|
||||
return offset
|
||||
}
|
@ -1,300 +0,0 @@
|
||||
import { nextTick } from 'vue'
|
||||
import { on, off } from 'evtd'
|
||||
import getScrollParent from '../../_utils/dom/get-scroll-parent'
|
||||
import { warn } from '../../_utils/naive/warn'
|
||||
import {
|
||||
getAdjustedPlacementOfTrackingElement,
|
||||
getTransformOriginByPlacement,
|
||||
getPosition
|
||||
} from './calc-placement-transform'
|
||||
|
||||
let viewMeasurerInitialized = false
|
||||
let viewMeasurer = null
|
||||
|
||||
if (!viewMeasurerInitialized) {
|
||||
viewMeasurer = document.getElementById('n-view-measurer')
|
||||
if (!viewMeasurer) {
|
||||
viewMeasurer = document.createElement('div')
|
||||
viewMeasurer.id = 'n-view-measurer'
|
||||
viewMeasurer.style = `
|
||||
position: fixed !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
top: 0 !important;
|
||||
bottom: 0 !important;
|
||||
pointer-events: none !important;
|
||||
visibility: hidden !important;
|
||||
`
|
||||
document.body.appendChild(viewMeasurer)
|
||||
}
|
||||
viewMeasurerInitialized = true
|
||||
}
|
||||
function getViewBoundingRect () {
|
||||
const view = viewMeasurer.getBoundingClientRect()
|
||||
return {
|
||||
left: view.left,
|
||||
top: view.top,
|
||||
right: view.right,
|
||||
bottom: view.bottom,
|
||||
width: view.width,
|
||||
height: view.height
|
||||
}
|
||||
}
|
||||
|
||||
function getActivatorRect (manuallyPositioned, x, y, trackedElement, viewRect) {
|
||||
if (manuallyPositioned) {
|
||||
return {
|
||||
top: y,
|
||||
left: x,
|
||||
height: 0,
|
||||
width: 0,
|
||||
right: viewRect.width - x,
|
||||
bottom: viewRect.height - y
|
||||
}
|
||||
} else {
|
||||
const triggerRect = trackedElement.getBoundingClientRect()
|
||||
return {
|
||||
left: triggerRect.left - viewRect.left,
|
||||
top: triggerRect.top - viewRect.top,
|
||||
bottom: viewRect.height + viewRect.top - triggerRect.bottom,
|
||||
right: viewRect.width + viewRect.left - triggerRect.right,
|
||||
width: triggerRect.width,
|
||||
height: triggerRect.height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dependencies:
|
||||
// methods.__placeableTracking
|
||||
// methods.__placeableTracked
|
||||
// methods.__placeableBody
|
||||
// methods.__placeableOffsetContainer
|
||||
// data.__placeableEnabled
|
||||
export default {
|
||||
inject: {
|
||||
NModal: {
|
||||
default: null
|
||||
},
|
||||
NDrawer: {
|
||||
default: null
|
||||
}
|
||||
},
|
||||
props: {
|
||||
placement: {
|
||||
validator (value) {
|
||||
return [
|
||||
'top',
|
||||
'bottom',
|
||||
'left',
|
||||
'right',
|
||||
'top-start',
|
||||
'top-end',
|
||||
'left-start',
|
||||
'left-end',
|
||||
'right-start',
|
||||
'right-end',
|
||||
'bottom-start',
|
||||
'bottom-end'
|
||||
].includes(value)
|
||||
},
|
||||
default: 'bottom'
|
||||
},
|
||||
flip: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
widthMode: {
|
||||
validator (value) {
|
||||
return ['self', 'trigger'].includes(value)
|
||||
},
|
||||
default: 'self'
|
||||
},
|
||||
manuallyPositioned: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
x: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
y: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
__placeableEnabled (value) {
|
||||
if (value) {
|
||||
if (!this.__placeableListenerAdded && !this.manuallyPositioned) {
|
||||
this.__addScrollListeners()
|
||||
this.__addResizeListener()
|
||||
this.__placeableListenerAdded = true
|
||||
}
|
||||
nextTick(this.__placeableSyncPosition)
|
||||
}
|
||||
},
|
||||
x () {
|
||||
nextTick(this.__placeableSyncPosition)
|
||||
},
|
||||
y () {
|
||||
nextTick(this.__placeableSyncPosition)
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
__placeableScrollListeners: [],
|
||||
__placeableAdjustedPlacement: this.placement,
|
||||
__placeableListenerAdded: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.__placeableEnabled) {
|
||||
if (!this.manuallyPositioned) {
|
||||
this.__addScrollListeners()
|
||||
this.__addResizeListener()
|
||||
this.__placeableListenerAdded = true
|
||||
}
|
||||
this.__placeableSyncPosition()
|
||||
}
|
||||
},
|
||||
beforeUnmount () {
|
||||
if (this.__placeableListenerAdded) {
|
||||
this.__removeScrollListeners()
|
||||
this.__removeResizeListener()
|
||||
}
|
||||
},
|
||||
created: __DEV__ ? function () {
|
||||
[
|
||||
'__placeableOffsetContainer',
|
||||
'__placeableTracking',
|
||||
'__placeableTracked',
|
||||
'__placeableBody'
|
||||
].forEach(key => {
|
||||
if (!this[key]) {
|
||||
warn('mixins/placeable', `\`${key}\` is not defined.`)
|
||||
}
|
||||
})
|
||||
} : undefined,
|
||||
methods: {
|
||||
__placeableSyncPosition () {
|
||||
if (!this.__placeableEnabled) {
|
||||
return
|
||||
}
|
||||
const trackingElement = this.__getTrackingElement()
|
||||
let trackedElement = null
|
||||
trackingElement.style.position = 'absolute'
|
||||
if (this.manuallyPositioned) {
|
||||
if (__DEV__ && !trackingElement) {
|
||||
warn('mixins/placeable', 'Tracking element not found.')
|
||||
return
|
||||
}
|
||||
} else {
|
||||
trackedElement = this.__getTrackedElement()
|
||||
if (__DEV__ && (!trackedElement || !trackingElement)) {
|
||||
warn('mixins/placeable', 'Traked element or tracking element not found.')
|
||||
return
|
||||
}
|
||||
}
|
||||
const viewRect = getViewBoundingRect()
|
||||
const triggerRect = getActivatorRect(this.manuallyPositioned, this.x, this.y, trackedElement, viewRect)
|
||||
const {
|
||||
widthMode
|
||||
} = this
|
||||
if (
|
||||
(widthMode === 'trigger' || widthMode === 'activator')
|
||||
) {
|
||||
const body = this.__getBodyElement()
|
||||
body.style.width = triggerRect.width + 'px'
|
||||
}
|
||||
let adjustedPlacement = this.placement
|
||||
let contentBoundingClientRect = null
|
||||
if (this.flip) {
|
||||
contentBoundingClientRect = {
|
||||
width: trackingElement.offsetWidth,
|
||||
height: trackingElement.offsetHeight
|
||||
}
|
||||
adjustedPlacement = getAdjustedPlacementOfTrackingElement(this.placement, triggerRect, contentBoundingClientRect, true)
|
||||
}
|
||||
const suggestedTransformOrigin = getTransformOriginByPlacement(adjustedPlacement)
|
||||
let offset = null
|
||||
this.__placeableAdjustedPlacement = adjustedPlacement
|
||||
const offsetContainer = this.__getOffsetContainer()
|
||||
offset = getPosition(
|
||||
adjustedPlacement,
|
||||
offsetContainer.getBoundingClientRect(),
|
||||
triggerRect
|
||||
)
|
||||
this.__setOffset(offset, suggestedTransformOrigin)
|
||||
},
|
||||
__getTrackingElement () {
|
||||
const { __placeableTracking } = this
|
||||
if (__placeableTracking) {
|
||||
const el = __placeableTracking()
|
||||
return el.$el || el
|
||||
} else if (__DEV__) {
|
||||
warn('mixins/placeable', 'No tracking element getter.')
|
||||
}
|
||||
},
|
||||
__getTrackedElement () {
|
||||
const { __placeableTracked } = this
|
||||
if (__placeableTracked) {
|
||||
const el = __placeableTracked()
|
||||
return el.$el || el
|
||||
} else if (__DEV__) {
|
||||
warn('mixins/placeable', 'No tracked element getter.')
|
||||
}
|
||||
},
|
||||
__getBodyElement () {
|
||||
const { __placeableBody } = this
|
||||
if (__placeableBody) {
|
||||
const el = __placeableBody()
|
||||
return el.$el || el
|
||||
} else if (__DEV__) {
|
||||
warn('mixins/placeable', 'No body element getter.')
|
||||
}
|
||||
},
|
||||
__getOffsetContainer () {
|
||||
const __placeableOffsetContainer = this.__placeableOffsetContainer
|
||||
if (__placeableOffsetContainer) {
|
||||
const el = __placeableOffsetContainer()
|
||||
return el.$el || el
|
||||
} else if (__DEV__) {
|
||||
warn('mixins/placeable', 'No offset container getter.')
|
||||
}
|
||||
},
|
||||
__setOffset (position, transformOrigin) {
|
||||
const el = this.__getTrackingElement()
|
||||
el.style.position = 'absolute'
|
||||
el.style.top = position.top
|
||||
el.style.left = position.left
|
||||
el.style.right = position.right
|
||||
el.style.bottom = position.bottom
|
||||
el.style.transform = position.transform
|
||||
el.style.transformOrigin = transformOrigin
|
||||
el.setAttribute('n-suggested-transform-origin', transformOrigin)
|
||||
},
|
||||
__addResizeListener () {
|
||||
on('resize', window, this.__placeableSyncPosition)
|
||||
},
|
||||
__addScrollListeners () {
|
||||
let currentElement = this.__getTrackedElement()
|
||||
while (true) {
|
||||
currentElement = getScrollParent(currentElement)
|
||||
if (currentElement === null) break
|
||||
this.__placeableScrollListeners.push([currentElement, this.__placeableSyncPosition])
|
||||
}
|
||||
for (const [el, handler] of this.__placeableScrollListeners) {
|
||||
on('scroll', el, handler, true)
|
||||
}
|
||||
},
|
||||
__removeResizeListener () {
|
||||
off('resize', window, this.__placeableSyncPosition)
|
||||
},
|
||||
__removeScrollListeners () {
|
||||
for (const [el, handler] of this.__placeableScrollListeners) {
|
||||
off('scroll', el, handler, true)
|
||||
}
|
||||
this.__placeableScrollListeners = []
|
||||
}
|
||||
}
|
||||
}
|
@ -33,25 +33,80 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
ref="firstHandleRef"
|
||||
class="n-slider-handle"
|
||||
tabindex="0"
|
||||
:style="firstHandleStyle"
|
||||
@mousedown="handleFirstHandleMouseDown"
|
||||
@mouseenter="handleFirstHandleMouseEnter"
|
||||
@mouseleave="handleFirstHandleMouseLeave"
|
||||
/>
|
||||
<div
|
||||
<v-binder>
|
||||
<v-target>
|
||||
<div
|
||||
ref="handleRef1"
|
||||
class="n-slider-handle"
|
||||
tabindex="0"
|
||||
:style="firstHandleStyle"
|
||||
@mousedown="handleFirstHandleMouseDown"
|
||||
@mouseenter="handleFirstHandleMouseEnter"
|
||||
@mouseleave="handleFirstHandleMouseLeave"
|
||||
/>
|
||||
</v-target>
|
||||
<v-follower
|
||||
ref="followerRef1"
|
||||
:show="mergedShowTooltip1"
|
||||
:to="adjustedTo"
|
||||
:placement="placement"
|
||||
:container-class="namespace"
|
||||
>
|
||||
<transition
|
||||
name="n-fade-in-scale-up-transition"
|
||||
:appear="isMounted"
|
||||
:css="!(active && prevActive)"
|
||||
>
|
||||
<div
|
||||
v-if="mergedShowTooltip1"
|
||||
class="n-slider-handle-indicator"
|
||||
:class="{
|
||||
[`n-${mergedTheme}-theme`]: mergedTheme
|
||||
}"
|
||||
>
|
||||
{{ handleValue1 }}
|
||||
</div>
|
||||
</transition>
|
||||
</v-follower>
|
||||
</v-binder>
|
||||
<v-binder
|
||||
v-if="range"
|
||||
ref="secondHandleRef"
|
||||
class="n-slider-handle"
|
||||
tabindex="0"
|
||||
:style="secondHandleStyle"
|
||||
@mousedown="handleSecondHandleMouseDown"
|
||||
@mouseenter="handleSecondHandleMouseEnter"
|
||||
@mouseleave="handleSecondHandleMouseLeave"
|
||||
/>
|
||||
>
|
||||
<v-target>
|
||||
<div
|
||||
ref="handleRef2"
|
||||
class="n-slider-handle"
|
||||
tabindex="0"
|
||||
:style="secondHandleStyle"
|
||||
@mousedown="handleSecondHandleMouseDown"
|
||||
@mouseenter="handleSecondHandleMouseEnter"
|
||||
@mouseleave="handleSecondHandleMouseLeave"
|
||||
/>
|
||||
</v-target>
|
||||
<v-follower
|
||||
ref="followerRef2"
|
||||
:show="mergedShowTooltip2"
|
||||
:to="adjustedTo"
|
||||
:placement="placement"
|
||||
:container-class="namespace"
|
||||
>
|
||||
<transition
|
||||
name="n-fade-in-scale-up-transition"
|
||||
:appear="isMounted"
|
||||
:css="!(active && prevActive)"
|
||||
>
|
||||
<div
|
||||
v-if="mergedShowTooltip2"
|
||||
class="n-slider-handle-indicator"
|
||||
:class="{
|
||||
[`n-${mergedTheme}-theme`]: mergedTheme
|
||||
}"
|
||||
>
|
||||
{{ handleValue2 }}
|
||||
</div>
|
||||
</transition>
|
||||
</v-follower>
|
||||
</v-binder>
|
||||
<div
|
||||
v-if="marks"
|
||||
class="n-slider-marks"
|
||||
@ -65,68 +120,35 @@
|
||||
{{ mark.label }}
|
||||
</div>
|
||||
</div>
|
||||
<n-base-lazy-teleport
|
||||
:show="showTooltip"
|
||||
adjust-to
|
||||
>
|
||||
<div
|
||||
ref="offsetContainerRef"
|
||||
v-zindexable="{ enabled: showTooltip }"
|
||||
class="n-positioning-container"
|
||||
:class="{
|
||||
[namespace]: namespace
|
||||
}"
|
||||
>
|
||||
<div
|
||||
ref="trackingRef"
|
||||
class="n-positioning-content"
|
||||
>
|
||||
<transition
|
||||
name="n-fade-in-scale-up-transition"
|
||||
:appear="isMounted"
|
||||
>
|
||||
<div
|
||||
v-if="showTooltip"
|
||||
class="n-slider-handle-indicator"
|
||||
:class="{
|
||||
[`n-${mergedTheme}-theme`]: mergedTheme
|
||||
}"
|
||||
>
|
||||
{{ activeHandleValue === null ? tooltipHoverDisplayValue : activeHandleValue }}
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</n-base-lazy-teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue'
|
||||
import { ref, toRef, computed, watch, nextTick } from 'vue'
|
||||
import {
|
||||
VBinder,
|
||||
VTarget,
|
||||
VFollower
|
||||
} from 'vueuc'
|
||||
import { useIsMounted, useMergedState } from 'vooks'
|
||||
import { on, off } from 'evtd'
|
||||
import {
|
||||
configurable,
|
||||
themeable,
|
||||
placeable,
|
||||
asFormItem,
|
||||
withCssr
|
||||
} from '../../_mixins'
|
||||
import {
|
||||
zindexable
|
||||
} from 'vdirs'
|
||||
import styles from './styles'
|
||||
import { warn } from '../../_utils/naive'
|
||||
import { call } from '../../_utils/vue'
|
||||
import { useIsMounted } from 'vooks'
|
||||
import { NBaseLazyTeleport } from '../../_base'
|
||||
import { warn, call, useAdjustedTo } from '../../_utils'
|
||||
|
||||
function handleFirstHandleMouseMove (e) {
|
||||
const railRect = this.railRef.getBoundingClientRect()
|
||||
const offsetRatio = (e.clientX - railRect.left) / railRect.width
|
||||
const newValue = this.min + (this.max - this.min) * offsetRatio
|
||||
if (this.range) {
|
||||
this.emitInputEvent([this.memoziedOtherValue, newValue])
|
||||
this.dispatchValueUpdate([this.memoziedOtherValue, newValue])
|
||||
} else {
|
||||
this.emitInputEvent(newValue)
|
||||
this.dispatchValueUpdate(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,22 +157,20 @@ function handleSecondHandleMouseMove (e) {
|
||||
const offsetRatio = (e.clientX - railRect.left) / railRect.width
|
||||
const newValue = this.min + (this.max - this.min) * offsetRatio
|
||||
if (this.range) {
|
||||
this.emitInputEvent([this.memoziedOtherValue, newValue])
|
||||
this.dispatchValueUpdate([this.memoziedOtherValue, newValue])
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'Slider',
|
||||
directives: {
|
||||
zindexable
|
||||
},
|
||||
components: {
|
||||
NBaseLazyTeleport
|
||||
VBinder,
|
||||
VTarget,
|
||||
VFollower
|
||||
},
|
||||
mixins: [
|
||||
configurable,
|
||||
themeable,
|
||||
placeable,
|
||||
withCssr(styles),
|
||||
asFormItem()
|
||||
],
|
||||
@ -187,6 +207,10 @@ export default {
|
||||
type: String,
|
||||
default: 'top'
|
||||
},
|
||||
showTooltip: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
'onUpdate:value': {
|
||||
type: Function,
|
||||
@ -201,34 +225,55 @@ export default {
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
setup () {
|
||||
setup (props) {
|
||||
const handleActive1Ref = ref(false)
|
||||
const handleActive2Ref = ref(false)
|
||||
const controlledShowTooltipRef = toRef(props, 'showTooltip')
|
||||
const mergedShowTooltip1Ref = useMergedState(
|
||||
controlledShowTooltipRef,
|
||||
handleActive1Ref
|
||||
)
|
||||
const mergedShowTooltip2Ref = useMergedState(
|
||||
controlledShowTooltipRef,
|
||||
handleActive2Ref
|
||||
)
|
||||
const handleClicked1Ref = ref(false)
|
||||
const handleClicked2Ref = ref(false)
|
||||
const activeRef = computed(() => {
|
||||
return handleActive1Ref.value || handleActive2Ref.value
|
||||
})
|
||||
const prevActiveRef = ref(activeRef.value)
|
||||
watch(activeRef, (value) => {
|
||||
nextTick(() => {
|
||||
prevActiveRef.value = value
|
||||
})
|
||||
})
|
||||
const clickedRef = computed(() => {
|
||||
return handleClicked1Ref.value || handleClicked2Ref.value
|
||||
})
|
||||
return {
|
||||
isMounted: useIsMounted(),
|
||||
adjustedTo: useAdjustedTo(props),
|
||||
mergedShowTooltip1: mergedShowTooltip1Ref,
|
||||
mergedShowTooltip2: mergedShowTooltip2Ref,
|
||||
handleActive1: handleActive1Ref,
|
||||
handleActive2: handleActive2Ref,
|
||||
handleClicked1: handleClicked1Ref,
|
||||
handleClicked2: handleClicked2Ref,
|
||||
memoziedOtherValue: ref(null),
|
||||
valueChangedByRailClick: ref(true),
|
||||
active: activeRef,
|
||||
prevActive: prevActiveRef,
|
||||
clicked: clickedRef,
|
||||
// https://github.com/vuejs/vue-next/issues/2283
|
||||
firstHandleRef: ref(null),
|
||||
secondHandleRef: ref(null),
|
||||
handleRef1: ref(null),
|
||||
handleRef2: ref(null),
|
||||
railRef: ref(null),
|
||||
offsetContainerRef: ref(null),
|
||||
trackingRef: ref(null)
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
unstableMemorizedRef: {},
|
||||
showTooltip: false,
|
||||
firstHandleActive: false,
|
||||
secondHandleActive: false,
|
||||
firstHandleClicked: false,
|
||||
secondHandleClicked: false,
|
||||
memoziedOtherValue: null,
|
||||
valueChangedByRailClick: true,
|
||||
tooltipHoverDisplayValue: ''
|
||||
followerRef1: ref(null),
|
||||
followerRef2: ref(null)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
__placeableEnabled () {
|
||||
return this.showTooltip
|
||||
},
|
||||
computedMarks () {
|
||||
const marks = []
|
||||
for (const value of Object.keys(this.marks)) {
|
||||
@ -244,25 +289,17 @@ export default {
|
||||
fillStyle () {
|
||||
if (this.range) {
|
||||
return {
|
||||
left: ((this.firstHandleValue - this.min) / (this.max - this.min) * 100) + '%',
|
||||
width: ((this.secondHandleValue - this.firstHandleValue) / (this.max - this.min) * 100) + '%'
|
||||
left: ((this.handleValue1 - this.min) / (this.max - this.min) * 100) + '%',
|
||||
width: ((this.handleValue2 - this.handleValue1) / (this.max - this.min) * 100) + '%'
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
left: 0,
|
||||
width: ((this.firstHandleValue - this.min) / (this.max - this.min) * 100) + '%'
|
||||
width: ((this.handleValue1 - this.min) / (this.max - this.min) * 100) + '%'
|
||||
}
|
||||
}
|
||||
},
|
||||
activeHandleValue () {
|
||||
if (this.firstHandleActive) {
|
||||
return this.firstHandleValue
|
||||
} else if (this.secondHandleActive) {
|
||||
return this.secondHandleValue
|
||||
}
|
||||
return null
|
||||
},
|
||||
firstHandleValue () {
|
||||
handleValue1 () {
|
||||
if (this.range) {
|
||||
if (this.value) {
|
||||
if (this.value[0] > this.value[1]) {
|
||||
@ -275,7 +312,7 @@ export default {
|
||||
return this.justifyValue(this.value)
|
||||
}
|
||||
},
|
||||
secondHandleValue () {
|
||||
handleValue2 () {
|
||||
if (this.range && this.value) {
|
||||
if (this.value[0] > this.value[1]) {
|
||||
return this.justifyValue(this.value[0])
|
||||
@ -287,21 +324,15 @@ export default {
|
||||
},
|
||||
firstHandleStyle () {
|
||||
return {
|
||||
left: ((this.firstHandleValue - this.min) / (this.max - this.min) * 100) + '%',
|
||||
zIndex: this.firstHandleActive ? 1 : 0
|
||||
left: ((this.handleValue1 - this.min) / (this.max - this.min) * 100) + '%',
|
||||
zIndex: this.handleClicked1 ? 1 : 0
|
||||
}
|
||||
},
|
||||
secondHandleStyle () {
|
||||
return {
|
||||
left: ((this.secondHandleValue - this.min) / (this.max - this.min) * 100) + '%',
|
||||
zIndex: this.secondHandleActive ? 1 : 0
|
||||
left: ((this.handleValue2 - this.min) / (this.max - this.min) * 100) + '%',
|
||||
zIndex: this.handleClicked2 ? 1 : 0
|
||||
}
|
||||
},
|
||||
active () {
|
||||
return this.firstHandleActive || this.secondHandleActive
|
||||
},
|
||||
clicked () {
|
||||
return this.firstHandleClicked || this.secondHandleClicked
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -310,8 +341,8 @@ export default {
|
||||
if (oldValue && oldValue[1] !== newValue[1]) {
|
||||
this.$nextTick(() => {
|
||||
if (!this.valueChangedByRailClick) {
|
||||
this.firstHandleActive = false
|
||||
this.secondHandleActive = true
|
||||
this.handleActive1 = false
|
||||
this.handleActive2 = true
|
||||
} else {
|
||||
this.valueChangedByRailClick = false
|
||||
}
|
||||
@ -320,8 +351,8 @@ export default {
|
||||
} else if (oldValue && oldValue[0] !== newValue[0]) {
|
||||
this.$nextTick(() => {
|
||||
if (!this.valueChangedByRailClick) {
|
||||
this.firstHandleActive = true
|
||||
this.secondHandleActive = false
|
||||
this.handleActive1 = true
|
||||
this.handleActive2 = false
|
||||
} else {
|
||||
this.valueChangedByRailClick = false
|
||||
}
|
||||
@ -330,8 +361,8 @@ export default {
|
||||
} else if (newValue[0] === newValue[1]) {
|
||||
this.$nextTick(() => {
|
||||
if (!this.valueChangedByRailClick) {
|
||||
this.firstHandleActive = false
|
||||
this.secondHandleActive = true
|
||||
this.handleActive1 = false
|
||||
this.handleActive2 = true
|
||||
} else {
|
||||
this.valueChangedByRailClick = false
|
||||
}
|
||||
@ -343,47 +374,22 @@ export default {
|
||||
if (this.range) {
|
||||
if (newValue && oldValue) {
|
||||
if (newValue[0] !== oldValue[0] || newValue[1] !== oldValue[1]) {
|
||||
this.__placeableSyncPosition()
|
||||
this.syncPosition()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.__placeableSyncPosition()
|
||||
this.syncPosition()
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('mousemove', this.handleFirstHandleMouseMove)
|
||||
window.removeEventListener('mouseup', this.handleFirstHandleMouseUp)
|
||||
window.removeEventListener('mousemove', this.handleSecondHandleMouseMove)
|
||||
window.removeEventListener('mouseup', this.handleSecondHandleMouseUp)
|
||||
off('mousemove', window, this.handleFirstHandleMouseMove)
|
||||
off('mouseup', window, this.handleFirstHandleMouseUp)
|
||||
off('mousemove', window, this.handleSecondHandleMouseMove)
|
||||
off('mouseup', window, this.handleSecondHandleMouseUp)
|
||||
},
|
||||
methods: {
|
||||
__placeableTracked () {
|
||||
if (this.firstHandleActive) {
|
||||
return this.firstHandleRef
|
||||
} else if (this.secondHandleActive) {
|
||||
return this.secondHandleRef
|
||||
}
|
||||
return this.$el // for registering scroll listeners
|
||||
},
|
||||
__placeableTracking () {
|
||||
if (this.trackingRef) {
|
||||
return (this.unstableMemorizedRef.tracking = this.trackingRef)
|
||||
} else {
|
||||
return this.unstableMemorizedRef.tracking
|
||||
}
|
||||
},
|
||||
__placeableOffsetContainer () {
|
||||
if (this.offsetContainerRef) {
|
||||
return (this.unstableMemorizedRef.offsetContainer = this.offsetContainerRef)
|
||||
} else {
|
||||
return this.unstableMemorizedRef.offsetContainer
|
||||
}
|
||||
},
|
||||
__placeableBody () {
|
||||
return null
|
||||
},
|
||||
doUpdateValue (value) {
|
||||
const {
|
||||
onChange,
|
||||
@ -396,37 +402,50 @@ export default {
|
||||
nTriggerFormInput()
|
||||
nTriggerFormChange()
|
||||
},
|
||||
doUpdateShow (show1, show2) {
|
||||
if (show1 !== undefined) {
|
||||
this.handleActive1 = show1
|
||||
}
|
||||
if (show2 !== undefined) {
|
||||
this.handleActive2 = show2
|
||||
}
|
||||
},
|
||||
syncPosition () {
|
||||
const { followerRef1, followerRef2 } = this
|
||||
if (followerRef1) followerRef1.syncPosition()
|
||||
if (followerRef2) followerRef2.syncPosition()
|
||||
},
|
||||
handleRailClick (e) {
|
||||
this.valueChangedByRailClick = true
|
||||
const railRect = this.railRef.getBoundingClientRect()
|
||||
const offsetRatio = (e.clientX - railRect.left) / railRect.width
|
||||
const newValue = this.min + (this.max - this.min) * offsetRatio
|
||||
if (!this.range) {
|
||||
this.emitInputEvent(newValue)
|
||||
this.firstHandleRef.focus()
|
||||
this.dispatchValueUpdate(newValue)
|
||||
this.handleRef1.focus()
|
||||
} else {
|
||||
if (this.value) {
|
||||
if (Math.abs(this.firstHandleValue - newValue) < Math.abs(this.secondHandleValue - newValue)) {
|
||||
this.emitInputEvent([newValue, this.secondHandleValue])
|
||||
this.firstHandleRef.focus()
|
||||
if (Math.abs(this.handleValue1 - newValue) < Math.abs(this.handleValue2 - newValue)) {
|
||||
this.dispatchValueUpdate([newValue, this.handleValue2])
|
||||
this.handleRef1.focus()
|
||||
} else {
|
||||
this.emitInputEvent([this.firstHandleValue, newValue])
|
||||
this.secondHandleRef.focus()
|
||||
this.dispatchValueUpdate([this.handleValue1, newValue])
|
||||
this.handleRef2.focus()
|
||||
}
|
||||
} else {
|
||||
this.emitInputEvent([newValue, newValue])
|
||||
this.firstHandleRef.focus()
|
||||
this.dispatchValueUpdate([newValue, newValue])
|
||||
this.handleRef1.focus()
|
||||
}
|
||||
}
|
||||
},
|
||||
handleKeyDownRight () {
|
||||
let firstHandleFocused = false
|
||||
let handleValue = null
|
||||
if (document.activeElement === this.firstHandleRef) {
|
||||
if (document.activeElement === this.handleRef1) {
|
||||
firstHandleFocused = true
|
||||
handleValue = this.firstHandleValue
|
||||
handleValue = this.handleValue1
|
||||
} else {
|
||||
handleValue = this.secondHandleValue
|
||||
handleValue = this.handleValue2
|
||||
}
|
||||
let nextValue = Math.floor(handleValue / this.step) * this.step + this.step
|
||||
if (this.marks) {
|
||||
@ -439,22 +458,22 @@ export default {
|
||||
}
|
||||
if (this.range) {
|
||||
if (firstHandleFocused) {
|
||||
this.emitInputEvent([nextValue, this.secondHandleValue])
|
||||
this.dispatchValueUpdate([nextValue, this.handleValue2])
|
||||
} else {
|
||||
this.emitInputEvent([this.firstHandleValue, nextValue])
|
||||
this.dispatchValueUpdate([this.handleValue1, nextValue])
|
||||
}
|
||||
} else {
|
||||
this.emitInputEvent(nextValue)
|
||||
this.dispatchValueUpdate(nextValue)
|
||||
}
|
||||
},
|
||||
handleKeyDownLeft () {
|
||||
let firstHandleFocused = false
|
||||
let handleValue = null
|
||||
if (document.activeElement === this.firstHandleRef) {
|
||||
if (document.activeElement === this.handleRef1) {
|
||||
firstHandleFocused = true
|
||||
handleValue = this.firstHandleValue
|
||||
handleValue = this.handleValue1
|
||||
} else {
|
||||
handleValue = this.secondHandleValue
|
||||
handleValue = this.handleValue2
|
||||
}
|
||||
let nextValue = Math.ceil(handleValue / this.step) * this.step - this.step
|
||||
if (this.marks) {
|
||||
@ -467,23 +486,23 @@ export default {
|
||||
}
|
||||
if (this.range) {
|
||||
if (firstHandleFocused) {
|
||||
this.emitInputEvent([nextValue, this.secondHandleValue])
|
||||
this.dispatchValueUpdate([nextValue, this.handleValue2])
|
||||
} else {
|
||||
this.emitInputEvent([this.firstHandleValue, nextValue])
|
||||
this.dispatchValueUpdate([this.handleValue1, nextValue])
|
||||
}
|
||||
} else {
|
||||
this.emitInputEvent(nextValue)
|
||||
this.dispatchValueUpdate(nextValue)
|
||||
}
|
||||
},
|
||||
switchFocus () {
|
||||
if (this.range) {
|
||||
const firstHandle = this.firstHandleRef
|
||||
const secondHandle = this.secondHandleRef
|
||||
const firstHandle = this.handleRef1
|
||||
const secondHandle = this.handleRef2
|
||||
if (firstHandle && secondHandle) {
|
||||
if (this.firstHandleActive && document.activeElement === secondHandle) {
|
||||
if (this.handleActive1 && document.activeElement === secondHandle) {
|
||||
this.disableTransitionOneTick()
|
||||
firstHandle.focus()
|
||||
} else if (this.secondHandleActive && document.activeElement === firstHandle) {
|
||||
} else if (this.handleActive2 && document.activeElement === firstHandle) {
|
||||
this.disableTransitionOneTick()
|
||||
secondHandle.focus()
|
||||
}
|
||||
@ -525,49 +544,41 @@ export default {
|
||||
},
|
||||
handleFirstHandleMouseDown () {
|
||||
if (this.range) {
|
||||
this.memoziedOtherValue = this.secondHandleValue
|
||||
this.memoziedOtherValue = this.handleValue2
|
||||
}
|
||||
this.firstHandleActive = true
|
||||
this.firstHandleClicked = true
|
||||
window.addEventListener('mouseup', this.handleFirstHandleMouseUp)
|
||||
window.addEventListener('mousemove', this.handleFirstHandleMouseMove)
|
||||
this.handleActive1 = true
|
||||
this.handleClicked1 = true
|
||||
on('mouseup', window, this.handleFirstHandleMouseUp)
|
||||
on('mousemove', window, this.handleFirstHandleMouseMove)
|
||||
},
|
||||
handleSecondHandleMouseDown () {
|
||||
if (this.range) {
|
||||
this.memoziedOtherValue = this.firstHandleValue
|
||||
this.memoziedOtherValue = this.handleValue1
|
||||
}
|
||||
this.secondHandleActive = true
|
||||
this.secondHandleClicked = true
|
||||
window.addEventListener('mouseup', this.handleSecondHandleMouseUp)
|
||||
window.addEventListener('mousemove', this.handleSecondHandleMouseMove)
|
||||
this.handleActive2 = true
|
||||
this.handleClicked2 = true
|
||||
on('mouseup', window, this.handleSecondHandleMouseUp)
|
||||
on('mousemove', window, this.handleSecondHandleMouseMove)
|
||||
},
|
||||
handleFirstHandleMouseUp (e) {
|
||||
this.secondHandleActive = false
|
||||
this.firstHandleActive = false
|
||||
this.secondHandleClicked = false
|
||||
this.firstHandleClicked = false
|
||||
if (!this.firstHandleRef.contains(e.target)) {
|
||||
this.showTooltip = false
|
||||
} else {
|
||||
this.tooltipHoverDisplayValue = this.firstHandleValue
|
||||
this.handleClicked2 = false
|
||||
this.handleClicked1 = false
|
||||
if (!this.handleRef1.contains(e.target)) {
|
||||
this.doUpdateShow(false, undefined)
|
||||
}
|
||||
window.removeEventListener('mouseup', this.handleFirstHandleMouseUp)
|
||||
window.removeEventListener('mousemove', this.handleFirstHandleMouseMove)
|
||||
off('mouseup', window, this.handleFirstHandleMouseUp)
|
||||
off('mousemove', window, this.handleFirstHandleMouseMove)
|
||||
},
|
||||
handleSecondHandleMouseUp (e) {
|
||||
this.secondHandleActive = false
|
||||
this.firstHandleActive = false
|
||||
this.secondHandleClicked = false
|
||||
this.firstHandleClicked = false
|
||||
if (!this.firstHandleRef.contains(e.target)) {
|
||||
this.showTooltip = false
|
||||
} else {
|
||||
this.tooltipHoverDisplayValue = this.secondHandleValue
|
||||
this.handleClicked2 = false
|
||||
this.handleClicked1 = false
|
||||
if (!this.handleRef1.contains(e.target)) {
|
||||
this.doUpdateShow(undefined, false)
|
||||
}
|
||||
window.removeEventListener('mouseup', this.handleSecondHandleMouseUp)
|
||||
window.removeEventListener('mousemove', this.handleSecondHandleMouseMove)
|
||||
off('mouseup', window, this.handleSecondHandleMouseUp)
|
||||
off('mousemove', window, this.handleSecondHandleMouseMove)
|
||||
},
|
||||
emitInputEvent (value) {
|
||||
dispatchValueUpdate (value) {
|
||||
if (this.range) {
|
||||
if (Array.isArray(value)) {
|
||||
if (value[0] > value[1]) {
|
||||
@ -598,56 +609,57 @@ export default {
|
||||
handleSecondHandleMouseMove,
|
||||
handleFirstHandleMouseEnter () {
|
||||
if (!this.active) {
|
||||
this.showTooltip = true
|
||||
this.firstHandleActive = true
|
||||
this.tooltipHoverDisplayValue = this.firstHandleValue
|
||||
this.doUpdateShow(true, undefined)
|
||||
this.handleActive1 = true
|
||||
this.$nextTick(() => {
|
||||
this.__placeableSyncPosition()
|
||||
this.syncPosition()
|
||||
})
|
||||
}
|
||||
},
|
||||
handleFirstHandleMouseLeave () {
|
||||
if (!this.active) this.showTooltip = false
|
||||
if (this.active && !this.clicked) {
|
||||
this.secondHandleActive = false
|
||||
this.firstHandleActive = false
|
||||
this.showTooltip = false
|
||||
if (!this.active) {
|
||||
this.doUpdateShow(false, false)
|
||||
} else if (!this.clicked) {
|
||||
this.handleActive2 = false
|
||||
this.handleActive1 = false
|
||||
this.doUpdateShow(false, false)
|
||||
}
|
||||
},
|
||||
handleSecondHandleMouseEnter () {
|
||||
if (!this.active) {
|
||||
this.showTooltip = true
|
||||
this.secondHandleActive = true
|
||||
this.tooltipHoverDisplayValue = this.secondHandleValue
|
||||
this.doUpdateShow(undefined, true)
|
||||
this.handleActive2 = true
|
||||
this.$nextTick(() => {
|
||||
this.__placeableSyncPosition()
|
||||
this.syncPosition()
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSecondHandleMouseLeave () {
|
||||
if (!this.active) this.showTooltip = false
|
||||
if (this.active && !this.clicked) {
|
||||
this.secondHandleActive = false
|
||||
this.firstHandleActive = false
|
||||
this.showTooltip = false
|
||||
if (!this.active) {
|
||||
this.doUpdateShow(false, false)
|
||||
} else if (!this.clicked) {
|
||||
this.handleActive2 = false
|
||||
this.handleActive1 = false
|
||||
this.doUpdateShow(false, false)
|
||||
}
|
||||
},
|
||||
disableTransitionOneTick () {
|
||||
const firstHandle = this.firstHandleRef
|
||||
if (firstHandle) {
|
||||
firstHandle.style.transition = 'none'
|
||||
const { handleRef1, handleRef2 } = this
|
||||
if (handleRef1) {
|
||||
handleRef1.style.transition = 'none'
|
||||
this.$nextTick(() => {
|
||||
if (this.firstHandleRef) {
|
||||
this.firstHandleRef.style.transition = null
|
||||
const { handleRef1 } = this
|
||||
if (handleRef1) {
|
||||
handleRef1.style.transition = ''
|
||||
}
|
||||
})
|
||||
}
|
||||
const secondHandle = this.secondHandleRef
|
||||
if (secondHandle) {
|
||||
secondHandle.style.transition = 'none'
|
||||
if (handleRef2) {
|
||||
handleRef2.style.transition = 'none'
|
||||
this.$nextTick(() => {
|
||||
if (this.secondHandleRef) {
|
||||
this.secondHandleRef.style.transition = null
|
||||
const { handleRef2 } = this
|
||||
if (handleRef2) {
|
||||
handleRef2.style.transition = ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user