1. 表单事件
概念:
form.onsubmit = () =>{}:当表单提交时触发的事件。form.onreset = () =>{}:当表单重置时触发的事件。input.onkeyup = () => {}:在文本框中,将按键抬起来时触发的事件。input.onblur = () => {}:当文本框丧失焦点时触发的事件。
布局:
<section id="test-onsubmit">
<form id="onsubmit-form" method="get" action="#">
<label>
<span>帐号:</span>
<input id="onsubmit-username-ipt" name="username" />
</label>
<label>
<span>密码:</span>
<input id="onsubmit-password-ipt" name="password" type="password"/>
</label>
<button type="submit">登录</button>
</form>
</section>
<section id="test-onreset">
<form id="onreset-form" method="get" action="#">
<label>
<span>帐号:</span>
<input id="onreset-username-ipt" name="username" />
</label>
<label>
<span>密码:</span>
<input id="onreset-password-ipt" name="password" type="password"/>
</label>
<button type="submit">登录</button>
<button type="reset">重置</button>
</form>
</section>
<section id="test-onkeyup">
<form id="onkeyup-form" method="get" action="#">
<label>
<span>帐号:</span>
<input id="onkeyup-username-ipt" name="username" />
</label>
<button type="submit">登录</button>
</form>
</section>
<section id="test-onblur">
<form id="onblur-form" method="get" action="#">
<label>
<span>帐号:</span>
<input id="onblur-username-ipt" name="username" />
</label>
<button type="submit">登录</button>
</form>
</section>
<script type="text/javascript">
window.onload = ()=>{
当表单提交时触发的事件。
let onsubmitForm = document.querySelector("#onsubmit-form");
onsubmitForm.onsubmit = () => {
let usernameIpt = document.querySelector("#onsubmit-username-ipt");
let passwordIpt = document.querySelector("#onsubmit-password-ipt");
if("" === usernameIpt["value"] || "" === passwordIpt["value"] ){
alert("账号或者密码不能为空!");
return false;
}
};
当表单重置时触发的事件。
let onresetForm = document.querySelector("#onreset-form");
onresetForm.onreset = () => {
let response = confirm("您将要重置表单,确认吗?");
if (!response) {
return false;
}
};
在文本框中,将按键抬起来时触发的事件。
let onkeyupUsernameIpt = document.querySelector("#onkeyup-username-ipt");
onkeyupUsernameIpt.onkeyup = () => {
onkeyupUsernameIpt["value"] = onkeyupUsernameIpt["value"].toUpperCase();
};
当文本框丧失焦点时触发的事件。
let onblurUsernameIpt = document.querySelector("#onblur-username-ipt");
onblurUsernameIpt.onblur = () => {
if (!onblurUsernameIpt["value"].match("^[\\w]+$")) {
onblurUsernameIpt["value"] = "";
onblurUsernameIpt.focus();
alert("账号中不允许存在非法字符!");
}
}
};
</script>
2. event关键字
概念: event 是一个函数中内置对象,用来获取事件的详细信息,如鼠标,键盘等:
- event兼容性:
ev = ev || event- IE9以下版本的浏览器仅支持函数体中直接使用
event。 - FF浏览器仅支持在函数参数中的一号位置直接定义
ev,命名可以更改。 - Chrome浏览器两种写法都支持。
- IE9以下版本的浏览器仅支持函数体中直接使用
- event事件冒泡:子元素会继续向上触发父元素的同类型事件:
event.cancelBubble = true:在子元素的事件中取消事件冒泡。
- event鼠标坐标:
event.clientX:获取鼠标点击时横坐标。event.clientY:获取鼠标点击时纵坐标。
布局:
<style type="text/css">
#test-body {
border: 1px solid red;
}
#test-sec {
margin-top: 100px;
height: 100px;
background: yellowgreen;
}
</style>
//子孙三代
<body id="test-body">
<section id="test-sec">
<button id="test-btn" type="button">事件冒泡</button>
</section>
<script type="text/javascript">
window.onload = () => {
//点击出坐标
document.onclick = ev => {
ev = ev || event;
let x = ev.clientX;
let y = ev.clientY;
console.log(x, y);
};
let testBody = document.querySelector("#test-body");
let testSec = document.querySelector("#test-sec");
let testBtn = document.querySelector("#test-btn");
testBody.onclick = () => {
alert("I am body...");
};
//阻止继续冒泡
testSec.onclick = (ev) => {
ev = ev || event;
alert("I am sec...");
ev.cancelBubble = true;
};
testBtn.onclick = () => {
alert("I am btn...");
};
};
</script>
</body>
2.1鼠标跟踪
概念:
document.onmousemove = () => {}:当鼠标在文档上移动时触发的事件。obj["style"]["width"]:获取当前宽度,值带单位,如50px,所以只适合设置。obj.offsetWidth:获取当前宽度,值不带单位,如50,适合计算,但不适合设置。document.documentElement.scrollLeft:获取当前滚动条距离页面左边界的距离。document.body.scrollLeft:IE9以下支持的写法。
document.documentElement.scrollTop:获取当前滚动条距离页面上边界的距离。document.body.scrollTop:IE9以下支持的写法。
布局:
<style type="text/css">
body {
height: 1000px;
width: 5000px;
}
#pen {
width: 50px;
height: 50px;
background-color: yellow;
border-radius: 50%;
position: absolute;
}
</style>
<section id="pen"></section>
<script type="text/javascript">
/*需求:让一个黄色的圆形跟随鼠标移动而移动。*/
window.onload = () => {
let pen = document.querySelector("#pen");
document.onmousemove = (ev) => {
ev = ev || event;
let [x, y] = [ev.clientX, ev.clientY];
let [width, height] = [pen.offsetWidth, pen.offsetHeight];
let scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
/*pen的左距离 = 鼠标横坐标 + 滚动条距离页面左边界的距离 - pen半宽 + "px"*/
pen["style"]["left"] = x + scrollLeft - (width / 2) + "px";
pen["style"]["top"] = y + scrollTop - (height / 2) + "px";
};
}
</script>
<style>
.bug {
width: 20px;
height: 20px;
border-radius: 50%;
position: absolute;
}
</style>
<body>
<section>
<img class="bug" src="../../z-image/bug.png" alt="">
<img class="bug" src="../../z-image/bug.png" alt="">
<img class="bug" src="../../z-image/bug.png" alt="">
<img class="bug" src="../../z-image/bug.png" alt="">
<img class="bug" src="../../z-image/bug.png" alt="">
<img class="bug" src="../../z-image/bug.png" alt="">
<img class="bug" src="../../z-image/bug.png" alt="">
<img class="bug" src="../../z-image/bug.png" alt="">
<img class="bug" src="../../z-image/bug.png" alt="">
</section>
<script type="text/javascript">
window.onload = () => {
document.onmousemove = (ev) => {
ev = ev || event;
let bugs = document.querySelectorAll(".bug");
bugs[0]["style"]["left"] = ev.clientX + "px";
bugs[0]["style"]["top"] = ev.clientY + "px";
for (let i = bugs.length - 1; i > 0; i--) {
bugs[i]["style"]["left"] = bugs[i - 1]["style"]["left"];
bugs[i]["style"]["top"] = bugs[i - 1]["style"]["top"];
}
}
}
</script>
2.2 鼠标拖拽
概念:
document.onmousedown = () => {}:当鼠标按下时触发的事件。document.onmousemove = () => {}:当鼠标移动时触发的事件。document.onmouseup = () => {}:当鼠标抬起时触发的事件。document.documentElement.clientWidth:获取屏幕宽。document.documentElement.clientHeight:获取屏幕高。
<style type="text/css">
#ball {
width: 100px;
height: 100px;
background: red;
position: absolute;
border-radius: 50%;
}
</style>
<section id="ball"></section>
<script type="text/javascript">
window.onload = () => {
let ball = document.querySelector("#ball");
/*鼠标按下时,计算l和t这两个恒定值*/
ball.onmousedown = (ev) => {
ev = ev || event;
let l = ev.clientX - ball.offsetLeft;
let t = ev.clientY - ball.offsetTop;
/*在鼠标按下的前提下移动**/
document.onmousemove = (ev) => {
ev = ev || event;
ball["style"]["left"] = ev.clientX - l + "px";
ball["style"]["top"] = ev.clientY - t + "px";
};
/*在鼠标按下的前提下抬起*/
document.onmouseup = () => document.onmousemove = null;
}
};
</script>
<style type="text/css">
body {
margin: 0;
}
#board {
width: 300px;
height: 300px;
background-color: red;
position: relative;
}
#empty {
width: 100px;
height: 100px;
background-color: white;
position: absolute;
left: 100px;
top: 100px;
}
#fill {
width: 100px;
height: 100px;
background-color: green;
position: absolute;
}
</style>
<section id="board">
<section id="empty"></section>
</section>
<section id="fill"></section>
<script type="text/javascript">
window.onload = () => {
let fill = document.querySelector("#fill");
fill.onmousedown = ev => {
ev = ev || event;
let l = ev.clientX - fill.offsetLeft;
let t = ev.clientY - fill.offsetTop;
document.onmousemove = ev => {
ev = ev || event;
fill["style"]["left"] = ev.clientX - l + "px";
fill["style"]["top"] = ev.clientY - t + "px";
};
document.onmouseup = () => {
document.onmousemove = null;
/* 如果<section>正好和 [空缺] 重合,则宣布成功*/
if (fill.offsetLeft === 100 && fill.offsetTop === 100) {
fill.style.backgroundColor = "red";
}} } }
</script>
2.3 键盘控制
概念:
event.keyCode:获取当前键盘码编号:如37表示左键,38表示上键等。document.onkeydown = () => {}:某个按键按下去时触发的事件。
<style type="text/css">
#board {
width: 1000px;
height: 500px;
outline: 5px solid gray;
position: relative;
margin: 0 auto;
}
#car {
width: 50px;
height: 50px;
background-color: green;
position: absolute;
}
</style>
<section id="board">
<section id="car"></section>
</section>
<script type="text/javascript">
const [leftKey, topKey, rightKey, bottomKey] = [37, 38, 39, 40];
const [horizontalStep, verticalStep] = [50, 50];
const [carWidth, carHeight] = [50, 50];
const [boardWidth, boardHeight] = [1000, 500];
/*用键盘的上下左右键控制单个section移动。*/
window.onload = () => {
let car = document.querySelector("#car");
document.onkeydown = (ev) => {
ev = ev || event;
switch (ev.keyCode) {
case leftKey :
if (car.offsetLeft <= 0) return;
car["style"]["left"] = car.offsetLeft - horizontalStep + "px";
break;
case topKey :
if (car.offsetTop <= 0) return;
car["style"]["top"] = car.offsetTop - verticalStep + "px";
break;
case rightKey :
if (car.offsetLeft >= boardWidth - carWidth) return;
car["style"]["left"] = car.offsetLeft + horizontalStep + "px";
break;
case bottomKey :
if (car.offsetTop >= boardHeight - carHeight) return;
car["style"]["top"] = car.offsetTop + verticalStep + "px";
break;
}
}
};
</script>
<style type="text/css">
#board {
width: 1000px;
height: 500px;
outline: 10px solid red;
position: relative;
margin: 0 auto;
}
.snake {
width: 50px;
height: 50px;
border-radius: 10px;
background-color: green;
position: absolute;
}
#snake-head {
background-color: black;
z-index: 1;
}
</style>
<body>
<section id="board">
<div class="snake" id="snake-head"></div>
<div class="snake"></div>
<div class="snake"></div>
<div class="snake"></div>
<div class="snake"></div>
</section>
<script type="text/javascript">
const [leftKey, topKey, rightKey, bottomKey] = [37, 38, 39, 40];
const [horizontalStep, verticalStep] = [50, 50];
const [snakeWidth, snakeHeight] = [50, 50];
const [boardWidth, boardHeight] = [1000, 500];
window.onload = () => {
document.onkeydown = () => {
snakeBodyMove();
snakeHeadMove();
};
};
/*后面的蛇身追赶前面的蛇身*/
function snakeBodyMove() {
let snakes = document.querySelectorAll(".snake");
for (let i = snakes.length - 1; i > 0; i--) {
snakes[i]["style"]["left"] = snakes[i - 1]["style"]["left"];
snakes[i]["style"]["top"] = snakes[i - 1]["style"]["top"];
}
}
function snakeHeadMove(ev) {
let snakeHead = document.querySelector("#snake-head");
ev = ev || event;
switch (ev.keyCode) {
case leftKey :
if (snakeHead.offsetLeft <= 0) return;
snakeHead["style"]["left"] = snakeHead.offsetLeft - horizontalStep + "px";
break;
case topKey :
if (snakeHead.offsetTop <= 0) return;
snakeHead["style"]["top"] = snakeHead.offsetTop - verticalStep + "px";
break;
case rightKey :
if (snakeHead.offsetLeft >= boardWidth - snakeWidth) return;
snakeHead["style"]["left"] = snakeHead.offsetLeft + horizontalStep + "px";
break;
case bottomKey :
if (snakeHead.offsetTop >= boardHeight - snakeHeight) return;
snakeHead["style"]["top"] = snakeHead.offsetTop + verticalStep + "px";
break;
}
}
</script>
2.4 组合提交
概念: 多功能键如 shift,alt 或者 ctrl 可以配合 keyCode 一起使用,但前提是快捷键没有被占用:
event.keyCode && event.shiftKey:keyCode配合shift键。event.keyCode && event.altKey:keyCode配合alt键。event.keyCode && event.ctrlKey:keyCode配合ctrl键。
<style type="text/css">
#screen {
width: 505px;
height: 200px;
outline: 1px solid red;
margin: 5px auto;
overflow-y: auto;
}
#msg {
text-align: center;
}
</style>
<section id="screen"></section>
<section id="msg">
<label>
<textarea id="textarea" rows="3" cols="60"></textarea>
</label>
</section>
<script type="text/javascript">
/*需求:模拟聊天框,使用 `shift + Enter` 组合提交信息。*/
window.onload = () => {
let screen = document.querySelector("#screen");
let textarea = document.querySelector("#textarea");
textarea.focus();
document.onkeydown = (ev) => {
ev = ev || event;
if (ev.keyCode === 13 && ev.shiftKey) {
let msgHead = `[赵四]:192.168.0.0:<br/>::`;
screen.innerHTML += msgHead + textarea["value"] + "<br/><br/>";
textarea["value"] = "";
textarea.focus();
}
}
}
</script>
2.5 右键菜单
概念: document.oncontextmenu = () => {}:单击鼠标右键时触发的事件。
<style type="text/css">
#context-menu {
width: 250px;
background-color: black;
display: none;
position: absolute;
}
#context-menu a {
text-decoration: none;
color: white;
}
#context-menu li {
margin: 5px 0;
list-style-type: none;
}
#context-menu .divider {
border-bottom: 1px solid gray;
margin-top: 5px;
margin-bottom: 5px;
margin-left: -40px;
height: 1px;
}
</style>
<nav>
<ul id="context-menu">
<li><a href="#">返回(B)</a></li>
<li><a href="#">前进(F)</a></li>
<li><a href="#">重新加载</a></li>
<li class="divider"></li>
<li><a href="#">另存为(A)...</a></li>
<li><a href="#">打印(p)...</a></li>
<li><a href="#">投射(C)...</a></li>
<li><a href="#">翻成中文(简体)(T)</a></li>
<li class="divider"></li>
<li><a href="#">查看网页源代码(V)</a></li>
<li><a href="#">检查(N)</a></li>
</ul>
</nav>
<script type="text/javascript">
/*需求:当在页面上点击鼠标右键的时候,弹出自己自定义的右键菜单。*/
window.onload = () => {
let contextMenu = document.querySelector("#context-menu");
document.oncontextmenu = (ev) => {
ev = ev || event;
contextMenu["style"]["left"] = ev.clientX + "px";
contextMenu["style"]["top"] = ev.clientY + "px";
contextMenu["style"]["display"] = "block";
return false;
};
document.onclick = () => {
contextMenu["style"]["display"] = "none";
}
};
</script>
3. 时间类型
概念: JS中通过 let now = new Date() 来创建本地时间对象:
now.getFullYear():返回今年是哪一个年。now.getMonth():返回现在是几月份,老外从12月份开始算1月份。now.getDate():返回今天是几号。now.getDay():返回今天是星期几。now.getHours():返回现在的小时数。now.getMinutes():返回现在的分钟数。now.getSeconds():返回现在的秒数。now.getMilliseconds():返回现在的毫秒数。
如果是用反引号作为字符串符号,那么可以在其中直接使用
${}插值表达式进行插值。
<style type="text/css">
#screen {
width: 250px;
height: 50px;
border: 1px solid red;
}
</style>
<section id="screen"></section>
<button id="current-date-btn">获取当前时间</button>
<script type="text/javascript">
/*需求:点击一个按钮,能够显示出当前的时间。*/
window.onload = () => {
let currentDateBtn = document.querySelector("#current-date-btn");
currentDateBtn.onclick = () => {
let screen = document.querySelector("#screen");
let now = new Date();
let yyyy = now.getFullYear();
let mm = now.getMonth() + 1;
let dd = now.getDate();
let day = now.getDay();
let hh = now.getHours();
let mi = now.getMinutes();
let ss = now.getSeconds();
screen.innerHTML = `${yyyy}年${mm}月${dd}日 星期${day} ${hh}:${mi}:${ss}`;
}
}
</script>
4.1 周期定时器
概念: 周期定时器会每隔X时间重复执行Y事件:
window.setInterval(fn, t):每隔t毫秒执行一次fn函数。- param1:定时函数的函数名,也可以直接使用一个匿名函数。
- param2:周期时间,单位毫秒。
- return:本次开启的定时器的编号,number类型。
window.clearInterval(id):通过定时器编号来关闭周期定时器。
<style type="text/css">
#screen {
width: 250px;
height: 50px;
border: 1px solid red;
}
</style>
<section id="screen"></section>
<button id="start-btn">开启周期定时器</button>
<button id="stop-btn">停止周期定时器</button>
<script type="text/javascript">
window.onload = () => {
let timer01;
let screen = document.querySelector("#screen");
let startBtn = document.querySelector("#start-btn");
startBtn.onclick = () => {
timer01 = setInterval(() => {
screen.innerHTML = `${new Date().getSeconds()}`;
}, 1000);
};
let stopBtn = document.querySelector("#stop-btn");
stopBtn.onclick = () => {
clearInterval(timer01);
};
}
</script>
<style type="text/css">
body {
text-align: center;
}
#clock {
width: 1000px;
margin: 0 auto;
border: 5px inset black;
padding: 20px;
color: red;
font-size: 50px;
}
#date{
font-size: 1em;
}
#time{
font-size: 0.8em;
}
</style>
<h4>数码时钟案例</h4>
<section id="clock">
<div id="date"></div>
<div id="time"></div>
</section>
<script type="text/javascript">
/*需求:制作一个数码时钟*/
onload = () => {
/*在定时器开启之前,先调用一次show;*/
task();
setInterval(task, 1000);
};
/*定时器任务*/
function task() {
let now = new Date();
let yy = now.getFullYear();
let mm = format(now.getMonth() + 1);
let dd = format(now.getDate());
let hh = format(now.getHours());
let mi = format(now.getMinutes());
let ss = format(now.getSeconds());
let dateArt = document.querySelector("#date");
let timeArt = document.querySelector("#time");
dateArt.innerHTML = `${yy} - ${mm} - ${dd}`;
timeArt.innerHTML = `${hh} : ${mi} : ${ss}`;
}
/*对一位数的值进行处理,在前面加上一个0,否则原样返回*/
function format(obj) {
return obj < 10 ? "0" + obj : obj;
}
</script>
4.2 延时定时器
概念: 延时定时器会在X时间后仅执行一次Y事件:
window.setTimeout(fn, t):t毫秒后执行一次fn函数。- param1:定时函数的函数名,也可以直接使用一个匿名函数。
- param2:延迟时间,单位毫秒。
- return:本次开启的定时器的编号,number类型。
window.clearTimeout(id):通过定时器编号来关闭延迟定时器。
<style type="text/css">
#screen {
width: 250px;
height: 50px;
border: 1px solid red;
}
</style>
<section id="screen"></section>
<button id="start-btn">开启延时定时器</button>
<button id="stop-btn">停止延时定时器</button>
<script type="text/javascript">
onload = () => {
let timer01;
let startBtn = document.querySelector("#start-btn");
let screen = document.querySelector("#screen");
startBtn.onclick = () => {
timer01 = setTimeout(() => {
screen.innerHTML = "start!";
}, 3000);
};
let stopBtn = document.querySelector("#stop-btn");
stopBtn.onclick = () => {
clearTimeout(timer01);
};
}
</script>
<style type="text/css">
#head {
width: 50px;
height: 50px;
background-color: red;
float: right;
margin-left: 10px;
}
#info {
width: 500px;
height: 500px;
background-color: blue;
display: none;
float: right;
}
</style>
<div id="head"></div>
<div id="info"></div>
<script type="text/javascript">
/* 思路:
1. head(头像)默认显示,info(信息)默认不显示。
2. 当鼠标移入头像head,立即显示信息info。
3. 当鼠标移入信息info,继续显示信息info。
4. 当鼠标移出头像head
- 进入空白区,开启延时定时器,0.5秒后关闭信息info。
- 在0.5秒内进入信息info,则关闭让信息info消失的延时定时器。
5. 当鼠标移出信息info
- 进入空白区,开启延时定时器,0.5秒后关闭信息info。
- 在0.5秒内进入头像head,则关闭让信息info消失的延时定时器。
*/
window.onload = () => {
let head = document.querySelector("#head");
let info = document.querySelector("#info");
let timer = null;
head.onmouseover = info.onmouseover = () => {
clearTimeout(timer);
info["style"]["display"] = "block";
};
head.onmouseout = info.onmouseout = () => {
timer = setTimeout(() => {
info["style"]["display"] = "none";
}, 500);
};
}
</script>
4.3 运动框架
概念: 常见运动分为匀速运动和缓冲运动两种类型:
- 匀速运动:速度 = 每次移动距离。
- 缓冲运动:速度 = 当前距离 / 缓冲常数。
- 计算机最小单位为整数级像素,所以
12.x像素全都视为12px,向下取整。
- 计算机最小单位为整数级像素,所以
案例 点击小球 匀速移动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
#board {
margin: 10px auto;
width: 600px;
height: 100px;
outline: 5px solid black;
position: relative;
}
#ball {
width: 100px;
height: 100px;
background-image: radial-gradient(circle at center, red, black);
border-radius: 50%;
position: absolute;
}
</style>
</head>
<body>
<section id="board">
<div id="ball"></div>
</section>
<script type="text/javascript">
const [period, speed] = [50, 10];/*每隔50ms移动10px*/
const [boardWidth, ballWidth] = [600, 100];
let timer, ball;
/* 需求:点击小球,小球开始匀速运动。*/
window.onload = () => {
ball = document.querySelector("#ball");
ball.onclick = () => {
clearInterval(timer);
timer = setInterval(move, period);
}
};
function move() {
if (ball.offsetLeft >= boardWidth - ballWidth) {
clearInterval(timer);
return;
}
ball["style"]["left"] = ball.offsetLeft + speed + "px";
}
</script>
</body>
</html>
案例 侧边栏
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
#sidebar {
width: 150px;
height: 200px;
background: #00CBCB;
position: absolute;
top: 50px;
left: -150px;
}
#sidebar span {
width: 20px;
height: 60px;
background: #00CBCB;
line-height: 20px;
position: absolute;
right: -20px;
top: 70px;
}
</style>
</head>
<body>
<section id="sidebar">
<span>侧边栏</span>
</section>
<script type="text/javascript">
let timer, sidebar;
let [speed, period] = [10, 50];
window.onload = () => {
sidebar = document.querySelector("#sidebar");
sidebar.onmouseover = () => move(0);
sidebar.onmouseout = () => move(-150);
};
function move(target) {
let currentSpeed = sidebar.offsetLeft > target ? -speed : speed;
clearInterval(timer);
timer = setInterval(() => {
if (sidebar.offsetLeft === target) {
clearInterval(timer);
return;
}
sidebar["style"]["left"] = sidebar.offsetLeft + currentSpeed + "px";
}, period);
}
</script>
</body>
</html>
案例 点击小球缓冲运动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
body {
margin: 0;
}
#ball {
width: 100px;
height: 100px;
background-image: radial-gradient(circle at center, red, black);
border-radius: 50%;
position: absolute;
}
#board {
margin: 10px auto;
width: 600px;
height: 100px;
outline: 5px solid black;
position: relative;
}
</style>
</head>
<body>
<section id="board">
<div id="ball"></div>
</section>
<script type="text/javascript">
const period = 50;
const [boardWidth, ballWidth] = [600, 100];
const speedNum = 10;
let speed, timer, ball;
/*需求: 点击小球,小球开始进行缓冲运动。*/
window.onload = () => {
ball = document.querySelector("#ball");
ball.onclick = () => {
clearInterval(timer);
timer = setInterval(() => {
if (ball.offsetLeft >= boardWidth - ballWidth) {
clearInterval(timer);
return;
}
speed = (boardWidth - ballWidth - ball.offsetLeft) / speedNum;
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
ball["style"]["left"] = ball.offsetLeft + speed + "px";
}, period);
}
};
</script>
</body>
</html>
案例 完美运动框架
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
section {
width: 200px;
height: 200px;
font-size: 10px;
background: red;
}
</style>
</head>
<body>
<section id="test-sec">完美运动框架</section>
<script type="text/javascript">
/*需求:将section高度变为500px,宽度变为1000px,字体大小变为50px。*/
window.onload = () => {
let testSec = document.querySelector("#test-sec");
let target = {"width": "500px", "height": "1000px", "fontSize": "50px"};
let params = {"target": target, "callback": callback};
testSec.onclick = () => move(testSec, params);
function callback() {
alert("change over!");
}
};
/* 完美运动框架
* obj:要发生运动的元素,object类型。
* params:运动参数,json类型:
* target: 运动目标,json类型。
* speedNum:缓冲常数,数值越大,幅度越大,默认10。
* period:运动周期,数值越大,运动越快,默认50毫秒。
* callback:运动结束后的回调函数,可以省略。
* */
function move(obj, params) {
const speedNum = params["speedNum"] ? params["speedNum"] : 10;
const period = params["period"] ? params["period"] : 50;
const target = params["target"] ? params["target"] : null;
const callback = params["callback"] ? params["callback"] : null;
if (!target) return;
/*清空指定物体之前所挂载的旧定时器*/
clearInterval(obj.timer);
/*对指定物体开启新定时器,周期为period*/
obj.timer = setInterval(() => {
/*遍历运动物体的目标参数*/
for (let key in target) {
//判断target中有没有key
if (target.hasOwnProperty(key)) {
/*获取参数目标值*/
let targetValue = parseInt(target[key]);
/*获取参数当前值*/
let currentValue = parseInt(css(obj, key));
/*如果达到目标参数停止定时器*/
if (currentValue === targetValue) {
clearInterval(obj.timer);
/*如果用户传入回调函数,则执行回调函数*/
if (callback) callback();
return;
}
/*计算缓冲速度,处理小数,运动*/
let speed = (targetValue - currentValue) / speedNum;
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
obj["style"][key] = currentValue + speed + "px";
}
}
}, period);
/*通过元素的样式key,来获取value*/
function css(obj, key) {
return obj["currentStyle"] ? obj["currentStyle"][key] : getComputedStyle(obj)[key];
}
}
</script>
</body>
</html>