console
class HTMLSwitchElement extends HTMLElement {
constructor() {
super();
this._root = this.attachShadow({ mode: "closed" });
this._track = document.createElement("div");
this._thumb = document.createElement("div");
this._root.appendChild(this._track);
this._track.appendChild(this._thumb);
this._thumb.classList.add("thumb");
this._track.classList.add("track");
let styleElem = document.createElement("style");
styleElem.textContent = `
.track {
position: relative;
width: 32px;
height: 10px;
background: #b9b9b9;
border-radius: 5px;
user-select: none;
cursor: pointer;
}
.thumb {
position: absolute;
left: 0;
top: 50%;
transform: translate(0, -50%);
width: 15px;
height: 15px;
background: #eee;
border-radius: 50%;
box-shadow: 0 0 2px #ccc;
transition: 0.1s background;
}
`;
this._root.appendChild(styleElem);
let _checked = false;
let pending = false;
let aid = null;
let _self = this;
function animateToggle() {
let trackRectangle = _self._track.getBoundingClientRect();
let thumbRectangle = _self._thumb.getBoundingClientRect();
let offsetX = thumbRectangle.left - trackRectangle.left;
let maxOffset = trackRectangle.width - thumbRectangle.width;
if (_checked) {
offsetX -= 1;
} else {
offsetX += 1;
}
offsetX = Math.min(maxOffset, Math.max(0, offsetX));
_self._thumb.style.left = offsetX + "px";
let percent = (offsetX / maxOffset) * 100;
_self._track.style.backgroundImage = `linear-gradient(to right,#f8bdc9 ${percent}%,transparent ${percent + 1}%)`;
if (offsetX <= 0 || offsetX >= maxOffset) {
cancelAnimationFrame(aid);
_checked = !_checked;
pending = false;
_self.dispatchEvent(new Event("checkedChange"));
if (_checked) {
_self._thumb.style.backgroundColor = "#41c87f";
} else {
_self._thumb.style.backgroundColor = "#eeeeee";
}
} else {
aid = requestAnimationFrame(animateToggle);
}
}
function schedule() {
if (!pending) {
pending = true;
animateToggle();
}
}
Object.defineProperty(this, "checked", {
enumerable: false,
configurable: false,
get() {
return _checked;
}
});
this._track.addEventListener("click", schedule);
this.style.display = "inline-block";
this.setChecked = function (val) {
val = Boolean(val);
if (_checked != val && !pending) {
schedule();
}
}
this.toggle = function () {
schedule();
}
}
}
customElements.define("switch-button", HTMLSwitchElement);
let switchBtn = document.querySelector("switch-button");
switchBtn.addEventListener("checkedChange", function () {
if (switchBtn.checked) {
console.log("开灯");
} else {
console.log("关灯");
}
});
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=, initial-scale=">
<meta http-equiv="X-UA-Compatible" content="">
<title></title>
</head>
<body>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
<switch-button></switch-button>
</body>
</html>
body {
background: #fff;
}