import { debounce } from '@opentiny/utils'
import { on, off } from '@opentiny/utils'
const getBoundingPosition =
({ state }) =>
() => {
const { slideMainPostion, positionList } = state
const list = positionList.slice()
const len = list.length
state.boundingIndex = {
left: -1,
right: -1
}
for (let i = 0; i < len; i++) {
if (list[i].right > slideMainPostion.right + 2) {
state.boundingIndex.right = i
break
}
}
for (let i = len - 1; i >= 0; i--) {
if (list[i].left < slideMainPostion.left) {
state.boundingIndex.left = i
break
}
}
}
const leftSlideHandler =
({ state, api }) =>
() => {
const { canLeftScroll, slideMainPostion, positionList, boundingIndex } = state
if (!canLeftScroll || state.timer) {
return
}
const position = boundingIndex.left !== -1 && positionList[boundingIndex.left]
if (position) {
api.animationHandler(position.left - slideMainPostion.left)
}
}
const rightSlideHandler =
({ state, api }) =>
() => {
const { canRightScroll, slideMainPostion, positionList, boundingIndex } = state
if (!canRightScroll || state.timer) {
return
}
const position = boundingIndex.right !== -1 && positionList[boundingIndex.right]
if (position) {
api.animationHandler(position.right - slideMainPostion.right)
}
}
const updatePosition = ({ state, vm, props, api }) =>
debounce(10, (isInit) => {
state.positionList = props.data.map((item, index) => {
const blockRef = vm.$refs['block' + index]
let position = {}
if (blockRef) {
if (Array.isArray(blockRef)) {
position = blockRef[0] && blockRef[0].getBoundingClientRect()
} else {
position = blockRef.getBoundingClientRect()
}
}
return Object.assign(position, { index })
})
state.slideMainPostion = vm.$refs.slideMain.getBoundingClientRect()
api.getBoundingPosition()
isInit === true && api.updatePosition()
})
const animationLoop =
({ state, api, vm }) =>
(offset, delay, scorllLeft, cb) => {
const elScrollLeft = vm.$refs.slideMain.scrollLeft
clearTimeout(state.timer)
if (elScrollLeft !== state.oldScrollLeft && Math.abs(elScrollLeft - scorllLeft) > Math.abs(offset)) {
state.timer = setTimeout(() => {
vm.$refs.slideMain.scrollLeft += offset
state.oldScrollLeft = elScrollLeft
api.animationLoop(offset, delay, scorllLeft, cb)
}, delay)
} else {
state.timer = null
vm.$refs.slideMain.scrollLeft = scorllLeft
cb && cb()
}
}
const animationHandler =
({ api, vm, props }) =>
(allOffset) => {
const { duration, delay } = props
const mathFn = allOffset > 0 ? Math.ceil : Math.floor
const offsetInt = mathFn(allOffset)
if (!duration) {
vm.$refs.slideMain.scrollLeft += offsetInt
api.updatePosition()
return
}
const offset = mathFn(offsetInt / (duration / delay))
const scorllLeft = vm.$refs.slideMain.scrollLeft + offsetInt
api.animationLoop(offset, delay, scorllLeft, () => {
api.updatePosition()
})
}
export const api = ['slideBarState', 'leftSlideHandler', 'rightSlideHandler', 'updatePosition']
export const renderless = (props, { reactive, onMounted, onUnmounted, computed }, { vm }) => {
const state = reactive({
timer: null,
oldScrollLeft: -1,
slideMainPostion: {},
positionList: [],
canLeftScroll: computed(() => !props.noArrow && state.boundingIndex.left !== -1),
canRightScroll: computed(() => !props.noArrow && state.boundingIndex.right !== -1),
boundingIndex: {
left: -1,
right: -1
}
})
const api = {}
Object.assign(api, {
slideBarState: state,
leftSlideHandler: leftSlideHandler({ state, api }),
rightSlideHandler: rightSlideHandler({ state, api }),
animationHandler: animationHandler({ api, vm, props }),
animationLoop: animationLoop({ state, api, vm }),
getBoundingPosition: getBoundingPosition({ state, api, vm }),
updatePosition: updatePosition({ state, vm, props, api })
})
onMounted(() => {
api.updatePosition(true)
on(window, 'resize', api.updatePosition)
})
onUnmounted(() => {
off(window, 'resize', api.updatePosition)
})
return api
}