在阿里巴巴和四十大盗的故事中,阿里巴巴因为无意中知道了开门的咒语人生发生了翻天覆地的变化,四十大盗也因为咒语的泄露最终丧命。芝麻开门的咒语作为重要的信息推动着故事的发展。下面由你来为门设置这道机关,输入芝麻开门后才能放行。
本题已经内置了初始代码,打开实验环境,目录结构如下:
├── index.css
├── index.html
└── index.js
选中 index.html
右键启动 Web Server 服务(Open with Live Server),让项目运行起来。
接着,打开环境右侧的【Web 服务】,就可以在浏览器中看到如下效果:
点击页面上的“点击弹出对话框,输入咒语”按钮,无任何反应。
找到
index.js
文件中的mPrompt
函数,完成函数中的 TODO 部分。
mPrompt
函数,mPrompt
调用后页面显示对话框。mPrompt
函数必须返回一个 promise
对象。promise
返回成功,promise
成功的值为输入的值。promise
返回失败,失败的值为 false
。完成后,最终页面效果如下:
const incantations = "芝麻开门";
function init(el) {
document.querySelector(".wrapper .btn").addEventListener("click", () => {
mPrompt()
.then((res) => {
if (res === incantations) {
document
.querySelectorAll("#door .doors")[0]
.classList.add("door-left");
document
.querySelectorAll("#door .doors")[1]
.classList.add("door-right");
}
})
.catch((err) => {
console.log(err);
});
});
}
/**
* @description: 调用函数,开启弹窗,记录输入框的内容,并通过 promise 异步返回输入框中的内容
* @return {Promise}
*/
function mPrompt() {
// 弹窗必须使用以下结构 template 保存的是弹窗的结构字符串,可以先转化为 DOM 再通过 appendChild 方式插入到 body 中
const template = `
<div class="modal">
<div class="message-box">
<div class="message-header">请输入咒语</div>
<div class="message-body">
<input type="text">
</div>
<div class="message-footer">
<button class="btn btn-small" id='cancel'>取消</button>
<button class="btn btn-small btn-primary" id='confirm'>确定</button>
</div>
</div>
</div>
`;
const div = document.createElement("div");
// TODO:待补充代码
div.innerHTML = template;
document.body.appendChild(div);
return new Promise((resolve,reject)=>{
const input = div.querySelector('input');
const cancelBtn = div.querySelector('#cancel');
const confirmBtn = div.querySelector('#confirm');
cancelBtn.addEventListener('click',()=>{
document.body.removeChild(div);
reject(false);
});
confirmBtn.addEventListener('click',()=>{
const inputValue = input.value;
document.body.removeChild(div);
resolve(inputValue);
});
});
}
<!DOCTYPE html>
<html lang="zh-CN">
<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>
<link rel="stylesheet" href="./index.css" />
<script src="./index.js"></script>
</head>
<body>
<div class="wrapper">
<button class="btn btn-large">点击弹出对话框,输入咒语</button>
</div>
<div id="door">
<div class="doors"></div>
<div class="doors"></div>
</div>
<script>
init();
</script>
</body>
</html>
1. 文档声明与头部设置:
<!DOCTYPE html>
声明文档类型为 HTML5。<html lang="zh - CN">
设置页面语言为中文(中国)。<head>
标签中: <meta charset="UTF - 8" />
设置字符编码为 UTF - 8,确保页面能正确显示各种字符。<meta http - equiv="X - UA - Compatible" content="IE=edge" />
让页面在 Internet Explorer 中以最新版本的渲染引擎显示。<meta name="viewport" content="width=device - width, initial - scale=1.0" />
使页面在不同设备上能正确显示,宽度根据设备屏幕宽度自适应。<title>芝麻开门</title>
设置页面标题为 “芝麻开门”。<link rel="stylesheet" href="./index.css" />
引入外部 CSS 文件 index.css
来设置页面样式。<script src="./index.js"></script>
引入外部 JavaScript 文件 index.js
,用于实现页面交互逻辑。2. 页面主体结构:
<body>
标签内: <div class="wrapper">
包裹一个按钮,.wrapper
类用于设置按钮的布局,使其在页面中水平居中显示。<button class="btn btn - large">点击弹出对话框,输入咒语</button>
定义了一个按钮,按钮上显示 “点击弹出对话框,输入咒语”,btn
和 btn - large
类用于设置按钮的样式。<div id="door">
定义了门的容器,内部有两个 .doors
元素,用于显示门的状态。<div class="doors"></div>
表示门的一部分,通过 CSS 样式设置其外观和动画效果。<script>init();</script>
在页面加载后立即调用 init
函数,该函数在 index.js
中定义,用于初始化按钮的点击事件。* {
margin: 0;
padding: 0;
}
.wrapper {
margin: 20px auto;
width: 220px;
}
#door {
display: flex;
justify-content: center;
}
.doors {
height: 150px;
width: 100px;
border: 2px solid #111;
transition: all 1s;
}
.doors:nth-child(1) {
border-right: 1px solid #111;
}
.doors:nth-child(2) {
border-left: 1px solid #111;
}
.door-left {
transform: translate(-20px, 0px) rotateY(50deg);
}
.door-right {
transform: translate(20px, 0px) rotateY(50deg);
}
.btn {
outline: none;
cursor: pointer;
background: #fff;
border: 1px solid #dcdfe6;
color: #666;
border-radius: 4px;
}
.btn-large {
padding: 12px 20px;
}
.btn-primary {
color: #fff;
background-color: #409eff;
border-color: #409eff;
}
.btn-small {
padding: 6px 10px;
}
.btn-success {
color: #fff;
background-color: #67c23a;
border-color: #67c23a;
}
.btn-info {
color: #fff;
background-color: #909399;
border-color: #909399;
}
.btn-warning {
color: #fff;
background-color: #e6a23c;
border-color: #e6a23c;
}
.btn-danger {
color: #fff;
background-color: #f56c6c;
border-color: #f56c6c;
}
.modal {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: #909090;
opacity: 0.8;
}
.message-box {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
width: 350px;
padding: 10px;
opacity: 1;
}
.message-header {
padding: 10px 0;
text-align: center;
}
.message-body {
padding: 15px 0;
width: 100%;
}
input {
-webkit-appearance: none;
background-color: #fff;
background-image: none;
border-radius: 4px;
border: 1px solid #dcdfe6;
box-sizing: border-box;
color: #606266;
display: inline-block;
font-size: inherit;
height: 40px;
line-height: 40px;
outline: none;
padding: 0 15px;
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
width: 100%;
}
.message-footer {
display: flex;
justify-content: flex-end;
}
.message-footer button {
margin-right: 10px;
}
1. 全局样式:
* { margin: 0; padding: 0; }
重置所有元素的内外边距为 0,消除浏览器默认样式的影响。2. 按钮和容器样式:
.wrapper
类设置了按钮容器的外边距为 20px 自动,宽度为 220px,使按钮在页面中水平居中显示。.btn
类设置了按钮的通用样式,包括轮廓、光标样式、背景颜色、边框、文本颜色和边框半径。btn - *
类(如 btn - large
、btn - primary
等)在 .btn
基础上进一步设置按钮的大小、背景颜色等不同样式。3. 门的样式:
#door
类设置了门容器的显示方式为弹性布局,并使其内部元素水平居中。.doors
类设置了门的高度、宽度、边框以及过渡效果,用于实现门打开的动画。.doors:nth - child(1)
和 .doors:nth - child(2)
分别设置了两扇门的左右边框样式。.door - left
和 .door - right
类通过 transform
属性设置门打开时的位置和旋转角度,实现开门动画。4. 弹窗样式:
.modal
类设置了弹窗背景的样式,包括绝对定位覆盖整个页面、背景颜色和透明度。.message - box
类设置了弹窗内容框的样式,包括绝对定位在页面中心、背景颜色、宽度和内边距。.message - header
、.message - body
和 .message - footer
类分别设置了弹窗头部、主体和底部的样式,如文本居中、内边距和布局方式。input
选择器设置了输入框的样式,包括外观、背景、边框、颜色等。.message - footer button
选择器设置了弹窗底部按钮的外边距。const incantations = "芝麻开门";
function init(el) {
document.querySelector(".wrapper .btn").addEventListener("click", () => {
mPrompt()
.then((res) => {
if (res === incantations) {
document
.querySelectorAll("#door .doors")[0]
.classList.add("door-left");
document
.querySelectorAll("#door .doors")[1]
.classList.add("door-right");
}
})
.catch((err) => {
console.log(err);
});
});
}
/**
* @description: 调用函数,开启弹窗,记录输入框的内容,并通过 promise 异步返回输入框中的内容
* @return {Promise}
*/
function mPrompt() {
// 弹窗必须使用以下结构 template 保存的是弹窗的结构字符串,可以先转化为 DOM 再通过 appendChild 方式插入到 body 中
const template = `
<div class="modal">
<div class="message-box">
<div class="message-header">请输入咒语</div>
<div class="message-body">
<input type="text">
</div>
<div class="message-footer">
<button class="btn btn-small" id='cancel'>取消</button>
<button class="btn btn-small btn-primary" id='confirm'>确定</button>
</div>
</div>
</div>
`;
const div = document.createElement("div");
div.innerHTML = template;
// 将弹窗添加到 body 中
document.body.appendChild(div);
return new Promise((resolve, reject) => {
// 获取输入框、取消按钮和确定按钮
const input = div.querySelector('input');
const cancelBtn = div.querySelector('#cancel');
const confirmBtn = div.querySelector('#confirm');
// 取消按钮点击事件处理
cancelBtn.addEventListener('click', () => {
// 移除弹窗
document.body.removeChild(div);
// 拒绝 promise,返回 false
reject(false);
});
// 确定按钮点击事件处理
confirmBtn.addEventListener('click', () => {
// 获取输入框的值
const inputValue = input.value;
// 移除弹窗
document.body.removeChild(div);
// 解决 promise,返回输入框的值
resolve(inputValue);
});
});
}
1. 常量与初始化函数:
const incantations = "芝麻开门";
定义了一个常量 incantations
,其值为 “芝麻开门”,用于与用户输入进行比较。function init(el) {... }
定义了初始化函数 init
,它为按钮添加点击事件监听器。当按钮被点击时,调用 mPrompt
函数,并根据返回的 Promise 结果来决定是否打开门。2. 弹窗函数:
function mPrompt() {... }
定义了创建和管理弹窗的函数。div
元素中。div
元素添加到 body
中显示弹窗。Promise
对象,在 Promise
的执行器函数中: Promise
,返回 false
。Promise
,返回输入框的值。四、工作流程 ▶️ 1. 页面加载:
incantations
常量、init
函数和 mPrompt
函数。init()
函数,为按钮添加点击事件监听器。2. 按钮点击:
init
函数中绑定的点击事件,调用 mPrompt
函数。3. 弹窗显示与交互:
mPrompt
函数创建弹窗的 DOM 结构并添加到 body
中,显示弹窗。mPrompt
函数中的取消按钮点击事件监听器会移除弹窗,并拒绝 Promise
,返回 false
。init
函数中 mPrompt
返回的 Promise 的 catch
块会捕获这个错误并在控制台打印错误信息。mPrompt
函数中的确定按钮点击事件监听器会获取输入框的值,移除弹窗,并解决 Promise
,返回输入框的值。4. 门的打开判断:
init
函数中 mPrompt
返回的 Promise 的 then
块接收输入框的值。incantations
常量(“芝麻开门”)进行比较。div
元素分别添加 door - left
和 door - right
类,触发 CSS 动画,实现门打开的效果。