Skip to content

HTML5新特性

本章将介绍HTML5的新增特性,包括新的API、表单增强、本地存储等功能。

HTML5概述

什么是HTML5?

HTML5是HTML的最新版本,于2014年正式发布。它不仅是对HTML4的升级,还包含了CSS3和JavaScript的新特性。

HTML5的设计目标

  1. 兼容性:向后兼容,支持现有网页
  2. 实用性:解决实际开发问题
  3. 互通性:遵循统一标准
  4. 通用访问:支持各种设备和平台

HTML5新特性概览

类别新特性
语义化标签header、nav、article、section、aside、footer等
多媒体video、audio、source、track
图形canvas、svg
表单增强新input类型、新属性、表单验证
本地存储localStorage、sessionStorage、IndexedDB
离线应用Service Worker、Cache API
地理位置Geolocation API
拖放Drag and Drop API
通信WebSocket、WebRTC
其他History API、Web Workers、WebGL等

新的文档声明

HTML5简化了文档声明:

html
<!-- HTML5文档声明(简洁) -->
<!DOCTYPE html>

<!-- HTML4文档声明(复杂) -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

新的表单特性

新增input类型

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>HTML5新增input类型</title>
</head>
<body>
    <form>
        <h2>HTML5新增input类型</h2>
        
        <!-- 邮箱类型:自动验证邮箱格式 -->
        <p>
            <label for="email">邮箱:</label>
            <input type="email" id="email" name="email" placeholder="example@mail.com">
        </p>
        
        <!-- URL类型:自动验证URL格式 -->
        <p>
            <label for="url">网址:</label>
            <input type="url" id="url" name="url" placeholder="https://example.com">
        </p>
        
        <!-- 电话类型:移动端会弹出数字键盘 -->
        <p>
            <label for="tel">电话:</label>
            <input type="tel" id="tel" name="tel" pattern="[0-9]{11}" placeholder="请输入手机号">
        </p>
        
        <!-- 搜索类型:带有清除按钮 -->
        <p>
            <label for="search">搜索:</label>
            <input type="search" id="search" name="search" placeholder="搜索内容">
        </p>
        
        <!-- 数字类型:带上下箭头 -->
        <p>
            <label for="number">数量:</label>
            <input type="number" id="number" name="number" min="1" max="100" step="1" value="1">
        </p>
        
        <!-- 范围类型:滑块选择 -->
        <p>
            <label for="range">音量:</label>
            <input type="range" id="range" name="range" min="0" max="100" value="50">
            <span id="rangeValue">50</span>
        </p>
        
        <!-- 日期选择 -->
        <p>
            <label for="date">日期:</label>
            <input type="date" id="date" name="date">
        </p>
        
        <!-- 时间选择 -->
        <p>
            <label for="time">时间:</label>
            <input type="time" id="time" name="time">
        </p>
        
        <!-- 日期时间选择 -->
        <p>
            <label for="datetime-local">日期时间:</label>
            <input type="datetime-local" id="datetime-local" name="datetime">
        </p>
        
        <!-- 月份选择 -->
        <p>
            <label for="month">月份:</label>
            <input type="month" id="month" name="month">
        </p>
        
        <!-- 周选择 -->
        <p>
            <label for="week">周:</label>
            <input type="week" id="week" name="week">
        </p>
        
        <!-- 颜色选择 -->
        <p>
            <label for="color">颜色:</label>
            <input type="color" id="color" name="color" value="#ff0000">
        </p>
        
        <button type="submit">提交</button>
    </form>
    
    <script>
        // 显示滑块当前值
        document.getElementById('range').addEventListener('input', function() {
            document.getElementById('rangeValue').textContent = this.value;
        });
    </script>
</body>
</html>

新增表单属性

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>HTML5新增表单属性</title>
</head>
<body>
    <form>
        <h2>HTML5新增表单属性</h2>
        
        <!-- placeholder:占位提示 -->
        <p>
            <label for="name">姓名:</label>
            <input type="text" id="name" name="name" placeholder="请输入您的姓名">
        </p>
        
        <!-- autofocus:自动获取焦点 -->
        <p>
            <label for="first">第一个输入框:</label>
            <input type="text" id="first" name="first" autofocus>
        </p>
        
        <!-- required:必填验证 -->
        <p>
            <label for="required">必填项:</label>
            <input type="text" id="required" name="required" required>
        </p>
        
        <!-- pattern:正则验证 -->
        <p>
            <label for="phone">手机号:</label>
            <input type="tel" id="phone" name="phone" pattern="^1[3-9]\d{9}$" 
                   title="请输入正确的手机号">
        </p>
        
        <!-- autocomplete:自动完成 -->
        <p>
            <label for="autocomplete">自动完成:</label>
            <input type="text" id="autocomplete" name="autocomplete" 
                   autocomplete="on" list="suggestions">
            <datalist id="suggestions">
                <option value="HTML">
                <option value="CSS">
                <option value="JavaScript">
                <option value="Vue">
                <option value="React">
            </datalist>
        </p>
        
        <!-- multiple:多选 -->
        <p>
            <label for="files">多文件上传:</label>
            <input type="file" id="files" name="files" multiple>
        </p>
        
        <!-- accept:文件类型限制 -->
        <p>
            <label for="images">图片上传:</label>
            <input type="file" id="images" name="images" accept="image/*">
        </p>
        
        <!-- form:指定所属表单 -->
        <input type="submit" value="提交" form="myForm">
    </form>
    
    <!-- 表单外的输入框也可以属于表单 -->
    <input type="text" name="outside" form="myForm" placeholder="表单外的输入框">
    
    <form id="myForm" action="/submit">
        <!-- 表单内容 -->
    </form>
</body>
</html>

datalist数据列表

<datalist> 为input提供预定义选项:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>datalist示例</title>
</head>
<body>
    <form>
        <h2>datalist数据列表</h2>
        
        <!-- 基本用法 -->
        <p>
            <label for="browser">选择浏览器:</label>
            <input type="text" id="browser" name="browser" list="browsers" 
                   placeholder="输入或选择浏览器">
            <datalist id="browsers">
                <option value="Chrome">
                <option value="Firefox">
                <option value="Safari">
                <option value="Edge">
                <option value="Opera">
            </datalist>
        </p>
        
        <!-- 带label的选项 -->
        <p>
            <label for="city">选择城市:</label>
            <input type="text" id="city" name="city" list="cities">
            <datalist id="cities">
                <option value="北京" label="首都">
                <option value="上海" label="经济中心">
                <option value="广州" label="南方门户">
                <option value="深圳" label="科技之城">
            </datalist>
        </p>
        
        <!-- 与number类型配合 -->
        <p>
            <label for="amount">金额:</label>
            <input type="number" id="amount" name="amount" list="amounts">
            <datalist id="amounts">
                <option value="100">
                <option value="500">
                <option value="1000">
                <option value="5000">
            </datalist>
        </p>
    </form>
</body>
</html>

output元素

<output> 用于显示计算结果:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>output示例</title>
</head>
<body>
    <form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
        <h2>计算器</h2>
        
        <p>
            <label for="a">数值A:</label>
            <input type="number" id="a" name="a" value="0">
        </p>
        
        <p>
            <label for="b">数值B:</label>
            <input type="number" id="b" name="b" value="0">
        </p>
        
        <p>
            <label>结果:</label>
            <!-- output显示计算结果 -->
            <output name="result" for="a b">0</output>
        </p>
    </form>
    
    <hr>
    
    <!-- 滑块示例 -->
    <form oninput="total.value = price.value * quantity.value">
        <h2>价格计算</h2>
        
        <p>
            <label for="price">单价:</label>
            <input type="number" id="price" name="price" value="10" step="0.01">
        </p>
        
        <p>
            <label for="quantity">数量:</label>
            <input type="range" id="quantity" name="quantity" min="1" max="100" value="1">
            <span id="qty">1</span>
        </p>
        
        <p>
            <label>总价:</label>
            <output name="total">10</output>
        </p>
    </form>
    
    <script>
        document.getElementById('quantity').addEventListener('input', function() {
            document.getElementById('qty').textContent = this.value;
        });
    </script>
</body>
</html>

本地存储

HTML5提供了多种本地存储方式,用于在客户端存储数据。

localStorage

localStorage 用于持久化存储数据,没有过期时间:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>localStorage示例</title>
</head>
<body>
    <h2>localStorage 本地存储</h2>
    
    <div>
        <label for="key">键:</label>
        <input type="text" id="key" placeholder="输入键名">
    </div>
    
    <div>
        <label for="value">值:</label>
        <input type="text" id="value" placeholder="输入值">
    </div>
    
    <div>
        <button onclick="saveData()">保存</button>
        <button onclick="loadData()">读取</button>
        <button onclick="removeData()">删除</button>
        <button onclick="clearAll()">清空</button>
    </div>
    
    <div>
        <h3>存储内容:</h3>
        <pre id="output"></pre>
    </div>
    
    <script>
        // 保存数据
        function saveData() {
            const key = document.getElementById('key').value;
            const value = document.getElementById('value').value;
            
            if (key && value) {
                // 使用localStorage.setItem()保存数据
                localStorage.setItem(key, value);
                showAll();
            }
        }
        
        // 读取数据
        function loadData() {
            const key = document.getElementById('key').value;
            
            if (key) {
                // 使用localStorage.getItem()读取数据
                const value = localStorage.getItem(key);
                document.getElementById('value').value = value || '未找到';
            }
        }
        
        // 删除数据
        function removeData() {
            const key = document.getElementById('key').value;
            
            if (key) {
                // 使用localStorage.removeItem()删除数据
                localStorage.removeItem(key);
                showAll();
            }
        }
        
        // 清空所有数据
        function clearAll() {
            // 使用localStorage.clear()清空所有数据
            localStorage.clear();
            showAll();
        }
        
        // 显示所有存储内容
        function showAll() {
            let output = '';
            
            // 遍历localStorage
            for (let i = 0; i < localStorage.length; i++) {
                const key = localStorage.key(i);
                const value = localStorage.getItem(key);
                output += key + ': ' + value + '\n';
            }
            
            document.getElementById('output').textContent = output || '暂无数据';
        }
        
        // 页面加载时显示所有数据
        showAll();
    </script>
</body>
</html>

sessionStorage

sessionStorage 用于会话存储,关闭浏览器后数据会被清除:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>sessionStorage示例</title>
</head>
<body>
    <h2>sessionStorage 会话存储</h2>
    
    <p>sessionStorage的数据在关闭浏览器标签页后会被清除。</p>
    
    <div>
        <label for="inputData">输入数据:</label>
        <input type="text" id="inputData">
        <button onclick="saveSession()">保存</button>
        <button onclick="loadSession()">读取</button>
    </div>
    
    <div>
        <p>存储的数据:<span id="sessionOutput"></span></p>
    </div>
    
    <script>
        // 保存到sessionStorage
        function saveSession() {
            const data = document.getElementById('inputData').value;
            // 使用sessionStorage存储数据
            sessionStorage.setItem('myData', data);
            document.getElementById('sessionOutput').textContent = data;
        }
        
        // 从sessionStorage读取
        function loadSession() {
            const data = sessionStorage.getItem('myData');
            document.getElementById('sessionOutput').textContent = data || '暂无数据';
        }
        
        // 页面加载时读取数据
        window.onload = function() {
            loadSession();
        };
    </script>
</body>
</html>

localStorage vs sessionStorage

特性localStoragesessionStorage
存储大小约5MB约5MB
生命周期永久存储会话期间(关闭标签页清除)
作用域同源的所有标签页共享仅当前标签页可用
APIsetItem/getItem/removeItem/clear相同

地理定位

Geolocation API 用于获取用户的地理位置:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>地理定位示例</title>
</head>
<body>
    <h2>地理定位 Geolocation</h2>
    
    <button onclick="getLocation()">获取我的位置</button>
    
    <div id="location"></div>
    
    <script>
        // 获取地理位置
        function getLocation() {
            const output = document.getElementById('location');
            
            // 检查浏览器是否支持地理定位
            if (navigator.geolocation) {
                output.innerHTML = '正在获取位置...';
                
                // 调用getCurrentPosition获取当前位置
                navigator.geolocation.getCurrentPosition(
                    showPosition,   // 成功回调
                    showError,      // 错误回调
                    {
                        enableHighAccuracy: true,  // 高精度定位
                        timeout: 5000,             // 超时时间
                        maximumAge: 0              // 不使用缓存位置
                    }
                );
            } else {
                output.innerHTML = '您的浏览器不支持地理定位';
            }
        }
        
        // 显示位置信息
        function showPosition(position) {
            const lat = position.coords.latitude;     // 纬度
            const lng = position.coords.longitude;    // 经度
            const accuracy = position.coords.accuracy; // 精度
            
            document.getElementById('location').innerHTML = 
                '纬度: ' + lat + '<br>' +
                '经度: ' + lng + '<br>' +
                '精度: ' + accuracy + '米<br>' +
                '<a href="https://www.google.com/maps?q=' + lat + ',' + lng + '" target="_blank">在地图中查看</a>';
        }
        
        // 错误处理
        function showError(error) {
            let message = '';
            
            switch (error.code) {
                case error.PERMISSION_DENIED:
                    message = '用户拒绝了定位请求';
                    break;
                case error.POSITION_UNAVAILABLE:
                    message = '位置信息不可用';
                    break;
                case error.TIMEOUT:
                    message = '请求超时';
                    break;
                default:
                    message = '未知错误';
            }
            
            document.getElementById('location').innerHTML = '错误: ' + message;
        }
    </script>
</body>
</html>

拖放API

HTML5提供了原生的拖放功能:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>拖放API示例</title>
    <style>
        .container {
            display: flex;
            gap: 20px;
            margin: 20px 0;
        }
        .box {
            width: 150px;
            height: 150px;
            border: 2px dashed #ccc;
            padding: 10px;
            display: flex;
            flex-wrap: wrap;
            align-content: flex-start;
            gap: 5px;
        }
        .draggable {
            width: 50px;
            height: 50px;
            background: #4CAF50;
            color: white;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: move;
            border-radius: 5px;
        }
        .box.drag-over {
            border-color: #4CAF50;
            background: #e8f5e9;
        }
    </style>
</head>
<body>
    <h2>拖放API Drag and Drop</h2>
    
    <p>将绿色方块从一个容器拖到另一个容器:</p>
    
    <div class="container">
        <!-- 源容器 -->
        <div class="box" id="box1">
            <div class="draggable" draggable="true" id="item1">1</div>
            <div class="draggable" draggable="true" id="item2">2</div>
            <div class="draggable" draggable="true" id="item3">3</div>
        </div>
        
        <!-- 目标容器 -->
        <div class="box" id="box2"></div>
    </div>
    
    <script>
        // 获取所有可拖动元素
        const draggables = document.querySelectorAll('.draggable');
        const boxes = document.querySelectorAll('.box');
        
        // 为每个可拖动元素添加事件
        draggables.forEach(draggable => {
            // 拖动开始
            draggable.addEventListener('dragstart', function(e) {
                // 设置拖动数据
                e.dataTransfer.setData('text/plain', this.id);
                // 添加拖动样式
                this.style.opacity = '0.5';
            });
            
            // 拖动结束
            draggable.addEventListener('dragend', function(e) {
                this.style.opacity = '1';
            });
        });
        
        // 为每个容器添加事件
        boxes.forEach(box => {
            // 拖动元素进入容器
            box.addEventListener('dragenter', function(e) {
                e.preventDefault();
                this.classList.add('drag-over');
            });
            
            // 拖动元素在容器上方移动
            box.addEventListener('dragover', function(e) {
                e.preventDefault(); // 必须阻止默认行为才能放置
            });
            
            // 拖动元素离开容器
            box.addEventListener('dragleave', function(e) {
                this.classList.remove('drag-over');
            });
            
            // 放置元素
            box.addEventListener('drop', function(e) {
                e.preventDefault();
                this.classList.remove('drag-over');
                
                // 获取拖动元素的ID
                const id = e.dataTransfer.getData('text/plain');
                const draggable = document.getElementById(id);
                
                // 将元素添加到新容器
                this.appendChild(draggable);
            });
        });
    </script>
</body>
</html>

Web Workers

Web Workers 允许在后台线程中运行JavaScript,不会阻塞页面:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Web Workers示例</title>
</head>
<body>
    <h2>Web Workers 后台线程</h2>
    
    <p>Web Workers可以在后台执行耗时任务,不会阻塞页面。</p>
    
    <div>
        <button onclick="startCalculation()">开始计算(使用Worker)</button>
        <button onclick="startBlocking()">开始计算(阻塞主线程)</button>
    </div>
    
    <div>
        <p>计算结果:<span id="result"></span></p>
        <p>页面状态:<input type="text" placeholder="输入测试页面是否卡顿"></p>
    </div>
    
    <script>
        // 使用Web Worker计算
        function startCalculation() {
            document.getElementById('result').textContent = '计算中...';
            
            // 创建Worker
            const worker = new Worker(URL.createObjectURL(new Blob([`
                // Worker代码
                let result = 0;
                for (let i = 0; i < 10000000000; i++) {
                    result += i;
                }
                // 发送结果回主线程
                postMessage(result);
            `])));
            
            // 接收Worker消息
            worker.onmessage = function(e) {
                document.getElementById('result').textContent = e.data;
                worker.terminate(); // 关闭Worker
            };
        }
        
        // 阻塞主线程计算(对比用)
        function startBlocking() {
            document.getElementById('result').textContent = '计算中...';
            
            // 这个计算会阻塞页面
            setTimeout(() => {
                let result = 0;
                for (let i = 0; i < 10000000000; i++) {
                    result += i;
                }
                document.getElementById('result').textContent = result;
            }, 100);
        }
    </script>
</body>
</html>

History API

History API 用于操作浏览器历史记录:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>History API示例</title>
</head>
<body>
    <h2>History API 历史记录管理</h2>
    
    <nav>
        <button onclick="goToPage('home')">首页</button>
        <button onclick="goToPage('about')">关于</button>
        <button onclick="goToPage('contact')">联系</button>
    </nav>
    
    <div id="content">
        <h3>欢迎访问首页</h3>
        <p>这是首页内容</p>
    </div>
    
    <div>
        <button onclick="history.back()">后退</button>
        <button onclick="history.forward()">前进</button>
        <button onclick="history.go(-2)">后退两步</button>
    </div>
    
    <script>
        // 页面内容
        const pages = {
            home: {
                title: '首页',
                content: '<h3>欢迎访问首页</h3><p>这是首页内容</p>'
            },
            about: {
                title: '关于',
                content: '<h3>关于我们</h3><p>这是关于页面内容</p>'
            },
            contact: {
                title: '联系',
                content: '<h3>联系方式</h3><p>这是联系页面内容</p>'
            }
        };
        
        // 导航到页面
        function goToPage(page) {
            const pageData = pages[page];
            
            // 更新页面内容
            document.getElementById('content').innerHTML = pageData.content;
            document.title = pageData.title;
            
            // 使用pushState添加历史记录
            history.pushState({ page: page }, pageData.title, '#' + page);
        }
        
        // 监听popstate事件(前进/后退时触发)
        window.addEventListener('popstate', function(e) {
            if (e.state) {
                const pageData = pages[e.state.page];
                document.getElementById('content').innerHTML = pageData.content;
                document.title = pageData.title;
            }
        });
    </script>
</body>
</html>

内容可编辑

contenteditable 属性使元素可编辑:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>内容可编辑示例</title>
    <style>
        .editable {
            border: 1px solid #ccc;
            padding: 15px;
            min-height: 100px;
            margin: 10px 0;
        }
        .editable:focus {
            outline: 2px solid #4CAF50;
        }
    </style>
</head>
<body>
    <h2>contenteditable 内容可编辑</h2>
    
    <h3>可编辑的div</h3>
    <div class="editable" contenteditable="true">
        这是一段可编辑的文字,点击即可修改内容。
    </div>
    
    <h3>可编辑的列表</h3>
    <ul contenteditable="true">
        <li>第一项(可编辑)</li>
        <li>第二项(可编辑)</li>
        <li>第三项(可编辑)</li>
    </ul>
    
    <h3>整个区域可编辑</h3>
    <div contenteditable="true" class="editable">
        <h4>标题也可以编辑</h4>
        <p>段落也可以编辑</p>
        <ul>
            <li>列表项也可以编辑</li>
        </ul>
    </div>
    
    <h3>保存编辑内容</h3>
    <div class="editable" contenteditable="true" id="saveArea">
        编辑后点击保存按钮
    </div>
    <button onclick="saveContent()">保存内容</button>
    <p>保存的内容:<span id="savedContent"></span></p>
    
    <script>
        function saveContent() {
            const content = document.getElementById('saveArea').innerHTML;
            localStorage.setItem('editableContent', content);
            document.getElementById('savedContent').textContent = '已保存到localStorage';
        }
        
        // 加载保存的内容
        window.onload = function() {
            const saved = localStorage.getItem('editableContent');
            if (saved) {
                document.getElementById('saveArea').innerHTML = saved;
            }
        };
    </script>
</body>
</html>

综合示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HTML5新特性综合示例</title>
    <style>
        * {
            box-sizing: border-box;
        }
        body {
            font-family: Arial, sans-serif;
            max-width: 1000px;
            margin: 0 auto;
            padding: 20px;
            background: #f5f5f5;
        }
        .section {
            background: white;
            padding: 20px;
            margin-bottom: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        h2 {
            color: #333;
            border-bottom: 2px solid #4CAF50;
            padding-bottom: 10px;
        }
        input, button {
            padding: 10px;
            margin: 5px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        button {
            background: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
        }
        button:hover {
            background: #45a049;
        }
        .note-area {
            width: 100%;
            min-height: 150px;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        .note-area:focus {
            outline: 2px solid #4CAF50;
        }
        .status {
            padding: 10px;
            margin: 10px 0;
            background: #e8f5e9;
            border-radius: 4px;
        }
    </style>
</head>
<body>
    <h1>HTML5新特性综合示例</h1>
    
    <!-- 本地存储示例 -->
    <section class="section">
        <h2>本地存储 - 记事本</h2>
        <p>使用localStorage保存笔记,刷新页面后内容仍然存在。</p>
        
        <textarea id="noteArea" class="note-area" placeholder="在这里输入笔记内容..."></textarea>
        
        <div>
            <button onclick="saveNote()">保存笔记</button>
            <button onclick="clearNote()">清空笔记</button>
        </div>
        
        <div id="noteStatus" class="status"></div>
    </section>
    
    <!-- 表单增强示例 -->
    <section class="section">
        <h2>表单增强</h2>
        
        <form id="enhancedForm">
            <p>
                <label for="email">邮箱:</label>
                <input type="email" id="email" name="email" required placeholder="example@mail.com">
            </p>
            
            <p>
                <label for="website">网站:</label>
                <input type="url" id="website" name="website" placeholder="https://">
            </p>
            
            <p>
                <label for="birthday">生日:</label>
                <input type="date" id="birthday" name="birthday">
            </p>
            
            <p>
                <label for="quantity">数量:</label>
                <input type="number" id="quantity" name="quantity" min="1" max="100" value="1">
            </p>
            
            <p>
                <label for="color">颜色:</label>
                <input type="color" id="color" name="color" value="#4CAF50">
            </p>
            
            <p>
                <label for="search">搜索:</label>
                <input type="search" id="search" name="search" list="suggestions" placeholder="输入或选择">
                <datalist id="suggestions">
                    <option value="HTML5">
                    <option value="CSS3">
                    <option value="JavaScript">
                    <option value="Vue.js">
                    <option value="React">
                </datalist>
            </p>
            
            <button type="submit">提交表单</button>
        </form>
    </section>
    
    <!-- 地理定位示例 -->
    <section class="section">
        <h2>地理定位</h2>
        <button onclick="getLocation()">获取我的位置</button>
        <div id="locationResult" class="status"></div>
    </section>
    
    <!-- 内容可编辑示例 -->
    <section class="section">
        <h2>内容可编辑</h2>
        <p>下面的区域可以直接编辑:</p>
        <div contenteditable="true" class="note-area">
            点击这里可以直接编辑内容,无需输入框。
        </div>
    </section>
    
    <!-- 拖放示例 -->
    <section class="section">
        <h2>拖放功能</h2>
        <p>将项目从一个列表拖到另一个列表:</p>
        
        <div style="display: flex; gap: 20px;">
            <div>
                <h4>待办事项</h4>
                <ul id="todoList" style="min-height: 100px; border: 2px dashed #ccc; padding: 10px; list-style: none;">
                    <li draggable="true" style="padding: 10px; background: #e3f2fd; margin: 5px 0; cursor: move;">任务1</li>
                    <li draggable="true" style="padding: 10px; background: #e3f2fd; margin: 5px 0; cursor: move;">任务2</li>
                    <li draggable="true" style="padding: 10px; background: #e3f2fd; margin: 5px 0; cursor: move;">任务3</li>
                </ul>
            </div>
            
            <div>
                <h4>已完成</h4>
                <ul id="doneList" style="min-height: 100px; border: 2px dashed #ccc; padding: 10px; list-style: none;"></ul>
            </div>
        </div>
    </section>
    
    <script>
        // ==================== 本地存储 ====================
        const noteArea = document.getElementById('noteArea');
        const noteStatus = document.getElementById('noteStatus');
        
        // 加载保存的笔记
        function loadNote() {
            const saved = localStorage.getItem('myNote');
            if (saved) {
                noteArea.value = saved;
                noteStatus.textContent = '已加载保存的笔记';
            }
        }
        
        // 保存笔记
        function saveNote() {
            localStorage.setItem('myNote', noteArea.value);
            noteStatus.textContent = '笔记已保存!保存时间:' + new Date().toLocaleString();
        }
        
        // 清空笔记
        function clearNote() {
            noteArea.value = '';
            localStorage.removeItem('myNote');
            noteStatus.textContent = '笔记已清空';
        }
        
        // 自动保存
        noteArea.addEventListener('input', function() {
            localStorage.setItem('myNote', this.value);
        });
        
        // 页面加载时读取笔记
        loadNote();
        
        // ==================== 地理定位 ====================
        function getLocation() {
            const result = document.getElementById('locationResult');
            
            if (navigator.geolocation) {
                result.textContent = '正在获取位置...';
                
                navigator.geolocation.getCurrentPosition(
                    function(position) {
                        const lat = position.coords.latitude.toFixed(6);
                        const lng = position.coords.longitude.toFixed(6);
                        result.innerHTML = '纬度: ' + lat + ', 经度: ' + lng + 
                            '<br><a href="https://www.google.com/maps?q=' + lat + ',' + lng + '" target="_blank">在地图中查看</a>';
                    },
                    function(error) {
                        result.textContent = '获取位置失败: ' + error.message;
                    }
                );
            } else {
                result.textContent = '您的浏览器不支持地理定位';
            }
        }
        
        // ==================== 拖放功能 ====================
        const todoList = document.getElementById('todoList');
        const doneList = document.getElementById('doneList');
        
        // 为所有列表添加拖放事件
        [todoList, doneList].forEach(list => {
            list.addEventListener('dragover', function(e) {
                e.preventDefault();
            });
            
            list.addEventListener('drop', function(e) {
                e.preventDefault();
                const data = e.dataTransfer.getData('text/plain');
                const item = document.querySelector('[data-id="' + data + '"]');
                if (item) {
                    item.style.background = '#c8e6c9';
                    this.appendChild(item);
                }
            });
        });
        
        // 为可拖动项添加事件
        document.querySelectorAll('[draggable="true"]').forEach((item, index) => {
            item.dataset.id = 'item-' + index;
            
            item.addEventListener('dragstart', function(e) {
                e.dataTransfer.setData('text/plain', this.dataset.id);
                this.style.opacity = '0.5';
            });
            
            item.addEventListener('dragend', function(e) {
                this.style.opacity = '1';
            });
        });
        
        // ==================== 表单提交 ====================
        document.getElementById('enhancedForm').addEventListener('submit', function(e) {
            e.preventDefault();
            alert('表单验证通过!数据已提交。');
        });
    </script>
</body>
</html>

本章小结

本章我们学习了HTML5的主要新特性:

  1. 表单增强:新增input类型(email、url、date、number等)、新属性(placeholder、required、pattern等)
  2. 本地存储:localStorage和sessionStorage
  3. 地理定位:Geolocation API获取用户位置
  4. 拖放功能:Drag and Drop API
  5. Web Workers:后台线程执行任务
  6. History API:管理浏览器历史记录
  7. 内容可编辑:contenteditable属性

HTML5还包含许多其他特性,如WebSocket、WebGL、IndexedDB、Service Worker等,这些内容可以在后续学习中深入探索。

教程总结

恭喜你完成了HTML教程的学习!你已经掌握了:

  • HTML基础概念和文档结构
  • 常用HTML标签的使用
  • 链接和图像的添加
  • 列表和表格的创建
  • 表单的设计和验证
  • 多媒体元素的嵌入
  • 语义化标签的应用
  • HTML5新特性

接下来,建议你:

  1. 多动手实践,创建自己的网页
  2. 学习CSS,美化你的网页
  3. 学习JavaScript,添加交互功能
  4. 了解前端框架,提升开发效率

祝你学习愉快!