十五、焦点事件&键盘事件
1. 焦点事件
onfocus =>获得焦点事件 onblur=>失去焦点事件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>焦点事件</title>
<style>
input{
outline: none;
}
/* 伪类选择器:focus,表示获得焦点样式 */
/* input:focus{
background-color: lightblue;
border: 2px solid red;
} */
</style>
</head>
<body>
<div>
<span>账号:</span>
<input type="text" placeholder="请输入账号">
</div>
<div>
<span>密码:</span>
<input type="password" placeholder="请输入密码">
</div>
<script>
let inputs = document.querySelectorAll('input')
inputs.forEach(r=>{
// 备份文本框的placeholder
let placeholder = r.placeholder
//获取焦点事件
r.onfocus = function(){
// 文本框的placeholder设置空
r.placeholder = ''
}
//失去焦点事件
r.onblur = function(){
// 文本框的placeholder恢复
r.placeholder = placeholder
}
})
</script>
</body>
</html>
网页显示为:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>焦点事件练习</title>
<style>
*{
margin: 0;
padding: 0;
list-style: none;
}
.txt{
border: 1px solid #ccc;
width: 200px;
margin: 10px;
padding: 6px;
border-radius: 5px;
}
.txt input{
outline: none;
width: 100%;
border: none;
}
.txt input.border{
border-bottom: 1px solid #eee;
}
.txt ul{
margin-top: 5px;
display: none;
}
</style>
</head>
<body>
<div class="txt">
<input type="text" id="search">
<ul id="list">
<li>卡布奇洛</li>
<li>巧克力</li>
<li>咖啡</li>
<li>蛋糕</li>
<li>饼干</li>
</ul>
</div>
<script>
// 获取列表
let list = document.querySelector('#list')
// 获取搜索框
let search = document.querySelector('#search')
// 获得焦点事件
search.onfocus = function(){
search.classList.add('border')
list.style.display = 'block'
}
// 失去焦点事件
search.onblur = function(){
search.classList.remove('border')
list.style.display = 'none'
}
</script>
</body>
</html>
网页显示为:
(1).拖动框效果
dom.offsetLeft =>获取元素的默认左边距dom.offsetTop =>获取元素的默认上边距
window.innerWidth=>视口宽度 window.innerHeight=> 视口高度
dom.offsetWidth =>获取元素可见宽度(width+border+padding)
dom.offsetHeight => 获取元素可见高度(height+border+padding)
e.pageX=>鼠标指针到X轴坐标e.pageY=>鼠标指针到Y轴坐标
<!DOCTYPE html>
<html>
<head>
<meta>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>拖动框效果(在一个范围内)</title>
<style>
* {
margin: 0;
padding: 0;
list-style: none;
}
.main{
/* 相对定位 */
position: relative;
width: 1000px;
height: 500px;
border: 10px solid red;
margin: 20px;
}
.box {
width: 200px;
height: 200px;
border: 1px solid #ccc;
/* 绝对定位 */
position: absolute;
top: 100px;
left: 100px;
}
.box .title {
height: 30px;
background-color: lightseagreen;
position: relative;
line-height: 30px;
padding-left: 10px;
}
.box .title .close {
width: 24px;
height: 24px;
line-height: 24px;
text-align: center;
background-color: lightcoral;
color: white;
position: absolute;
right: 3px;
top: 3px;
border-radius: 50%;
cursor: pointer;
}
</style>
</head>
<body>
<div class="main">
<div class="box">
<div class="title">
我是标题
<div class="close">X</div>
</div>
</div>
</div>
<script>
// 获取main
let main = document.querySelector('.main')
//获取box
let box = document.querySelector('.box')
// offsetWidth返回元素的可见宽度
// console.log(main.offsetWidth);
// clientWidth返回元素的可用宽度
// console.log(main.clientWidth);
// offsetLeft返回元素到左外边距
// console.log(main.offsetLeft);
// 计算出左外边距
let mleft = (main.offsetWidth-main.clientWidth)/2 + main.offsetLeft
//获取title
let title = document.querySelector('.title')
//获取close
let close1 = document.querySelector('.close')
//关闭按钮点击事件
close1.onmousedown = function (e) {
// 阻止事件冒泡
// e.stopPropagation();
box.style.display = 'none'
}
let isdown = false //表示鼠标是按下
let offX = 0 //鼠标到容器的左边距
let offY = 0 //鼠标到容器的上边距
let maxLeft = main.clientWidth - box.offsetWidth //最大左右移动距离
let maxTop = main.clientHeight - box.offsetHeight //最大上下移动距离
//标题鼠标按下事件
title.onmousedown = function (e) {
// pageX,pageY 是点击处距离视口(0,0)坐标的距离
// offsetX,offsetY 是点击处距离当前容器的距离
let { offsetX, offsetY } = e
offX = offsetX
offY = offsetY
//鼠标按下
isdown = true
}
//窗口鼠标移动事件(注意:该事件给window)
window.onmousemove = function (e) {
// 阻止默认行为,防止拖动的是文字
e.preventDefault();
if (isdown) {
let { pageX, pageY } = e
let left = pageX-mleft-offX //计算出left值
let top = pageY-mleft-offY //计算出top值
// 判断left值
if(left<0) left = 0
else if(left>maxLeft) left = maxLeft
// 判断top值
if(top<0) top = 0
else if(top>maxTop) top = maxTop
box.style.left = left +'px'
box.style.top = top +'px'
}
}
//窗口鼠标弹起事件(注意:该事件给window)
window.onmouseup = function () {
//鼠标弹起
isdown = false
}
//窗口失去焦点事件(注意:该事件给window)
window.onblur = function(){
//鼠标弹起
isdown = false
}
</script>
</body>
</html>
网页显示为:
(2).右键菜单
e.target=>获取具体的元素
e.preventDefault()=>阻止默认行为 比如:阻止超链接跳转,阻止右键点击事件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>右键菜单</title>
<style>
*{
margin: 0;
padding: 0;
list-style: none;
}
.main{
width: 500px;
height: 500px;
border: 10px solid red;
margin: 10px;
position: relative;
overflow: hidden;
}
.menu{
width: 100px;
background-color: lightblue;
text-align: center;
position: absolute;
/* 隐藏并占空间 */
visibility: hidden;
}
.menu li{
line-height: 24px;
font-size: 14px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="main">
<ul class="menu">
<li>添加学生</li>
<li>查询学生</li>
<li>修改学生</li>
<li>删除学生</li>
</ul>
</div>
<script>
let main = document.querySelector('.main')
let menu = document.querySelector('.menu')
// 算出菜单的最大left
let maxLeft = main.clientWidth - menu.offsetWidth
console.log(maxLeft);
// 算出菜单的最大top
let maxTop = main.clientHeight - menu.offsetHeight
// 容器的右键点击事件
main.oncontextmenu = function(e){
//获取鼠标指针容器里面的位置
let {offsetX,offsetY} = e
// 阻止默认行为
e.preventDefault();
menu.style.visibility = 'visible'
//left不能越界
if(offsetX>maxLeft) offsetX = maxLeft
//top不能越界
if(offsetY>maxTop) offsetY = maxTop
menu.style.left = offsetX+'px'
menu.style.top = offsetY+'px'
}
// 容器的点击事件
main.onclick = function(){
menu.style.visibility = 'hidden'
}
//给所有的li注册点击事件
document.querySelectorAll('li').forEach(r=>{
r.onclick = function(){
alert('执行'+r.innerHTML)
menu.style.visibility = 'hidden'
}
})
</script>
</body>
</html>
网页显示为:
(3).选项卡
classList.remove() => 移除样式 classList.add() => 添加样式
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>选项卡效果</title>
<style>
*{
margin: 0;
padding: 0;
list-style: none;
}
.box{
width:500px;
border: 1px solid #ccc;
padding: 10px;
margin: 10px;
}
.titles{
display: flex;
}
.titles li{
border: 1px solid #ccc;
padding: 2px 10px;
margin-right: 4px;
cursor: pointer;
}
.titles li.active{
background-color: lightcoral;
color: white;
}
.contents{
margin-top: 5px;
border: 1px solid #ccc;
padding: 5px;
}
.contents li{
display: none;
}
.contents li.show{
display: block;
}
</style>
</head>
<body>
<div class="box">
<ul class="titles">
<li class="active">奔驰</li>
<li>宝马</li>
<li>奥迪</li>
<li>大众</li>
</ul>
<ul class="contents">
<li class="show">
梅赛德斯-奔驰(Mercedes-Benz)是世界闻名的豪华汽车品牌。1886年1月,
卡尔·本茨发明了世界上第一辆三轮汽车,获得专利(专利号:DRP 37435 [1] ),
被誉为“汽车的发明者”。与此同时,奔驰的另一位创始人戈特利布·戴姆勒发明了世界上第一辆四轮汽车。
</li>
<li>
宝马(BMW),中文全称为巴伐利亚发动机制造厂股份有限公司,德国汽车品牌,
宝马的车系有i、X、Z、纯数字4个车型,1、2、3、4、5、6、7、8等几个系列,
还有在各系基础上进行改进的M系(宝马官方的高性能改装部门),宝马公司创建于1916年,
总部设在德国巴伐利亚州慕尼黑,BMW的蓝白标志宝马总部所在地巴伐利亚州州旗的颜色
</li>
<li>
德国豪华汽车品牌,其标志为四个圆环相扣。现为德国大众汽车公司的子公司。
2018年12月20日,2018世界品牌500强排行榜发布,奥迪位列51位。 [2]
2019年10月,Interbrand发布的全球品牌百强榜排名42。
</li>
<li>
大众汽车(德语:Volkswagen)是一家总部位于德国沃尔夫斯堡的汽车制造公司,
也是世界四大汽车生产商之一的大众集团的核心企业。
2019年位居《财富》世界500强第9位。
</li>
</ul>
</div>
<script>
// 获取所有的titles
let titles = document.querySelectorAll('.titles li')
// 获取所有的contents
let contents = document.querySelectorAll('.contents li')
// titles注册点击事件
titles.forEach((r,i)=>{
r.onclick = function(){
//移除当前高亮样式
document.querySelector('.titles li.active').classList.remove('active')
//切换高亮
r.classList.add('active')
//隐藏当前显示内容
document.querySelector('.contents li.show').classList.remove('show')
//切换显示
contents[i].classList.add('show')
}
})
</script>
</body>
</html>
网页显示为:
2. 键盘事件
onkeydown => 按键按下事件 onkeypress => 按键产生字符事件
onkeyup =>按键弹起事件e.keyCode => 返回按键码
注意:注册事件时要加on,触发时不需要on
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>键盘事件</title>
</head>
<body>
<div>
<span>请输入搜索内容:</span>
<input type="text" id="txt">
<button id="btn">搜索</button>
</div>
<script>
// 获取文本框
let txt = document.querySelector('#txt')
// 获取按钮
let btn = document.querySelector('#btn')
//搜索按钮注册点击事件
btn.onclick = function(){
alert('正在搜索'+txt.value)
}
// 键盘按下事件
txt.onkeydown = function(){
console.log('键盘按下');
}
// 键盘产生字符
txt.onkeypress = function(){
console.log('按键产生字符');
}
// 键盘弹起事件
txt.onkeyup = function(e){
console.log('键盘弹起');
//获取键盘编码
let {keyCode} = e
//判断是否是回车键
if(keyCode===13){
// onclick属性用于注册事件
// click()方法用于执行事件
btn.click()
}
}
</script>
</body>
</html>
网页与控制台显示为:
(1).打字游戏
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>打字游戏</title>
<style>
* {
margin: 0;
padding: 0;
list-style: none;
}
.content {
width: 800px;
height: 600px;
background-color: black;
margin: 0 auto;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
overflow: hidden;
}
.content .zm {
width: 30px;
height: 30px;
line-height: 30px;
background-color: chartreuse;
color: white;
text-align: center;
position: absolute;
}
.msg {
position: absolute;
left: 50%;
top: 50%;
width: 400px;
height: 200px;
line-height: 200px;
text-align: center;
transform: translate(-50%, -50%);
background-color: thistle;
font-size: 22px;
color: blue;
}
</style>
</head>
<body>
<div class="content">
<div class="msg">
按回车键开始/空格暂停/ESC重新开始
</div>
</div>
<script>
//定义一个字母文本
let zmtxts = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
//获取元素
let content = document.querySelector(".content")
//定义一个创建颜色的方法
function $color() {
let color = "#"
// 定义颜色字符串
let str = "0123456789ABCDEF"
for (let i = 0; i < 6; i++) {
color += str[Math.floor(Math.random() * 16)]
}
return color
}
//定义两个全局变量并赋值为空方便后面清除定时器
let time1 = null
let time2 = null
//定义创建字母方块的方法
function $craete() {
// 该定时器生成字母
time1 = setInterval(() => {
// 创建一个字母元素
let zm = document.createElement("div")
// 设置字母文本
zm.innerHTML = zmtxts[Math.floor(Math.random() * 26)]
// 设置字母样式
zm.className = "zm"
// 设置字母方块在盒子里面的左边距
zm.style.left = Math.random() * 770 + "px"
zm.style.backgroundColor = $color()
// 将字符添加到容器中
content.appendChild(zm)
}, 1000);
}
//定义移动字母方块的方法
function $move() {
// 该定位器让字符往下掉
time2 = setInterval(() => {
// 获取所有的字母
let zms = document.querySelectorAll(".zm")
// 让所有的字母往下掉
zms.forEach(zm => {
// 重新设置字母的top
let top = zm.offsetTop
top = top + 10
zm.style.top = top + "px"
// 判断字母的top值如果大于容器的高度
if (top > content.offsetHeight) {
//删除自己
zm.remove()
}
})
}, 300);
}
// 给window注册键盘弹起事件
onkeyup = function (e) {
//当按下enter键执行
if (e.keyCode === 13) {
// 如果定时器是空,开启定时器
if (time1 === null && time2 === null) {
$craete()
$move()
document.querySelector(".msg").style.display = "none"
}
}
//当按下空格键执行
else if (e.keyCode === 32) {
clearInterval(time1)
time1 = null
clearInterval(time2)
time2 = null
document.querySelector(".msg").style.display = "block"
}
//当按下ESC键执行
else if (e.keyCode === 27) {
//清除定时器
clearInterval(time1)
time1 = null
clearInterval(time2)
time2 = null,
//清除所有的字母
[...document.querySelectorAll(".zm")].forEach(zm => zm.remove())
document.querySelector(".msg").style.display = "block"
}
//在开启状态下才能消除元素
if (time1 && time2) {
[...document.querySelectorAll(".zm")].find(zm => zm.innerHTML === e.key.toUpperCase()).remove()
}
}
</script>
</body>
</html>
(2).贪吃蛇
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>贪吃蛇游戏</title>
<style>
* {
margin: 0;
padding: 0;
list-style: none;
}
.content {
width: 800px;
height: 600px;
background: linear-gradient(to top, rgba(46, 199, 219, 0.438), rgba(0, 0, 255, 0.555), rgba(223, 93, 115, 0.562));
margin: 0 auto;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
overflow: hidden;
}
.content .mine {
width: 30px;
height: 30px;
background-color: red;
position: absolute;
display: none;
}
.content .key {
position: absolute;
width: 300px;
height: 200px;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: white;
font-weight: bold;
font-size: 12px;
background: radial-gradient(rgba(211, 76, 76, 0.541), rgba(66, 66, 219, 0.685), rgba(27, 18, 20, 0.459));
}
.content .key .title {
position: absolute;
top: 30px;
left: 100px;
color: red;
}
.sw {
width: 30px;
height: 30px;
position: absolute;
background-color: burlywood;
}
.count {
width: 160px;
height: 30px;
line-height: 30px;
position: absolute;
right: 0px;
top: 0px;
color: red;
text-align: center;
}
.s {
position: absolute;
left: 50%;
top: 50%;
width: 100px;
height: 100px;
transform: translate(-50%, -50%);
}
.a {
margin: 10px 0;
text-align: center;
border: 1px solid rgb(214, 196, 196);
color: blue;
background-color: white;
}
.btn {
width: 100px;
height: 20px;
color: blue;
font-size: 12px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="content"></div>
<script>
//定义一个创建元素的方法
function $c(tagName) {
return document.createElement(tagName)
}
//创建本身以及定位自身位置
let content = document.querySelector(".content")
let mine = $c("div")
let key = $c("div")
let list = $c("ul")
let start = $c("li")
let btn1 = $c("button")
let bspeed = $c("li")
let pause = $c("li")
let restart = $c("li")
let btn2 = $c("button")
let title = $c("h3")
let count = $c("div")
mine.className = "mine"
key.className = "key"
title.className = "title"
count.className = "count"
list.className = "s"
start.className = "a"
btn1.className = "btn"
btn2.className = "btn"
bspeed.className = "a"
pause.className = "a"
restart.className = "a"
title.innerHTML = "欢迎来到贪吃蛇"
btn1.innerHTML = "按enter开始"
bspeed.innerHTML = "按空格切换速度"
pause.innerHTML = "按ESC暂停"
btn2.innerHTML = "按shift重新开始"
content.appendChild(mine)
content.appendChild(key)
content.appendChild(count)
list.appendChild(start)
list.appendChild(bspeed)
list.appendChild(pause)
list.appendChild(restart)
key.appendChild(title)
key.appendChild(list)
start.appendChild(btn1)
restart.appendChild(btn2)
//设置本身初始位置在中心
let maxLeft = content.offsetWidth - 30
let maxTop = content.offsetHeight - 30
mine.style.left = maxLeft / 2 + "px"
mine.style.top = maxTop / 2 + "px"
//定义本身初始方向向左
let direction = "L"
//定义本身速度为100(注意此100为100ms即为本身移动定时器的时间)
let speed = 100
//通过键盘控制方向和速度
onkeyup = function (e) {
// A:65 W:87 D:68 S:83
//左:37 上:38 右:39 下:40
switch (e.keyCode) {
case 37:
direction = "L"
break;
case 65:
direction = "L"
break;
case 38:
direction = "T"
break;
case 87:
direction = "T"
break;
case 39:
direction = "R"
break;
case 68:
direction = "R"
break;
case 83:
direction = "B"
break;
case 40:
direction = "B"
break;
case 32:
speed = (speed === 100) ? 50 : 100
clear()
move()
$cteateFood()
$checkCrash()
$gameOver()
break;
case 27:
clear()
document.querySelector(".key").style.display = "block"
break;
case 13:
if (time1 === null) {
move()
$cteateFood()
$checkCrash()
$gameOver()
document.querySelector(".key").style.display = "none"
}
break;
case 16:
window.location.reload()
break;
}
}
let time1 = null
//定义一个本身移动的方法
function move() {
time1 = setInterval(() => {
let mine = document.querySelector(".mine")
mine.style.display = "block"
let left = mine.offsetLeft
let top = mine.offsetTop
switch (direction) {
case "L":
left = left - 15
break;
case "T":
top = top - 15
break;
case "R":
left = left + 15
break;
case "B":
top = top + 15
break;
}
mine.style.left = left + "px"
mine.style.top = top + "px"
}, speed);
}
//定义颜色方法
function $color() {
let color = "#"
let str = "0123456789ABCDEF"
for (let i = 0; i < 6; i++) {
color += str[Math.floor(Math.random() * 16)]
}
return color
}
let time2 = null
//定义生成食物的方法
function $cteateFood() {
time2 = setInterval(() => {
let sw = $c("div")
sw.className = "sw"
sw.style.backgroundColor = $color()
document.querySelector(".content").appendChild(sw)
let left = content.offsetWidth - 30
let top = content.offsetHeight - 30
sw.style.left = Math.floor(Math.random() * left) + "px"
sw.style.top = Math.floor(Math.random() * top) + "px"
}, 1000);
}
//定义两个物体碰撞的方法
function $twoDomCrash(dom1, dom2) {
let left1 = dom1.offsetLeft
let top1 = dom1.offsetTop
let right1 = dom1.offsetWidth + left1
let bottom1 = dom1.offsetHeight + top1
let left2 = dom2.offsetLeft
let top2 = dom2.offsetTop
let right2 = dom2.offsetWidth + left2
let bottom2 = dom2.offsetHeight + top2
if (left1 < left2 && left2 < right1 && (top1 < top2 && top2 < bottom1 || top1 < bottom2 && bottom2 < bottom1)) {
return true
} else if (left1 < right2 && right2 < right1 && (top1 < top2 && top2 < bottom1 || top1 < bottom2 && bottom2 < bottom1)) {
return true
} else if (left2 < left1 && left1 < right2 && (top2 < top1 && top1 < bottom2 || top2 < bottom1 && bottom1 < bottom2)) {
return true
} else if (left2 < right1 && right1 < right2 && (top2 < top1 && top1 < bottom2 || top2 < bottom1 && bottom1 < bottom2)) {
return true
} else {
return false
}
}
let time3 = null
//检查是否碰撞的方法
function $checkCrash() {
time3 = setInterval(() => {
[...document.querySelectorAll(".sw")].find(sw => {
if ($twoDomCrash(sw, mine)) {
sw.remove()
}
})
}, 10);
}
let time4 = null
//判断游戏结束的方法
function $gameOver() {
time4 = setInterval(() => {
let count = document.querySelector(".count")
let swcount = document.querySelectorAll(".sw").length
count.innerHTML = "现在有" + swcount + "个食物"
let left = mine.offsetLeft
let top = mine.offsetTop
if (swcount > 20) {
clear()
alert("食物过多")
document.querySelectorAll(".sw").forEach(sw => sw.remove())
document.querySelector(".key").style.display = "block"
count.innerHTML = "现在有0个食物"
} else if (left < 0 || left > maxLeft || top < 0 || top > maxTop) {
clear()
alert("你已撞墙")
document.querySelectorAll(".sw").forEach(sw => sw.remove())
document.querySelector(".key").style.display = "block"
count.innerHTML = "现在有0个食物"
}
}, 10);
}
//清除定时器的方法
function clear() {
clearInterval(time1)
time1 = null
clearInterval(time2)
time2 = null
clearInterval(time3)
time3 = null
clearInterval(time4)
time4 = null
}
[...document.querySelectorAll(".btn")][0].onclick = function () {
if (time1 === null) {
move()
$cteateFood()
$checkCrash()
$gameOver()
document.querySelector(".key").style.display = "none"
}
},
[...document.querySelectorAll(".btn")][1].onclick = function () {
window.location.reload()
}
</script>
</body>
</html>