从零构建电影展示页面:原生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>
相关推荐
陈随易9 分钟前
Gitea v1.24.0发布,自建github神器
前端·后端·程序员
前端付豪12 分钟前
汇丰银行技术架构揭秘:全球交易稳定背后的“微服务+容灾+零信任安全体系”
前端·后端·架构
邹荣乐14 分钟前
uni-app开发微信小程序的报错[渲染层错误]排查及解决
前端·微信小程序·uni-app
今天出摊吗15 分钟前
表单元素的默认提交行为
前端
今天出摊吗16 分钟前
CSS 动态视口单位 dvh 和 dvw
前端
南方kenny17 分钟前
React组件化实战:从零打造智能TodoList清单
前端·react.js·aigc
JacksonGao18 分钟前
前端三国志:React、Vue 与 Svelte 之战
前端·前端框架
CharlesYoung1868118 分钟前
记录一次引入循环,导致undefined
前端
FogLetter18 分钟前
从add函数类型判断说起:NaN的奇幻漂流与JS数据类型的奥秘
前端·javascript
半懂19 分钟前
webpack-sourceMap
前端