前言
在现代Web开发中,有许多看似简单但实则精妙的技术细节值得我们深入探讨。本文将解析一个电影展示网站项目中的关键技术点,包括表单处理、CSS动画、布局技术等,并揭示它们背后的设计哲学和最佳实践。
让我们一起来看看页面效果吧🚀🚀后面还有代码总结
表单处理的现代化演进
阻止默认表单提交行为
oForm.addEventListener('submit', function (event) {
event.preventDefault();
})
在早期Web开发中,表单提交会导致页面刷新,这种体验在现代Web应用中已经显得过时。event.preventDefault()
的作用是阻止表单的默认提交行为,转而使用JavaScript的fetch
API异步获取数据,实现了无刷新页面更新。
技术演进:
- 传统方式:表单提交 → 页面刷新 → 服务器返回新页面
- 现代方式:表单提交 → JavaScript拦截 → AJAX请求 → 动态更新DOM
这种转变不仅提升了用户体验,还减少了网络流量和服务器负载。
输入验证与用户体验优化
<input type="text" id="search" class="search" placeholder="Search" required>
这个简单的输入框包含了多个提升用户体验的特性:
- placeholder:HTML5引入的属性,在不占用输入值的情况下提供提示信息,引导用户输入正确内容。
- required:同样来自HTML5,指定该字段为必填项,浏览器会自动进行基本验证,无需额外JavaScript代码。
- trim()方法:在JavaScript中使用
trim()
去除用户输入两端的空白字符,防止因意外空格导致搜索失败。
const search = oInput.value.trim();
trim()
是字符串原型方法,它会返回一个新字符串,去除原始字符串两端的空白字符(包括空格、制表符、换行符等)。这在表单处理中尤为重要,因为用户可能会无意中输入前后空格。
CSS布局与动画技术
弹性布局与响应式设计
main{
display: flex;
justify-content: center;
flex-wrap: wrap;
}
这段CSS代码创建了一个灵活的容器布局:
- display: flex:启用Flexbox布局模型,为子元素提供灵活的排列方式。
- justify-content: center:使子元素在主轴上居中对齐。
- flex-wrap: wrap:允许子元素在容器宽度不足时自动换行,这是实现响应式布局的关键。
flex-wrap的取值:
nowrap
(默认):不换行,可能溢出容器wrap
:按需换行,第一行在上方wrap-reverse
:按需换行,第一行在下方
悬停动画与transform属性
.overview{
position: absolute;
transform: translateY(101%);
transition: transform 0.3s ease-in;
}
.movie:hover .overview{
transform: translateY(0);
}
这段代码实现了电影卡片悬停时显示简介的动画效果:
- translateY(101%) :初始时将元素向下移动其自身高度的101%,完全隐藏于容器外。
- transition:定义属性变化的过渡效果,这里指定
transform
属性在0.3秒内以ease-in
曲线完成变化。 - :hover伪类:当鼠标悬停在电影卡片上时,将
translateY
重置为0,触发平滑的上滑动画。
为什么使用transform而不是top/bottom?
- transform不会触发重排(reflow),只触发重绘(repaint),性能更好
- transform动画由GPU加速,特别适合移动设备的动画效果
- 不会影响文档流中的其他元素
滚动处理与overflow-y
.overview{
overflow-y: auto;
min-height: 100%;
}
当简介内容过长时,这些属性确保内容可滚动而不破坏布局:
- overflow-y: auto:在垂直方向上,当内容超出容器时自动显示滚动条。
- min-height: 100% :确保容器至少填满父元素的高度,即使内容较少时也能保持一致的视觉效果。
overflow-y的取值:
visible
:内容可以溢出容器(默认)hidden
:裁剪溢出内容scroll
:始终显示滚动条auto
:仅在需要时显示滚动条
JavaScript最佳实践
模块化函数设计
const getMovies = (keyword) => {
let reqUrl = keyword ? SEARCH_API + keyword : API_URL;
fetch(reqUrl)
.then(res => res.json())
.then(data => showMovies(data.results));
}
const showMovies = (movies) => {
main.innerHTML = movies.map(movie => {
const {poster_path, title, vote_average, overview} = movie
return `...`;
}).join('')
}
这段代码展示了良好的函数模块化设计:
- 单一职责原则:
getMovies
只负责获取数据,showMovies
只负责渲染数据。 - 参数化设计:
getMovies
接受keyword
参数,可以同时处理默认加载和搜索两种场景。 - 解构赋值:使用ES6的解构语法从movie对象中提取所需属性,代码更简洁。
- 模板字符串:使用反引号(
`
)创建多行HTML字符串,并嵌入变量,提高可读性。
异步数据处理
fetch(reqUrl)
.then(res => res.json())
.then(data => showMovies(data.results));
使用现代fetch
API处理异步请求,相比传统的XMLHttpRequest更简洁直观。注意.json()
方法也是异步的,需要再次使用.then()
处理。
性能优化技巧
-
脚本加载策略:
<script src="./script.js"></script>
放在body末尾,避免阻塞HTML解析和页面渲染。
-
批量DOM操作:
main.innerHTML = movies.map(...).join('')
使用
innerHTML
一次性更新所有电影卡片,而不是多次操作DOM,减少重排次数。 -
CSS动画优化:
transition: transform 0.3s ease-in;
优先使用transform和opacity等不影响布局的属性做动画,性能更好。
代码
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>电影</title>
<link rel="stylesheet" href="./common.css">
</head>
<body>
<header>
<form action="" id="form">
<input type="text"
id="search"
class="search"
placeholder="Search"
required
>
</form>
</header>
<main id="main"></main>
<!-- 尽快看到页面 -->
<!-- script 会阻塞html下载 越大,看到页面等越久 -->
<script src="./script.js"></script>
</body>
</html>
CSS代码
main{
display: flex;
justify-content: center;
flex-wrap: wrap;
}
.movie{
width: 300px;
margin: 1rem;
position: relative;
}
.movie img {
width: 100%;
}
.overview{
background-color:#fff;
padding: 2rem;
position: absolute;
left: 0;
right: 0;
bottom: 0;
right: 0;
min-height: 100%;
transform: translateY(101%);
overflow-y: auto;
transition: transform 0.3s ease-in;
}
.movie:hover .overview{
transform: translateY(0);
}
JavaScript代码
// 配置
// 电影接口地址
const API_URL = 'https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=3fd2be6f0c70a2a598f084ddfb75487c&page=1'
const IMG_PATH = 'https://image.tmdb.org/t/p/w1280'
const SEARCH_API = 'https://api.themoviedb.org/3/search/movie?api_key=3fd2be6f0c70a2a598f084ddfb75487c&query="'
// DOM 编程 原生JS
// 返回的DOM 节点对象
const oForm = document.querySelector('#form');
const oInput = document.querySelector('#search');
console.log(oForm);
// 获取电影
const getMovies = (keyword) => {
let reqUrl = '';
if (keyword) {
// 搜索
reqUrl = SEARCH_API + keyword;
} else {
reqUrl = API_URL;
}
fetch(reqUrl)
// 二进制流
.then(res => res.json())
.then(data => {
showMovies(data.results);
})
}
// movie list render
const showMovies = (movies) => {
main.innerHTML = '';
main.innerHTML = movies.map(movie => {
// es6解构
// 右边{}解给左侧{} es6优雅快捷
// 立马成为常量或变量
const {poster_path , title , vote_average , overview} = movie
return `
<div class="movie">
<img src="${IMG_PATH + poster_path}" alt="${title}">
<div class="movie-info">
<h3>${title}</h3>
<span>${vote_average}</span>
</div>
<div class="overview">
<h3>Overview</h3>
${overview}
</div>
</div>
`}
).join('')
}
// 页面加载完成后执行
window.onload = function () {
getMovies();
}
oForm.addEventListener('submit', function (event) {
// 事件对象event
event.preventDefault();
const search = oInput.value.trim();
if (search) {
// 搜索电影
getMovies(search)
}
})
总结
这个电影网站项目虽然不大,但包含了现代Web开发的许多最佳实践:
- 表单处理:使用
preventDefault
阻止默认提交,结合fetch
实现无刷新体验 - 用户体验:通过
placeholder
、required
和trim
提升表单可用性 - 布局技术:Flexbox实现灵活的响应式布局
- 动画技术:transform和transition创建高性能动画
- 代码组织:模块化函数设计和清晰的关注点分离
这些技术的恰当运用,使得这个项目既具有良好的用户体验,又保持了代码的可维护性和性能。理解这些"不常见但重要"的技术细节,是成为高级前端开发者的关键。