🚀 从零打造本地美食清单应用:HTML+CSS+JS 全流程详解

237 阅读6分钟

大家好~ 今天带大家手把手实现一个「本地美食清单」应用,支持添加美食、展示清单,还会穿插前端基础知识点和实用技巧,新手也能轻松跟上!话不多说,开干!💪

🌟 项目预览与目标

先看看我们要做什么:
一个简洁美观的美食清单工具,用户可以输入美食名称并添加到列表中,页面有优雅的布局和交互效果。最终效果如下(示意图):

  • 居中的半透明卡片布局

  • 背景图自适应显示

  • 表单提交添加美食项

  • 支持后续扩展本地存储(localStorage)

涉及技术栈:HTML5 结构 + CSS3 样式 + JavaScript 交互,适合巩固前端基础的小伙伴~ 😊

📂 项目文件结构

先理清我们的文件组织,清晰的结构是高效开发的开始:

美食清单应用/
├─ index.html       # 页面主结构
├─ common.css       # 样式表
└─ common.js        # 交互逻辑

🔨 step 1:HTML 结构搭建(语义化先行)

HTML 是页面的骨架,我们用语义化标签搭建清晰的结构,方便后续维护和 SEO。

核心代码解析(index.html):

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!-- 移动端适配关键配置 -->
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, viewport-fit=cover">
  <title>Local TAPAS</title>
  <link rel="stylesheet" href="./common.css"> <!-- 引入样式 -->
</head>
<body>
  <div class="wrapper"> <!-- 主容器 -->
    <h2>Local TAPAS</h2> <!-- 标题 -->
    <p>请添加您的TAPAS</p> <!-- 提示文本 -->
    <ul class="plates"> <!-- 美食列表容器 -->
      <li>Loading Tapas...</li> <!-- 初始占位文本 -->
    </ul>
    <form class="add-items"> <!-- 添加表单 -->
      <input 
        type="text"
        placeholder="Item Name"
        name="item"
        required  <!-- 表单验证不能为空 -->
      >
      <input type="submit" value="+ Add Item"> <!-- 提交按钮 -->
    </form>
  </div>
  <script src="./common.js"></script> <!-- 引入交互逻辑 -->
</body>
</html>

关键知识点:

  1. viewport 配置 📱
    width=device-width:让页面宽度等于设备宽度
    user-scalable=no:禁止用户缩放,保证移动端布局一致性(来自 readme 知识点)
    viewport-fit=cover:适配全面屏(避免刘海遮挡)
  2. 语义化标签 📝
    使用 <ul> + <li> 展示列表(符合语义),<form> 处理用户输入,结构清晰且利于浏览器解析。

🎨 step 2:CSS 样式设计(视觉美化)

CSS 负责让页面「好看」,我们从布局到细节逐步优化,让界面既美观又易用。

1. 全局样式与布局

    /* 基础重置与全局配置 */
    html {
      box-sizing: border-box; /* 盒模型:border和padding不影响宽高 */
      min-height: 100vh; /* 最小高度为视口高度,保证全屏显示 */
      /* Flex布局:让内容居中 */
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      text-align: center;
      /* 背景图设置 */
      background: url("http://wes.io/hx9M/on-la-la.jpg") center no-repeat;
      background-size: cover; /* 背景图等比例缩放,填满容器(裁剪多余部分) */
    }

    * {
      box-sizing: inherit; /* 继承html的box-sizing,统一盒模型 */
    }

知识点:box-sizing: border-box 的妙用 🧩

默认情况下,元素的 width 不包含 border 和 padding,导致布局计算麻烦。设置 border-box 后,width 直接等于「内容 + border+padding」,布局更可控!

2. 容器与卡片样式

    .wrapper {
      padding: 20px;
      min-width: 350px; /* 最小宽度,避免移动端过窄 */
      background-color: rgba(123,255,255,0.95); /* 半透明青色背景 */
      box-shadow: 0 0 0 10px rgba(0,0,0,0.1); /* 外边框阴影,营造立体效果 */
    }

    .wrapper h2 {
      text-align: center;
      margin: 0;
      font-weight: 200; /* 轻量级字体,更优雅 */
    }

细节亮点 ✨

  • rgba(123,255,255,0.95):半透明背景(alpha 值 0.95),既遮挡背景图又保留通透感
  • box-shadow:用「0 0 0 10px」模拟边框,比直接设置 border 更有层次感

3. 列表与表单样式

    /* 美食列表样式 */
    .plates {
      margin: 0;
      padding: 0;
      text-align: left;
      list-style: none; /* 去掉默认列表圆点 */
    }

    .plates li {
      border-bottom: 1px solid rgba(0,0,0,0.2); /* 底部边框分隔项 */
      padding: 10px 0;
      display: flex; /* 弹性布局,方便内容对齐 */
    }

    .plates label {
      flex: 1; /* 占满剩余空间 */
      cursor: pointer; /* 鼠标悬停显示手型,提示可点击 */
    }

    /* 表单样式 */
    .add-items {
      margin-top: 20px; /* 与列表保持距离 */
    }

    .add-items input {
      padding: 10px; /* 输入框内边距,方便输入 */
      outline: 0; /* 去掉默认聚焦边框 */
      border: 1px solid rgba(0,0,0,0.1); /* 浅色边框,不突兀 */
    }

交互优化 🖱️

  • 列表项用 border-bottom 分隔,视觉上更清晰
  • 标签 cursor: pointer 提示用户「可点击」,提升交互体验

💻 step 3:JavaScript 交互逻辑(功能实现)

JS 让页面「动起来」,我们实现「添加美食到列表」的核心功能,逐步完善逻辑。

1. 基础逻辑:获取元素与监听事件

// 获取DOM元素
const addItems = document.querySelector('.add-items'); // 表单元素
const itemsList = document.querySelector('.plates'); // 列表容器

// 存储美食列表数据(后续可持久化到localStorage)
let items = [];

// 表单提交事件处理函数
function addItem(e) {
  e.preventDefault(); // 阻止表单默认提交(避免页面刷新)
  
  // 获取用户输入的美食名称
  const input = this.querySelector('[name="item"]');
  const text = input.value.trim(); // 去除首尾空格
  
  // 若输入不为空,则添加到列表
  if (text) {
    const item = {
      text: text,
      done: false // 标记是否完成(后续可扩展勾选功能)
    };
    
    items.push(item); // 存入数据数组
    input.value = ''; // 清空输入框
    renderItems(); // 重新渲染列表
  }
}

// 监听表单提交事件
addItems.addEventListener('submit', addItem);

2. 渲染列表:将数据展示到页面

// 渲染列表函数
function renderItems() {
  // 拼接HTML字符串(将数组数据转为DOM结构)
  itemsList.innerHTML = items.map((item, index) => `
    <li>
      <label for="item${index}">${item.text}</label>
      <input 
        type="checkbox" 
        id="item${index}" 
        ${item.done ? 'checked' : ''}
      >
    </li>
  `).join(''); // 数组转字符串
}

逻辑解析 🧠

  • items.map(...):遍历数据数组,生成每个列表项的 HTML
  • ${item.done ? 'checked' : ''}:动态添加勾选状态(为后续「完成」功能预留)
  • join(''):将数组转为字符串,避免渲染时出现逗号

3. 扩展:本地存储(localStorage)

为了让数据在页面刷新后不丢失,我们用 localStorage 持久化保存数据:

// 从localStorage读取数据(页面加载时)
function loadItems() {
  const storedItems = localStorage.getItem('tapasItems');
  if (storedItems) {
    items = JSON.parse(storedItems); // 字符串转对象
    renderItems();
  }
}

// 保存数据到localStorage
function saveItems() {
  localStorage.setItem('tapasItems', JSON.stringify(items)); // 对象转字符串
}

// 优化addItem函数:添加后保存数据
function addItem(e) {
  // ... 之前的逻辑 ...
  if (text) {
    // ... 添加item到items ...
    saveItems(); // 新增:保存到本地存储
    renderItems();
  }
}

// 页面加载时读取数据
loadItems();

知识点:localStorage 用法 🗄️

  • localStorage 是浏览器提供的本地存储方案,数据持久化(除非手动清除)
  • 只能存储字符串,因此需要 JSON.stringify() 和 JSON.parse() 转换格式

📚 进阶知识点拓展

除了核心功能,这些知识点能让你对前端开发理解更深~

1. CSS 背景图适配:cover vs contain

  • background-size: cover:背景图等比例缩放,填满容器(可能裁剪部分图像),适合作为全屏背景
  • background-size: contain:背景图等比例缩放,完整显示(可能留空白),适合需要展示完整图像的场景

2. Stylus 预处理器(高效写 CSS)

Stylus 是 CSS 超集,支持缩进语法、变量、模块化,让写 CSS 更高效:

# 安装Stylus
npm install -g stylus

# 编译.styl文件为.css(实时监听)
stylus --watch style.styl -o style.css

示例(Stylus 语法):

// 变量定义
bgColor = rgba(123,255,255,0.95)

.wrapper
  padding: 20px
  background: bgColor // 使用变量
  box-shadow: 0 0 0 10px rgba(0,0,0,0.1)

3. 移动端适配:viewport 配置

<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
  • width=device-width:页面宽度等于设备宽度
  • user-scalable=no:禁止用户缩放,保证布局一致性
  • 移动端开发必加,否则页面可能被默认缩放导致错乱!

🎯 总结与扩展方向

到这里,一个基础的美食清单应用就完成了!功能包括:
✅ 添加美食到列表
✅ 数据本地存储(刷新不丢失)
✅ 响应式布局(适配移动端)

效果图

image.png

你还可以继续扩展:

  • 添加「删除美食」按钮 🗑️

  • 实现「批量勾选完成」功能 ✅

  • 美化勾选样式(如文字划线效果)

希望这篇教程能帮你巩固 HTML、CSS、JS 基础,动手试试吧!有问题欢迎在评论区交流~ 😊