网页预览

你可以先想象一下这个网页的样子:

用JS做一个甜品的网页代码
(图片来源网络,侵删)
  • 顶部:有一个导航栏,包含网站标题、菜单链接和一个购物车图标。
  • 主体
    • 一个引人注目的英雄区域,展示主打甜品和一句欢迎语。
    • 一个“精选甜品”部分,以卡片形式展示多种甜品,每个卡片都有图片、名称、描述、价格和“加入购物车”按钮。
    • 一个“关于我们”部分,介绍甜品店的特色。
  • 交互:点击“加入购物车”按钮,右上角的购物车图标会更新数量,并弹出提示。
  • 底部:一个简单的页脚。

最终代码 (HTML, CSS, JS)

你可以直接复制以下所有代码,保存为一个 .html 文件(desserts.html),然后用浏览器打开它,就能看到完整效果了。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">甜蜜时刻 - 您的专属甜品天堂</title>
    <style>
        /* --- 全局样式和变量 --- */
        :root {
            --primary-color: #ff6b81;
            --secondary-color: #ffd166;
            --dark-color: #2d3436;
            --light-color: #f8f9fa;
            --text-color: #636e72;
            --shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
        }
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        body {
            color: var(--text-color);
            line-height: 1.6;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 0 20px;
        }
        h1, h2, h3 {
            color: var(--dark-color);
            margin-bottom: 1rem;
        }
        a {
            text-decoration: none;
            color: var(--primary-color);
        }
        img {
            max-width: 100%;
            height: auto;
            display: block;
        }
        .btn {
            display: inline-block;
            background: var(--primary-color);
            color: white;
            padding: 12px 24px;
            border: none;
            border-radius: 50px;
            cursor: pointer;
            font-size: 1rem;
            transition: all 0.3s ease;
            text-align: center;
        }
        .btn:hover {
            background: #ff5268;
            transform: translateY(-2px);
            box-shadow: var(--shadow);
        }
        /* --- 导航栏 --- */
        .navbar {
            background: white;
            padding: 1rem 0;
            position: fixed;
            top: 0;
            width: 100%;
            z-index: 1000;
            box-shadow: var(--shadow);
        }
        .navbar .container {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .navbar .logo {
            font-size: 1.5rem;
            font-weight: bold;
            color: var(--primary-color);
        }
        .navbar .nav-links {
            list-style: none;
            display: flex;
        }
        .navbar .nav-links li {
            margin-left: 20px;
        }
        .navbar .nav-links a {
            color: var(--dark-color);
            font-weight: 500;
        }
        .cart-icon {
            position: relative;
            font-size: 1.5rem;
            cursor: pointer;
        }
        .cart-count {
            position: absolute;
            top: -8px;
            right: -8px;
            background: var(--primary-color);
            color: white;
            border-radius: 50%;
            width: 20px;
            height: 20px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 0.8rem;
            font-weight: bold;
        }
        /* --- 主要内容区域 --- */
        main {
            margin-top: 80px; /* 为固定导航栏留出空间 */
        }
        /* --- 英雄区域 --- */
        .hero {
            background: linear-gradient(rgba(255, 107, 129, 0.8), rgba(255, 107, 129, 0.8)), url('https://images.unsplash.com/photo-1553279768-865429fa0078?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80') no-repeat center center/cover;
            color: white;
            text-align: center;
            padding: 100px 20px;
        }
        .hero h1 {
            font-size: 3rem;
            margin-bottom: 1rem;
        }
        .hero p {
            font-size: 1.2rem;
            max-width: 600px;
            margin: 0 auto 2rem;
        }
        /* --- 精选甜品 --- */
        .desserts {
            padding: 60px 0;
            background: #f8f9fa;
        }
        .section-title {
            text-align: center;
            font-size: 2.5rem;
            margin-bottom: 3rem;
        }
        .desserts-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 30px;
        }
        .dessert-card {
            background: white;
            border-radius: 10px;
            overflow: hidden;
            box-shadow: var(--shadow);
            transition: transform 0.3s ease;
        }
        .dessert-card:hover {
            transform: translateY(-10px);
        }
        .dessert-card img {
            height: 250px;
            object-fit: cover;
        }
        .dessert-info {
            padding: 20px;
        }
        .dessert-info h3 {
            font-size: 1.5rem;
            margin-bottom: 0.5rem;
        }
        .dessert-info p {
            color: var(--text-color);
            margin-bottom: 1rem;
        }
        .dessert-footer {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .price {
            font-size: 1.5rem;
            font-weight: bold;
            color: var(--primary-color);
        }
        /* --- 关于我们 --- */
        .about {
            padding: 60px 0;
            text-align: center;
        }
        .about p {
            max-width: 800px;
            margin: 0 auto 2rem;
            font-size: 1.1rem;
        }
        /* --- 页脚 --- */
        footer {
            background: var(--dark-color);
            color: white;
            text-align: center;
            padding: 20px;
        }
        /* --- 提示信息 --- */
        .toast {
            position: fixed;
            bottom: 30px;
            right: 30px;
            background: var(--primary-color);
            color: white;
            padding: 15px 25px;
            border-radius: 50px;
            box-shadow: var(--shadow);
            transform: translateY(100px);
            opacity: 0;
            transition: all 0.3s ease;
        }
        .toast.show {
            transform: translateY(0);
            opacity: 1;
        }
        /* --- 响应式设计 --- */
        @media (max-width: 768px) {
            .navbar .container {
                flex-direction: column;
            }
            .navbar .nav-links {
                margin-top: 1rem;
            }
            .hero h1 {
                font-size: 2rem;
            }
            .desserts-grid {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <!-- 导航栏 -->
    <nav class="navbar">
        <div class="container">
            <a href="#" class="logo">🍰 甜蜜时刻</a>
            <ul class="nav-links">
                <li><a href="#home">首页</a></li>
                <li><a href="#desserts">甜品</a></li>
                <li><a href="#about">关于我们</a></li>
                <li><a href="#contact">联系我们</a></li>
            </ul>
            <div class="cart-icon">
                🛒
                <span class="cart-count" id="cart-count">0</span>
            </div>
        </div>
    </nav>
    <main>
        <!-- 英雄区域 -->
        <section id="home" class="hero">
            <div class="container">
                <h1>每一口,都是幸福的味道</h1>
                <p>我们用心烘焙,为您带来最新鲜、最美味的甜品,点亮您的每一天。</p>
                <a href="#desserts" class="btn">探索甜品</a>
            </div>
        </section>
        <!-- 精选甜品 -->
        <section id="desserts" class="desserts">
            <div class="container">
                <h2 class="section-title">精选甜品</h2>
                <div class="desserts-grid" id="desserts-grid">
                    <!-- 甜品卡片将通过JS动态生成 -->
                </div>
            </div>
        </section>
        <!-- 关于我们 -->
        <section id="about" class="about">
            <div class="container">
                <h2 class="section-title">关于我们</h2>
                <p>
                    甜蜜时刻始于2025年,由一位热爱烘焙的糕点师创立,我们相信,甜品不仅仅是食物,
                    它更是情感的传递和美好的回忆,我们坚持使用最优质的天然原料,
                    从源头把控品质,只为给您带来最纯粹、最安心的甜蜜体验。
                </p>
                <a href="#" class="btn">了解更多</a>
            </div>
        </section>
    </main>
    <!-- 页脚 -->
    <footer>
        <div class="container">
            <p>&copy; 2025 甜蜜时刻. All rights reserved. | Made with ❤️</p>
        </div>
    </footer>
    <!-- 提示信息 -->
    <div class="toast" id="toast">已加入购物车!</div>
    <script>
        // --- 甜品数据 ---
        const desserts = [
            {
                id: 1,
                name: '草莓芝士蛋糕',
                description: '新鲜草莓与浓郁芝士的完美融合,酸甜可口,入口即化。',
                price: 38,
                image: 'https://images.unsplash.com/photo-1488477181946-6428a0291777?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80'
            },
            {
                id: 2,
                name: '巧克力熔岩蛋糕',
                description: '温热的巧克力蛋糕,切开时中心如熔岩般流淌,是巧克力爱好者的终极梦想。',
                price: 42,
                image: 'https://images.unsplash.com/photo-1567620905732-2d1ec7ab7445?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80'
            },
            {
                id: 3,
                name: '提拉米苏',
                description: '经典意式甜品,咖啡的微苦与马斯卡彭奶酪的醇厚交织,层次丰富。',
                price: 45,
                image: 'https://images.unsplash.com/photo-1505252585461-04db1eb84625?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80'
            },
            {
                id: 4,
                name: '芒果千层蛋糕',
                description: '层层叠叠的薄饼与香甜的芒果奶油,热带风情,清新不腻。',
                price: 48,
                image: 'https://images.unsplash.com/photo-1559056199-641a0ac8b55e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80'
            },
            {
                id: 5,
                name: '抹茶红豆千层',
                description: '日式经典,抹茶的微苦与红豆的香甜,带来宁静而满足的味蕾体验。',
                price: 40,
                image: 'https://images.unsplash.com/photo-1576107616104-496e48092fac?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80'
            },
            {
                id: 6,
                name: '法式马卡龙礼盒',
                description: '色彩缤纷的法式小圆饼,酥脆外壳,柔软内馅,是精致的午后茶点。',
                price: 68,
                image: 'https://images.unsplash.com/photo-1603133872878-684f208fb84b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1770&q=80'
            }
        ];
        // --- 购物车状态 ---
        let cart = [];
        // --- DOM 元素 ---
        const dessertsGrid = document.getElementById('desserts-grid');
        const cartCountElement = document.getElementById('cart-count');
        const toast = document.getElementById('toast');
        // --- 渲染甜品列表 ---
        function renderDesserts() {
            dessertsGrid.innerHTML = desserts.map(dessert => `
                <div class="dessert-card">
                    <img src="${dessert.image}" alt="${dessert.name}">
                    <div class="dessert-info">
                        <h3>${dessert.name}</h3>
                        <p>${dessert.description}</p>
                        <div class="dessert-footer">
                            <span class="price">¥${dessert.price}</span>
                            <button class="btn add-to-cart-btn" data-id="${dessert.id}">加入购物车</button>
                        </div>
                    </div>
                </div>
            `).join('');
            // 为所有“加入购物车”按钮添加点击事件
            document.querySelectorAll('.add-to-cart-btn').forEach(button => {
                button.addEventListener('click', (e) => {
                    const dessertId = parseInt(e.target.getAttribute('data-id'));
                    addToCart(dessertId);
                });
            });
        }
        // --- 添加到购物车 ---
        function addToCart(dessertId) {
            const dessert = desserts.find(d => d.id === dessertId);
            if (dessert) {
                cart.push(dessert);
                updateCartCount();
                showToast(`${dessert.name} 已加入购物车!`);
            }
        }
        // --- 更新购物车数量 ---
        function updateCartCount() {
            cartCountElement.textContent = cart.length;
        }
        // --- 显示提示信息 ---
        function showToast(message) {
            toast.textContent = message;
            toast.classList.add('show');
            setTimeout(() => {
                toast.classList.remove('show');
            }, 3000); // 3秒后自动隐藏
        }
        // --- 初始化页面 ---
        renderDesserts();
    </script>
</body>
</html>

代码结构解析

  1. HTML 结构 (<body> 部分)

    • <nav>: 导航栏,包含Logo、菜单链接和购物车图标,购物车图标里有一个 <span> 用于显示商品数量。
    • <main>: 网页的主体内容。
      • <section class="hero">: 首页的欢迎横幅。
      • <section class="desserts">: 展示甜品的核心区域,里面的 <div class="desserts-grid"> 是一个容器,我们通过JS动态地把甜品卡片放进去。
      • <section class="about">: 关于我们的介绍。
    • <footer>: 页脚。
    • <div class="toast">: 用于显示“已加入购物车”等提示信息,默认是隐藏的。
  2. CSS 样式 (<style> 部分)

    • root: 定义了全局的CSS变量,方便统一管理颜色、阴影等,修改起来非常方便。
    • .navbar: 导航栏的样式,设置了 position: fixed 让它固定在页面顶部。
    • .hero: 英雄区域的样式,使用了 background: linear-gradientbackground-image 创建了一个带图片和遮罩的背景。
    • .desserts-grid: 使用了 display: grid 布局,这是一个非常现代和强大的布局工具。repeat(auto-fit, minmax(300px, 1fr)) 的意思是让卡片自动换行,并且每个卡片的宽度至少为300px,最大可以占据一整行,这使得页面在不同屏幕尺寸下都能很好地自适应。
    • .dessert-card: 单个甜品卡片的样式,添加了 box-shadowhover 效果,让卡片看起来更立体,鼠标悬停时有轻微上浮的动画。
    • .toast: 提示信息的样式,通过 transformopacity 实现了滑入滑出的动画效果。
    • @media (max-width: 768px): 媒体查询,当屏幕宽度小于768px(如手机)时,应用这里的样式,比如让导航栏和甜品网格变为单列布局,以获得更好的移动端体验。
  3. JavaScript 交互 (<script> 部分)

    • desserts 数组: 存储了所有甜品的数据,包括ID、名称、描述、价格和图片链接,这样做的好处是数据和表现分离,以后想修改或增加甜品,只需要修改这个数组即可。
    • cart 数组: 用来存储已经加入购物车的商品。
    • renderDesserts() 函数: 这个函数是核心,它遍历 desserts 数组,为每个甜品生成一个HTML卡片字符串,然后把这些字符串拼接起来,最后通过 innerHTML 放到 desserts-grid 容器里,它还为每个“加入购物车”按钮绑定了点击事件。
    • addToCart(dessertId) 函数: 当点击“加入购物车”按钮时触发,它根据ID找到对应的甜品,将其添加到 cart 数组中,然后调用 updateCartCount() 更新购物车图标上的数字,并调用 showToast() 显示提示。
    • updateCartCount()showToast(): 这两个是辅助函数,分别用于更新UI上的购物车数量和显示提示信息。
    • renderDesserts(): 在页面加载时调用一次,负责初始化甜品列表。

这个例子从零开始,为你构建了一个功能完整、视觉美观的甜品网页,并详细解释了每一部分的作用,你可以基于这个代码进行修改和扩展,比如添加真正的购物车结算页面、筛选功能等。