Javascript 深入学习基础·4

document.getElementById(...)

document.getElementById(...) 是 JavaScript 中一个非常基础且常用的方法,用于获取 HTML 文档中特定元素的引用。

以下是关于该方法的详细用法说明:

📖 基本语法

javascript 复制代码
const element = document.getElementById(id);
  • 参数 (id) :一个字符串,代表要获取的元素的 id 属性值。
  • 返回值
    • 如果找到匹配的元素,返回该 Element 对象
    • 如果未找到,返回 null

💡 代码示例

假设你有以下 HTML 结构:

javascript 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>getElementById 示例</title>
</head>
<body>

    <h1 id="main-title">欢迎访问我的网站</h1>
    <p id="intro">这是一个段落。</p>
    <button onclick="changeText()">点击修改标题</button>

    <script>
        function changeText() {
            // 1. 获取元素
            const titleElement = document.getElementById("main-title");
            
            // 2. 检查元素是否存在 (良好的编程习惯)
            if (titleElement) {
                // 3. 修改元素内容
                titleElement.innerText = "标题已被 JavaScript 修改!";
                titleElement.style.color = "red";
            }
        }
    </script>
</body>
</html>

⚠️ 注意事项与最佳实践

  • ID 的唯一性

    HTML 规范规定,id 在页面中必须是唯一 的。如果页面中有多个元素拥有相同的 idgetElementById 只会返回它在 DOM 树中遇到的第一个元素。

  • 区分大小写
    id 匹配是区分大小写的(在 HTML 文档中通常不区分,但在 XML/XHTML 中区分)。建议保持一致。

  • 执行时机

    JavaScript 代码执行时,必须确保目标元素已经被加载到 DOM 中。

    • 错误做法 :在 <head> 中直接运行脚本获取 <body> 中的元素(此时元素尚未渲染)。
    • 正确做法 :将 <script> 标签放在 </body> 之前,或者使用 DOMContentLoaded 事件。
  • 性能

    它是获取元素最快的方法之一,因为浏览器会利用哈希表来快速查找 ID。


🆚 与其他选择器的对比

表格

方法 描述 兼容性
document.getElementById('id') 通过 ID 获取单个元素 所有浏览器 (包括极老版本)
document.querySelector('#id') 使用 CSS 选择器获取第一个匹配元素 IE8+ (IE8仅支持部分选择器)
document.getElementById('id').style 直接操作内联样式 所有浏览器

提示 :虽然 querySelector 功能更强大,但在只需要通过 ID 获取元素时,getElementById 仍然是性能最好且语义最清晰的选择。


document

document 对象是 Web 前端开发中最核心、最基础的对象之一。简单来说,它是 JavaScript 与你网页(HTML/XML)之间的桥梁

当浏览器加载一个网页时,它会创建一个 document 对象,这个对象代表了整个页面的结构(即 DOM 树)。通过它,JavaScript 才能"看见"并修改页面上的内容、结构和样式。

以下是关于 document 对象的详细介绍:

🌟 核心概念

  • 身份 :它是浏览器内置的全局对象,是 window 对象的属性(即 window.document),也是文档对象模型(DOM)的根节点
  • 作用:它将静态的 HTML 转化为可编程的树状结构(节点树)。你可以通过它来查找元素、修改文本、改变颜色、响应用户点击等。
  • 访问 :在任何标准浏览器的脚本中,都可以直接通过 document 关键字访问。

🛠️ 常用属性 (获取信息)

document 提供了许多属性来获取页面的基本信息:

表格

属性 描述 示例
document.title 获取或设置网页标题 (<title> 标签内容) document.title = "新标题"
document.URL 获取当前页面的完整网址 console.log(document.URL)
document.domain 获取当前页面的域名 console.log(document.domain)
document.cookie 获取或设置与当前文档相关的 Cookie document.cookie
document.body 获取页面的 <body> 元素对象 document.body.style.background = "#fff"
document.head 获取页面的 <head> 元素对象 document.head

⚡ 常用方法 (执行操作)

这是 document 最强大的部分,主要用于查找和操作页面元素。

1. 查找元素 (选择器)

这是开发中最常用的功能:

  • document.getElementById('id') :通过元素的 id 获取单个元素(速度最快,最常用)。
  • document.querySelector('css选择器') :返回匹配 CSS 选择器的第一个元素(功能强大,支持类名、标签等)。
  • document.querySelectorAll('css选择器') :返回匹配 CSS 选择器的所有元素(返回一个静态列表)。
  • document.getElementsByClassName('class'):通过类名获取一组元素。
  • document.getElementsByTagName('tag'):通过标签名(如 'div', 'p')获取一组元素。
2. 创建与修改元素
  • document.createElement('tag') :创建一个新的 HTML 元素节点(如创建一个新的 div)。
  • document.createTextNode('text'):创建一个新的文本节点。
  • document.write('text') :向文档流中写入内容(注意:如果在页面加载完成后使用,会清空整个页面,现代开发中极少使用)。

💻 代码实战示例

以下是一个简单的交互示例,展示了如何使用 document 对象:

javascript 复制代码
// 1. 修改网页标题
document.title = "我的动态网页";

// 2. 获取元素并修改内容
const header = document.getElementById("main-header");
if (header) {
    header.innerText = "欢迎回来,用户!";
    header.style.color = "blue"; // 修改样式
}

// 3. 创建新元素并添加到页面
const newParagraph = document.createElement("p");
newParagraph.innerText = "这是通过 JS 动态添加的段落。";
document.body.appendChild(newParagraph); // 将新元素挂载到 body 下

// 4. 监听文档加载完成事件
document.addEventListener("DOMContentLoaded", () => {
    console.log("HTML 文档已完全加载并解析完成");
});

⚠️ 注意事项

  1. 执行时机 :JavaScript 代码必须在 HTML 元素加载之后 执行。如果脚本放在 <head> 中且没有延迟,可能会因为找不到元素(返回 null)而报错。通常建议将 <script> 标签放在 </body> 之前,或使用 DOMContentLoaded 事件。
  2. 性能 :频繁操作 DOM(如循环中反复添加节点)会触发浏览器的重排(Reflow)和重绘(Repaint),影响性能。建议使用 DocumentFragment 或先拼接字符串再一次性插入。
  3. 安全性 :使用 innerHTMLdocument.write 插入用户输入的内容时,必须进行消毒处理,否则容易导致跨站脚本攻击(XSS)。

代码源码

javascript 复制代码
function showMainApp() {
    document.getElementById('loginPage').style.display = 'none';
    document.getElementById('mainApp').style.display = 'flex';

    // 获取用户角色列表
    const userRoles = currentUser?.roles || [currentUser?.role].filter(r => r);

    // 获取所有导航按钮
    const navItems = {
        products: document.querySelector('.nav-item[data-page="products"]'),
        orders: document.querySelector('.nav-item[data-page="orders"]'),
        dispatch: document.querySelector('.nav-item[data-page="dispatch"]'),
        admin: document.querySelector('.nav-item[data-page="admin"]'),
        observer: document.getElementById('observerNavItem'),
        recorder: document.getElementById('recorderNavItem'),
        maintainer: document.getElementById('maintainerNavItem')
    };+

这段代码看起来是一个典型的前端登录跳转逻辑,主要用于在用户登录成功后,隐藏登录页面并显示主应用界面,同时根据用户的角色权限来动态处理导航栏的显示。

不过,代码在最后一行 navItems 对象定义结束后出现了 + 号,这表明代码被截断了,或者后面还有逻辑未粘贴出来。

以下是代码的详细分析、补全建议以及潜在问题的修复:

代码功能分析

  1. 页面切换
    • loginPage 的样式设为 display: 'none'(隐藏)。
    • mainApp 的样式设为 display: 'flex'(显示)。
  2. 角色处理
    • 尝试从 currentUser 对象中提取角色。
    • 逻辑:优先使用 roles 数组;如果没有,则尝试将单个 role 属性转为数组。
  3. DOM 元素获取
    • 获取了产品、订单、发货、管理等标准导航项。
    • 获取了观察者、记录员、维护者等特定角色的导航项。

代码补全与优化建议

由于代码在 navItems 定义后中断,通常接下来的逻辑是根据用户角色显示或隐藏这些导航按钮

以下是补全后的代码示例,包含了权限判断逻辑和安全性增强:

javascript 复制代码
function showMainApp() {
    // 1. 切换页面显示
    const loginPage = document.getElementById('loginPage');
    const mainApp = document.getElementById('mainApp');
    
    if (loginPage) loginPage.style.display = 'none';
    if (mainApp) mainApp.style.display = 'flex';

    // 2. 规范化用户角色数据 (防止报错)
    // 假设 currentUser 已在全局或闭包中定义
    const userRoles = currentUser?.roles || (currentUser?.role ? [currentUser.role] : []);

    // 3. 获取所有导航按钮的 DOM 元素
    const navItems = {
        products: document.querySelector('.nav-item[data-page="products"]'),
        orders: document.querySelector('.nav-item[data-page="orders"]'),
        dispatch: document.querySelector('.nav-item[data-page="dispatch"]'),
        admin: document.querySelector('.nav-item[data-page="admin"]'),
        // 特定角色导航项
        observer: document.getElementById('observerNavItem'),
        recorder: document.getElementById('recorderNavItem'),
        maintainer: document.getElementById('maintainerNavItem')
    };

    // 4. [补全部分] 基于角色的访问控制 (RBAC) 逻辑
    // 定义每个菜单项所需的角色权限
    const permissions = {
        products: ['admin', 'staff', 'viewer'], // 示例角色
        orders: ['admin', 'staff'],
        dispatch: ['admin', 'dispatcher'],
        admin: ['admin'], // 仅管理员可见
        observer: ['observer'],
        recorder: ['recorder'],
        maintainer: ['maintainer']
    };

    // 遍历导航项,检查权限
    for (const [key, element] of Object.entries(navItems)) {
        if (element) {
            // 检查用户角色列表中是否包含该菜单所需的角色
            // 这里假设 permissions[key] 是一个数组
            const requiredRoles = permissions[key] || [];
            const hasAccess = userRoles.some(role => requiredRoles.includes(role));

            // 如果没有权限,则隐藏该菜单项
            if (!hasAccess) {
                element.style.display = 'none';
            } else {
                // 如果有权限,确保它是可见的 (防止之前被隐藏)
                element.style.display = ''; // 或者 'flex', 'block' 取决于你的CSS
            }
        }
    }
}

关键改进点说明

  1. 空值检查
    • 原代码直接使用 document.getElementById(...),如果 HTML 中不存在这些 ID,后续操作会报错。
    • 优化后增加了 if (element) 判断。
  2. 角色数组的健壮性
    • 原代码:[currentUser?.role].filter(r => r) 是一种写法,但如果 role 是字符串,这会创建一个包含字符串的数组。
    • 优化后:(currentUser?.role ? [currentUser.role] : []) 更加明确,确保始终得到一个干净的字符串数组。
  3. 权限映射
    • 单纯获取 DOM 元素是不够的,必须有一个配置对象(如上面的 permissions)来定义"谁可以看到什么",然后通过循环来动态控制 style.display
相关推荐
粥里有勺糖2 小时前
视野修炼-技术周刊第129期 | 上一次古法编程是什么时候
前端·javascript·github
whuhewei2 小时前
JS获取CSS动画的旋转角度
前端·javascript·css
蓝黑20202 小时前
Vue组件通信之v-model
前端·javascript·vue
charlie1145141912 小时前
通用GUI编程技术——图形渲染实战(二十九)——Direct2D架构与资源体系:GPU加速2D渲染入门
开发语言·c++·学习·架构·图形渲染·win32
像素之间2 小时前
为什么运行时要加set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve
前端·javascript·vue.js
CheerWWW2 小时前
C++学习笔记——线程、计时器、多维数组、排序
c++·笔记·学习
M ? A2 小时前
Vue转React实战:defineProps精准迁移实战
前端·javascript·vue.js·经验分享·react.js·开源·vureact
克里斯蒂亚诺·罗纳尔达2 小时前
智能体学习16——学习与适应(Learning-and-Adaptation)-深入解读
深度学习·学习·机器学习
如意猴3 小时前
【前端】002--怎样制作一个简历界面?
开发语言·前端·javascript