20个前端面试实操题,你能手敲出来吗?
在实际编码环境中完成这些题目,例如在CodePen、JSFiddle等在线平台上进行练习。在完成每个题目后,总结自己的实现思路和遇到的问题,有助于加深理解。
以下是20个前端面试实操题,涵盖HTML、CSS、JavaScript、前端框架(如React和Vue)以及性能优化等多个方面:
一、HTML/CSS
1.实现响应式布局
创建一个网页,包含一个顶部导航栏、一个主内容区域和一个页脚,要求在不同屏幕宽度上都能良好显示。
1.效果图
下面是一个实现响应式布局的示例代码,通过使用HTML和CSS来设置不同屏幕尺寸下的布局。
2.HTML 代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<!-- 设置视口以实现响应式 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>响应式布局示例</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<h1>响应式布局示例</h1>
<nav>
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">关于我们</a></li>
<li><a href="#">服务</a></li>
<li><a href="#">联系方式</a></li>
</ul>
</nav>
</header>
<main>
<section>
<h2>主要内容区域</h2>
<p>这里的内容将在不同屏幕尺寸下自动调整布局。</p>
</section>
<aside>
<h2>侧边栏</h2>
<p>侧边栏内容</p>
</aside>
</main>
<footer>
<p>© 2023 响应式布局示例</p>
</footer>
</body>
</html>
3.CSS 代码 (styles.css)
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
line-height: 1.6;
}
header {
background: #35424a;
color: #ffffff;
padding: 10px 0;
text-align: center;
}
nav {
background: #e8491d;
}
nav ul {
list-style: none;
padding: 0;
}
nav ul li {
display: inline;
margin-right: 20px;
}
nav ul li a {
color: #ffffff;
text-decoration: none;
}
main {
display: flex;
flex-wrap: wrap;
padding: 20px;
}
section {
flex: 3;
padding: 10px;
background: #f4f4f4;
margin-right: 10px;
}
aside {
flex: 1;
padding: 10px;
background: #e7e7e7;
}
footer {
text-align: center;
padding: 10px 0;
background: #35424a;
color: #ffffff;
}
/* 响应式样式 */
@media (max-width: 768px) {
nav ul li {
display: block;
margin: 10px 0;
}
main {
flex-direction: column;
}
section, aside {
margin-right: 0;
margin-bottom: 10px;
}
}
4.代码说明
- 1.HTML 结构
包含头部(header)、导航(nav)、主内容区域(main)、内容区(section)、侧边栏(aside),和底部(footer)。
- 2.CSS 样式
- 使用
box-sizing
属性使得元素的总宽度包含 padding 和 border。 - 设置了基础样式,包括背景色、字体颜色、间距等。
- 在
main
中使用 Flexbox 来实现主内容区与侧边栏的布局,支持灵活的调整。 - 媒体查询(
@media
)用于调整移动设备上的布局,使得导航项垂直排列,并将主内容和侧边栏改为竖直排列。
你可以将以上代码放入HTML文件和CSS文件中,打开HTML文件并调整窗口大小,即可查看响应式效果。
2.CSS Grid 布局
使用CSS Grid实现一个简单的照片墙,要求在不同大小的屏幕上都有极好的排列效果。
1.效果图
1920x1080
1024x768
768x1024
2.HTML 代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>照片墙示例</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<h1>照片墙</h1>
</header>
<main class="photo-grid">
<div class="photo-item"><img src="photo1.jpg" alt="照片1"></div>
<div class="photo-item"><img src="photo2.jpg" alt="照片2"></div>
<div class="photo-item"><img src="photo3.jpg" alt="照片3"></div>
<div class="photo-item"><img src="photo4.jpg" alt="照片4"></div>
<div class="photo-item"><img src="photo5.jpg" alt="照片5"></div>
<div class="photo-item"><img src="photo6.jpg" alt="照片6"></div>
</main>
<footer>
<p>© 2023 照片墙示例</p>
</footer>
</body>
</html>
3.CSS 代码 (styles.css)
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
}
header {
text-align: center;
background: #35424a;
color: #ffffff;
padding: 20px 0;
}
main.photo-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* 创建自适应网格 */
gap: 10px; /* 列间距 */
padding: 20px;
}
.photo-item img {
width: 100%; /* 使图像适应父容器 */
border-radius: 8px; /* 圆角 */
display: block; /* 去掉底部空隙 */
}
footer {
text-align: center;
padding: 20px 0;
background: #35424a;
color: #ffffff;
}
4.代码说明
- 1.HTML 结构:
- 包含头部(header)、主要的照片墙区域(main)以及底部(footer)。
- 每个照片项使用一个
div
元素封装图片,方便使用CSS进行样式处理。
- 2.CSS 样式:
- 使用 CSS Grid 创建响应式网格布局,
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr))
使得每一列的最小宽度为 200px,且根据屏幕大小自动填充。 - 设置了元素的间距(gap)和padding,使得照片之间有足够的空隙。
- 图像设为
width: 100%
,确保它们能够适应各自的容器。
5.使用说明
- 请在照片墙中的
src
属性中填写正确的图像路径,确保图片能够正常显示。 - 将以上代码放入HTML文件和CSS文件中并在浏览器中打开即可查看照片墙效果。
- 调整浏览器宽度可以看到照片墙的响应式布局效果。
3.自定义按钮样式
创建一个自定义按钮,并在不同状态(正常、悬停、点击)下应用不同的样式,使用CSS过渡效果增强交互。
1.效果图
2.HTML 代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>自定义按钮示例</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<button class="custom-button">点击我</button>
</body>
</html>
3.CSS 代码 (styles.css)
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f4f4f4;
font-family: Arial, sans-serif;
}
.custom-button {
background-color: #3498db; /* 正常状态背景色 */
color: white; /* 字体颜色 */
border: none; /* 去掉边框 */
padding: 15px 30px; /* 内边距 */
border-radius: 5px; /* 圆角 */
font-size: 16px; /* 字体大小 */
cursor: pointer; /* 鼠标指针 */
transition: background-color 0.3s ease, transform 0.1s ease; /* 设置过渡效果 */
}
/* 悬停状态 */
.custom-button:hover {
background-color: #2980b9; /* 悬停状态背景色 */
}
/* 点击状态 */
.custom-button:active {
transform: scale(0.95); /* 点击状态缩放效果 */
background-color: #1c6691; /* 点击状态背景色 */
}
4.代码说明
- 1.HTML 结构:
- 创建了一个按钮元素,使用了
class
属性来应用CSS样式。
- 2.CSS 样式:
- 定义了按钮的基本样式,包括背景色、字体颜色、内边距、圆角等。
- 使用
transition
属性为按钮的背景色和缩放效果设置了过渡时间,使得效果更加平滑。 :hover
伪类用于定义鼠标悬停时的样式变化。:active
伪类用于定义按钮被点击时的样式变化,这里使用了缩放效果使得按钮在点击时稍微变小,产生“按下”的感觉。
5.使用说明
将以上HTML和CSS代码分别放入对应的文件中,并在浏览器中打开HTML文件即可查看效果。你可以将按钮的样式进一步调整,以符合你的设计需求。通过尝试不同的颜色和过渡效果,可以实现更加丰富的用户体验。
4.实现一个模态框
使用HTML和CSS创建一个模态框,并用JavaScript控制其显示和隐藏状态。
1.效果图
2.HTML 代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模态框示例</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<button id="openModal" class="open-button">打开模态框</button>
<div id="modal" class="modal">
<div class="modal-content">
<span class="close-button">×</span>
<h2>模态框标题</h2>
<p>这是一个简单的模态框示例。</p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
3.CSS 代码 (styles.css)
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.open-button {
padding: 10px 20px;
background-color: #3498db;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.open-button:hover {
background-color: #2980b9;
}
.modal {
display: none; /* 初始状态隐藏 */
position: fixed; /* 固定位置 */
z-index: 1; /* 在最上层 */
left: 0;
top: 0;
width: 100%; /* 全宽 */
height: 100%; /* 全高 */
overflow: auto; /* 允许滚动 */
background-color: rgb(0,0,0); /* 黑色背景 */
background-color: rgba(0,0,0,0.4); /* 半透明 */
}
.modal-content {
background-color: #fefefe;
margin: 15% auto; /* 在视口中垂直居中 */
padding: 20px;
border: 1px solid #888;
width: 80%; /* 宽度 */
max-width: 500px; /* 最大宽度 */
border-radius: 5px; /* 圆角 */
}
.close-button {
color: #aaa;
float: right; /* 向右浮动 */
font-size: 28px;
font-weight: bold;
}
.close-button:hover,
.close-button:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
4.JavaScript 代码 (script.js)
// 获取模态框和按钮
const modal = document.getElementById("modal");
const openModalButton = document.getElementById("openModal");
const closeButton = document.getElementsByClassName("close-button")[0];
// 当点击“打开模态框”按钮时,显示模态框
openModalButton.onclick = function() {
modal.style.display = "block";
}
// 当点击关闭按钮时,隐藏模态框
closeButton.onclick = function() {
modal.style.display = "none";
}
// 当点击模态框外部时,隐藏模态框
window.onclick = function(event) {
if (event.target === modal) {
modal.style.display = "none";
}
}
5.代码说明
-
HTML 结构:
- 包含一个按钮用于打开模态框和模态框本身,模态框内包含关闭按钮、标题和内容。
-
CSS 样式:
- 设置了模态框的基本样式,包括背景和居中效果。
.modal
类的display
属性初始设为none
,使模态框在页面加载时隐藏。
-
JavaScript 功能:
- 获取模态框、打开按钮和关闭按钮。
- 为打开按钮添加点击事件,当点击时将模态框的
display
设置为block
,使其显示。 - 为关闭按钮和模态框外部区域添加事件,使用户可以通过点击关闭模态框。
6.使用说明
将上述代码分别保存为HTML、CSS和JavaScript文件,然后在浏览器中打开HTML文件即可查看模态框效果。点击“打开模态框”按钮即可显示模态框,点击关闭按钮或模态框外部区域即可关闭模态框。
二、JavaScript
5.深拷贝和浅拷贝函数
实现两个函数,一个进行对象的深拷贝,一个进行对象的浅拷贝。要求分别处理不同层级的属性和数组。
1.浅拷贝函数
浅拷贝仅复制对象的第一层属性,如果属性是引用类型(如数组或对象),则复制的是引用。
function shallowCopy(obj) {
if (obj === null || typeof obj !== 'object') {
return obj; // 不是对象或数组,直接返回
}
const copy = Array.isArray(obj) ? [] : {}; // 判断是数组还是对象
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = obj[key]; // 仅复制第一层属性
}
}
return copy;
}
2.深拷贝函数
深拷贝会递归复制对象的所有层级属性,包括嵌套对象和数组。
function deepCopy(obj) {
if (obj === null) return null; // 处理null情况
if (typeof obj !== 'object') return obj; // 不是对象,直接返回
// 初始化返回值是数组还是对象
const copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 递归拷贝每个属性
copy[key] = deepCopy(obj[key]);
}
}
return copy;
}
3.使用示例
const original = {
number: 1,
string: "hello",
array: [1, 2, 3],
object: {
nestedNumber: 2,
nestedArray: [4, 5, 6]
}
};
// 进行浅拷贝
const shallowCopied = shallowCopy(original);
shallowCopied.array[0] = 99; // 修改数组的第一项
shallowCopied.object.nestedNumber = 100; // 修改嵌套对象中的值
console.log(original); // original.array[0]仍为1,original.object.nestedNumber仍为2
console.log(shallowCopied);
// 进行深拷贝
const deepCopied = deepCopy(original);
deepCopied.array[0] = 200; // 修改数组的第一项
deepCopied.object.nestedNumber = 300; // 修改嵌套对象中的值
console.log(original); // original数组和对象的值保持不变
console.log(deepCopied);
4.代码说明
-
浅拷贝 (
shallowCopy
):- 先检查是否为
null
或非对象,若是则直接返回值。 - 使用
Array.isArray()
来判断是数组还是对象,初始化拷贝对象。 - 只复制对象的第一层属性,若属性为引用类型,复制的是引用。
- 先检查是否为
-
深拷贝 (
deepCopy
):- 同样先检查是否为
null
。 - 如果是基本数据类型,直接返回。
- 根据属性类型初始化拷贝对象。
- 通过递归调用
deepCopy
函数来复制所有层级的属性,确保所有引用类型的值都会被完整拷贝。
- 同样先检查是否为
以上实现可以适应一般情况下的对象和数组深浅拷贝需求。
6.使用 Promise 实现异步请求
创建一个函数,通过使用Promise封装一个AJAX请求,获取数据并处理结果,支持.then()与.catch()的用法。
1.示例代码
function fetchData(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest(); // 创建新的AJAX请求
xhr.open("GET", url, true); // 初始化请求,使用GET方法
xhr.onreadystatechange = function() {
// 当请求状态改变时会调用这个函数
if (xhr.readyState === 4) { // 请求完成
if (xhr.status >= 200 && xhr.status < 300) {
// 请求成功,解析JSON数据
resolve(JSON.parse(xhr.responseText));
} else {
// 请求失败,返回错误信息
reject(new Error(`请求失败,状态码: ${xhr.status}`));
}
}
};
xhr.onerror = function() {
// 处理网络错误
reject(new Error("网络错误"));
};
xhr.send(); // 发送请求
});
}
2.使用示例
const apiUrl = "https://jsonplaceholder.typicode.com/posts/1"; // 示例API
fetchData(apiUrl)
.then(data => {
console.log("获取到的数据:", data);
})
.catch(error => {
console.error("错误:", error.message);
});
3.代码说明
-
fetchData(url)
:- 接收一个URL参数,用于进行AJAX请求。
- 返回一个Promise对象,Promise构造函数的作用是封装异步操作。
-
XHR设置:
- 使用
XMLHttpRequest
创建一个新的AJAX请求。 - 调用
open
方法来初始化请求,指定请求类型(GET)和URL。 - 使用
onreadystatechange
属性设置响应处理函数。 - 当请求完成 (
readyState === 4
)且状态码在200到299之间时,解析返回的JSON数据并解决Promise(resolve
)。 - 如果请求失败,使用
reject
返回错误信息。
- 使用
-
错误处理:
- 使用
onerror
来处理潜在的网络错误,并将错误信息通过reject
返回。
- 使用
-
使用示例:
- 调用
fetchData
函数并使用.then()
处理成功的结果,使用.catch()
处理错误情况。
- 调用
4.注意
- 上述
apiUrl
是一个示例API,实际使用时请根据需要替换为有效的API接口。 - 如果希望处理其他HTTP方法(如POST),可以对
fetchData
函数进行修改,增加参数来支持不同的方法和请求体。
7.防抖与节流函数
实现防抖(debounce)和节流(throttle)函数,并说明它们的使用场景。
1.防抖(Debounce)函数
防抖的意思是在事件触发后,延迟一段时间再执行函数。如果在等待时间内又触发了事件,则重新计时。常用于处理用户输入、按钮点击等场景,以减少执行次数。
示例代码
function debounce(func, delay) {
let timer;
return function(...args) {
const context = this;
clearTimeout(timer); // 清除上一次的定时器
timer = setTimeout(() => {
func.apply(context, args); // 在最后一次事件触发后执行
}, delay);
};
}
2.节流(Throttle)函数
节流的意思是,在一定时间内只允许执行一次函数。即使在这段时间内事件被多次触发,也只会执行一次。常用于处理高频率触发的事件,如滚动、窗口缩放等,以降低事件处理频率。
示例代码
function throttle(func, delay) {
let lastTime = 0; // 记录上次执行时间
return function(...args) {
const context = this;
const now = Date.now();
if (now - lastTime >= delay) { // 如果到达了规定的时间间隔
lastTime = now;
func.apply(context, args); // 执行函数
}
};
}
3.使用场景
-
防抖(Debounce)使用场景:
- 输入框实时搜索:用户输入时防抖,只有在停止输入后的一段时间内才发送请求,提高性能。
- 窗口调整大小事件:在用户调整窗口大小时防抖,避免多次触发与调整窗口相关的逻辑。
- 提交表单:防止多次提交表单或重复点击按钮。
-
节流(Throttle)使用场景:
- 滚动事件:在滚动页面时,每隔一定时间执行一次事件处理,避免过于频繁地执行。
- 拖拽操作:在拖拽事件中节流,确保在拖拽行为中只执行特定的逻辑。
- 持续请求:在某些需要定时请求的场景下,使用节流来限制请求频率。
4.使用示例
// 防抖示例
const inputField = document.getElementById('search');
inputField.addEventListener('input', debounce(function() {
console.log('发送请求:', this.value);
}, 300));
// 节流示例
const button = document.getElementById('submit');
button.addEventListener('click', throttle(function() {
console.log('按钮被点击');
}, 1000));
以上代码展示了如何在输入框和按钮上实现防抖和节流功能。根据具体需求,选择合适的技术来提高性能和用户体验。
8.简单的表单验证
在HTML中创建一个表单,使用JavaScript进行输入的验证,确保输入符合特定格式(如邮箱、手机号等),并给出即时反馈。
1.效果图
2.HTML 代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>表单验证示例</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h2>用户注册</h2>
<form id="userForm">
<div class="form-group">
<label for="email">邮箱:</label>
<input type="text" id="email" placeholder="请输入邮箱" required>
<small class="feedback" id="emailFeedback"></small>
</div>
<div class="form-group">
<label for="phone">手机号:</label>
<input type="text" id="phone" placeholder="请输入手机号" required>
<small class="feedback" id="phoneFeedback"></small>
</div>
<button type="submit">注册</button>
</form>
</div>
<script src="script.js"></script>
</body>
</html>
3.CSS 代码 (styles.css)
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
background: white;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 15px;
}
.feedback {
color: red;
font-size: 12px;
}
input {
padding: 10px;
width: 100%;
box-sizing: border-box;
}
button {
padding: 10px 15px;
background-color: #3498db;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #2980b9;
}
4.JavaScript 代码 (script.js)
document.getElementById('userForm').addEventListener('submit', function(event) {
event.preventDefault(); // 防止表单提交
const email = document.getElementById('email').value;
const phone = document.getElementById('phone').value;
let valid = true;
// 验证邮箱
const emailFeedback = document.getElementById('emailFeedback');
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // 简单的邮箱正则表达式
if (!emailPattern.test(email)) {
emailFeedback.textContent = "请输入有效的邮箱地址";
valid = false;
} else {
emailFeedback.textContent = ""; // 清除反馈
}
// 验证手机号
const phoneFeedback = document.getElementById('phoneFeedback');
const phonePattern = /^1[3-9]\d{9}$/; // 中国手机号格式
if (!phonePattern.test(phone)) {
phoneFeedback.textContent = "请输入有效的手机号";
valid = false;
} else {
phoneFeedback.textContent = ""; // 清除反馈
}
// 如果所有输入都有效,提交表单
if (valid) {
alert("表单已成功提交!");
// 这里可以进行表单提交的处理
// 例如:使用 AJAX 提交数据
}
});
5.代码说明
-
HTML结构:
- 创建了一个简单的用户注册表单,包括邮箱输入框和手机号输入框。
- 每个输入框下方有一个
<small>
元素用于显示验证反馈。
-
CSS样式:
- 设置了基本的样式,使表单美观且用户友好。
-
JavaScript功能:
- 在表单提交时,使用
event.preventDefault()
阻止默认的表单提交行为。 - 使用正则表达式对邮箱和手机号进行验证。
- 如果输入不符合格式,显示相应的错误信息;否则,清空反馈信息并显示提交成功提示。
- 在表单提交时,使用
6.使用说明
将以上代码分别保存为HTML、CSS和JavaScript文件,然后在浏览器中打开HTML文件即可查看表单验证效果。输入邮箱和手机号后,系统会即时反馈输入是否有效。
三、DOM 操作
9.动态创建列表
使用JavaScript动态创建一个待办事项列表,允许用户添加新事项并删除已完成事项。
1.效果图
2.代码
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>待办事项列表</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin: 5px 0;
}
button {
margin-left: 10px;
}
</style>
</head>
<body>
<h1>待办事项列表</h1>
<input type="text" id="new-task" placeholder="添加新事项">
<button id="add-task">添加事项</button>
<ul id="task-list"></ul>
<script>
// 获取 DOM 元素
const taskInput = document.getElementById('new-task');
const addTaskButton = document.getElementById('add-task');
const taskList = document.getElementById('task-list');
// 添加新事项
addTaskButton.addEventListener('click', function() {
const taskText = taskInput.value;
if (taskText.trim() === '') {
alert('请输入事项内容');
return;
}
const li = document.createElement('li');
li.textContent = taskText;
const deleteButton = document.createElement('button');
deleteButton.textContent = '删除';
deleteButton.addEventListener('click', function() {
taskList.removeChild(li);
});
li.appendChild(deleteButton);
taskList.appendChild(li);
taskInput.value = ''; // 清空输入框
});
// 按回车键也可以添加事项
taskInput.addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
addTaskButton.click();
}
});
</script>
</body>
</html>
3.说明
- HTML结构:创建了一个简单的输入框,用于输入待办事项,一个添加按钮和一个空的无序列表(
<ul>
)来展示待办事项。 - CSS样式:简单的样式,使得页面更美观。
- JavaScript逻辑:
- 监听添加按钮的点击事件,如果输入框不为空,则将输入的内容创建为一个新的列表项(
<li>
)。 - 每个列表项后面都有一个删除按钮,点击后可以删除该事项。
- 还添加了一个键盘事件监听,使得用户按下回车键也可以添加事项。
- 监听添加按钮的点击事件,如果输入框不为空,则将输入的内容创建为一个新的列表项(
10.图片懒加载
实现图片懒加载功能,使得页面初始加载时只加载可视区域的图片,其他图片在用户滑动时才加载。
实现图片懒加载功能可以显著提升页面的加载性能,特别是对于包含大量图片的页面。下面是一个使用HTML、CSS和JavaScript实现的简单示例,展示了如何在用户滚动时才加载图片。
1.HTML部分
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片懒加载示例</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="image-container">
<img class="lazy" data-src="https://via.placeholder.com/600x400/FF5733/FFFFFF?text=图片1" alt="图片1">
<img class="lazy" data-src="https://via.placeholder.com/600x400/33FF57/FFFFFF?text=图片2" alt="图片2">
<img class="lazy" data-src="https://via.placeholder.com/600x400/3357FF/FFFFFF?text=图片3" alt="图片3">
<img class="lazy" data-src="https://via.placeholder.com/600x400/FFD700/FFFFFF?text=图片4" alt="图片4">
<img class="lazy" data-src="https://via.placeholder.com/600x400/FF33A8/FFFFFF?text=图片5" alt="图片5">
<img class="lazy" data-src="https://via.placeholder.com/600x400/33FFF5/FFFFFF?text=图片6" alt="图片6">
</div>
<script src="script.js"></script>
</body>
</html>
2.CSS部分 (styles.css)
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.image-container {
display: flex;
flex-direction: column;
align-items: center;
margin: 20px;
}
img {
width: 100%;
max-width: 600px;
height: auto;
margin: 10px 0;
opacity: 0; /* 初始隐藏图片 */
transition: opacity 0.5s ease-in;
}
img.loaded {
opacity: 1; /* 图片加载后显示 */
}
3.JavaScript部分 (script.js)
document.addEventListener("DOMContentLoaded", function () {
const lazyImages = document.querySelectorAll('.lazy');
const options = {
root: null, // 视口为当前可视区域
rootMargin: '0px',
threshold: 0.1 // 交叉阈值
};
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // 将data-src的值赋给src属性
img.classList.add('loaded');
observer.unobserve(img); // 观察完成后不再观察该图片
}
});
}, options);
lazyImages.forEach(img => {
imageObserver.observe(img); // 开始观察每个懒加载图片
});
});
4.使用说明
- 创建一个新的HTML文件,将上述HTML代码放入该文件中。
- 创建一个
styles.css
文件,将上述CSS代码放入其中。 - 创建一个
script.js
文件,将JavaScript代码放入里面。 - 打开HTML文件,页面初始加载时只会加载可视区域内的图片,其余图片在用户滚动到它们时才会被加载。
5.说明
- 在HTML中,使用
data-src
属性来存放实际的图片链接,初始不设置src
。这样,浏览器不会加载它们。 - JavaScript使用
IntersectionObserver
来监测图片何时进入可视区域,并在合适的时候将其加载。 - CSS设置了图片的初始透明度,并在加载完成后渐变为可见。
这种方法高效且简单,可以用于各种需要懒加载的场景。
四、前端框架
11.React 计数器
使用React创建一个简单的计数器组件,包括加、减和重置功能。
1.创建计数器组件
你可以按照以下步骤创建一个计数器组件:
-
确保你已经安装了 Node.js 和 npm,然后使用 Create React App 创建一个新的 React 应用:
npx create-react-app counter-app cd counter-app
-
在
src
目录中,创建一个新的文件Counter.js
,并添加以下代码:
// Counter.js
import React, { useState } from 'react';
const Counter = () => {
// 使用 useState 钩子来创建计数器的状态
const [count, setCount] = useState(0);
// 加法函数
const handleAdd = () => {
setCount(count + 1);
};
// 减法函数
const handleSubtract = () => {
setCount(count - 1);
};
// 重置函数
const handleReset = () => {
setCount(0);
};
return (
<div style={{ textAlign: 'center', marginTop: '50px' }}>
<h1>计数器</h1>
<h2>{count}</h2>
<button onClick={handleAdd}>加</button>
<button onClick={handleSubtract}>减</button>
<button onClick={handleReset}>重置</button>
</div>
);
};
export default Counter;
- 接下来,打开
src/App.js
文件,并将其内容更改为:
// App.js
import React from 'react';
import Counter from './Counter';
function App() {
return (
<div className="App">
<Counter />
</div>
);
}
export default App;
- 最后,在终端中启动 React 应用:
npm start
2.说明
- useState 钩子:用于创建状态变量
count
及其更新函数setCount
,初始值为0
。 - 按钮处理函数:
handleAdd
:点击加按钮时,增加计数器的值。handleSubtract
:点击减按钮时,减少计数器的值。handleReset
:点击重置按钮时,计数器值回归到0
。
- 在组件的返回部分,展示当前计数并提供三个按钮以进行增减和重置操作。
你可以根据需要对样式、功能等进行扩展。上述代码可直接在创建的 React 应用中运行。
12.Vue 待办事项应用
使用Vue框架创建一个待办事项应用,能够添加、删除和标记完成的事项。
1.效果图
2.创建待办事项应用
-
搭建 Vue 项目:如果你还没有 Vue CLI,可以使用以下命令安装:
npm install -g @vue/cli
然后创建一个新的 Vue 项目:
vue create todo-app cd todo-app
-
修改
src/App.vue
文件:将文件内容修改为以下代码:
<template>
<div id="app">
<h1>待办事项列表</h1>
<input v-model="newTask" @keyup.enter="addTask" placeholder="添加新事项" />
<button @click="addTask">添加</button>
<ul>
<li v-for="(task, index) in tasks" :key="index" :class="{ completed: task.completed }">
<span @click="toggleTask(index)">{{ task.text }}</span>
<button @click="removeTask(index)">删除</button>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
newTask: '',
tasks: [],
};
},
methods: {
addTask() {
if (this.newTask.trim() === '') {
alert('请输入事项内容');
return;
}
this.tasks.push({ text: this.newTask, completed: false });
this.newTask = ''; // 清空输入框
},
removeTask(index) {
this.tasks.splice(index, 1); // 删除事项
},
toggleTask(index) {
this.tasks[index].completed = !this.tasks[index].completed; // 切换完成状态
},
},
};
</script>
<style>
#app {
text-align: center;
margin: 50px;
}
.completed {
text-decoration: line-through; /* 完成事项划线 */
}
ul {
list-style-type: none; /* 去掉列表样式 */
padding: 0;
}
li {
margin: 5px 0;
}
button {
margin-left: 10px;
}
</style>
3.说明:
- 模板部分:包含一个输入框、添加按钮和待办事项列表。通过
v-model
双向绑定输入框内容,使用v-for
渲染待办事项。 - 数据部分:使用
data
返回新任务内容和任务数组。每个任务包含文本和完成状态。 - 方法部分:
addTask
:添加新事项,如果输入为空则弹出提示。removeTask
:根据索引移除指定事项。toggleTask
:切换任务的完成状态。
- 样式部分:简单的样式,包括完成事项的划线效果。
- 运行项目:在终端中启动 Vue 应用:
npm run serve
完成后的效果
你可以在浏览器中通过访问 http://localhost:8080
来查看待办事项应用,用户可以添加新事项、删除事项并标记完成!
这样,你就完成了一个简单的待办事项应用。你可以根据需要继续扩展功能或美化界面。
13.使用 React Hooks
使用React Hooks实现一个使用localStorage的计数器,可以在页面刷新后保存状态。
1.创建计数器组件
-
确保你已经创建了一个 React 应用,如果还没有,可以使用 Create React App 创建一个:
npx create-react-app storage-counter cd storage-counter
-
在
src
目录中修改App.js
文件,并添加以下代码:
// App.js
import React, { useState, useEffect } from 'react';
function App() {
// 从 localStorage 中获取初始值,如果没有则默认为 0
const [count, setCount] = useState(() => {
const savedCount = localStorage.getItem('count');
return savedCount !== null ? JSON.parse(savedCount) : 0;
});
// 每当 count 变化时,将其保存到 localStorage
useEffect(() => {
localStorage.setItem('count', JSON.stringify(count));
}, [count]);
// 加法函数
const handleAdd = () => {
setCount(prevCount => prevCount + 1);
};
// 减法函数
const handleSubtract = () => {
setCount(prevCount => prevCount - 1);
};
// 重置函数
const handleReset = () => {
setCount(0);
};
return (
<div style={{ textAlign: 'center', marginTop: '50px' }}>
<h1>计数器</h1>
<h2>{count}</h2>
<button onClick={handleAdd}>加</button>
<button onClick={handleSubtract}>减</button>
<button onClick={handleReset}>重置</button>
</div>
);
}
export default App;
2.代码说明:
- 初始状态:使用
useState
来设置count
的初始值,从localStorage
中获取。如果没有存储的值,则默认为0
。 - useEffect:当
count
值发生变化时,使用localStorage.setItem
将其存储到localStorage
中。注意,每次更新计数器时都会触发这个副作用。 - 处理函数:
handleAdd
:增加计数器的值。handleSubtract
:减少计数器的值。handleReset
:将计数器重置为0
。
- 运行项目:在终端中启动 React 应用:
npm start
3.完成后的效果
在浏览器中访问 http://localhost:3000
,你会看到一个计数器组件。当你增加或减少计数时,状态会保存在 localStorage
中,刷新页面后仍然可以保持原来的计数值。
这就是一个使用 React Hooks 和 localStorage
实现的简单计数器应用。你可以根据需要进一步扩展功能或美化界面。
14.Vue 路由实现
使用Vue Router实现一个简单的多页面应用,包含首页及关于页,并能够正确切换。
1.创建 Vue 应用
-
确保你已经安装了 Vue CLI,如果还没有,可以通过以下命令安装:
npm install -g @vue/cli
-
使用 Vue CLI 创建一个新的 Vue 项目:
vue create multi-page-app cd multi-page-app
-
安装 Vue Router:
vue add router
在安装过程中,选择 "Yes" 以 "Use history mode for router?" 问题。
-
项目结构:项目创建后,它会自动生成一些文件。打开
src
目录,主要关注以下文件:src/router/index.js
:配置路由的地方。src/views/Home.vue
:默认生成的首页组件。src/views/About.vue
:你需要手动创建的关于页组件。
-
创建 About.vue 组件:在
src/views
目录下创建About.vue
文件,并添加以下代码:
<!-- src/views/About.vue -->
<template>
<div>
<h1>关于页</h1>
<p>这是一个关于页的简单示例。</p>
</div>
</template>
<script>
export default {
name: 'About',
};
</script>
<style scoped>
/* 添加样式(可选) */
</style>
- 配置路由:打开
src/router/index.js
,确保它包含首页和关于页的路由配置。代码如下:
import Vue from 'vue';
import Router from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
Vue.use(Router);
export default new Router({
mode: 'history', // 使用 HTML5 History 模式
routes: [
{
path: '/',
name: 'Home',
component: Home,
},
{
path: '/about',
name: 'About',
component: About,
},
],
});
- 修改 App.vue 文件:更新
src/App.vue
文件,以便可以导航:
<template>
<div id="app">
<nav>
<router-link to="/">首页</router-link>
<router-link to="/about">关于</router-link>
</nav>
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
};
</script>
<style>
nav {
margin-bottom: 20px;
}
nav a {
margin: 0 15px;
text-decoration: none;
}
nav a.router-link-active {
font-weight: bold;
}
</style>
- 运行项目:用以下命令启动 Vue 应用:
npm run serve
2.完成后的效果
在浏览器中访问 http://localhost:8080
,你会看到一个简单的多页面应用:
- 首页:包含了主页内容。
- 关于页:点击“关于”链接后会切换到关于页。
你可以通过在导航中切换链接,查看不同的页面内容。这个示例展示了如何使用 Vue Router 实现基本的路由功能。你可以根据需要继续扩展和美化这个应用。
五、性能优化
15.图片优化
解释如何使用不同的图片格式(如WebP)、压缩图片和使用延迟加载来优化网页性能。
优化网页性能是提升用户体验和提高搜索引擎排名的重要方面。使用不同的图片格式、压缩图片和延迟加载 (lazy loading) 是三种常见的方法。以下是对这些方法的详细解释:
1. 使用不同的图片格式
-
WebP:WebP 是一种现代的图像格式,具有较小的文件大小,同时保持高质量图像。相比于传统的 JPEG 和 PNG 格式,WebP 可以减少图像的大小,通常可以减少 30% 到 80% 的文件大小,这对网页加载速度有显著的帮助。
-
使用方法: 在 HTML 中使用
<img>
标签时,可以直接设置src
为 WebP 格式的图像文件。例如:<img src="image.webp" alt="描述">
-
浏览器支持: 确保你的用户使用的浏览器支持 WebP 格式,常见浏览器如 Chrome、Firefox、Edge 和 Opera 支持 WebP,但某些旧版本的浏览器(例如某些版本的 Safari)可能不支持。因此,可以考虑使用
<picture>
标签提供多个格式的图片:<picture> <source srcset="image.webp" type="image/webp"> <source srcset="image.jpg" type="image/jpeg"> <img src="image.jpg" alt="描述"> </picture>
-
2. 压缩图片
-
图片压缩:无论是使用哪些格式,减少图片的文件大小都会提高加载速度。可以通过以下几种方式压缩图片:
- 在线工具(如 TinyPNG、ImageOptim 等)
- 图片处理软件(如 Photoshop,通过“保存为 Web”功能进行优化)
- 使用命令行工具(如 ImageMagick)。
-
使用方法: 在上传图片到网站之前,先通过压缩工具降低文件大小。压缩后,保证图片质量满足需求,避免过度压缩导致图像变得模糊或失真。
3. 使用延迟加载(Lazy Loading)
-
延迟加载:延迟加载是一种技术,仅在用户滚动到视口(viewport)内时加载特定的图像,这样可以减少初始加载时的数据量,提高页面加载速度和用户体验。
-
使用方法: 在现代 HTML 中,可以直接在
<img>
标签中使用loading="lazy"
属性:<img src="image.jpg" alt="描述" loading="lazy">
这会告诉浏览器在用户滚动到该图像附近时再加载它。
-
-
实现方式: 对于不支持
loading
属性的浏览器,你可以借助 JavaScript 实现延迟加载功能。通过监听滚动事件,判断图像是否在可视区域内,来加载图像。
总结
优化网页性能是一个综合性的工作,使用合适的图片格式(如 WebP)、有效地压缩图片和采用延迟加载技术,能够显著改善网页的加载速度和用户体验。建议开发者在构建网站时,将这些优化措施作为标准做法,以提供更顺畅的浏览体验。
16.减少HTTP请求
讨论如何通过合并文件(如CSS和JS)、使用CDN和利用浏览器缓存来减少HTTP请求。
减少 HTTP 请求是优化网页性能的重要策略。通过合并文件、使用内容分发网络 (CDN) 和利用浏览器缓存,可以有效减少 HTTP 请求的数量,提高网页加载速度和性能。以下是对这些方法的详细讨论:
1. 合并文件
-
合并 CSS 和 JS 文件:将多个 CSS 和 JavaScript 文件合并成一个文件,这样可以减少浏览器发出的 HTTP 请求数量。每个请求都需要时间进行建立和关闭连接,合并文件能够有效减少这些开销。
-
使用方法:
- CSS:将多个样式表的内容合并到一个文件中。在构建过程中(如使用 Webpack、Gulp 等工具),可以配置任务来自动化合并过程。
- JS:同样,可以将多个 JavaScript 文件合并为一个文件。这样,用户在访问页面时只需请求一个文件,而不是多个。
-
注意事项:
- 合并文件后需要注意文件大小,可能会导致某些文件较大,增加初始加载时间。
- 为了在开发中方便调试,可以考虑在开发环境中保持文件分开,生产环境中使用合并后的文件。
-
2. 使用 CDN(内容分发网络)
-
CDN 的优势:CDN 是一种通过分布在全球的服务器网络提供内容的解决方案,可以将静态资源(如图片、CSS、JavaScript 等)存储在离用户地理位置更近的服务器上。这可以减少资源的加载时间和带宽的开销。
-
使用方法:
- 将公共库(如 jQuery、Bootstrap 等)加载到 CDN,而不是在自己的网站上托管这些文件。
- 使用 CDN 还可以利用其缓存机制,用户在不同网站上访问相同资源时,可能会从浏览器缓存中直接获取,而不需重新下载。
-
选择合适的 CDN:选择成熟且广泛使用的 CDN 服务,如 Cloudflare、Amazon CloudFront、Akamai 等,以确保高可用性和快速的内容分发。
-
3. 利用浏览器缓存
-
浏览器缓存机制:利用浏览器缓存,可以让用户在第一次访问网站时下载的资源在后续访问中复用。通过正确设置 HTTP 头,可以指定哪些资源缓存多长时间。
-
使用方法:
- 设置
Cache-Control
和Expires
响应头,以定义浏览器应存储文件的时长。例如,可以设置静态资源(如图片、CSS、JS)进行长时间缓存,而动态内容则设置较短的缓存时间。 - 确保为版本变更的文件使用不同的文件名(例如使用哈希值),这样在文件更新时可以确保用户获取到最新版本。
- 设置
-
示例:
Cache-Control: public, max-age=31536000
这表示该资源被允许缓存,并且可以在 1 年内保持有效。
-
总结
通过合并文件、使用 CDN 和利用浏览器缓存,可以显著减少 HTTP 请求数量,从而提高网页的加载速度和用户体验。在实际开发中,建议结合这些策略,系统化地优化网页性能,使得用户在访问网站时能够获得更快的响应和更顺畅的体验。
六、综合应用
17.创建卡片组件
使用HTML/CSS和JavaScript创建一个用户卡片组件,显示用户的基本信息和操作按钮。
1.效果图
2.HTML
<html lang="zh"></html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户卡片组件</title>
<link rel="stylesheet" href="./css/styles.css">
</head>
<body>
<header>
<h1>用户卡片组件</h1>
</header>
<div class="user-card">
<img src="./images/logo.jpg" alt="用户头像" class="user-avatar">
<div class="user-info">
<h2 class="user-name">用户姓名</h2>
<p class="user-email">用户邮箱: user@example.com</p>
<p class="user-role">角色: 管理员</p>
</div>
<div class="user-actions">
<button class="action-button" onclick="editUser()">编辑</button>
<button class="action-button" onclick="deleteUser()">删除</button>
</div>
<script src="./js/modal.js"></script>
<style src="./css/styles.css"></style>
</div>
</body>
</html>
3.CSS
.user-card {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 16px;
display: flex;
flex-direction: column;
align-items: center;
width: 250px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.user-info {
display: flex;
align-items: center;
width: 100%;
margin-bottom: 16px;
}
.user-avatar {
border-radius: 50%;
margin-right: 16px;
}
.user-details {
flex: 1;
}
.user-name {
margin: 0;
font-size: 1.2em;
}
.user-email {
margin: 0;
color: #888;
}
.user-bio {
margin: 0;
font-size: 0.9em;
color: #555;
}
.user-actions {
display: flex;
gap: 8px;
}
.btn-edit {
background-color: #4CAF50;
color: white;
border: none;
padding: 8px 12px;
border-radius: 4px;
cursor: pointer;
}
.btn-delete {
background-color: #F44336;
color: white;
border: none;
padding: 8px 12px;
border-radius: 4px;
cursor: pointer;
}
.btn-edit:hover {
background-color: #45a049;
}
.btn-delete:hover {
background-color: #e53935;
}
4.JavaScript
function editUser() {
alert("编辑用户信息");
}
function deleteUser() {
if (confirm("确定要删除该用户吗?")) {
alert("用户已删除");
}
}
5.使用说明
- 在HTML部分,将用户的相关信息替换成实际的数据。
- 在CSS部分可以调整样式以符合你的设计需求。
- JavaScript部分包含简单的编辑和删除功能,实际使用中可以根据具体需求进行调整。
通过以上代码,你可以创建一个基本的用户卡片组件,展示用户的基本信息并提供编辑和删除的操作按钮。
18.实现搜索功能
创建一个带有搜索框的列表,输入内容时,对列表进行过滤,实时显示匹配结果。
1.效果图
2.HTML部分
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>实时搜索列表</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<input type="text" id="searchInput" placeholder="请输入搜索内容" onkeyup="filterList()">
<ul id="itemList">
<li>苹果</li>
<li>香蕉</li>
<li>橙子</li>
<li>葡萄</li>
<li>草莓</li>
<li>蓝莓</li>
</ul>
</div>
<script src="script.js"></script>
</body>
</html>
3.CSS部分 (styles.css)
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.container {
width: 300px;
}
input {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border: 1px solid #ccc;
border-radius: 4px;
}
ul {
list-style-type: none;
padding: 0;
}
li {
padding: 8px;
border: 1px solid #ddd;
margin-top: -1px; /* 重叠边框 */
}
li:hover {
background-color: #f0f0f0;
}
4.JavaScript部分 (script.js)
function filterList() {
const input = document.getElementById('searchInput').value.toLowerCase();
const listItems = document.querySelectorAll('#itemList li');
listItems.forEach((item) => {
const text = item.textContent.toLowerCase();
if (text.includes(input)) {
item.style.display = 'block'; // 显示匹配的项
} else {
item.style.display = 'none'; // 隐藏不匹配的项
}
});
}
5.使用说明
- 创建一个新的HTML文件,将上述HTML代码放入该文件中。
- 创建一个
styles.css
文件,把上述CSS代码放入其中。 - 创建一个
script.js
文件,把JavaScript代码放入里面。 - 打开HTML文件,你将看到一个带有搜索框的列表。输入内容时,列表将根据匹配结果实时更新。
这样,你就完成了一个基本的带有搜索框的列表功能,用户可以通过输入内容来过滤显示匹配的结果。
19.自制分页组件
创建一个分页组件,允许用户控制每页显示的数据条数,并能够切换不同的页码。
1.效果图
2.HTML部分
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分页组件</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<div id="dataContainer"></div>
<div class="pagination">
<button id="prevButton" onclick="changePage(-1)">上一页</button>
<span id="pageInfo"></span>
<button id="nextButton" onclick="changePage(1)">下一页</button>
<select id="pageSizeSelect" onchange="changePageSize()">
<option value="5">每页显示 5 条</option>
<option value="10">每页显示 10 条</option>
<option value="20">每页显示 20 条</option>
</select>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
3.CSS部分 (styles.css)
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.container {
width: 500px;
}
.pagination {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20px;
}
button {
padding: 6px 12px;
margin: 0 5px;
border: 1px solid #ccc;
border-radius: 4px;
cursor: pointer;
}
button:disabled {
background-color: #f0f0f0;
cursor: not-allowed;
}
select {
padding: 6px;
}
4.JavaScript部分 (script.js)
let currentPage = 1;
let pageSize = 5; // 默认每页显示 5 条
const data = Array.from({ length: 100 }, (_, i) => `数据条目 ${i + 1}`); // 示例数据
function renderData() {
const dataContainer = document.getElementById('dataContainer');
dataContainer.innerHTML = ''; // 清空容器
const start = (currentPage - 1) * pageSize;
const end = start + pageSize;
const currentData = data.slice(start, end);
currentData.forEach(item => {
const div = document.createElement('div');
div.textContent = item;
dataContainer.appendChild(div);
});
updatePageInfo();
toggleButtons();
}
function updatePageInfo() {
const pageInfo = document.getElementById('pageInfo');
const totalPages = Math.ceil(data.length / pageSize);
pageInfo.textContent = `第 ${currentPage} 页 / 共 ${totalPages} 页`;
}
function toggleButtons() {
document.getElementById('prevButton').disabled = currentPage === 1;
document.getElementById('nextButton').disabled = currentPage === Math.ceil(data.length / pageSize);
}
function changePage(direction) {
currentPage += direction;
renderData();
}
function changePageSize() {
const select = document.getElementById('pageSizeSelect');
pageSize = parseInt(select.value);
currentPage = 1; // 重置到第一页
renderData();
}
// 初始渲染
renderData();
5.使用说明
- 创建一个新的HTML文件,将上述HTML代码放入该文件中。
- 创建一个
styles.css
文件,把上述CSS代码放入其中。 - 创建一个
script.js
文件,把JavaScript代码放入里面。 - 打开HTML文件,你将看到一个分页组件。它显示数据条目,用户可以通过下方的按钮和下拉框控制每页显示的数据条数和切换页码。
这个简单的分页组件能够满足基本的分页需求,用户可自由切换不同的页码和每页显示的数据条数。
20.自定义下拉菜单
使用HTML、CSS和JavaScript实现一个自定义下拉菜单,要求可以选择多个选项,并能够动态显示已选择的项。
1.效果图
2.HTML部分
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>自定义多选下拉菜单</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="dropdown">
<div class="dropdown-select" onclick="toggleDropdown()">
<span id="selectedItems">请选择选项</span>
<span class="arrow">▼</span>
</div>
<div class="dropdown-list" id="dropdownList">
<label><input type="checkbox" value="选项 1" onchange="updateSelectedItems(this)"> 选项 1</label>
<label><input type="checkbox" value="选项 2" onchange="updateSelectedItems(this)"> 选项 2</label>
<label><input type="checkbox" value="选项 3" onchange="updateSelectedItems(this)"> 选项 3</label>
<label><input type="checkbox" value="选项 4" onchange="updateSelectedItems(this)"> 选项 4</label>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
3.CSS部分 (styles.css)
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.dropdown {
position: relative;
width: 200px;
}
.dropdown-select {
border: 1px solid #ccc;
padding: 10px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
}
.dropdown-list {
display: none;
border: 1px solid #ccc;
border-top: none;
position: absolute;
background-color: white;
width: 100%;
max-height: 150px;
overflow-y: auto;
z-index: 10;
}
.dropdown-list label {
display: block;
padding: 10px;
}
.dropdown-list label:hover {
background-color: #f0f0f0;
}
.arrow {
margin-left: 10px;
}
4.JavaScript部分 (script.js)
function toggleDropdown() {
const dropdownList = document.getElementById('dropdownList');
dropdownList.style.display = dropdownList.style.display === 'block' ? 'none' : 'block';
}
document.addEventListener('click', function (event) {
const dropdown = document.querySelector('.dropdown');
const dropdownList = document.getElementById('dropdownList');
if (!dropdown.contains(event.target)) {
dropdownList.style.display = 'none';
}
});
function updateSelectedItems(checkbox) {
const selectedItems = document.getElementById('selectedItems');
const options = Array.from(document.querySelectorAll('.dropdown-list input[type="checkbox"]'));
const selectedValues = options.filter(option => option.checked).map(option => option.value);
if (selectedValues.length > 0) {
selectedItems.textContent = selectedValues.join(', ');
} else {
selectedItems.textContent = '请选择选项';
}
}
5.使用说明
- 创建一个新的HTML文件,将上述HTML代码放入该文件中。
- 创建一个
styles.css
文件,把上述CSS代码放入其中。 - 创建一个
script.js
文件,把JavaScript代码放入里面。 - 打开HTML文件,点击下拉菜单,选择多个选项,已选择的项会动态显示在下拉菜单中。
这个自定义多选下拉菜单能够满足基本的选择需求,并且适应各种情况的应用。用户可以自由选择多个选项,且界面友好易用。
七、练习建议
在实际编码环境中完成这些题目,例如在CodePen、JSFiddle等在线平台上进行练习。
在完成每个题目后,总结自己的实现思路和遇到的问题,有助于加深理解。
如果时间允许,可以对每个实操题进行扩展,例如加入更多的交互功能或改进用户体验。
以上题目能够全面考察候选人的前端开发能力,帮助招聘团队评估应聘者的实际技能。希望对你准备面试或自我练习有所帮助!
更多推荐
所有评论(0)