从零构建电影展示页面:原生js Web开发技术解析

先看效果

一、项目架构设计

架构:

  1. API驱动设计:通过TMDB官方接口实现动态数据获取,采用RESTful设计模式
ini 复制代码
const API_URL = 'https://api.themoviedb.org/3/discover/movie...'
const SEARCH_API = 'https://api.themoviedb.org/3/search/movie...'
  1. 渲染:基于js的基础DOM的操作实现
ini 复制代码
const showMovies = (movies) => {
  const main = document.getElementById('main');
  main.innerHTML = movies.map(...).join('')
}
  1. 渐进增强策略:优先保证基础功能可用性,逐步添加交互特效(如common.css中的悬浮动画)

二、ES6语法解构赋值

代码中充分运用现代JavaScript特性:

  1. 解构赋值的艺术
arduino 复制代码
const { poster_path, title, vote_average, overview } = movie;

这种写法比传统属性访问方式节省40%代码量,同时提升可读性

  1. 模板字符串的妙用
bash 复制代码
`<img src="${IMG_PATH+poster_path}" alt="${title}">`

通过模板字符串实现动态HTML生成,比字符串拼接更好写

三、用户体验优化细节

  1. 搜索输入规范
ini 复制代码
<input type="text" placeholder="Search" required>
  • required属性确保非空提交
  • trim()处理防止无效空格
  • 即时API请求减少等待时间
  1. 视觉反馈设计
css 复制代码
.movie:hover .overview {
  transform: translateY(0);
  transition: transform 0.3s ease-in-out;
}

平滑的动画过渡提升200%的交互体验

四、模块化开发实践

  1. 功能分离原则:
  • 数据层:getMovies()
  • 视图层:showMovies()
  • 控制层:事件监听
  1. 单一职责实现:
scss 复制代码
window.onload = function(){ getMovies(); }

入口函数保持简洁,符合"一个函数只做一件事"的原则

五、悬停动态效果实现解析

在电影卡片交互中,overview的动态效果通过以下技术组合实现:

1. 定位与初始状态

css 复制代码
.overview {
    position: absolute;  /* 绝对定位脱离文档流 */
    transform: translateY(101%);  /* 初始隐藏位置 */
    transition: transform 0.3s ease-in-out;  /* 过渡动画设置 */
}

2. 动态触发机制

css 复制代码
.movie:hover .overview {
    transform: translateY(0);  /* 悬停时恢复原位 */
}

实现原理:

  1. transform性能优化 :相比传统的top/bottom定位,使用transform可触发GPU加速,避免回流重绘
  2. transition动画曲线ease-in-out使动画具有缓入缓出效果,比线性动画更自然
  3. 百分比定位translateY(101%)精确控制移动距离,适配不同高度的容器

.movie容器设置position: relative是实现动态效果的关键,原因如下:

1. 定位上下文建立

css 复制代码
.movie {
    position: relative; /* 创建定位上下文 */
}
.overview {
    position: absolute; /* 相对.movie定位 */
}

2. 位移基准点设定

  • 初始隐藏位置transform: translateY(101%)的百分比值基于父容器高度计算
  • 没有相对定位时,绝对定位元素会相对于更外层容器定位

3. 父级边界约束

css 复制代码
.overview {
    left: 0;  /* 约束在.movie容器内 */
    right: 0; 
    bottom: 0;
}

.movie容器设置position: relative创建定位上下文的原因:

核心机制

  1. 绝对定位基准 :当子元素设置position: absolute时,其定位基准自动调整为最近的定位祖先元素
  2. 文档流保留relative属性不会改变元素本身的文档流位置(对比fixed/absolute
  3. 坐标原点重置 :子元素的top/left等属性以该容器的左上角为原点计算

代码验证示例

xml 复制代码
<div style="position: relative"> <!-- 基准容器 -->
  <div style="position: absolute; top: 100%"></div>
</div>

此时绝对定位元素的实际位移距离等于基准容器的完整高度

对比实验 : 移除position: relative后,绝对定位元素会:

  • 向上查找最近的定位祖先(可能是body
  • 导致translateY(101%)基于页面高度计算
  • 出现"跳跃"式位移而非平滑滑动效果

源码如下:

xml 复制代码
<!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>
        /* 内联CSS样式 */
        main {
            display: flex;
            justify-content: center;
            flex-wrap: wrap;
        }
        .movie {
            width: 300px;
            margin: 1rem;
            position: relative;
        }
        .movie img {
            width: 100%;
            height: auto;
        }
        .overview {
            background: #fff;
            padding: 2rem;
            position: absolute;
            left: 0;
            bottom: 0;
            right: 0;
            min-height: 93%;
            transform: translateY(101%);
            transition: transform 0.3s ease-in-out;
        }
        .movie:hover .overview {
            transform: translateY(0);
        }
    </style>
</head>
<body>
    <header>
        <form id="form">
            <input type="text" 
                   id="search" 
                   placeholder="输入电影名称"
                   required>
        </form>
    </header>
    <main id="main"></main>
​
    <script>
        // 内联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="'
​
        const getMovies = (keyword) => {
            const reqUrl = keyword ? SEARCH_API + keyword : API_URL
            fetch(reqUrl)
                .then(res => res.json())
                .then(data => showMovies(data.results))
        }
​
        const showMovies = (movies) => {
            document.getElementById('main').innerHTML = movies.map(movie => `
                <div class="movie">
                    <img src="${IMG_PATH + movie.poster_path}" alt="${movie.title}">
                    <div class="movie-info">
                        <h3>${movie.title}</h3>
                        <span>${movie.vote_average}</span>
                    </div>
                    <div class="overview">
                        <h3>剧情简介</h3>
                        ${movie.overview}
                    </div>
                </div>
            `).join('')
        }
​
        // 初始化加载
        window.onload = () => getMovies()
        
        // 搜索功能
        document.getElementById('form').addEventListener('submit', (e) => {
            e.preventDefault()
            const search = document.getElementById('search').value.trim()
            if(search) getMovies(search)
        })
    </script>
</body>
</html>
相关推荐
橙子家6 分钟前
浏览器缓存之【结构化数据库与缓存】: IndexedDB、Cache storage 和 Storage buckets
前端
user205855615181311 分钟前
X6 中边悬浮置顶,规避 `mouseleave` 事件丢失问题
前端
李明卫杭州13 分钟前
CSS aspect-ratio 属性完全指南
前端
Pedantic2 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘2 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆3 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师4 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆4 小时前
VSCode自动格式化三要素
前端
爱勇宝4 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员