123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- /*
- 简单使用时:
- <template>
- <div class="relic-list">
- <div
- ref="listEl"
- class="the-list"
- >
- <button @click="onClickBtn"></button>
- <div class="content">
- slflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsdfsdflsdflkslkfsjdfsdfslflsfdjsflksfdlkskdfsfdlsfdlsdflsfksdfsd123456789over!
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import { ref, computed, watch, watchEffect, onMounted } from "vue"
- import useSmoothSwipe from '@/useFunctions/useSmoothSwipe.js'
- import { useWindowSize } from '@vueuse/core'
- const listEl = ref(null)
- const { width: windowWidth, height: windowHeight } = useWindowSize()
- const { haveSwipedThisTime, translateLength } = useSmoothSwipe({
- scrollTargetRef: listEl,
- viewportWidth: windowWidth,
- })
- function onClickBtn(e) {
- if (!haveSwipedThisTime.value) {
- console.log('button click!')
- }
- }
- </script>
- */
- import { ref, unref, watch, watchEffect, onMounted, onBeforeUnmount } from 'vue'
- export default function useSmoothSwipe({
- scrollTargetRef,
- maxTranslateLength,
- viewportWidth = document.documentElement.clientWidth,
- speedFactor = 1,
- damping = 0.003,
- enableAutoMoving = false
- } = {}) {
- const isOperating = ref(false)
- const haveSwipedThisTime = ref(false)
- let haveSwipedThisTimeTimeoutId = null
- let lastMoveEventTimeStamp = 0
- let lastCursorPos = 0
- let moveSpeed = ref(0)
- let translateLength = ref(0)
- let maxTranslateLengthInner = Infinity
- let isAutoMoving = ref(false)
- let beginAutoMoveIntervalId = null
- let lastAnimationTimeStamp = 0
- let animationFrameId = null
- //
- watch(moveSpeed, (v) => {
- if (!haveSwipedThisTime.value && v) {
- haveSwipedThisTime.value = true
- }
- })
- watch(isOperating, (v) => {
- if (v) {
- clearTimeout(haveSwipedThisTimeTimeoutId)
- haveSwipedThisTime.value = false
- } else {
- clearTimeout(haveSwipedThisTimeTimeoutId)
- haveSwipedThisTimeTimeoutId = setTimeout(() => {
- haveSwipedThisTime.value = false
- }, 333)
- }
- })
- // compute maxTranslateLengthInner
- watchEffect(() => {
- if (maxTranslateLength) {
- maxTranslateLengthInner = unref(maxTranslateLength) - unref(viewportWidth)
- if (maxTranslateLengthInner < 0) {
- maxTranslateLengthInner = 0
- }
- }
- })
- function computeMaxTranslateLengthInnerByScrollTarget() {
- maxTranslateLengthInner = scrollTargetRef.value.scrollWidth - unref(viewportWidth)
- }
- function onWheel(e) {
- moveSpeed.value += e.deltaY / 200
- }
- function speedUp(v) {
- console.log('sdf')
- moveSpeed.value += v
- }
- /**
- * swipe begin
- */
- function onMouseDown(e) {
- isOperating.value = true
- moveSpeed.value = 0
- lastMoveEventTimeStamp = 0
- lastAnimationTimeStamp = Date.now()
- lastCursorPos = e.clientX
- if (beginAutoMoveIntervalId) {
- clearInterval(beginAutoMoveIntervalId)
- beginAutoMoveIntervalId = null
- }
- if (isAutoMoving.value) {
- isAutoMoving.value = false
- }
- }
- function onTouchStart(e) {
- isOperating.value = true
- moveSpeed.value = 0
- lastMoveEventTimeStamp = 0
- lastAnimationTimeStamp = Date.now()
- lastCursorPos = e.changedTouches[0].clientX
- if (beginAutoMoveIntervalId) {
- clearInterval(beginAutoMoveIntervalId)
- beginAutoMoveIntervalId = null
- }
- if (isAutoMoving.value) {
- isAutoMoving.value = false
- }
- }
- /**
- * swiping
- */
- function onMouseMove(e) {
- if (isOperating.value) {
- // 疯狂操作的极端情况下两个时间戳之间的时差会不合理,甚至为0
- if (lastMoveEventTimeStamp && (e.timeStamp - lastMoveEventTimeStamp > 1)) {
- // 更新speed
- const currentMoveSpeed = - (e.clientX - lastCursorPos) / (e.timeStamp - lastMoveEventTimeStamp) * unref(speedFactor)
- moveSpeed.value = moveSpeed.value * 0.9 + currentMoveSpeed * 0.1
- lastCursorPos = e.clientX
- }
- lastMoveEventTimeStamp = e.timeStamp
- }
- }
- function onTouchMove(e) {
- if (isOperating.value && e.changedTouches.length === 1) {
- // 疯狂操作的极端情况下两个时间戳之间的时差会不合理,甚至为0
- if (lastMoveEventTimeStamp && (e.timeStamp - lastMoveEventTimeStamp > 1)) {
- // 更新speed
- const currentMoveSpeed = - (e.changedTouches[0].clientX - lastCursorPos) / (e.timeStamp - lastMoveEventTimeStamp) * unref(speedFactor)
- moveSpeed.value = moveSpeed.value * 0.9 + currentMoveSpeed * 0.1
- lastCursorPos = e.changedTouches[0].clientX
- }
- lastMoveEventTimeStamp = e.timeStamp
- }
- }
- /**
- * swipe end
- */
- function onMouseUp(e) {
- isOperating.value = false
- e.stopPropagation()
- beginAutoMoveIntervalId = setInterval(() => {
- if (moveSpeed.value === 0 && unref(enableAutoMoving)) {
- isAutoMoving.value = true
- }
- }, 2000)
- }
- function onTouchEnd(e) {
- isOperating.value = false
- beginAutoMoveIntervalId = setInterval(() => {
- if (moveSpeed.value === 0 && unref(enableAutoMoving)) {
- isAutoMoving.value = true
- }
- }, 2000)
- }
- function onMouseLeave() {
- isOperating.value = false
- beginAutoMoveIntervalId = setInterval(() => {
- if (moveSpeed.value === 0 && unref(enableAutoMoving)) {
- isAutoMoving.value = true
- }
- }, 2000)
- }
- function onTouchCancel() {
- isOperating.value = false
- beginAutoMoveIntervalId = setInterval(() => {
- if (moveSpeed.value === 0 && unref(enableAutoMoving)) {
- isAutoMoving.value = true
- }
- }, 2000)
- }
- beginAutoMoveIntervalId = setInterval(() => {
- if (moveSpeed.value === 0 && unref(enableAutoMoving)) {
- isAutoMoving.value = true
- }
- }, 2000)
- watch(isAutoMoving, (vNew) => {
- if (vNew) {
- moveSpeed.value = 0.03
- } else {
- moveSpeed.value = 0
- }
- })
- onBeforeUnmount(() => {
- clearInterval(beginAutoMoveIntervalId)
- })
- // 在每一帧更新镜头速度、位置
- function animationFrameTask() {
- const timeStamp = Date.now()
- const timeElapsed = timeStamp - lastAnimationTimeStamp
- if (!isAutoMoving.value) {
- // 速度减慢
- if (moveSpeed.value > 0) {
- moveSpeed.value -= unref(damping) * timeElapsed
- if (moveSpeed.value < 0) {
- moveSpeed.value = 0
- }
- } else if (moveSpeed.value < 0) {
- moveSpeed.value += unref(damping) * timeElapsed
- if (moveSpeed.value > 0) {
- moveSpeed.value = 0
- }
- }
- }
- // 根据速度更新位置
- translateLength.value += moveSpeed.value * timeElapsed
- if (translateLength.value < 0) {
- translateLength.value = 0
- moveSpeed.value = 0
- } else if (translateLength.value > maxTranslateLengthInner) {
- if (isAutoMoving.value) {
- translateLength.value = 0
- } else {
- translateLength.value = maxTranslateLengthInner
- moveSpeed.value = 0
- }
- }
- lastAnimationTimeStamp = timeStamp
- animationFrameId = requestAnimationFrame(animationFrameTask)
- }
- onMounted(() => {
- animationFrameId = requestAnimationFrame(animationFrameTask)
- })
- onBeforeUnmount(() => {
- cancelAnimationFrame(animationFrameId)
- })
- if (scrollTargetRef) {
- watch(scrollTargetRef, (v) => {
- if (v) {
- v.addEventListener('wheel', onWheel)
- v.addEventListener('mousedown', onMouseDown)
- v.addEventListener('mouseleave', onMouseLeave)
- v.addEventListener('mousemove', onMouseMove)
- v.addEventListener('mouseup', onMouseUp)
- // v.addEventListener('touchstart', onTouchStart)
- // v.addEventListener('touchmove', onTouchMove)
- // v.addEventListener('touchend', onTouchEnd)
- // v.addEventListener('touchcancel', onTouchCancel)
- }
- }, {
- immediate: true,
- })
- watch(translateLength, (v) => {
- scrollTargetRef.value && (scrollTargetRef.value.scrollLeft = v)
- })
- }
- return {
- onWheel,
- onMouseDown,
- onMouseLeave,
- onMouseMove,
- onMouseUp,
- onTouchStart,
- onTouchMove,
- onTouchEnd,
- onTouchCancel,
- translateLength,
- haveSwipedThisTime,
- computeMaxTranslateLengthInnerByScrollTarget,
- speedUp
- }
- }
|