Skip to content

3.4 其他表单元素

关键词: HTML5表单元素, textarea多行文本, select下拉列表, button按钮, label标签, fieldset字段集, datalist数据列表, 表单组件

学习目标

  • 掌握HTML5表单中的其他重要元素
  • 理解各种表单元素的作用和使用场景
  • 学会创建复杂的表单结构
  • 掌握表单元素的样式定制和交互处理

3.4.1 多行文本(textarea)

基本语法

html
<textarea name="description" id="description"></textarea>

详细介绍

textarea元素用于输入多行文本,适合长篇内容如评论、描述、留言等。

重要属性

1. 基础属性

html
<textarea name="content" 
          id="content"
          rows="5" 
          cols="50"
          placeholder="请输入内容..."
          maxlength="500"
          required
          readonly
          disabled></textarea>

属性说明:

  • rows: 可见行数
  • cols: 可见列数(字符宽度)
  • placeholder: 提示文本
  • maxlength: 最大字符数
  • required: 必填字段
  • readonly: 只读模式
  • disabled: 禁用状态

2. 实际应用示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>多行文本示例</title>
    <style>
        .textarea-container {
            max-width: 600px;
            margin: 20px auto;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 8px;
        }
        
        .form-group {
            margin-bottom: 20px;
        }
        
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        
        .textarea-input {
            width: 100%;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
            font-size: 14px;
            font-family: inherit;
            resize: vertical;
            transition: border-color 0.3s;
        }
        
        .textarea-input:focus {
            outline: none;
            border-color: #007bff;
            box-shadow: 0 0 0 2px rgba(0,123,255,0.25);
        }
        
        .char-counter {
            text-align: right;
            font-size: 12px;
            color: #666;
            margin-top: 5px;
        }
        
        .char-counter.warning {
            color: #ffc107;
        }
        
        .char-counter.danger {
            color: #dc3545;
        }
        
        .textarea-toolbar {
            display: flex;
            gap: 10px;
            margin-bottom: 10px;
            padding: 8px;
            background-color: #f8f9fa;
            border-radius: 4px;
        }
        
        .toolbar-btn {
            padding: 5px 10px;
            border: 1px solid #ccc;
            background-color: white;
            border-radius: 3px;
            cursor: pointer;
            font-size: 12px;
        }
        
        .toolbar-btn:hover {
            background-color: #e9ecef;
        }
        
        .auto-resize {
            min-height: 100px;
            overflow-y: hidden;
        }
        
        .preview-container {
            margin-top: 15px;
            padding: 15px;
            border: 1px solid #ddd;
            border-radius: 4px;
            background-color: #f8f9fa;
        }
        
        .preview-title {
            font-weight: bold;
            margin-bottom: 10px;
            color: #333;
        }
        
        .preview-content {
            white-space: pre-wrap;
            font-family: inherit;
            line-height: 1.5;
        }
    </style>
</head>
<body>
    <div class="textarea-container">
        <h3>多行文本示例</h3>
        
        <form>
            <div class="form-group">
                <label for="comment">评论内容:</label>
                <textarea id="comment" name="comment" 
                          class="textarea-input" rows="4" 
                          placeholder="请输入您的评论..." 
                          maxlength="500" 
                          oninput="updateCharCount('comment', 500)"></textarea>
                <div class="char-counter" id="comment-counter">0/500</div>
            </div>
            
            <div class="form-group">
                <label for="description">产品描述:</label>
                <div class="textarea-toolbar">
                    <button type="button" class="toolbar-btn" onclick="formatText('description', 'bold')">粗体</button>
                    <button type="button" class="toolbar-btn" onclick="formatText('description', 'italic')">斜体</button>
                    <button type="button" class="toolbar-btn" onclick="formatText('description', 'underline')">下划线</button>
                    <button type="button" class="toolbar-btn" onclick="insertText('description', '• ')">列表</button>
                    <button type="button" class="toolbar-btn" onclick="clearText('description')">清空</button>
                </div>
                <textarea id="description" name="description" 
                          class="textarea-input" rows="6" 
                          placeholder="请输入产品描述..." 
                          oninput="updatePreview('description')"></textarea>
                <div class="preview-container" id="description-preview">
                    <div class="preview-title">预览:</div>
                    <div class="preview-content" id="description-content">内容将在这里显示...</div>
                </div>
            </div>
            
            <div class="form-group">
                <label for="auto-resize">自动调整高度:</label>
                <textarea id="auto-resize" name="auto-resize" 
                          class="textarea-input auto-resize" 
                          placeholder="输入内容时高度会自动调整..." 
                          oninput="autoResize(this)"></textarea>
            </div>
            
            <div class="form-group">
                <label for="code-editor">代码编辑器:</label>
                <textarea id="code-editor" name="code-editor" 
                          class="textarea-input" rows="8" 
                          placeholder="请输入代码..." 
                          style="font-family: 'Courier New', monospace; background-color: #f4f4f4;"
                          oninput="highlightCode(this)"></textarea>
            </div>
            
            <button type="submit">提交</button>
        </form>
    </div>
    
    <script>
        function updateCharCount(textareaId, maxLength) {
            const textarea = document.getElementById(textareaId);
            const counter = document.getElementById(textareaId + '-counter');
            const currentLength = textarea.value.length;
            
            counter.textContent = `${currentLength}/${maxLength}`;
            
            // 根据剩余字符数改变颜色
            if (currentLength > maxLength * 0.9) {
                counter.className = 'char-counter danger';
            } else if (currentLength > maxLength * 0.8) {
                counter.className = 'char-counter warning';
            } else {
                counter.className = 'char-counter';
            }
        }
        
        function formatText(textareaId, format) {
            const textarea = document.getElementById(textareaId);
            const start = textarea.selectionStart;
            const end = textarea.selectionEnd;
            const selectedText = textarea.value.substring(start, end);
            
            if (selectedText) {
                let formattedText = selectedText;
                
                switch (format) {
                    case 'bold':
                        formattedText = `**${selectedText}**`;
                        break;
                    case 'italic':
                        formattedText = `*${selectedText}*`;
                        break;
                    case 'underline':
                        formattedText = `__${selectedText}__`;
                        break;
                }
                
                textarea.value = textarea.value.substring(0, start) + 
                               formattedText + 
                               textarea.value.substring(end);
                
                // 重新定位光标
                textarea.selectionStart = start;
                textarea.selectionEnd = start + formattedText.length;
                textarea.focus();
                
                updatePreview(textareaId);
            }
        }
        
        function insertText(textareaId, text) {
            const textarea = document.getElementById(textareaId);
            const start = textarea.selectionStart;
            const end = textarea.selectionEnd;
            
            textarea.value = textarea.value.substring(0, start) + 
                           text + 
                           textarea.value.substring(end);
            
            textarea.selectionStart = textarea.selectionEnd = start + text.length;
            textarea.focus();
            
            updatePreview(textareaId);
        }
        
        function clearText(textareaId) {
            const textarea = document.getElementById(textareaId);
            if (confirm('确定要清空所有内容吗?')) {
                textarea.value = '';
                textarea.focus();
                updatePreview(textareaId);
            }
        }
        
        function updatePreview(textareaId) {
            const textarea = document.getElementById(textareaId);
            const previewContent = document.getElementById(textareaId + '-content');
            
            if (previewContent) {
                let content = textarea.value;
                
                // 简单的Markdown渲染
                content = content
                    .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
                    .replace(/\*(.*?)\*/g, '<em>$1</em>')
                    .replace(/__(.*?)__/g, '<u>$1</u>')
                    .replace(/\n/g, '<br>');
                
                previewContent.innerHTML = content || '内容将在这里显示...';
            }
        }
        
        function autoResize(textarea) {
            textarea.style.height = 'auto';
            textarea.style.height = textarea.scrollHeight + 'px';
        }
        
        function highlightCode(textarea) {
            // 简单的语法高亮(仅作演示)
            const code = textarea.value;
            
            // 检测可能的编程语言
            if (code.includes('function') || code.includes('var') || code.includes('const')) {
                textarea.style.backgroundColor = '#fff3cd';
            } else if (code.includes('<') && code.includes('>')) {
                textarea.style.backgroundColor = '#d4edda';
            } else if (code.includes('def') || code.includes('import')) {
                textarea.style.backgroundColor = '#d1ecf1';
            } else {
                textarea.style.backgroundColor = '#f4f4f4';
            }
        }
        
        // 初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 为所有textarea添加字符计数
            document.querySelectorAll('textarea[maxlength]').forEach(textarea => {
                const maxLength = parseInt(textarea.getAttribute('maxlength'));
                if (maxLength) {
                    updateCharCount(textarea.id, maxLength);
                }
            });
        });
    </script>
</body>
</html>

易错点提醒

  1. 默认内容:textarea的默认内容写在开闭标签之间,不是value属性
  2. resize属性:可以控制用户是否能调整大小
  3. 字体继承:textarea默认使用等宽字体,可能需要设置font-family

3.4.2 下拉列表(select、option)

基本语法

html
<select name="city" id="city">
    <option value="beijing">北京</option>
    <option value="shanghai">上海</option>
    <option value="guangzhou">广州</option>
</select>

详细介绍

select元素创建下拉列表,option元素定义选项。

重要特性

1. 基础使用

html
<select name="country" id="country" required>
    <option value="">请选择国家</option>
    <option value="china">中国</option>
    <option value="usa">美国</option>
    <option value="japan">日本</option>
</select>

2. 实际应用示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>下拉列表示例</title>
    <style>
        .select-container {
            max-width: 600px;
            margin: 20px auto;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 8px;
        }
        
        .form-group {
            margin-bottom: 20px;
        }
        
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        
        .select-input {
            width: 100%;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
            font-size: 14px;
            background-color: white;
        }
        
        .select-input:focus {
            outline: none;
            border-color: #007bff;
            box-shadow: 0 0 0 2px rgba(0,123,255,0.25);
        }
        
        .select-multiple {
            height: 120px;
        }
        
        .select-group {
            display: flex;
            gap: 15px;
        }
        
        .select-group .form-group {
            flex: 1;
        }
        
        .option-group {
            background-color: #f8f9fa;
            font-weight: bold;
            color: #495057;
        }
        
        .custom-select {
            position: relative;
        }
        
        .custom-select-trigger {
            width: 100%;
            padding: 10px 30px 10px 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
            background-color: white;
            cursor: pointer;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .custom-select-trigger:focus {
            outline: none;
            border-color: #007bff;
            box-shadow: 0 0 0 2px rgba(0,123,255,0.25);
        }
        
        .custom-select-options {
            position: absolute;
            top: 100%;
            left: 0;
            right: 0;
            background-color: white;
            border: 1px solid #ccc;
            border-top: none;
            border-radius: 0 0 4px 4px;
            max-height: 200px;
            overflow-y: auto;
            z-index: 1000;
            display: none;
        }
        
        .custom-select-option {
            padding: 10px;
            cursor: pointer;
            transition: background-color 0.2s;
        }
        
        .custom-select-option:hover {
            background-color: #f8f9fa;
        }
        
        .custom-select-option.selected {
            background-color: #007bff;
            color: white;
        }
        
        .summary-box {
            margin-top: 20px;
            padding: 15px;
            background-color: #f8f9fa;
            border-radius: 4px;
            border-left: 4px solid #007bff;
        }
    </style>
</head>
<body>
    <div class="select-container">
        <h3>下拉列表示例</h3>
        
        <form>
            <div class="form-group">
                <label for="country">国家:</label>
                <select id="country" name="country" class="select-input" 
                        onchange="updateCities()" required>
                    <option value="">请选择国家</option>
                    <option value="china">中国</option>
                    <option value="usa">美国</option>
                    <option value="japan">日本</option>
                    <option value="korea">韩国</option>
                </select>
            </div>
            
            <div class="form-group">
                <label for="city">城市:</label>
                <select id="city" name="city" class="select-input" disabled>
                    <option value="">请先选择国家</option>
                </select>
            </div>
            
            <div class="form-group">
                <label for="category">产品分类:</label>
                <select id="category" name="category" class="select-input">
                    <option value="">请选择分类</option>
                    <optgroup label="电子产品">
                        <option value="phone">手机</option>
                        <option value="computer">电脑</option>
                        <option value="tablet">平板</option>
                    </optgroup>
                    <optgroup label="家用电器">
                        <option value="tv">电视</option>
                        <option value="fridge">冰箱</option>
                        <option value="washer">洗衣机</option>
                    </optgroup>
                    <optgroup label="服装鞋帽">
                        <option value="clothing">服装</option>
                        <option value="shoes">鞋子</option>
                        <option value="accessories">配饰</option>
                    </optgroup>
                </select>
            </div>
            
            <div class="form-group">
                <label for="skills">技能(可多选):</label>
                <select id="skills" name="skills" class="select-input select-multiple" 
                        multiple onchange="updateSkillsSummary()">
                    <option value="html">HTML</option>
                    <option value="css">CSS</option>
                    <option value="javascript">JavaScript</option>
                    <option value="react">React</option>
                    <option value="vue">Vue.js</option>
                    <option value="angular">Angular</option>
                    <option value="nodejs">Node.js</option>
                    <option value="python">Python</option>
                    <option value="java">Java</option>
                    <option value="php">PHP</option>
                </select>
                <div style="font-size: 12px; color: #666; margin-top: 5px;">
                    按住Ctrl键可选择多个选项
                </div>
            </div>
            
            <div class="form-group">
                <label for="priority">优先级:</label>
                <select id="priority" name="priority" class="select-input" 
                        onchange="updatePriorityStyle(this)">
                    <option value="">请选择优先级</option>
                    <option value="low">低</option>
                    <option value="medium">中</option>
                    <option value="high">高</option>
                    <option value="urgent">紧急</option>
                </select>
            </div>
            
            <div class="form-group">
                <label>自定义下拉列表:</label>
                <div class="custom-select" id="custom-select">
                    <div class="custom-select-trigger" tabindex="0" 
                         onclick="toggleCustomSelect()" onkeydown="handleCustomSelectKey(event)">
                        <span id="custom-select-value">请选择主题</span>
                        <span>▼</span>
                    </div>
                    <div class="custom-select-options" id="custom-select-options">
                        <div class="custom-select-option" onclick="selectCustomOption('light', '浅色主题')">
                            🌞 浅色主题
                        </div>
                        <div class="custom-select-option" onclick="selectCustomOption('dark', '深色主题')">
                            🌙 深色主题
                        </div>
                        <div class="custom-select-option" onclick="selectCustomOption('auto', '自动切换')">
                            🔄 自动切换
                        </div>
                        <div class="custom-select-option" onclick="selectCustomOption('colorful', '彩色主题')">
                            🎨 彩色主题
                        </div>
                    </div>
                </div>
                <input type="hidden" id="custom-select-hidden" name="theme" value="">
            </div>
            
            <div class="summary-box">
                <h4>选择汇总:</h4>
                <p><strong>国家:</strong><span id="country-summary">未选择</span></p>
                <p><strong>城市:</strong><span id="city-summary">未选择</span></p>
                <p><strong>分类:</strong><span id="category-summary">未选择</span></p>
                <p><strong>技能:</strong><span id="skills-summary">未选择</span></p>
                <p><strong>优先级:</strong><span id="priority-summary">未选择</span></p>
                <p><strong>主题:</strong><span id="theme-summary">未选择</span></p>
            </div>
            
            <button type="submit">提交</button>
        </form>
    </div>
    
    <script>
        // 城市数据
        const cityData = {
            china: ['北京', '上海', '广州', '深圳', '杭州', '成都'],
            usa: ['纽约', '洛杉矶', '芝加哥', '休斯顿', '费城', '凤凰城'],
            japan: ['东京', '大阪', '京都', '横滨', '名古屋', '神户'],
            korea: ['首尔', '釜山', '大邱', '仁川', '光州', '大田']
        };
        
        function updateCities() {
            const countrySelect = document.getElementById('country');
            const citySelect = document.getElementById('city');
            const selectedCountry = countrySelect.value;
            
            // 清空城市选项
            citySelect.innerHTML = '<option value="">请选择城市</option>';
            
            if (selectedCountry && cityData[selectedCountry]) {
                citySelect.disabled = false;
                
                cityData[selectedCountry].forEach(city => {
                    const option = document.createElement('option');
                    option.value = city.toLowerCase();
                    option.textContent = city;
                    citySelect.appendChild(option);
                });
            } else {
                citySelect.disabled = true;
            }
            
            updateSummary();
        }
        
        function updateSkillsSummary() {
            const skillsSelect = document.getElementById('skills');
            const selectedSkills = Array.from(skillsSelect.selectedOptions).map(option => option.text);
            
            document.getElementById('skills-summary').textContent = 
                selectedSkills.length > 0 ? selectedSkills.join(', ') : '未选择';
        }
        
        function updatePriorityStyle(select) {
            const priority = select.value;
            
            switch (priority) {
                case 'low':
                    select.style.backgroundColor = '#d4edda';
                    select.style.color = '#155724';
                    break;
                case 'medium':
                    select.style.backgroundColor = '#fff3cd';
                    select.style.color = '#856404';
                    break;
                case 'high':
                    select.style.backgroundColor = '#f8d7da';
                    select.style.color = '#721c24';
                    break;
                case 'urgent':
                    select.style.backgroundColor = '#dc3545';
                    select.style.color = 'white';
                    break;
                default:
                    select.style.backgroundColor = 'white';
                    select.style.color = 'black';
            }
            
            updateSummary();
        }
        
        function toggleCustomSelect() {
            const options = document.getElementById('custom-select-options');
            const isVisible = options.style.display === 'block';
            
            options.style.display = isVisible ? 'none' : 'block';
            
            if (!isVisible) {
                // 点击外部关闭
                document.addEventListener('click', closeCustomSelect);
            }
        }
        
        function closeCustomSelect(event) {
            const customSelect = document.getElementById('custom-select');
            
            if (!customSelect.contains(event.target)) {
                document.getElementById('custom-select-options').style.display = 'none';
                document.removeEventListener('click', closeCustomSelect);
            }
        }
        
        function selectCustomOption(value, text) {
            document.getElementById('custom-select-value').textContent = text;
            document.getElementById('custom-select-hidden').value = value;
            document.getElementById('custom-select-options').style.display = 'none';
            document.removeEventListener('click', closeCustomSelect);
            
            // 更新选中状态
            document.querySelectorAll('.custom-select-option').forEach(option => {
                option.classList.remove('selected');
            });
            event.target.classList.add('selected');
            
            updateSummary();
        }
        
        function handleCustomSelectKey(event) {
            if (event.key === 'Enter' || event.key === ' ') {
                event.preventDefault();
                toggleCustomSelect();
            }
        }
        
        function updateSummary() {
            const country = document.getElementById('country');
            const city = document.getElementById('city');
            const category = document.getElementById('category');
            const priority = document.getElementById('priority');
            const theme = document.getElementById('custom-select-hidden');
            
            document.getElementById('country-summary').textContent = 
                country.selectedOptions[0]?.text || '未选择';
            
            document.getElementById('city-summary').textContent = 
                city.selectedOptions[0]?.text || '未选择';
            
            document.getElementById('category-summary').textContent = 
                category.selectedOptions[0]?.text || '未选择';
            
            document.getElementById('priority-summary').textContent = 
                priority.selectedOptions[0]?.text || '未选择';
            
            document.getElementById('theme-summary').textContent = 
                document.getElementById('custom-select-value').textContent === '请选择主题' ? 
                '未选择' : document.getElementById('custom-select-value').textContent;
        }
        
        // 监听所有select变化
        document.querySelectorAll('select').forEach(select => {
            select.addEventListener('change', updateSummary);
        });
        
        // 初始化
        updateSkillsSummary();
    </script>
</body>
</html>

易错点提醒

  1. 默认选项:第一个option通常作为提示,value为空
  2. multiple属性:启用多选,需要在服务器端处理数组
  3. optgroup:用于分组选项,不能被选择

3.4.3 数据列表(datalist)

基本语法

html
<input type="text" list="browsers">
<datalist id="browsers">
    <option value="Chrome">
    <option value="Firefox">
    <option value="Safari">
    <option value="Edge">
</datalist>

详细介绍

datalist元素为输入框提供预定义选项列表,用户可以选择或自由输入。

实际应用示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>数据列表示例</title>
    <style>
        .datalist-container {
            max-width: 500px;
            margin: 20px auto;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 8px;
        }
        
        .form-group {
            margin-bottom: 20px;
        }
        
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }
        
        .datalist-input {
            width: 100%;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
            font-size: 14px;
        }
        
        .datalist-input:focus {
            outline: none;
            border-color: #007bff;
            box-shadow: 0 0 0 2px rgba(0,123,255,0.25);
        }
        
        .input-group {
            display: flex;
            gap: 10px;
        }
        
        .input-group .datalist-input {
            flex: 1;
        }
        
        .add-btn {
            padding: 10px 15px;
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        
        .suggestion-info {
            font-size: 12px;
            color: #666;
            margin-top: 5px;
        }
        
        .selected-items {
            margin-top: 10px;
            display: flex;
            flex-wrap: wrap;
            gap: 5px;
        }
        
        .selected-item {
            padding: 5px 10px;
            background-color: #e3f2fd;
            border: 1px solid #2196f3;
            border-radius: 15px;
            font-size: 12px;
            display: flex;
            align-items: center;
            gap: 5px;
        }
        
        .remove-item {
            cursor: pointer;
            color: #2196f3;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <div class="datalist-container">
        <h3>数据列表示例</h3>
        
        <form>
            <div class="form-group">
                <label for="browser">浏览器:</label>
                <input type="text" id="browser" name="browser" 
                       class="datalist-input" list="browsers" 
                       placeholder="请选择或输入浏览器名称">
                <datalist id="browsers">
                    <option value="Chrome">Google Chrome</option>
                    <option value="Firefox">Mozilla Firefox</option>
                    <option value="Safari">Apple Safari</option>
                    <option value="Edge">Microsoft Edge</option>
                    <option value="Opera">Opera</option>
                </datalist>
                <div class="suggestion-info">可以选择建议项或输入自定义内容</div>
            </div>
            
            <div class="form-group">
                <label for="email-domain">邮箱域名:</label>
                <input type="text" id="email-domain" name="email-domain" 
                       class="datalist-input" list="email-domains" 
                       placeholder="请输入邮箱域名">
                <datalist id="email-domains">
                    <option value="gmail.com">
                    <option value="yahoo.com">
                    <option value="hotmail.com">
                    <option value="outlook.com">
                    <option value="qq.com">
                    <option value="163.com">
                    <option value="126.com">
                    <option value="sina.com">
                </datalist>
            </div>
            
            <div class="form-group">
                <label for="programming-language">编程语言:</label>
                <div class="input-group">
                    <input type="text" id="programming-language" name="programming-language" 
                           class="datalist-input" list="languages" 
                           placeholder="请选择编程语言">
                    <button type="button" class="add-btn" onclick="addLanguage()">添加</button>
                </div>
                <datalist id="languages">
                    <option value="JavaScript">
                    <option value="Python">
                    <option value="Java">
                    <option value="C++">
                    <option value="C#">
                    <option value="PHP">
                    <option value="Ruby">
                    <option value="Go">
                    <option value="Rust">
                    <option value="Swift">
                </datalist>
                <div class="selected-items" id="selected-languages"></div>
            </div>
            
            <div class="form-group">
                <label for="color-name">颜色名称:</label>
                <input type="text" id="color-name" name="color-name" 
                       class="datalist-input" list="colors" 
                       placeholder="请输入颜色名称" 
                       oninput="updateColorPreview(this.value)">
                <datalist id="colors">
                    <option value="red">红色</option>
                    <option value="blue">蓝色</option>
                    <option value="green">绿色</option>
                    <option value="yellow">黄色</option>
                    <option value="purple">紫色</option>
                    <option value="orange">橙色</option>
                    <option value="pink">粉色</option>
                    <option value="brown">棕色</option>
                    <option value="black">黑色</option>
                    <option value="white">白色</option>
                </datalist>
                <div id="color-preview" style="width: 100px; height: 30px; border: 1px solid #ccc; margin-top: 10px; border-radius: 4px;"></div>
            </div>
            
            <div class="form-group">
                <label for="city-search">城市搜索:</label>
                <input type="text" id="city-search" name="city-search" 
                       class="datalist-input" list="cities" 
                       placeholder="请输入城市名称" 
                       oninput="searchCities(this.value)">
                <datalist id="cities">
                    <!-- 动态生成选项 -->
                </datalist>
                <div class="suggestion-info">输入时会动态搜索匹配的城市</div>
            </div>
            
            <button type="submit">提交</button>
        </form>
    </div>
    
    <script>
        // 城市数据
        const allCities = [
            '北京', '上海', '广州', '深圳', '杭州', '成都', '重庆', '天津',
            '南京', '苏州', '武汉', '西安', '青岛', '大连', '厦门', '宁波',
            '长沙', '无锡', '福州', '济南', '太原', '长春', '哈尔滨', '昆明',
            '贵阳', '南宁', '乌鲁木齐', '兰州', '石家庄', '银川', '西宁', '呼和浩特'
        ];
        
        let selectedLanguages = [];
        
        function addLanguage() {
            const input = document.getElementById('programming-language');
            const language = input.value.trim();
            
            if (language && !selectedLanguages.includes(language)) {
                selectedLanguages.push(language);
                input.value = '';
                updateSelectedLanguages();
            }
        }
        
        function updateSelectedLanguages() {
            const container = document.getElementById('selected-languages');
            container.innerHTML = '';
            
            selectedLanguages.forEach(language => {
                const item = document.createElement('div');
                item.className = 'selected-item';
                item.innerHTML = `
                    <span>${language}</span>
                    <span class="remove-item" onclick="removeLanguage('${language}')">×</span>
                `;
                container.appendChild(item);
            });
        }
        
        function removeLanguage(language) {
            selectedLanguages = selectedLanguages.filter(lang => lang !== language);
            updateSelectedLanguages();
        }
        
        function updateColorPreview(colorName) {
            const preview = document.getElementById('color-preview');
            const colorMap = {
                'red': '#ff0000',
                'blue': '#0000ff',
                'green': '#008000',
                'yellow': '#ffff00',
                'purple': '#800080',
                'orange': '#ffa500',
                'pink': '#ffc0cb',
                'brown': '#a52a2a',
                'black': '#000000',
                'white': '#ffffff'
            };
            
            const color = colorMap[colorName.toLowerCase()];
            if (color) {
                preview.style.backgroundColor = color;
                preview.style.border = color === '#ffffff' ? '1px solid #ccc' : 'none';
            } else {
                preview.style.backgroundColor = 'transparent';
                preview.style.border = '1px solid #ccc';
            }
        }
        
        function searchCities(query) {
            const datalist = document.getElementById('cities');
            datalist.innerHTML = '';
            
            if (query.length < 1) return;
            
            const matchedCities = allCities.filter(city => 
                city.toLowerCase().includes(query.toLowerCase())
            );
            
            matchedCities.slice(0, 10).forEach(city => {
                const option = document.createElement('option');
                option.value = city;
                datalist.appendChild(option);
            });
        }
        
        // 为编程语言输入添加回车事件
        document.getElementById('programming-language').addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                e.preventDefault();
                addLanguage();
            }
        });
        
        // 初始化城市搜索
        searchCities('');
    </script>
</body>
</html>

易错点提醒

  1. list属性:input的list属性值必须与datalist的id匹配
  2. 浏览器兼容性:旧版本浏览器不支持datalist
  3. option标签:datalist中的option可以只有value属性

3.4.4 按钮元素(button)

基本语法

html
<button type="button">普通按钮</button>
<button type="submit">提交按钮</button>
<button type="reset">重置按钮</button>

详细介绍

button元素比input type="button"更灵活,可以包含HTML内容。

实际应用示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>按钮元素示例</title>
    <style>
        .button-container {
            max-width: 600px;
            margin: 20px auto;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 8px;
        }
        
        .button-group {
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
            flex-wrap: wrap;
        }
        
        .btn {
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            transition: all 0.3s ease;
            display: flex;
            align-items: center;
            gap: 5px;
        }
        
        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
        }
        
        .btn:active {
            transform: translateY(0);
        }
        
        .btn:disabled {
            opacity: 0.5;
            cursor: not-allowed;
            transform: none;
        }
        
        .btn-primary {
            background-color: #007bff;
            color: white;
        }
        
        .btn-secondary {
            background-color: #6c757d;
            color: white;
        }
        
        .btn-success {
            background-color: #28a745;
            color: white;
        }
        
        .btn-danger {
            background-color: #dc3545;
            color: white;
        }
        
        .btn-warning {
            background-color: #ffc107;
            color: #212529;
        }
        
        .btn-info {
            background-color: #17a2b8;
            color: white;
        }
        
        .btn-outline {
            background-color: transparent;
            border: 2px solid #007bff;
            color: #007bff;
        }
        
        .btn-outline:hover {
            background-color: #007bff;
            color: white;
        }
        
        .btn-large {
            padding: 15px 30px;
            font-size: 18px;
        }
        
        .btn-small {
            padding: 5px 10px;
            font-size: 12px;
        }
        
        .btn-loading {
            position: relative;
            overflow: hidden;
        }
        
        .btn-loading::after {
            content: '';
            position: absolute;
            top: 50%;
            left: 50%;
            width: 16px;
            height: 16px;
            margin: -8px 0 0 -8px;
            border: 2px solid transparent;
            border-top: 2px solid currentColor;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        .btn-icon {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
        }
        
        .btn-floating {
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 60px;
            height: 60px;
            border-radius: 50%;
            background-color: #007bff;
            color: white;
            border: none;
            cursor: pointer;
            box-shadow: 0 4px 8px rgba(0,0,0,0.3);
            font-size: 24px;
            z-index: 1000;
        }
        
        .btn-floating:hover {
            transform: scale(1.1);
        }
        
        .action-buttons {
            display: flex;
            gap: 10px;
            margin-top: 20px;
        }
        
        .progress-bar {
            width: 100%;
            height: 20px;
            background-color: #e9ecef;
            border-radius: 10px;
            overflow: hidden;
            margin: 10px 0;
        }
        
        .progress-fill {
            height: 100%;
            background-color: #007bff;
            transition: width 0.3s ease;
        }
        
        .demo-section {
            margin: 20px 0;
            padding: 15px;
            border: 1px solid #e9ecef;
            border-radius: 4px;
        }
        
        .demo-section h4 {
            margin-top: 0;
            color: #495057;
        }
    </style>
</head>
<body>
    <div class="button-container">
        <h3>按钮元素示例</h3>
        
        <div class="demo-section">
            <h4>基础按钮样式</h4>
            <div class="button-group">
                <button class="btn btn-primary" type="button">主要按钮</button>
                <button class="btn btn-secondary" type="button">次要按钮</button>
                <button class="btn btn-success" type="button">成功按钮</button>
                <button class="btn btn-danger" type="button">危险按钮</button>
                <button class="btn btn-warning" type="button">警告按钮</button>
                <button class="btn btn-info" type="button">信息按钮</button>
            </div>
        </div>
        
        <div class="demo-section">
            <h4>按钮尺寸</h4>
            <div class="button-group">
                <button class="btn btn-primary btn-large" type="button">大按钮</button>
                <button class="btn btn-primary" type="button">正常按钮</button>
                <button class="btn btn-primary btn-small" type="button">小按钮</button>
            </div>
        </div>
        
        <div class="demo-section">
            <h4>按钮状态</h4>
            <div class="button-group">
                <button class="btn btn-primary" type="button">正常状态</button>
                <button class="btn btn-primary" type="button" disabled>禁用状态</button>
                <button class="btn btn-outline" type="button">轮廓按钮</button>
                <button class="btn btn-primary btn-loading" type="button" id="loading-btn">
                    <span id="loading-text">加载中...</span>
                </button>
            </div>
        </div>
        
        <div class="demo-section">
            <h4>图标按钮</h4>
            <div class="button-group">
                <button class="btn btn-primary" type="button">
                    <span>📁</span>
                    <span>打开文件</span>
                </button>
                <button class="btn btn-success" type="button">
                    <span>💾</span>
                    <span>保存</span>
                </button>
                <button class="btn btn-danger" type="button">
                    <span>🗑️</span>
                    <span>删除</span>
                </button>
                <button class="btn btn-info btn-icon" type="button" title="设置">
                    <span>⚙️</span>
                </button>
                <button class="btn btn-warning btn-icon" type="button" title="帮助">
                    <span>❓</span>
                </button>
            </div>
        </div>
        
        <div class="demo-section">
            <h4>交互按钮</h4>
            <div class="button-group">
                <button class="btn btn-primary" type="button" onclick="showAlert()">
                    显示警告
                </button>
                <button class="btn btn-success" type="button" onclick="startProgress()">
                    开始进度
                </button>
                <button class="btn btn-info" type="button" onclick="toggleContent()">
                    切换内容
                </button>
                <button class="btn btn-secondary" type="button" onclick="copyText()">
                    复制文本
                </button>
            </div>
            
            <div class="progress-bar" id="progress-bar" style="display: none;">
                <div class="progress-fill" id="progress-fill" style="width: 0%;"></div>
            </div>
            
            <div id="toggle-content" style="display: none; margin-top: 10px; padding: 10px; background-color: #f8f9fa; border-radius: 4px;">
                <p>这是可切换显示的内容!</p>
            </div>
        </div>
        
        <div class="demo-section">
            <h4>表单按钮</h4>
            <form onsubmit="handleSubmit(event)">
                <div style="margin-bottom: 15px;">
                    <label for="demo-input">输入内容:</label>
                    <input type="text" id="demo-input" placeholder="请输入一些内容" style="width: 100%; padding: 8px; margin-top: 5px;">
                </div>
                
                <div class="button-group">
                    <button class="btn btn-primary" type="submit">
                        <span>✅</span>
                        <span>提交表单</span>
                    </button>
                    <button class="btn btn-secondary" type="reset">
                        <span>🔄</span>
                        <span>重置表单</span>
                    </button>
                    <button class="btn btn-danger" type="button" onclick="clearForm()">
                        <span>🗑️</span>
                        <span>清空表单</span>
                    </button>
                </div>
            </form>
        </div>
        
        <div class="demo-section">
            <h4>按钮组</h4>
            <div class="button-group">
                <button class="btn btn-outline" type="button" onclick="setAlignment('left')">
                    ◀️ 左对齐
                </button>
                <button class="btn btn-outline" type="button" onclick="setAlignment('center')">
                    ⏺️ 居中
                </button>
                <button class="btn btn-outline" type="button" onclick="setAlignment('right')">
                    ▶️ 右对齐
                </button>
            </div>
            
            <div id="alignment-demo" style="margin-top: 10px; padding: 10px; border: 1px solid #ddd; text-align: left;">
                这是对齐演示文本
            </div>
        </div>
    </div>
    
    <!-- 浮动按钮 -->
    <button class="btn-floating" onclick="scrollToTop()" title="回到顶部">
        ⬆️
    </button>
    
    <script>
        function showAlert() {
            alert('这是一个警告消息!');
        }
        
        function startProgress() {
            const progressBar = document.getElementById('progress-bar');
            const progressFill = document.getElementById('progress-fill');
            
            progressBar.style.display = 'block';
            progressFill.style.width = '0%';
            
            let progress = 0;
            const interval = setInterval(() => {
                progress += 10;
                progressFill.style.width = progress + '%';
                
                if (progress >= 100) {
                    clearInterval(interval);
                    setTimeout(() => {
                        progressBar.style.display = 'none';
                    }, 1000);
                }
            }, 200);
        }
        
        function toggleContent() {
            const content = document.getElementById('toggle-content');
            const isVisible = content.style.display !== 'none';
            
            content.style.display = isVisible ? 'none' : 'block';
            
            // 更新按钮文本
            const btn = event.target;
            btn.textContent = isVisible ? '显示内容' : '隐藏内容';
        }
        
        function copyText() {
            const text = '这是要复制的文本内容';
            navigator.clipboard.writeText(text).then(() => {
                const btn = event.target;
                const originalText = btn.textContent;
                btn.textContent = '已复制!';
                btn.style.backgroundColor = '#28a745';
                
                setTimeout(() => {
                    btn.textContent = originalText;
                    btn.style.backgroundColor = '';
                }, 2000);
            });
        }
        
        function handleSubmit(event) {
            event.preventDefault();
            const input = document.getElementById('demo-input');
            
            if (input.value.trim() === '') {
                alert('请输入内容!');
                return;
            }
            
            alert(`提交的内容:${input.value}`);
        }
        
        function clearForm() {
            document.getElementById('demo-input').value = '';
        }
        
        function setAlignment(alignment) {
            const demo = document.getElementById('alignment-demo');
            demo.style.textAlign = alignment;
            
            // 更新按钮状态
            document.querySelectorAll('.button-group button').forEach(btn => {
                btn.classList.remove('btn-primary');
                btn.classList.add('btn-outline');
            });
            
            event.target.classList.remove('btn-outline');
            event.target.classList.add('btn-primary');
        }
        
        function scrollToTop() {
            window.scrollTo({
                top: 0,
                behavior: 'smooth'
            });
        }
        
        // 模拟加载按钮
        function simulateLoading() {
            const loadingBtn = document.getElementById('loading-btn');
            const loadingText = document.getElementById('loading-text');
            
            loadingBtn.disabled = true;
            loadingText.style.opacity = '0';
            
            setTimeout(() => {
                loadingBtn.disabled = false;
                loadingText.style.opacity = '1';
                loadingText.textContent = '加载完成!';
                
                setTimeout(() => {
                    loadingText.textContent = '加载中...';
                }, 2000);
            }, 3000);
        }
        
        // 初始化加载按钮
        document.getElementById('loading-btn').addEventListener('click', simulateLoading);
        
        // 显示浮动按钮
        window.addEventListener('scroll', () => {
            const floatingBtn = document.querySelector('.btn-floating');
            if (window.scrollY > 100) {
                floatingBtn.style.display = 'flex';
            } else {
                floatingBtn.style.display = 'none';
            }
        });
    </script>
</body>
</html>

易错点提醒

  1. 默认type:button的默认type是submit,在表单中要注意
  2. 禁用状态:disabled按钮不会触发点击事件
  3. 按钮内容:button可以包含HTML内容,比input更灵活

3.4.5 标签元素(label)

基本语法

html
<label for="username">用户名:</label>
<input type="text" id="username" name="username">

<!-- 或者包裹形式 -->
<label>
    用户名:
    <input type="text" name="username">
</label>

详细介绍

label元素为表单控件提供标签,提高可访问性和用户体验。

实际应用示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>标签元素示例</title>
    <style>
        .label-container {
            max-width: 500px;
            margin: 20px auto;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 8px;
        }
        
        .form-group {
            margin-bottom: 20px;
        }
        
        .label-style1 {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            color: #333;
        }
        
        .label-style2 {
            display: flex;
            align-items: center;
            gap: 10px;
            cursor: pointer;
            padding: 10px;
            border: 1px solid #e0e0e0;
            border-radius: 4px;
            transition: background-color 0.2s;
        }
        
        .label-style2:hover {
            background-color: #f8f9fa;
        }
        
        .label-style3 {
            position: relative;
            display: block;
            padding: 15px 0 5px 0;
            cursor: pointer;
        }
        
        .label-style3 input {
            width: 100%;
            padding: 8px 0;
            border: none;
            border-bottom: 2px solid #ddd;
            background: transparent;
            font-size: 16px;
            transition: border-color 0.3s;
        }
        
        .label-style3 input:focus {
            outline: none;
            border-bottom-color: #007bff;
        }
        
        .label-style3 .label-text {
            position: absolute;
            top: 15px;
            left: 0;
            color: #666;
            pointer-events: none;
            transition: all 0.3s;
        }
        
        .label-style3 input:focus + .label-text,
        .label-style3 input:not(:placeholder-shown) + .label-text {
            top: 0;
            font-size: 12px;
            color: #007bff;
        }
        
        .input-field {
            width: 100%;
            padding: 8px;
            border: 1px solid #ccc;
            border-radius: 4px;
            font-size: 14px;
        }
        
        .input-field:focus {
            outline: none;
            border-color: #007bff;
            box-shadow: 0 0 0 2px rgba(0,123,255,0.25);
        }
        
        .checkbox-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        
        .radio-group {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        
        .custom-checkbox {
            display: flex;
            align-items: center;
            gap: 10px;
            cursor: pointer;
            padding: 8px;
            border-radius: 4px;
            transition: background-color 0.2s;
        }
        
        .custom-checkbox:hover {
            background-color: #f8f9fa;
        }
        
        .custom-checkbox input[type="checkbox"] {
            width: 18px;
            height: 18px;
            cursor: pointer;
        }
        
        .custom-radio {
            display: flex;
            align-items: center;
            gap: 10px;
            cursor: pointer;
            padding: 8px;
            border-radius: 4px;
            transition: background-color 0.2s;
        }
        
        .custom-radio:hover {
            background-color: #f8f9fa;
        }
        
        .custom-radio input[type="radio"] {
            width: 18px;
            height: 18px;
            cursor: pointer;
        }
        
        .required-label::after {
            content: ' *';
            color: #dc3545;
        }
        
        .help-text {
            font-size: 12px;
            color: #666;
            margin-top: 5px;
        }
    </style>
</head>
<body>
    <div class="label-container">
        <h3>标签元素示例</h3>
        
        <form>
            <div class="form-group">
                <label for="name" class="label-style1 required-label">姓名</label>
                <input type="text" id="name" name="name" class="input-field" required>
                <div class="help-text">请输入您的真实姓名</div>
            </div>
            
            <div class="form-group">
                <label for="email" class="label-style1 required-label">邮箱</label>
                <input type="email" id="email" name="email" class="input-field" required>
                <div class="help-text">我们将使用此邮箱联系您</div>
            </div>
            
            <div class="form-group">
                <label class="label-style3">
                    <input type="text" placeholder=" " required>
                    <span class="label-text">浮动标签输入框</span>
                </label>
            </div>
            
            <div class="form-group">
                <label class="label-style3">
                    <input type="password" placeholder=" " required>
                    <span class="label-text">密码</span>
                </label>
            </div>
            
            <div class="form-group">
                <div class="label-style1">兴趣爱好(多选):</div>
                <div class="checkbox-group">
                    <label class="custom-checkbox">
                        <input type="checkbox" name="hobbies" value="reading">
                        <span>📚 阅读</span>
                    </label>
                    <label class="custom-checkbox">
                        <input type="checkbox" name="hobbies" value="music">
                        <span>🎵 音乐</span>
                    </label>
                    <label class="custom-checkbox">
                        <input type="checkbox" name="hobbies" value="sports">
                        <span>⚽ 运动</span>
                    </label>
                    <label class="custom-checkbox">
                        <input type="checkbox" name="hobbies" value="travel">
                        <span>✈️ 旅行</span>
                    </label>
                </div>
            </div>
            
            <div class="form-group">
                <div class="label-style1">性别(单选):</div>
                <div class="radio-group">
                    <label class="custom-radio">
                        <input type="radio" name="gender" value="male">
                        <span>👨 男性</span>
                    </label>
                    <label class="custom-radio">
                        <input type="radio" name="gender" value="female">
                        <span>👩 女性</span>
                    </label>
                    <label class="custom-radio">
                        <input type="radio" name="gender" value="other">
                        <span>🤷 其他</span>
                    </label>
                </div>
            </div>
            
            <div class="form-group">
                <label class="label-style2">
                    <input type="checkbox" name="newsletter" value="yes">
                    <span>📧 订阅我们的新闻通讯</span>
                </label>
            </div>
            
            <div class="form-group">
                <label class="label-style2">
                    <input type="checkbox" name="terms" value="agreed" required>
                    <span>✅ 我同意用户协议和隐私政策</span>
                </label>
            </div>
            
            <button type="submit" style="width: 100%; padding: 12px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer;">
                提交注册
            </button>
        </form>
    </div>
    
    <script>
        // 为表单添加交互效果
        document.querySelectorAll('input').forEach(input => {
            input.addEventListener('focus', function() {
                this.parentElement.style.borderColor = '#007bff';
            });
            
            input.addEventListener('blur', function() {
                this.parentElement.style.borderColor = '';
            });
        });
        
        // 处理表单提交
        document.querySelector('form').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const formData = new FormData(this);
            const data = {};
            
            for (let [key, value] of formData.entries()) {
                if (data[key]) {
                    // 处理多选项
                    if (Array.isArray(data[key])) {
                        data[key].push(value);
                    } else {
                        data[key] = [data[key], value];
                    }
                } else {
                    data[key] = value;
                }
            }
            
            console.log('提交的数据:', data);
            alert('表单提交成功!请查看控制台输出。');
        });
    </script>
</body>
</html>

易错点提醒

  1. for属性:label的for属性值必须与表单控件的id匹配
  2. 嵌套结构:label可以包裹表单控件,此时不需要for属性
  3. 点击行为:点击label会自动聚焦到关联的表单控件

3.4.6 字段集(fieldset、legend)

基本语法

html
<fieldset>
    <legend>个人信息</legend>
    <label for="name">姓名:</label>
    <input type="text" id="name" name="name">
</fieldset>

详细介绍

fieldset用于将相关的表单控件分组,legend为组提供标题。

实际应用示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>字段集示例</title>
    <style>
        .fieldset-container {
            max-width: 700px;
            margin: 20px auto;
            padding: 20px;
        }
        
        .custom-fieldset {
            border: 2px solid #007bff;
            border-radius: 8px;
            padding: 20px;
            margin-bottom: 20px;
            background-color: #f8f9fa;
        }
        
        .custom-fieldset:disabled {
            opacity: 0.6;
            background-color: #e9ecef;
        }
        
        .custom-legend {
            background-color: #007bff;
            color: white;
            padding: 8px 15px;
            border-radius: 4px;
            font-weight: bold;
            margin-bottom: 15px;
        }
        
        .form-row {
            display: flex;
            gap: 15px;
            margin-bottom: 15px;
        }
        
        .form-col {
            flex: 1;
        }
        
        .form-group {
            margin-bottom: 15px;
        }
        
        label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            color: #333;
        }
        
        input, select, textarea {
            width: 100%;
            padding: 8px;
            border: 1px solid #ccc;
            border-radius: 4px;
            font-size: 14px;
        }
        
        input:focus, select:focus, textarea:focus {
            outline: none;
            border-color: #007bff;
            box-shadow: 0 0 0 2px rgba(0,123,255,0.25);
        }
        
        .checkbox-group {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        
        .checkbox-item {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .radio-group {
            display: flex;
            gap: 20px;
        }
        
        .radio-item {
            display: flex;
            align-items: center;
            gap: 5px;
        }
        
        .fieldset-actions {
            display: flex;
            gap: 10px;
            margin-top: 20px;
        }
        
        .btn {
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            transition: background-color 0.3s;
        }
        
        .btn-primary {
            background-color: #007bff;
            color: white;
        }
        
        .btn-secondary {
            background-color: #6c757d;
            color: white;
        }
        
        .btn-danger {
            background-color: #dc3545;
            color: white;
        }
        
        .btn:hover {
            opacity: 0.9;
        }
        
        .btn:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }
        
        .nested-fieldset {
            border: 1px solid #dee2e6;
            border-radius: 4px;
            padding: 15px;
            margin-top: 15px;
            background-color: white;
        }
        
        .nested-fieldset legend {
            font-size: 14px;
            font-weight: bold;
            color: #495057;
            padding: 0 10px;
        }
        
        .section-toggle {
            float: right;
            background: none;
            border: none;
            color: #007bff;
            cursor: pointer;
            font-size: 12px;
        }
        
        .section-content {
            transition: all 0.3s ease;
        }
        
        .section-content.collapsed {
            display: none;
        }
    </style>
</head>
<body>
    <div class="fieldset-container">
        <h3>字段集示例</h3>
        
        <form>
            <fieldset class="custom-fieldset">
                <legend class="custom-legend">
                    基本信息
                    <button type="button" class="section-toggle" onclick="toggleSection('basic')">
                        收起
                    </button>
                </legend>
                
                <div class="section-content" id="basic-content">
                    <div class="form-row">
                        <div class="form-col">
                            <label for="first-name">名:</label>
                            <input type="text" id="first-name" name="first-name" required>
                        </div>
                        <div class="form-col">
                            <label for="last-name">姓:</label>
                            <input type="text" id="last-name" name="last-name" required>
                        </div>
                    </div>
                    
                    <div class="form-row">
                        <div class="form-col">
                            <label for="email">邮箱:</label>
                            <input type="email" id="email" name="email" required>
                        </div>
                        <div class="form-col">
                            <label for="phone">电话:</label>
                            <input type="tel" id="phone" name="phone">
                        </div>
                    </div>
                    
                    <div class="form-group">
                        <label for="birth-date">出生日期:</label>
                        <input type="date" id="birth-date" name="birth-date">
                    </div>
                </div>
            </fieldset>
            
            <fieldset class="custom-fieldset">
                <legend class="custom-legend">
                    联系信息
                    <button type="button" class="section-toggle" onclick="toggleSection('contact')">
                        收起
                    </button>
                </legend>
                
                <div class="section-content" id="contact-content">
                    <div class="form-group">
                        <label for="address">地址:</label>
                        <textarea id="address" name="address" rows="3" placeholder="请输入详细地址"></textarea>
                    </div>
                    
                    <div class="form-row">
                        <div class="form-col">
                            <label for="city">城市:</label>
                            <input type="text" id="city" name="city">
                        </div>
                        <div class="form-col">
                            <label for="postal-code">邮编:</label>
                            <input type="text" id="postal-code" name="postal-code">
                        </div>
                    </div>
                    
                    <div class="form-group">
                        <label for="country">国家:</label>
                        <select id="country" name="country">
                            <option value="">请选择国家</option>
                            <option value="china">中国</option>
                            <option value="usa">美国</option>
                            <option value="japan">日本</option>
                            <option value="korea">韩国</option>
                        </select>
                    </div>
                </div>
            </fieldset>
            
            <fieldset class="custom-fieldset">
                <legend class="custom-legend">
                    偏好设置
                    <button type="button" class="section-toggle" onclick="toggleSection('preferences')">
                        收起
                    </button>
                </legend>
                
                <div class="section-content" id="preferences-content">
                    <div class="form-group">
                        <label>通知方式:</label>
                        <div class="checkbox-group">
                            <label class="checkbox-item">
                                <input type="checkbox" name="notification" value="email">
                                <span>邮件通知</span>
                            </label>
                            <label class="checkbox-item">
                                <input type="checkbox" name="notification" value="sms">
                                <span>短信通知</span>
                            </label>
                            <label class="checkbox-item">
                                <input type="checkbox" name="notification" value="push">
                                <span>推送通知</span>
                            </label>
                        </div>
                    </div>
                    
                    <div class="form-group">
                        <label>语言偏好:</label>
                        <div class="radio-group">
                            <label class="radio-item">
                                <input type="radio" name="language" value="zh-CN">
                                <span>中文</span>
                            </label>
                            <label class="radio-item">
                                <input type="radio" name="language" value="en-US">
                                <span>English</span>
                            </label>
                            <label class="radio-item">
                                <input type="radio" name="language" value="ja-JP">
                                <span>日本語</span>
                            </label>
                        </div>
                    </div>
                    
                    <fieldset class="nested-fieldset">
                        <legend>隐私设置</legend>
                        <div class="checkbox-group">
                            <label class="checkbox-item">
                                <input type="checkbox" name="privacy" value="profile-public">
                                <span>公开个人资料</span>
                            </label>
                            <label class="checkbox-item">
                                <input type="checkbox" name="privacy" value="allow-contact">
                                <span>允许他人联系我</span>
                            </label>
                            <label class="checkbox-item">
                                <input type="checkbox" name="privacy" value="marketing">
                                <span>接收营销信息</span>
                            </label>
                        </div>
                    </fieldset>
                </div>
            </fieldset>
            
            <fieldset class="custom-fieldset" id="admin-section">
                <legend class="custom-legend">
                    管理员设置
                    <button type="button" class="section-toggle" onclick="toggleSection('admin')">
                        收起
                    </button>
                </legend>
                
                <div class="section-content" id="admin-content">
                    <div class="form-group">
                        <label for="admin-role">管理员角色:</label>
                        <select id="admin-role" name="admin-role">
                            <option value="">请选择角色</option>
                            <option value="super-admin">超级管理员</option>
                            <option value="admin">管理员</option>
                            <option value="moderator">版主</option>
                        </select>
                    </div>
                    
                    <div class="form-group">
                        <label for="admin-notes">管理员备注:</label>
                        <textarea id="admin-notes" name="admin-notes" rows="3" placeholder="请输入管理员备注"></textarea>
                    </div>
                </div>
            </fieldset>
            
            <div class="fieldset-actions">
                <button type="submit" class="btn btn-primary">保存信息</button>
                <button type="reset" class="btn btn-secondary">重置表单</button>
                <button type="button" class="btn btn-secondary" onclick="toggleAdminSection()">
                    切换管理员模式
                </button>
                <button type="button" class="btn btn-danger" onclick="disableForm()">
                    禁用表单
                </button>
            </div>
        </form>
    </div>
    
    <script>
        function toggleSection(sectionId) {
            const content = document.getElementById(sectionId + '-content');
            const button = event.target;
            
            if (content.classList.contains('collapsed')) {
                content.classList.remove('collapsed');
                button.textContent = '收起';
            } else {
                content.classList.add('collapsed');
                button.textContent = '展开';
            }
        }
        
        function toggleAdminSection() {
            const adminSection = document.getElementById('admin-section');
            const button = event.target;
            
            if (adminSection.disabled) {
                adminSection.disabled = false;
                button.textContent = '禁用管理员模式';
            } else {
                adminSection.disabled = true;
                button.textContent = '启用管理员模式';
            }
        }
        
        function disableForm() {
            const fieldsets = document.querySelectorAll('fieldset');
            const button = event.target;
            
            fieldsets.forEach(fieldset => {
                if (fieldset.id !== 'admin-section') {
                    fieldset.disabled = !fieldset.disabled;
                }
            });
            
            button.textContent = fieldsets[0].disabled ? '启用表单' : '禁用表单';
        }
        
        // 处理表单提交
        document.querySelector('form').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const formData = new FormData(this);
            const data = {};
            
            for (let [key, value] of formData.entries()) {
                if (data[key]) {
                    if (Array.isArray(data[key])) {
                        data[key].push(value);
                    } else {
                        data[key] = [data[key], value];
                    }
                } else {
                    data[key] = value;
                }
            }
            
            console.log('提交的数据:', data);
            alert('表单提交成功!请查看控制台输出。');
        });
    </script>
</body>
</html>

易错点提醒

  1. disabled属性:fieldset的disabled属性会禁用其内部所有表单控件
  2. legend位置:legend必须是fieldset的第一个子元素
  3. 样式问题:fieldset的默认样式在不同浏览器中可能不同

本节要点回顾

  • 多行文本(textarea):用于输入长文本内容,支持自动调整高度
  • 下拉列表(select、option):单选或多选列表,支持分组和默认选项
  • 数据列表(datalist):提供输入建议的列表,增强用户体验
  • 按钮元素(button):比input更灵活的按钮,支持丰富内容
  • 标签元素(label):提高表单可访问性,正确关联表单控件
  • 字段集(fieldset、legend):分组相关的表单控件,提供清晰结构

相关学习资源

常见问题FAQ

Q: textarea如何防止用户调整大小?

A: 使用CSS的resize: none属性可以禁止用户调整textarea大小。

Q: select元素如何实现多选?

A: 添加multiple属性即可启用多选功能,用户可以使用Ctrl/Cmd键多选。

Q: datalist在不支持的浏览器中会怎样?

A: 不支持的浏览器会忽略datalist,input仍然正常工作,只是没有建议功能。

Q: fieldset的disabled属性有什么作用?

A: 会禁用fieldset内部的所有表单控件,常用于条件性启用表单区域。


下一节预览第3章第5节 - 表单验证 - 学习HTML5表单验证技术