表单脚本

表单是 Web 应用中收集用户输入的主要方式,JavaScript 提供了丰富的表单操作 API。

表单基础

获取表单

// 通过 ID 获取表单
const form = document.getElementById('myForm')

// 通过索引获取表单
const form = document.forms[0]

// 通过 name 属性获取表单
const form = document.forms['formName']

// 获取所有表单
const forms = document.forms
console.log(forms.length)  // 表单数量

表单属性

const form = document.getElementById('myForm')

// 基本属性
console.log(form.action)     // 提交 URL
console.log(form.method)     // 提交方法 (GET/POST)
console.log(form.name)       // 表单名称
console.log(form.target)     // 目标窗口

// 表单状态
console.log(form.elements)   // 所有表单控件
console.log(form.length)     // 表单控件数量
console.log(form.acceptCharset) // 接受的字符集
console.log(form.enctype)    // 编码类型

表单字段

获取表单字段

// 通过索引获取
const field1 = form.elements[0]

// 通过 name 属性获取
const field2 = form.elements['fieldName']

// 通过 ID 获取(会自动添加到 elements 集合)
const field3 = form.elements['fieldId']

表单字段通用属性

const input = form.elements['username']

// 基本属性
console.log(input.type)      // 字段类型
console.log(input.value)     // 字段值
console.log(input.name)      // 字段名称
console.log(input.form)      // 所属表单

// 状态属性
console.log(input.disabled)  // 是否禁用
console.log(input.readOnly)  // 是否只读
console.log(input.tabIndex)  // 制表符顺序

// 方法
input.focus()    // 获取焦点
input.blur()     // 失去焦点

文本框脚本

单行文本框

const textInput = document.getElementById('textInput')

// 获取和设置值
textInput.value = 'Default text'
console.log(textInput.value)

// 事件处理
textInput.addEventListener('focus', () => {
  console.log('Input focused')
})

textInput.addEventListener('blur', () => {
  console.log('Input blurred')
})

textInput.addEventListener('change', () => {
  console.log('Value changed:', textInput.value)
})

textInput.addEventListener('input', () => {
  console.log('Value changing:', textInput.value)
})

// 选择文本
textInput.select()

// 选择部分文本
textInput.setSelectionRange(0, 5)

// 获取选中文本
console.log(textInput.selectionStart, textInput.selectionEnd)

多行文本框

const textarea = document.getElementById('textarea')

// 多行文本框特有属性
console.log(textarea.rows)     // 行数
console.log(textarea.cols)     // 列数

// 自动调整高度
function autoResize(textarea) {
  textarea.style.height = 'auto'
  textarea.style.height = textarea.scrollHeight + 'px'
}

textarea.addEventListener('input', () => autoResize(textarea))

选择框脚本

单选选择框

const select = document.getElementById('singleSelect')

// 获取选项
console.log(select.options)    // HTMLOptionsCollection
console.log(select.length)     // 选项数量

// 获取和设置选中值
console.log(select.value)      // 选中选项的 value
console.log(select.selectedIndex) // 选中选项的索引

// 设置选中项
select.selectedIndex = 2
select.value = 'option3'

// 遍历选项
for (let option of select.options) {
  console.log(option.value, option.text, option.selected)
}

// 添加选项
const newOption = new Option('New Option', 'newValue')
select.add(newOption)

// 移除选项
select.remove(1)  // 移除索引为1的选项

多选选择框

const multiSelect = document.getElementById('multiSelect')

// 获取所有选中值
function getSelectedValues(select) {
  return Array.from(select.options)
    .filter(option => option.selected)
    .map(option => option.value)
}

console.log(getSelectedValues(multiSelect))

// 设置多选
multiSelect.options[0].selected = true
multiSelect.options[2].selected = true

// 全选/取消全选
function selectAll(select, selected) {
  for (let option of select.options) {
    option.selected = selected
  }
}

表单序列化

基本序列化

function serialize(form) {
  const parts = []
  const elements = form.elements

  for (let element of elements) {
    // 跳过没有 name 属性的字段
    if (!element.name) continue

    // 跳过禁用的字段
    if (element.disabled) continue

    // 跳过未选中的单选和复选框
    if (element.type === 'radio' || element.type === 'checkbox') {
      if (!element.checked) continue
    }

    // 跳过重置按钮和提交按钮
    if (element.type === 'reset' || element.type === 'submit') continue

    // 跳过文件字段
    if (element.type === 'file') continue

    parts.push(`${encodeURIComponent(element.name)}=${encodeURIComponent(element.value)}`)
  }

  return parts.join('&')
}

const serializedData = serialize(document.getElementById('myForm'))

FormData

// 创建 FormData 对象
const formData = new FormData(document.getElementById('myForm'))

// 手动添加数据
formData.append('extraField', 'extraValue')

// 获取数据
for (let [key, value] of formData.entries()) {
  console.log(key, value)
}

// 发送数据
fetch('/submit', {
  method: 'POST',
  body: formData
})

富文本编辑

contenteditable

<div id="editor" contenteditable="true">
  <p>在这里编辑内容...</p>
</div>
const editor = document.getElementById('editor')

// 获取和设置内容
console.log(editor.innerHTML)
editor.innerHTML = '<p>New content</p>'

// 监听输入
editor.addEventListener('input', () => {
  console.log('Content changed:', editor.innerHTML)
})

// 基本格式化命令
function formatText(command, value = null) {
  document.execCommand(command, false, value)
}

// 使用示例
document.getElementById('boldBtn').addEventListener('click', () => {
  formatText('bold')
})

document.getElementById('italicBtn').addEventListener('click', () => {
  formatText('italic')
})

document.getElementById('linkBtn').addEventListener('click', () => {
  const url = prompt('Enter URL:')
  if (url) formatText('createLink', url)
})

表单验证

HTML5 验证

<form id="validationForm">
  <input type="email" name="email" required>
  <input type="password" name="password" minlength="8">
  <input type="number" name="age" min="18" max="120">
  <input type="text" name="zip" pattern="[0-9]{5}">
  <button type="submit">Submit</button>
</form>
const form = document.getElementById('validationForm')

// 检查表单有效性
form.addEventListener('submit', (event) => {
  if (!form.checkValidity()) {
    event.preventDefault()
    console.log('Form is invalid')
  }
})

// 实时验证
const inputs = form.querySelectorAll('input')
inputs.forEach(input => {
  input.addEventListener('input', () => {
    if (input.validity.valid) {
      input.classList.remove('invalid')
      input.classList.add('valid')
    } else {
      input.classList.remove('valid')
      input.classList.add('invalid')
    }
  })
})

// 自定义验证消息
const password = form.elements['password']
password.addEventListener('input', () => {
  if (password.validity.tooShort) {
    password.setCustomValidity('密码至少需要8个字符')
  } else {
    password.setCustomValidity('')
  }
})

自定义验证

function validateForm(form) {
  const errors = []

  // 自定义验证规则
  const email = form.elements['email']
  if (!isValidEmail(email.value)) {
    errors.push('邮箱格式不正确')
  }

  const password = form.elements['password']
  if (password.value.length < 8) {
    errors.push('密码至少需要8个字符')
  }

  const confirmPassword = form.elements['confirmPassword']
  if (password.value !== confirmPassword.value) {
    errors.push('两次输入的密码不一致')
  }

  return errors
}

function isValidEmail(email) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
  return regex.test(email)
}

// 使用自定义验证
form.addEventListener('submit', (event) => {
  const errors = validateForm(form)
  if (errors.length > 0) {
    event.preventDefault()
    displayErrors(errors)
  }
})

总结

表单脚本是 Web 开发中的重要组成部分:

  1. 表单基础:获取表单和表单属性
  2. 表单字段:操作不同类型的表单控件
  3. 文本框脚本:单行和多行文本框的操作
  4. 选择框脚本:单选和多选选择框
  5. 表单序列化:将表单数据转换为字符串或 FormData
  6. 富文本编辑:使用 contenteditable 创建富文本编辑器
  7. 表单验证:HTML5 验证和自定义验证

掌握表单脚本可以创建更好的用户交互体验。