2021-04-29 18:42:52 +08:00
|
|
|
|
2021-04-30 11:29:02 +08:00
|
|
|
import React, { useCallback, useEffect, useReducer, useRef } from 'react';
|
2021-04-29 18:42:52 +08:00
|
|
|
|
2021-04-30 11:29:02 +08:00
|
|
|
import { MdArrowBack, MdArrowForward } from 'react-icons/md'
|
2021-04-29 18:42:52 +08:00
|
|
|
|
|
|
|
export function throttle(callback, limit) {
|
|
|
|
let handler = null; // Initially, we're not waiting
|
|
|
|
return (...args) => { // We return a throttled function
|
|
|
|
if (!handler) { // If we're not waiting
|
|
|
|
callback(...args); // Execute users function
|
|
|
|
handler = setTimeout(() => handler = null, limit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function debounce(callback, delay) {
|
|
|
|
let handler = null;
|
|
|
|
return (...args) => {
|
|
|
|
clearTimeout(handler);
|
|
|
|
handler = setTimeout(() => callback(...args), delay);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const transTime = 200
|
|
|
|
|
|
|
|
const elastic = `transform ${transTime}ms cubic-bezier(0.4, 0.0, 0.2, 1)`;
|
|
|
|
|
2021-04-30 11:29:02 +08:00
|
|
|
function reducer(state, action) {
|
|
|
|
switch (action.type) {
|
|
|
|
case 'set-rect':
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
rect: action.rect
|
|
|
|
};
|
|
|
|
case 'resize':
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
rect: action.rect,
|
|
|
|
dragLeft: state.pg * action.rect.width,
|
|
|
|
dragging: true
|
|
|
|
};
|
|
|
|
case 'move':
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
pg: state.pg + action.del,
|
|
|
|
dragging: false
|
|
|
|
};
|
|
|
|
case 'drag-start':
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
dragLeft: state.pg * state.rect.width,
|
|
|
|
dragging: true
|
|
|
|
};
|
|
|
|
case 'drag':
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
dragLeft: state.dragLeft - action.move
|
|
|
|
};
|
|
|
|
case 'drag-end':
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
pg: Math.round(state.dragLeft / state.rect.width),
|
|
|
|
dragging: false
|
|
|
|
};
|
|
|
|
default:
|
|
|
|
console.log('wtf')
|
|
|
|
console.error(action)
|
|
|
|
}
|
|
|
|
}
|
2021-04-29 18:42:52 +08:00
|
|
|
|
|
|
|
export const Carousel = () => {
|
|
|
|
const arr = [1, 2, 3]
|
|
|
|
|
|
|
|
const ref = useRef(null)
|
2021-04-30 11:29:02 +08:00
|
|
|
const [state, dispatch] = useReducer(reducer, { rect: {}, pg: 0, dragLeft: 0, dragging: false })
|
2021-04-29 18:42:52 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2021-04-30 11:29:02 +08:00
|
|
|
dispatch({ type: 'set-rect', rect: ref.current.getBoundingClientRect() })
|
2021-04-29 18:42:52 +08:00
|
|
|
}, [ref])
|
|
|
|
|
|
|
|
|
|
|
|
const updateSize = useCallback(
|
|
|
|
debounce(
|
|
|
|
() => {
|
2021-04-30 11:29:02 +08:00
|
|
|
dispatch({ type: 'resize', rect: ref.current.getBoundingClientRect() })
|
2021-04-29 18:42:52 +08:00
|
|
|
}
|
|
|
|
, 200
|
|
|
|
)
|
|
|
|
, []
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
window.addEventListener('resize', updateSize)
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
|
|
return <>
|
2021-04-30 11:29:02 +08:00
|
|
|
|
|
|
|
|
|
|
|
<div className='bg-transparent h-full w-full'
|
2021-04-29 18:42:52 +08:00
|
|
|
ref={ref}
|
|
|
|
>
|
2021-04-30 11:29:02 +08:00
|
|
|
{state.rect.width &&
|
|
|
|
<div className='absolute top-0 overflow-visible bg-green-400 h-full'
|
2021-04-29 18:42:52 +08:00
|
|
|
|
2021-04-30 11:29:02 +08:00
|
|
|
onMouseDown={() => dispatch({ type: 'drag-start' })}
|
|
|
|
onMouseMove={(e) => e.buttons == 1 && dispatch({ type: 'drag', move: e.movementX })}
|
|
|
|
onMouseUp={() => dispatch({ type: 'drag-end' })}
|
2021-04-29 18:42:52 +08:00
|
|
|
|
|
|
|
style={{
|
2021-04-30 11:29:02 +08:00
|
|
|
width: 1 * state.rect.width,
|
|
|
|
transform: `translateX(${state.dragging ? -state.dragLeft : -state.pg * state.rect.width}px)`,
|
|
|
|
transition: state.dragging ? null : elastic
|
|
|
|
}}
|
|
|
|
>
|
2021-04-29 18:42:52 +08:00
|
|
|
{
|
|
|
|
arr.map((e, idx) => {
|
|
|
|
|
|
|
|
return <div key={idx} style={{}}>
|
|
|
|
hi {e}
|
|
|
|
</div>
|
|
|
|
})
|
|
|
|
}
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
</div>
|
2021-04-30 11:29:02 +08:00
|
|
|
|
|
|
|
<div className='select-none absolute w-12 h-12 top-0 bottom-0 my-auto -left-24 fill-current bg-gray-100 rounded-full'
|
|
|
|
onClick={() => dispatch({ type: "move", del: -1 })}
|
|
|
|
>
|
|
|
|
<MdArrowBack className="w-full h-full text-gray-700 p-3" />
|
|
|
|
</div>
|
|
|
|
<div className='select-none absolute w-12 h-12 top-0 bottom-0 my-auto -right-24 fill-current bg-gray-100 rounded-full'
|
|
|
|
onClick={() => dispatch({ type: "move", del: 1 })}
|
|
|
|
>
|
|
|
|
<MdArrowForward className="w-full h-full text-gray-700 p-3" />
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className="flex w-full -bottom-8 absolute flex justify-center items-center">
|
|
|
|
{arr.map((ele, idx) => (
|
|
|
|
<div key={idx} className={`h-2 w-2 mx-1 rounded-full ${idx == state.pg ? 'bg-gray-50' : 'bg-gray-500'}`}></div>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
|
2021-04-29 18:42:52 +08:00
|
|
|
</>
|
|
|
|
|
|
|
|
}
|