DOM基础概念
什么是DOM
DOM(Document Object Model,文档对象模型)是HTML和XML文档的编程接口。它将文档表示为节点树,每个节点都是一个对象,代表文档的一部分。
<!DOCTYPE html>
<html>
<head>
<title>DOM示例</title>
</head>
<body>
<div id="container">
<h1 class="title">标题</h1>
<p class="content">这是一段文本</p>
<ul>
<li>项目1</li>
<li>项目2</li>
</ul>
</div>
</body>
</html>
// DOM树结构
// document
// └── html
// ├── head
// │ └── title
// │ └── "DOM示例" (文本节点)
// └── body
// └── div#container
// ├── h1.title
// │ └── "标题" (文本节点)
// ├── p.content
// │ └── "这是一段文本" (文本节点)
// └── ul
// ├── li
// │ └── "项目1" (文本节点)
// └── li
// └── "项目2" (文本节点)
// DOM节点类型
console.log('文档节点:', document.nodeType); // 9
console.log('元素节点:', document.body.nodeType); // 1
console.log('文本节点:', document.body.firstChild.nodeType); // 3
console.log('注释节点:', 8); // 注释节点类型
DOM节点关系
// 获取DOM元素
const container = document.getElementById('container');
const title = document.querySelector('.title');
const items = document.querySelectorAll('li');
// 父子关系
console.log('父节点:', title.parentNode);
console.log('父元素:', title.parentElement);
console.log('子节点:', container.childNodes);
console.log('子元素:', container.children);
console.log('第一个子节点:', container.firstChild);
console.log('第一个子元素:', container.firstElementChild);
console.log('最后一个子节点:', container.lastChild);
console.log('最后一个子元素:', container.lastElementChild);
// 兄弟关系
console.log('下一个兄弟节点:', title.nextSibling);
console.log('下一个兄弟元素:', title.nextElementSibling);
console.log('上一个兄弟节点:', title.previousSibling);
console.log('上一个兄弟元素:', title.previousElementSibling);
// 遍历DOM树
function traverseDOM(node, depth = 0) {
const indent = ' '.repeat(depth);
if (node.nodeType === Node.ELEMENT_NODE) {
console.log(`${indent}元素: ${node.tagName.toLowerCase()}`);
// 遍历属性
if (node.attributes.length > 0) {
for (const attr of node.attributes) {
console.log(`${indent} 属性: ${attr.name}="${attr.value}"`);
}
}
// 遍历子节点
for (const child of node.childNodes) {
traverseDOM(child, depth + 1);
}
} else if (node.nodeType === Node.TEXT_NODE) {
const text = node.textContent.trim();
if (text) {
console.log(`${indent}文本: "${text}"`);
}
}
}
// traverseDOM(document.body);
元素选择和查找
基本选择方法
// 1. 通过ID选择(返回单个元素或null)
const elementById = document.getElementById('container');
console.log('通过ID选择:', elementById);
// 2. 通过类名选择(返回HTMLCollection)
const elementsByClass = document.getElementsByClassName('content');
console.log('通过类名选择:', elementsByClass);
// 3. 通过标签名选择(返回HTMLCollection)
const elementsByTag = document.getElementsByTagName('li');
console.log('通过标签名选择:', elementsByTag);
// 4. 通过name属性选择(返回NodeList)
const elementsByName = document.getElementsByName('username');
console.log('通过name选择:', elementsByName);
// 5. CSS选择器(返回第一个匹配元素或null)
const elementBySelector = document.querySelector('.title');
console.log('CSS选择器(单个):', elementBySelector);
// 6. CSS选择器(返回所有匹配元素的NodeList)
const elementsBySelector = document.querySelectorAll('li');
console.log('CSS选择器(多个):', elementsBySelector);
// HTMLCollection vs NodeList
console.log('HTMLCollection是否为数组:', Array.isArray(elementsByClass)); // false
console.log('NodeList是否为数组:', Array.isArray(elementsBySelector)); // false
// 转换为数组
const classArray = Array.from(elementsByClass);
const selectorArray = [...elementsBySelector];
console.log('转换为数组:', classArray, selectorArray);
高级选择技巧
// 复杂CSS选择器
const examples = {
// 后代选择器
descendants: document.querySelectorAll('#container p'),
// 直接子元素选择器
directChildren: document.querySelectorAll('#container > li'),
// 相邻兄弟选择器
adjacentSibling: document.querySelectorAll('h1 + p'),
// 通用兄弟选择器
generalSibling: document.querySelectorAll('h1 ~ p'),
// 属性选择器
byAttribute: document.querySelectorAll('[data-id]'),
byAttributeValue: document.querySelectorAll('[data-id="123"]'),
byAttributeContains: document.querySelectorAll('[class*="btn"]'),
byAttributeStarts: document.querySelectorAll('[class^="nav"]'),
byAttributeEnds: document.querySelectorAll('[class$="active"]'),
// 伪类选择器
firstChild: document.querySelectorAll('li:first-child'),
lastChild: document.querySelectorAll('li:last-child'),
nthChild: document.querySelectorAll('li:nth-child(2n)'), // 偶数项
notSelector: document.querySelectorAll('li:not(.disabled)'),
// 伪元素选择器(注意:querySelector不能选择伪元素)
// before: document.querySelectorAll('p::before'), // 无效
// 组合选择器
multiple: document.querySelectorAll('h1, h2, h3'),
complex: document.querySelectorAll('#container .content:not(.hidden)')
};
console.log('高级选择器示例:', examples);
// 自定义选择器函数
function selectElements(selector, context = document) {
try {
const elements = context.querySelectorAll(selector);
return Array.from(elements);
} catch (error) {
console.error('无效的选择器:', selector, error);
return [];
}
}
// 链式选择器
class ElementSelector {
constructor(elements) {
this.elements = Array.isArray(elements) ? elements : [elements];
}
static select(selector) {
const elements = Array.from(document.querySelectorAll(selector));
return new ElementSelector(elements);
}
filter(selector) {
const filtered = this.elements.filter(el => el.matches(selector));
return new ElementSelector(filtered);
}
find(selector) {
const found = [];
this.elements.forEach(el => {
found.push(...el.querySelectorAll(selector));
});
return new ElementSelector(found);
}
parent() {
const parents = this.elements.map(el => el.parentElement).filter(Boolean);
return new ElementSelector(parents);
}
children(selector) {
const children = [];
this.elements.forEach(el => {
const childElements = Array.from(el.children);
if (selector) {
children.push(...childElements.filter(child => child.matches(selector)));
} else {
children.push(...childElements);
}
});
return new ElementSelector(children);
}
get(index) {
return this.elements[index] || null;
}
first() {
return this.elements[0] || null;
}
last() {
return this.elements[this.elements.length - 1] || null;
}
length() {
return this.elements.length;
}
toArray() {
return [...this.elements];
}
}
// 使用链式选择器
const selectedElements = ElementSelector
.select('#container')
.find('li')
.filter(':not(.disabled)');
console.log('链式选择结果:', selectedElements.toArray());
元素内容操作
文本内容操作
// 创建测试元素
const testDiv = document.createElement('div');
testDiv.innerHTML = `
<h2>标题</h2>
<p>段落文本 <strong>粗体</strong> 更多文本</p>
<!-- 这是注释 -->
`;
document.body.appendChild(testDiv);
// textContent vs innerText vs innerHTML
console.log('textContent:', testDiv.textContent);
// 输出:"\n 标题\n 段落文本 粗体 更多文本\n \n"
console.log('innerText:', testDiv.innerText);
// 输出:"标题\n段落文本 粗体 更多文本"
console.log('innerHTML:', testDiv.innerHTML);
// 输出:"\n <h2>标题</h2>\n <p>段落文本 <strong>粗体</strong> 更多文本</p>\n <!-- 这是注释 -->\n"
// 设置内容
const contentDiv = document.createElement('div');
// 设置纯文本(安全,会转义HTML)
contentDiv.textContent = '<script>alert("XSS")</script>普通文本';
console.log('textContent设置后:', contentDiv.innerHTML);
// 输出:"<script>alert("XSS")</script>普通文本"
// 设置HTML(不安全,会执行HTML)
contentDiv.innerHTML = '<em>强调文本</em> 和 <strong>重要文本</strong>';
console.log('innerHTML设置后:', contentDiv.innerHTML);
// 安全的HTML设置
function setHTMLSafely(element, htmlString) {
// 创建临时元素
const temp = document.createElement('div');
temp.innerHTML = htmlString;
// 移除所有脚本标签
const scripts = temp.querySelectorAll('script');
scripts.forEach(script => script.remove());
// 移除危险属性
const allElements = temp.querySelectorAll('*');
allElements.forEach(el => {
const dangerousAttrs = ['onclick', 'onload', 'onerror', 'onmouseover'];
dangerousAttrs.forEach(attr => {
if (el.hasAttribute(attr)) {
el.removeAttribute(attr);
}
});
});
element.innerHTML = temp.innerHTML;
}
// 文本操作工具函数
class TextUtils {
static getTextLength(element) {
return element.textContent.length;
}
static getWordCount(element) {
const text = element.textContent.trim();
return text ? text.split(/\s+/).length : 0;
}
static truncateText(element, maxLength, suffix = '...') {
const text = element.textContent;
if (text.length <= maxLength) return;
const truncated = text.slice(0, maxLength - suffix.length);
element.textContent = truncated + suffix;
}
static highlightText(element, searchTerm, className = 'highlight') {
const text = element.textContent;
const regex = new RegExp(`(${searchTerm})`, 'gi');
const highlightedHTML = text.replace(regex, `<span class="${className}">$1</span>`);
element.innerHTML = highlightedHTML;
}
static removeHighlight(element) {
const highlighted = element.querySelectorAll('.highlight');
highlighted.forEach(span => {
span.outerHTML = span.textContent;
});
}
}
// 使用文本工具
const textElement = document.createElement('p');
textElement.textContent = 'JavaScript是一种强大的编程语言,广泛用于Web开发。';
document.body.appendChild(textElement);
console.log('文本长度:', TextUtils.getTextLength(textElement));
console.log('单词数量:', TextUtils.getWordCount(textElement));
// TextUtils.truncateText(textElement, 20);
// TextUtils.highlightText(textElement, 'JavaScript');
HTML内容操作
// innerHTML的高级用法
class HTMLBuilder {
constructor() {
this.html = '';
}
tag(tagName, content = '', attributes = {}) {
const attrs = Object.entries(attributes)
.map(([key, value]) => `${key}="${value}"`)
.join(' ');
const attrString = attrs ? ` ${attrs}` : '';
this.html += `<${tagName}${attrString}>${content}</${tagName}>`;
return this;
}
text(content) {
this.html += content;
return this;
}
br() {
this.html += '<br>';
return this;
}
build() {
return this.html;
}
clear() {
this.html = '';
return this;
}
}
// 使用HTML构建器
const htmlBuilder = new HTMLBuilder();
const generatedHTML = htmlBuilder
.tag('div', '', { class: 'container', id: 'main' })
.tag('h1', '欢迎', { class: 'title' })
.tag('p', '这是一个段落')
.br()
.tag('button', '点击我', { class: 'btn btn-primary', 'data-action': 'click' })
.build();
console.log('生成的HTML:', generatedHTML);
// 模板系统
class SimpleTemplate {
constructor(template) {
this.template = template;
}
render(data) {
let result = this.template;
// 替换变量 {{variable}}
result = result.replace(/\{\{\s*(\w+)\s*\}\}/g, (match, key) => {
return data[key] !== undefined ? data[key] : match;
});
// 处理条件 {{#if condition}}...{{/if}}
result = result.replace(/\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g, (match, condition, content) => {
return data[condition] ? content : '';
});
// 处理循环 {{#each array}}...{{/each}}
result = result.replace(/\{\{#each\s+(\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g, (match, arrayName, itemTemplate) => {
const array = data[arrayName];
if (!Array.isArray(array)) return '';
return array.map(item => {
let itemHTML = itemTemplate;
// 替换 {{this}} 为当前项
itemHTML = itemHTML.replace(/\{\{this\}\}/g, item);
// 如果item是对象,替换其属性
if (typeof item === 'object') {
Object.keys(item).forEach(key => {
const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
itemHTML = itemHTML.replace(regex, item[key]);
});
}
return itemHTML;
}).join('');
});
return result;
}
}
// 使用模板系统
const template = new SimpleTemplate(`
<div class="user-card">
<h2>{{name}}</h2>
{{#if email}}
<p>邮箱: {{email}}</p>
{{/if}}
<h3>技能:</h3>
<ul>
{{#each skills}}
<li>{{this}}</li>
{{/each}}
</ul>
<h3>项目:</h3>
<ul>
{{#each projects}}
<li>
<strong>{{name}}</strong> - {{description}}
</li>
{{/each}}
</ul>
</div>
`);
const userData = {
name: '张三',
email: 'zhangsan@example.com',
skills: ['JavaScript', 'React', 'Node.js'],
projects: [
{ name: '项目A', description: '一个很棒的项目' },
{ name: '项目B', description: '另一个项目' }
]
};
const renderedHTML = template.render(userData);
console.log('渲染的HTML:', renderedHTML);
// 创建并插入到页面
const templateContainer = document.createElement('div');
templateContainer.innerHTML = renderedHTML;
document.body.appendChild(templateContainer);
元素属性操作
标准属性操作
// 创建测试元素
const testElement = document.createElement('input');
testElement.type = 'text';
testElement.id = 'test-input';
testElement.className = 'form-control';
document.body.appendChild(testElement);
// 获取属性
console.log('ID属性:', testElement.id);
console.log('类名:', testElement.className);
console.log('类型:', testElement.type);
// 使用getAttribute/setAttribute
console.log('getAttribute ID:', testElement.getAttribute('id'));
console.log('getAttribute class:', testElement.getAttribute('class'));
// 设置属性
testElement.setAttribute('placeholder', '请输入文本');
testElement.setAttribute('data-validation', 'required');
testElement.setAttribute('maxlength', '100');
// 检查属性是否存在
console.log('是否有placeholder:', testElement.hasAttribute('placeholder'));
console.log('是否有title:', testElement.hasAttribute('title'));
// 移除属性
testElement.removeAttribute('maxlength');
// 获取所有属性
console.log('所有属性:');
for (const attr of testElement.attributes) {
console.log(`${attr.name}: ${attr.value}`);
}
// 属性操作工具类
class AttributeManager {
constructor(element) {
this.element = element;
}
set(name, value) {
this.element.setAttribute(name, value);
return this;
}
get(name) {
return this.element.getAttribute(name);
}
has(name) {
return this.element.hasAttribute(name);
}
remove(name) {
this.element.removeAttribute(name);
return this;
}
toggle(name, value) {
if (this.has(name)) {
this.remove(name);
} else {
this.set(name, value || '');
}
return this;
}
setMultiple(attributes) {
Object.entries(attributes).forEach(([name, value]) => {
this.set(name, value);
});
return this;
}
getAll() {
const attrs = {};
for (const attr of this.element.attributes) {
attrs[attr.name] = attr.value;
}
return attrs;
}
copy(targetElement) {
for (const attr of this.element.attributes) {
targetElement.setAttribute(attr.name, attr.value);
}
return this;
}
}
// 使用属性管理器
const attrManager = new AttributeManager(testElement);
attrManager
.set('data-role', 'input')
.set('aria-label', '文本输入框')
.setMultiple({
'data-validate': 'true',
'data-min-length': '3'
});
console.log('所有属性:', attrManager.getAll());
数据属性操作
// 数据属性(data-*)操作
const dataElement = document.createElement('div');
document.body.appendChild(dataElement);
// 使用dataset API
dataElement.dataset.userId = '123';
dataElement.dataset.userName = 'john_doe';
dataElement.dataset.isActive = 'true';
dataElement.dataset.createdAt = new Date().toISOString();
// 复杂数据类型
dataElement.dataset.config = JSON.stringify({
theme: 'dark',
language: 'zh-CN',
features: ['feature1', 'feature2']
});
// 读取数据属性
console.log('用户ID:', dataElement.dataset.userId);
console.log('用户名:', dataElement.dataset.userName);
console.log('是否激活:', dataElement.dataset.isActive === 'true');
// 解析复杂数据
const config = JSON.parse(dataElement.dataset.config);
console.log('配置:', config);
// 遍历所有数据属性
console.log('所有数据属性:');
for (const [key, value] of Object.entries(dataElement.dataset)) {
console.log(`${key}: ${value}`);
}
// 数据属性管理器
class DataManager {
constructor(element) {
this.element = element;
}
set(key, value) {
if (typeof value === 'object') {
this.element.dataset[key] = JSON.stringify(value);
} else {
this.element.dataset[key] = String(value);
}
return this;
}
get(key, defaultValue = null) {
const value = this.element.dataset[key];
if (value === undefined) return defaultValue;
// 尝试解析JSON
try {
return JSON.parse(value);
} catch {
return value;
}
}
getNumber(key, defaultValue = 0) {
const value = this.get(key);
const num = Number(value);
return isNaN(num) ? defaultValue : num;
}
getBoolean(key, defaultValue = false) {
const value = this.get(key);
if (typeof value === 'boolean') return value;
if (typeof value === 'string') {
return value.toLowerCase() === 'true';
}
return defaultValue;
}
getArray(key, defaultValue = []) {
const value = this.get(key);
return Array.isArray(value) ? value : defaultValue;
}
has(key) {
return key in this.element.dataset;
}
remove(key) {
delete this.element.dataset[key];
return this;
}
clear() {
for (const key in this.element.dataset) {
delete this.element.dataset[key];
}
return this;
}
getAll() {
const data = {};
for (const [key, value] of Object.entries(this.element.dataset)) {
data[key] = this.get(key);
}
return data;
}
}
// 使用数据管理器
const dataManager = new DataManager(dataElement);
dataManager
.set('score', 95)
.set('tags', ['javascript', 'dom', 'web'])
.set('metadata', { version: '1.0', author: 'developer' });
console.log('分数:', dataManager.getNumber('score'));
console.log('标签:', dataManager.getArray('tags'));
console.log('元数据:', dataManager.get('metadata'));
console.log('所有数据:', dataManager.getAll());
类名操作
// 创建测试元素
const classElement = document.createElement('div');
classElement.className = 'container active';
document.body.appendChild(classElement);
// 传统方式操作类名
console.log('当前类名:', classElement.className);
classElement.className += ' highlight';
classElement.className = classElement.className.replace('active', 'inactive');
// 使用classList API(推荐)
const classList = classElement.classList;
// 添加类名
classList.add('new-class');
classList.add('class1', 'class2', 'class3'); // 添加多个
// 移除类名
classList.remove('highlight');
classList.remove('class1', 'class2'); // 移除多个
// 切换类名
classList.toggle('active'); // 如果存在则移除,不存在则添加
classList.toggle('visible', true); // 强制添加
classList.toggle('hidden', false); // 强制移除
// 检查类名
console.log('是否包含container:', classList.contains('container'));
console.log('是否包含active:', classList.contains('active'));
// 替换类名
classList.replace('inactive', 'active');
// 遍历类名
console.log('所有类名:');
classList.forEach((className, index) => {
console.log(`${index}: ${className}`);
});
// 类名管理器
class ClassManager {
constructor(element) {
this.element = element;
this.classList = element.classList;
}
add(...classNames) {
this.classList.add(...classNames);
return this;
}
remove(...classNames) {
this.classList.remove(...classNames);
return this;
}
toggle(className, force) {
this.classList.toggle(className, force);
return this;
}
replace(oldClass, newClass) {
this.classList.replace(oldClass, newClass);
return this;
}
contains(className) {
return this.classList.contains(className);
}
clear() {
this.element.className = '';
return this;
}
set(classNames) {
if (Array.isArray(classNames)) {
this.element.className = classNames.join(' ');
} else {
this.element.className = classNames;
}
return this;
}
get() {
return Array.from(this.classList);
}
hasAny(...classNames) {
return classNames.some(className => this.contains(className));
}
hasAll(...classNames) {
return classNames.every(className => this.contains(className));
}
addIf(condition, ...classNames) {
if (condition) {
this.add(...classNames);
}
return this;
}
removeIf(condition, ...classNames) {
if (condition) {
this.remove(...classNames);
}
return this;
}
toggleGroup(groupClasses, activeClass) {
// 移除组中的所有类,然后添加激活的类
this.remove(...groupClasses);
this.add(activeClass);
return this;
}
}
// 使用类名管理器
const classManager = new ClassManager(classElement);
classManager
.add('btn', 'btn-primary')
.addIf(true, 'enabled')
.toggleGroup(['small', 'medium', 'large'], 'medium');
console.log('最终类名:', classManager.get());
// 条件类名应用
function applyConditionalClasses(element, conditions) {
const manager = new ClassManager(element);
Object.entries(conditions).forEach(([className, condition]) => {
if (typeof condition === 'function') {
manager.addIf(condition(), className);
} else {
manager.addIf(condition, className);
}
});
return manager;
}
// 使用条件类名
const testDiv = document.createElement('div');
const isLoggedIn = true;
const userRole = 'admin';
const score = 85;
applyConditionalClasses(testDiv, {
'logged-in': isLoggedIn,
'guest': !isLoggedIn,
'admin': userRole === 'admin',
'high-score': score > 80,
'perfect-score': () => score === 100
});
console.log('条件类名结果:', testDiv.className);
样式操作
内联样式操作
// 创建测试元素
const styleElement = document.createElement('div');
styleElement.textContent = '样式测试元素';
document.body.appendChild(styleElement);
// 直接设置样式属性
styleElement.style.color = 'red';
styleElement.style.fontSize = '20px';
styleElement.style.backgroundColor = '#f0f0f0';
styleElement.style.padding = '10px';
styleElement.style.border = '2px solid blue';
// 使用cssText一次性设置多个样式
styleElement.style.cssText = `
color: green;
font-size: 24px;
background-color: yellow;
padding: 15px;
border-radius: 5px;
margin: 10px 0;
`;
// 获取样式值
console.log('颜色:', styleElement.style.color);
console.log('字体大小:', styleElement.style.fontSize);
console.log('所有内联样式:', styleElement.style.cssText);
// 移除样式属性
styleElement.style.removeProperty('background-color');
// 或者设置为空字符串
styleElement.style.backgroundColor = '';
// 样式操作工具类
class StyleManager {
constructor(element) {
this.element = element;
this.style = element.style;
}
set(property, value) {
if (typeof property === 'object') {
// 批量设置
Object.entries(property).forEach(([prop, val]) => {
this.style[this.camelCase(prop)] = val;
});
} else {
this.style[this.camelCase(property)] = value;
}
return this;
}
get(property) {
return this.style[this.camelCase(property)];
}
remove(property) {
this.style.removeProperty(this.kebabCase(property));
return this;
}
toggle(property, value1, value2) {
const current = this.get(property);
this.set(property, current === value1 ? value2 : value1);
return this;
}
has(property) {
return this.get(property) !== '';
}
clear() {
this.style.cssText = '';
return this;
}
copy(targetElement) {
targetElement.style.cssText = this.style.cssText;
return this;
}
// 工具方法:转换为驼峰命名
camelCase(str) {
return str.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
}
// 工具方法:转换为短横线命名
kebabCase(str) {
return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
}
// 动画相关方法
animate(keyframes, options = {}) {
return this.element.animate(keyframes, {
duration: 300,
easing: 'ease',
...options
});
}
fadeIn(duration = 300) {
this.set('opacity', '0');
return this.animate([
{ opacity: 0 },
{ opacity: 1 }
], { duration });
}
fadeOut(duration = 300) {
return this.animate([
{ opacity: 1 },
{ opacity: 0 }
], { duration });
}
slideDown(duration = 300) {
const height = this.element.scrollHeight;
this.set({ height: '0', overflow: 'hidden' });
return this.animate([
{ height: '0px' },
{ height: `${height}px` }
], { duration });
}
slideUp(duration = 300) {
const height = this.element.scrollHeight;
return this.animate([
{ height: `${height}px` },
{ height: '0px' }
], { duration });
}
}
// 使用样式管理器
const styleManager = new StyleManager(styleElement);
styleManager
.set({
'background-color': 'lightblue',
'border-radius': '10px',
'box-shadow': '0 2px 4px rgba(0,0,0,0.1)',
'transition': 'all 0.3s ease'
})
.set('transform', 'scale(1.1)');
// 计算样式获取
function getComputedStyles(element, properties) {
const computed = window.getComputedStyle(element);
if (Array.isArray(properties)) {
const result = {};
properties.forEach(prop => {
result[prop] = computed.getPropertyValue(prop);
});
return result;
} else if (properties) {
return computed.getPropertyValue(properties);
} else {
// 返回所有计算样式
const allStyles = {};
for (let i = 0; i < computed.length; i++) {
const prop = computed[i];
allStyles[prop] = computed.getPropertyValue(prop);
}
return allStyles;
}
}
// 获取计算样式示例
console.log('计算后的颜色:', getComputedStyles(styleElement, 'color'));
console.log('多个样式:', getComputedStyles(styleElement, ['width', 'height', 'margin']));
CSS类和样式表操作
// 动态创建样式表
function createStyleSheet(css) {
const style = document.createElement('style');
style.textContent = css;
document.head.appendChild(style);
return style;
}
// 创建主题样式
const themeStyles = createStyleSheet(`
.theme-dark {
background-color: #333;
color: #fff;
}
.theme-light {
background-color: #fff;
color: #333;
}
.btn-animated {
transition: all 0.3s ease;
transform: scale(1);
}
.btn-animated:hover {
transform: scale(1.05);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
`);
// 样式表管理器
class StyleSheetManager {
constructor() {
this.sheets = new Map();
}
create(id, css) {
if (this.sheets.has(id)) {
this.update(id, css);
return this.sheets.get(id);
}
const style = document.createElement('style');
style.id = id;
style.textContent = css;
document.head.appendChild(style);
this.sheets.set(id, style);
return style;
}
update(id, css) {
const style = this.sheets.get(id);
if (style) {
style.textContent = css;
}
return style;
}
remove(id) {
const style = this.sheets.get(id);
if (style) {
style.remove();
this.sheets.delete(id);
}
return this;
}
toggle(id, css) {
if (this.sheets.has(id)) {
this.remove(id);
} else {
this.create(id, css);
}
return this;
}
exists(id) {
return this.sheets.has(id);
}
getAll() {
return Array.from(this.sheets.keys());
}
}
// 使用样式表管理器
const styleManager = new StyleSheetManager();
// 创建响应式样式
styleManager.create('responsive', `
@media (max-width: 768px) {
.responsive-text {
font-size: 14px;
}
}
@media (min-width: 769px) {
.responsive-text {
font-size: 18px;
}
}
`);
// 主题切换器
class ThemeManager {
constructor() {
this.currentTheme = 'light';
this.themes = {
light: {
'--bg-color': '#ffffff',
'--text-color': '#333333',
'--border-color': '#dddddd',
'--accent-color': '#007bff'
},
dark: {
'--bg-color': '#333333',
'--text-color': '#ffffff',
'--border-color': '#555555',
'--accent-color': '#66b3ff'
},
blue: {
'--bg-color': '#e3f2fd',
'--text-color': '#0d47a1',
'--border-color': '#90caf9',
'--accent-color': '#1976d2'
}
};
this.init();
}
init() {
// 创建CSS变量样式
const css = `
:root {
${this.getCSSVariables(this.currentTheme)}
}
body {
background-color: var(--bg-color);
color: var(--text-color);
transition: all 0.3s ease;
}
.themed-element {
border: 1px solid var(--border-color);
background-color: var(--bg-color);
color: var(--text-color);
}
.accent {
color: var(--accent-color);
}
`;
const styleManager = new StyleSheetManager();
styleManager.create('theme-variables', css);
}
getCSSVariables(themeName) {
const theme = this.themes[themeName];
return Object.entries(theme)
.map(([key, value]) => `${key}: ${value};`)
.join('\n ');
}
setTheme(themeName) {
if (!this.themes[themeName]) {
console.warn(`主题 '${themeName}' 不存在`);
return;
}
this.currentTheme = themeName;
// 更新CSS变量
const root = document.documentElement;
Object.entries(this.themes[themeName]).forEach(([key, value]) => {
root.style.setProperty(key, value);
});
// 触发主题变更事件
document.dispatchEvent(new CustomEvent('themechange', {
detail: { theme: themeName }
}));
}
getTheme() {
return this.currentTheme;
}
getAvailableThemes() {
return Object.keys(this.themes);
}
addTheme(name, variables) {
this.themes[name] = variables;
}
}
// 使用主题管理器
const themeManager = new ThemeManager();
// 创建主题切换按钮
const themeButton = document.createElement('button');
themeButton.textContent = '切换主题';
themeButton.className = 'themed-element';
themeButton.style.cssText = 'padding: 10px; margin: 10px; cursor: pointer;';
let themeIndex = 0;
const themes = themeManager.getAvailableThemes();
themeButton.addEventListener('click', () => {
themeIndex = (themeIndex + 1) % themes.length;
themeManager.setTheme(themes[themeIndex]);
themeButton.textContent = `当前主题: ${themes[themeIndex]}`;
});
document.body.appendChild(themeButton);
// 监听主题变更
document.addEventListener('themechange', (event) => {
console.log('主题已切换到:', event.detail.theme);
});
本章总结
本章详细介绍了DOM操作的核心概念和技术:
- DOM基础:理解了DOM树结构、节点类型和节点关系
- 元素选择:掌握了各种元素选择方法,包括传统方法和现代CSS选择器
- 内容操作:学习了文本和HTML内容的读取、设置和安全处理
- 属性操作:了解了标准属性、数据属性和类名的操作方法
- 样式操作:掌握了内联样式、CSS类和动态样式表的管理
- 工具类设计:通过各种管理器类展示了如何封装DOM操作
DOM操作是前端开发的基础技能,熟练掌握这些技术能够帮助我们构建动态、交互性强的Web应用。这些知识为后续学习事件处理、动画效果等高级主题奠定了坚实基础。
下一章我们将学习事件处理机制,包括事件监听、事件委托和自定义事件。