先看示例图

不允许出父元素

只允许横向(或纵向)

示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>橡皮筋回弹效果示例</title>
<style>
style > * {
margin: 0;
padding: 0;
}
.box_wrapper {
width: 200px;
height: 200px;
border: 1px solid red;
margin: 0 auto;
margin-top: 200px;
}
#box {
width: 100px;
height: 100px;
background-color: black;
}
</style>
</head>
<body>
<div class="box_wrapper">
<div id="box"></div>
</div>
<script>
function iosRebound(
element,
{ direction, relativeFather, moveReduce = 4 }
) {
let maxX,
maxY,
minX = 0,
minY = 0;
let preStartX, preStartY, startX, startY, offsetX, offsetY;
if (relativeFather) {
const parentNode = element.parentNode;
maxX =
parentNode.offsetWidth - element.offsetWidth + element.offsetLeft;
maxY =
parentNode.offsetHeight - element.offsetHeight + element.offsetTop;
minX = element.offsetLeft;
minY = element.offsetTop;
} else {
maxX = window.innerWidth - element.offsetWidth;
maxY = window.innerHeight - element.offsetHeight;
}
function startDrag(e) {
element.style.transition = "";
e.preventDefault();
if (!direction || direction == "x") {
offsetX = element.offsetLeft;
preStartX = element.offsetLeft;
startX = e.type === "mousedown" ? e.clientX : e.touches[0].clientX;
}
if (!direction || direction == "y") {
offsetY = element.offsetTop;
preStartY = element.offsetTop;
startY = e.type === "mousedown" ? e.clientY : e.touches[0].clientY;
}
const moveEvent = e.type === "mousedown" ? "mousemove" : "touchmove";
const stopEvent = e.type === "mousedown" ? "mouseup" : "touchend";
document.addEventListener(moveEvent, drag, { passive: false });
document.addEventListener(stopEvent, stopDrag);
}
function drag(e) {
e.preventDefault();
let x, y;
if (!direction || direction == "x") {
const clientX =
e.type === "mousemove" ? e.clientX : e.touches[0].clientX;
x = offsetX + (clientX - startX) / moveReduce;
x = Math.min(Math.max(x, minX), maxX);
element.style.left = x + "px";
}
if (!direction || direction == "y") {
const clientY =
e.type === "mousemove" ? e.clientY : e.touches[0].clientY;
y = offsetY + (clientY - startY) / moveReduce;
y = Math.min(Math.max(y, minY), maxY);
element.style.top = y + "px";
}
}
function stopDrag() {
element.style.transition = "0.3s";
if (!direction || direction == "x") {
element.style.left = preStartX + "px";
}
if (!direction || direction == "y") {
element.style.top = preStartY + "px";
}
if (window.innerWidth <= 1024) {
document.removeEventListener("touchmove", drag);
document.removeEventListener("touchend", stopDrag);
} else {
document.removeEventListener("mousemove", drag);
document.removeEventListener("mouseup", stopDrag);
}
}
const isMobile =
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
);
element.style.cursor = "move";
element.style.position = "absolute";
element.addEventListener(
isMobile ? "touchstart" : "mousedown",
startDrag
);
}
iosRebound(document.getElementById("box"), {
direction: "",
relativeFather: false,
moveReduce: 4,
});
</script>
</body>
</html>
封装代码
function iosRebound(element, { direction, relativeFather, moveReduce = 4 }) {
if (!element) return console.error("需要元素");
let maxX,
maxY,
minX = 0,
minY = 0;
let preStartX, preStartY, startX, startY, offsetX, offsetY;
if (relativeFather) {
const parentNode = element.parentNode;
maxX = parentNode.offsetWidth - element.offsetWidth + element.offsetLeft;
maxY = parentNode.offsetHeight - element.offsetHeight + element.offsetTop;
minX = element.offsetLeft;
minY = element.offsetTop;
} else {
maxX = window.innerWidth - element.offsetWidth;
maxY = window.innerHeight - element.offsetHeight;
}
function startDrag(e) {
element.style.transition = "";
e.preventDefault();
if (!direction || direction == "x") {
offsetX = element.offsetLeft;
preStartX = element.offsetLeft;
startX = e.type === "mousedown" ? e.clientX : e.touches[0].clientX;
}
if (!direction || direction == "y") {
offsetY = element.offsetTop;
preStartY = element.offsetTop;
startY = e.type === "mousedown" ? e.clientY : e.touches[0].clientY;
}
const moveEvent = e.type === "mousedown" ? "mousemove" : "touchmove";
const stopEvent = e.type === "mousedown" ? "mouseup" : "touchend";
document.addEventListener(moveEvent, drag, { passive: false });
document.addEventListener(stopEvent, stopDrag);
}
function drag(e) {
e.preventDefault();
let x, y;
if (!direction || direction == "x") {
const clientX = e.type === "mousemove" ? e.clientX : e.touches[0].clientX;
x = offsetX + (clientX - startX) / moveReduce;
x = Math.min(Math.max(x, minX), maxX);
element.style.left = x + "px";
}
if (!direction || direction == "y") {
const clientY = e.type === "mousemove" ? e.clientY : e.touches[0].clientY;
y = offsetY + (clientY - startY) / moveReduce;
y = Math.min(Math.max(y, minY), maxY);
element.style.top = y + "px";
}
}
function stopDrag() {
element.style.transition = "0.3s";
if (!direction || direction == "x") {
element.style.left = preStartX + "px";
}
if (!direction || direction == "y") {
element.style.top = preStartY + "px";
}
if (window.innerWidth <= 1024) {
document.removeEventListener("touchmove", drag);
document.removeEventListener("touchend", stopDrag);
} else {
document.removeEventListener("mousemove", drag);
document.removeEventListener("mouseup", stopDrag);
}
}
const isMobile =
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
);
element.style.cursor = "move";
element.style.position = "absolute";
element.addEventListener(isMobile ? "touchstart" : "mousedown", startDrag);
}