Toggle navigation
在线编辑器
在线代码
文本比较
jQuery下载
前端库
在线手册
登录/注册
下载代码
html
css
js
分享到微信朋友圈
X
html
-
-
°
--
F
C
css
@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500&display=swap"); * { border: 0; box-sizing: border-box; margin: 0; padding: 0; } :root { --hue: 223; --bg: hsl(var(--hue),10%,70%); --fg: hsl(var(--hue),10%,10%); --primary: hsl(var(--hue),90%,55%); --trans-dur: 0.3s; font-size: calc(16px + (20 - 16) * (100vw - 320px) / (1280 - 320)); } body, button { font: 1em/1.5 Montserrat, sans-serif; } body { background-color: var(--bg); color: var(--fg); height: 100vh; display: grid; place-items: center; transition: background-color var(--trans-dur), color var(--trans-dur); } .t, .t__inner, .t__inner:before, .t__inner:after, .t__drag { border-radius: 50%; } .t { --temp-hue: 50; box-shadow: 0 0 0.1em hsl(var(--hue),10%,90%), 0 0 0.3em hsl(var(--hue),10%,80%), 0 0 0.1em hsl(var(--hue),10%,40%) inset; display: grid; place-items: center; position: relative; width: 16em; height: 16em; transition: box-shadow 0.3s; z-index: 0; } .t__inner { background-color: hsl(var(--hue),10%,80%); position: relative; width: 11.5em; height: 11.5em; transition: background-color 0.3s; } .t__inner:before, .t__inner:after { content: ""; display: block; position: absolute; } .t__inner:before { background-image: linear-gradient(hsl(var(--hue),10%,95%),hsl(var(--hue),10%,65%)); top: -0.25em; left: -0.25em; width: 12em; height: 12em; z-index: -1; } .t__inner:after { background-image: linear-gradient(hsl(var(--temp-hue),90%,100%),hsl(var(--temp-hue),90%,50%)); box-shadow: 0 -0.25em 2em hsla(var(--temp-hue),90%,55%,0.3), 0 2em 1em hsl(var(--temp-hue),20%,55%); top: -0.25em; left: -0.375em; width: 12.25em; height: 12.25em; z-index: -2; } .t__drag, .t__value, .t__units { position: absolute; } .t__drag, .t__unit { background: transparent; -webkit-appearance: none; appearance: none; } .t__drag { cursor: grab; display: block; width: 100%; height: 100%; z-index: 2; -webkit-tap-highlight-color: transparent; } .t__drag:focus { outline: transparent; } .t__arrows { display: block; position: absolute; top: -2.25em; left: -2.25em; opacity: 0; width: 16em; height: auto; transition: opacity 0.15s linear; z-index: 1; } .t__drag:not(.t__drag--dragging):hover ~ .t__arrows { opacity: 1; transition-delay: 0.3s; } .t__drag--dragging ~ .t__arrows { opacity: 0; transition-delay: 0s; } .t__drag--dragging ~ .t__units { z-index: 0; } .t__value, .t__unit { text-shadow: 0 0.15em 0.1em hsla(var(--hue),10%,10%,0.1); } .t__value { display: flex; justify-content: flex-end; align-items: center; padding-right: 3em; inset: 0; z-index: 0; } .t__digit, .t__degree { display: inline-block; line-height: 1; -webkit-user-select: none; user-select: none; } .t__digit { font-size: 3em; font-weight: 300; text-align: center; width: 1ch; } .t__degree { color: hsl(var(--hue),10%,50%); font-size: 2em; transform: translateY(-0.5ch); } .t__units { top: calc(50% - 1.5em); right: 1.5em; z-index: 3; } .t__unit { color: hsl(var(--hue),10%,65%); display: block; font-size: 1em; font-weight: 500; line-height: 1; width: 1.5em; height: 1.5em; } .t__unit[aria-pressed="true"] { color: currentColor; } .t__sr { clip: rect(1px,1px,1px,1px); overflow: hidden; position: absolute; width: 1px; height: 1px; } /* Dark theme */ @media (prefers-color-scheme: dark) { :root { --bg: hsl(var(--hue),10%,20%); --fg: hsl(var(--hue),10%,90%); } .t { box-shadow: 0 0 0.1em hsl(var(--hue),10%,40%), 0 0 0.3em hsl(var(--hue),10%,30%), 0 0 0.1em hsl(var(--hue),10%,0%) inset; } .t__inner { background-color: hsl(var(--hue),10%,30%); } .t__inner:before { background-image: linear-gradient(hsl(var(--hue),10%,45%),hsl(var(--hue),10%,15%)); } .t__inner:after { background-image: linear-gradient(hsl(var(--temp-hue),90%,10%),hsl(var(--temp-hue),90%,50%)); box-shadow: 0 -0.25em 2em hsla(var(--temp-hue),90%,55%,0.3), 0 2em 1em hsl(var(--temp-hue),20%,25%); } .t__value { text-shadow: 0 0.15em 0.1em hsla(var(--hue),10%,10%,0.2); } .t__degree { color: hsl(var(--hue),10%,70%); } .t__unit { color: hsl(var(--hue),10%,45%); } }
JavaScript
window.addEventListener("DOMContentLoaded",() => { const thermostat = new Thermostat(".t"); }); class Thermostat { constructor(qs) { this.el = document.querySelector(qs); this.temp = 60; this.scale = "f"; this.min = { f: 60, c: 16, hue: 10, angle: 0 }; this.max = { f: 90, c: 32, hue: 50, angle: 359 }; this.init(); } init() { const dataAttr = "[data-drag]"; const dragEl = this.el?.querySelector(dataAttr); const draggingClass = "t__drag--dragging"; dragEl?.addEventListener("keydown",this.changeTemp.bind(this)); this.el?.addEventListener("click",this.changeScale.bind(this)); Draggable.create(dataAttr,{ type: "rotation", bounds: { minRotation: this.min.angle, maxRotation: this.max.angle }, onDrag: () => { this.temp = this.tempFromDrag(); this.updateDisplay(); dragEl.classList.add(draggingClass); }, onDragEnd: () => { dragEl.classList.remove(draggingClass); } }); this.updateDisplay(); } changeTemp(e) { const { key } = e; const step = 1; // value change if (key === "ArrowUp" || key === "ArrowRight") this.temp += step; else if (key === "ArrowDown" || key === "ArrowLeft") this.temp -= step; // keep within bounds if (this.temp < this.min[this.scale]) this.temp = this.min[this.scale]; else if (this.temp > this.max[this.scale]) this.temp = this.max[this.scale]; this.updateDisplay(); } changeScale(e) { if (e.target.hasAttribute("data-scale") && this.scale !== e.target.value) { this.scale = e.target.value; const rawTemp = this.scale === "f" ? this.CToF(this.temp) : this.FToC(this.temp); this.temp = Math.round(rawTemp); this.updateDisplay(); } } setAriaPressed() { const scale = this.el?.querySelectorAll("[data-scale]"); if (scale) { Array.from(scale).forEach(s => { s.setAttribute("aria-pressed",s.value === this.scale); }); } } setDigits() { // screen reader value const sr = this.el?.querySelector("[data-temp-sr]"); if (sr) sr.textContent = `${this.temp}°${this.scale.toUpperCase()}`; // displayed value const tempDigits = this.el?.querySelectorAll("[data-temp]"); if (tempDigits) { const digitString = String(this.temp).split("").reverse(); Array.from(tempDigits).reverse().forEach((digit,i) => { digit.textContent = digitString[i]; }) } } setTone() { const minHue = this.min.hue; const maxHue = this.max.hue; const temp = this.temp; const minTemp = this.min[this.scale]; const maxTemp = this.max[this.scale]; const hueDiff = maxHue - minHue; const relativeHue = hueDiff * ((temp - minTemp) / (maxTemp - minTemp)); const hue = Math.round(maxHue - relativeHue); this.el?.style.setProperty("--temp-hue",hue); } CToF(c) { return c * (9 / 5) + 32; } FToC(f) { return (f - 32) * (5 / 9); } angleFromMatrix(transVal) { const matrixVal = transVal.split("(")[1].split(")")[0].split(","); const [cos1,sin] = matrixVal.slice(0,2); let angle = Math.round(Math.atan2(sin,cos1) * (180 / Math.PI)); if (angle < 0) angle += 360; return angle; } tempFromDrag() { const drag = this.el.querySelector(".t__drag") if (drag) { const dragCS = window.getComputedStyle(drag); const trans = dragCS.getPropertyValue("transform"); const dragAngle = this.angleFromMatrix(trans); const relAngle = dragAngle - this.min.angle; const angleFrac = relAngle / (this.max.angle - this.min.angle); const tempRange = this.max[this.scale] - this.min[this.scale]; const result = angleFrac * tempRange + this.min[this.scale]; return Math.round(result); } } updateDisplay() { this.setDigits(); this.setAriaPressed(); this.setTone(); } }
粒子
时间
文字
hover
canvas
3d
游戏
音乐
火焰
水波
轮播图
鼠标跟随
动画
css
加载动画
导航
菜单
按钮
滑块
tab
弹出层
统计图
svg
×
Close
在线代码下载提示
开通在线代码永久免费下载,需支付20jQ币
开通后,在线代码模块中所有代码可终身免费下!
您已开通在线代码永久免费下载,关闭提示框后,点下载代码可直接下载!
您已经开通过在线代码永久免费下载
对不起,您的jQ币不足!可通过发布资源 或
直接充值获取jQ币
取消
开通下载
<!doctype html> <html> <head> <meta charset="utf-8"> <title>极简恒温器旋钮效果-jq22.com</title> <script src="https://www.jq22.com/jquery/jquery-1.10.2.js"></script> <style>
</style> </head> <body>
<script>
</script>
</body> </html>
2012-2021 jQuery插件库版权所有
jquery插件
|
jq22工具库
|
网页技术
|
广告合作
|
在线反馈
|
版权声明
沪ICP备13043785号-1
浙公网安备 33041102000314号