Web 前端技术 第 5 周

JavaScript基础:语法、交互与数据获取

介绍JavaScript核心语法、函数与作用域、事件处理与DOM操作,以及异步编程基础,帮助读者为新闻页面添加动态交互与实时数据功能。

2026-03-31 第 5 周

学习要点

  • 掌握JavaScript变量、数据类型与控制结构的基本语法规则
  • 理解函数与作用域的工作机制,能够编写可复用的功能模块
  • 掌握事件监听与DOM操作方法,为新闻页面添加用户交互逻辑
  • 了解异步编程的核心概念,能够使用fetch从接口获取新闻数据并渲染至页面

正文

变量、数据类型与运算符

JavaScript是运行于浏览器端的脚本语言,负责赋予网页动态行为。在HTML与CSS构建页面结构和视觉呈现之后,JavaScript承担"行为层"的职责——响应用户操作、更新内容、与服务器通信。

变量是存储数据的命名容器。JavaScript提供三个声明关键字:var(函数作用域,已较少使用)、let(块级作用域,可重新赋值)和const(块级作用域,声明后不可重新赋值)。当前最佳实践是优先使用const,仅在需要重新赋值时改用let

1
2
3
const headline = "财政部发布2025年预算草案";  // 新闻标题,不会改变
let pageViews = 0;                             // 浏览量,会随访问递增
let isBreaking = true;                         // 是否为突发新闻

JavaScript拥有七种原始数据类型,新闻开发中最常用的包括:string(字符串,用于标题、正文、作者名等文本内容)、number(数值,用于阅读量、评论数、发布时间戳)、boolean(布尔值,用于标记是否置顶、是否已读等状态)以及nullundefined(分别表示"有意为空"与"尚未赋值")。此外,objectarray属于引用类型,常用于存储结构化新闻数据。

运算符方面,算术运算符(+-*/%)处理数值计算;比较运算符中应优先使用严格相等===而非==,因为后者会进行隐式类型转换,可能引发难以排查的逻辑错误;逻辑运算符&&(与)、||(或)、!(非)常见于条件判断。

1
2
3
const wordCount = 1200;
const readingTime = Math.ceil(wordCount / 300);  // 估算阅读时长(分钟)
console.log(`预计阅读时间:${readingTime} 分钟`); // 模板字符串,反引号包裹

控制结构

控制结构决定代码的执行路径,是实现新闻页面逻辑判断与批量处理的基础工具。

条件语句if...else if...else根据布尔表达式的真假选择执行分支。类比新闻编辑的稿件分类决策:收到一篇稿件,先判断是否为突发新闻,是则标红置顶,否则再判断是否为专题报道,最后按普通稿件处理。

1
2
3
4
5
6
7
8
9
const priority = "breaking";

if (priority === "breaking") {
    console.log("标记为突发新闻,置顶显示");
} else if (priority === "feature") {
    console.log("标记为专题报道,放入专题版块");
} else {
    console.log("普通新闻,按发布时间排列");
}

循环语句用于遍历重复性数据。for循环适合已知迭代次数的场景;for...of循环适合遍历数组;while循环适合条件未知的情形。新闻列表、评论区、标签云等场景均需循环渲染。

1
2
3
4
5
const articles = ["气候峰会闭幕", "央行宣布降准", "女足亚洲杯夺冠"];

for (const title of articles) {
    console.log(`• ${title}`);  // 逐条打印新闻标题
}

switch语句适合多分支的类型判断,例如根据新闻类别("politics""economy""sports")渲染不同的图标或色标。

函数与作用域

函数是可复用的代码块,将特定逻辑封装为可命名、可调用的单元。类比新闻采编流程中的标准化操作手册:每次发布新闻时,"排版格式化"这一操作步骤是固定的,将其封装为函数即可在每篇新闻发布时直接调用,无需重复编写相同代码。

JavaScript支持三种函数写法:函数声明函数表达式箭头函数。函数声明会被"提升"(hoisting)至所在作用域顶部,可在声明之前调用;函数表达式与箭头函数则不具备此特性。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 函数声明:格式化发布时间
function formatPublishTime(timestamp) {
    const date = new Date(timestamp);
    return `${date.getFullYear()}${date.getMonth() + 1}${date.getDate()}日`;
}

// 箭头函数:生成新闻摘要(取正文前100字)
const generateExcerpt = (content, length = 100) => content.slice(0, length) + "……";

console.log(formatPublishTime(1743350400000));          // "2025年3月31日"
console.log(generateExcerpt("近日,国务院发布……", 20)); // "近日,国务院发布……"

作用域(Scope)决定变量在代码中的可见范围。JavaScript存在三个层次的作用域:全局作用域(整个脚本均可访问)、函数作用域(仅函数内部可见)和块级作用域letconst{}内有效)。理解作用域可以避免变量污染——如同报社的内部系统权限分级:全局变量相当于全员可见的公告,局部变量相当于只在某个编辑部门内流通的内部文件。

闭包(Closure)是函数与其词法环境的组合,允许内层函数访问外层函数的变量,常用于封装私有状态,例如记录某篇新闻被点击的次数而不暴露计数器变量到全局。

事件处理与DOM操作

DOM(Document Object Model,文档对象模型)是浏览器将HTML文档解析为树状对象结构的表示形式。JavaScript通过DOM API读取或修改页面中的任意元素,实现内容的动态更新。

获取元素的常用方法:

1
2
3
const title = document.getElementById("article-title");         // 通过id获取单个元素
const tags = document.querySelectorAll(".news-tag");            // 通过CSS选择器获取所有匹配元素
const firstPara = document.querySelector(".article-body p");    // 获取第一个匹配元素

修改元素内容与样式:

1
2
3
4
title.textContent = "更新:洪水已致32人遇难";   // 更新文字内容(不解析HTML标签)
title.innerHTML = "<strong>更新</strong>:洪水已致32人遇难"; // 可解析HTML标签
title.style.color = "red";                       // 修改内联样式
title.classList.add("breaking-news");            // 添加CSS类名

事件处理(Event Handling)是浏览器与用户交互的核心机制。当用户点击按钮、滚动页面或提交表单时,浏览器会触发对应的事件对象,JavaScript通过addEventListener注册回调函数加以响应。这一机制类似于新闻热线电话:电话铃声是"事件",接线员拿起电话的动作是"事件监听器",其后的应答处理是"回调函数"。

1
2
3
4
5
6
7
8
const likeBtn = document.getElementById("like-btn");
let likeCount = 0;

likeBtn.addEventListener("click", function(event) {
    likeCount++;                                              // 点赞数加一
    likeBtn.textContent = `👍 ${likeCount}`;                 // 更新按钮显示
    likeBtn.setAttribute("aria-label", `已有${likeCount}人点赞`); // 更新无障碍属性
});

常用事件类型包括:click(点击)、input(表单输入)、submit(表单提交)、scroll(页面滚动)、DOMContentLoaded(DOM加载完成)。

异步编程基础与数据获取

同步代码逐行顺序执行,前一行完成后才执行下一行;异步代码则允许在等待某操作(如网络请求)完成的同时继续执行后续代码。新闻页面加载稿件列表时,若以同步方式请求服务器,整个页面将冻结至数据返回——这对用户体验而言是不可接受的。异步机制则允许页面保持响应状态,待数据就绪后再行渲染。

JavaScript处理异步操作的现代方式是Promiseasync/await语法。Promise代表一个"承诺"——某个异步操作最终会完成(resolved)或失败(rejected)。async/await是基于Promise的语法糖,使异步代码在写法上接近同步,可读性大幅提升。

fetch API是浏览器内置的网络请求接口,常用于从新闻数据接口(REST API)获取JSON格式的稿件数据。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// async函数:从新闻API获取头条列表
async function fetchTopNews(category) {
    try {
        // 向API发起GET请求,category为新闻类别参数
        const response = await fetch(`https://api.example.com/news?category=${category}`);

        if (!response.ok) {
            throw new Error(`请求失败,状态码:${response.status}`);
        }

        const data = await response.json();  // 将响应体解析为JSON对象
        return data.articles;                // 返回文章数组
    } catch (error) {
        console.error("获取新闻数据时出错:", error.message);
        return [];  // 出错时返回空数组,避免页面崩溃
    }
}

// 调用函数并渲染结果
fetchTopNews("politics").then(articles => {
    articles.forEach(article => {
        console.log(`[${article.source}] ${article.title}`);
    });
});

try...catch结构用于捕获异步操作中的错误,确保网络故障或接口异常不会导致页面脚本全面崩溃——这一错误处理习惯与新闻核实流程中的"备稿机制"同理:主要信源失联时,启用备用信源而非直接开天窗。

实践示例

场景:为一个新闻专题页面构建"实时头条滚动"组件,从模拟数据接口获取新闻标题,并允许用户点击标题展开摘要。

目标:使用fetch获取新闻数据,用DOM操作将其渲染为列表,并通过事件监听实现展开/收起摘要的交互效果。

实现步骤

步骤一:编写HTML骨架

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>今日头条</title>
    <style>
        .news-item { border-bottom: 1px solid #ddd; padding: 12px 0; cursor: pointer; }
        .news-title { font-weight: bold; color: #1a1a1a; }
        .news-excerpt { display: none; color: #555; margin-top: 8px; font-size: 0.9em; }
        .news-excerpt.visible { display: block; }  /* 展开状态 */
        .breaking .news-title { color: #c0392b; }  /* 突发新闻标红 */
    </style>
</head>
<body>
    <h1>今日头条</h1>
    <div id="news-list">加载中……</div>
    <script src="app.js"></script>
</body>
</html>

步骤二:在app.js中定义模拟数据与渲染函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 模拟新闻API返回的数据(实际项目中替换为真实fetch请求)
const mockNewsData = [
    {
        id: 1,
        title: "国家发展改革委:上半年GDP增速达5.2%",
        excerpt: "国家发展改革委新闻发言人今日表示,上半年全国经济运行总体平稳,GDP同比增长5.2%,就业、物价保持稳定。",
        isBreaking: false
    },
    {
        id: 2,
        title: "【突发】南方多省遭遇强降雨,已启动Ⅱ级响应",
        excerpt: "气象部门发布暴雨红色预警,广东、福建、浙江三省已启动防汛Ⅱ级应急响应,当地驻军部队进入待命状态。",
        isBreaking: true
    },
    {
        id: 3,
        title: "第十八届全国新闻摄影大赛获奖名单公布",
        excerpt: "中国新闻摄影学会今日公布本届大赛获奖结果,共评出金银铜奖及优秀奖共计102件作品,涵盖新闻现场、人物、体育等类别。",
        isBreaking: false
    }
];

// 模拟异步获取数据(使用Promise包装,模拟网络延迟)
function fetchNews() {
    return new Promise(resolve => {
        setTimeout(() => resolve(mockNewsData), 800);  // 模拟800ms网络延迟
    });
}

步骤三:渲染新闻列表并绑定交互事件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 将单条新闻数据渲染为DOM元素
function renderNewsItem(article) {
    const item = document.createElement("div");
    item.classList.add("news-item");
    if (article.isBreaking) item.classList.add("breaking");  // 突发新闻添加特殊样式

    // 创建标题元素
    const titleEl = document.createElement("p");
    titleEl.classList.add("news-title");
    titleEl.textContent = article.title;

    // 创建摘要元素(默认隐藏)
    const excerptEl = document.createElement("p");
    excerptEl.classList.add("news-excerpt");
    excerptEl.textContent = article.excerpt;

    // 点击标题切换摘要显示状态
    titleEl.addEventListener("click", () => {
        excerptEl.classList.toggle("visible");  // toggle:有则移除,无则添加
    });

    item.appendChild(titleEl);
    item.appendChild(excerptEl);
    return item;
}

// 主函数:获取数据并渲染页面
async function initNewsList() {
    const container = document.getElementById("news-list");
    container.textContent = "加载中……";  // 显示加载状态

    try {
        const articles = await fetchNews();     // 等待数据返回
        container.textContent = "";             // 清空加载提示

        articles.forEach(article => {
            const itemEl = renderNewsItem(article);
            container.appendChild(itemEl);      // 将每条新闻插入容器
        });
    } catch (error) {
        container.textContent = "新闻加载失败,请稍后刷新页面。";
        console.error(error);
    }
}

// 页面DOM加载完成后执行初始化
document.addEventListener("DOMContentLoaded", initNewsList);

效果说明:页面加载后显示"加载中……"字样,约800毫秒后新闻列表渲染完成。标题为突发新闻的条目以红色字体显示,普通条目保持默认黑色。点击任意标题,该条摘要在下方展开;再次点击则收起。若数据加载发生异常,页面显示友好的错误提示,不会出现空白崩溃。整个组件无需刷新页面即可完成内容展示与交互,体现了JavaScript在新闻前端动态化中的核心作用。

练习

  1. 基础练习:在上方示例的基础上,为每条新闻添加一个"来源"字段(如"新华社""央视新闻"),并在渲染时以灰色小字显示在标题下方。参考renderNewsItem函数的结构,用document.createElement创建对应元素并设置样式。

  2. 进阶练习:在页面顶部添加一个文本输入框(<input type="text" id="search-box">),监听其input事件,根据用户输入的关键词实时过滤新闻列表——仅显示标题中包含该关键词的条目,无匹配时显示"未找到相关新闻"。提示:使用String.prototype.includes()方法进行字符串匹配,并结合DOM的display属性控制显示与隐藏。

  3. 综合练习:选取一个公开的新闻或天气类API(如NewsAPI的免费接口或Open-Meteo气象接口),参考本章fetch示例,编写完整的数据获取与渲染逻辑,将真实数据呈现在一个自制的新闻资讯卡片页面中。页面应包含:数据加载状态提示、至少一种用户交互(点击、筛选或搜索),以及网络错误时的友好提示文案。结合你对新闻读者体验的理解,撰写不少于200字的设计说明,阐述你在数据呈现与交互设计上的决策逻辑。

本章小结

  • 变量与数据类型letconst是现代JavaScript的变量声明方式,字符串、数值、布尔值等原始类型构成新闻数据处理的基础单元。
  • 控制结构if...elsefor...of等语句控制代码的执行路径与遍历逻辑,是动态渲染新闻列表、分类处理稿件的核心工具。
  • 函数与作用域:函数将可复用逻辑封装为独立单元,块级作用域(let/const)有效防止变量污染,闭包则支持封装私有状态。
  • 事件处理与DOM操作addEventListener监听用户行为,querySelector系列方法定位页面元素,二者配合实现新闻页面的动态交互。
  • 异步编程与fetchasync/await配合fetch API以同步写法处理异步网络请求,try...catch保障错误不影响页面正常运行。

延伸阅读

  • MDN Web Docs — JavaScript 指南 — Mozilla维护的权威JavaScript中文文档,覆盖从语法基础到高级特性的完整参考。
  • javascript.info — 以清晰的章节结构和丰富的交互练习讲解现代JavaScript,提供完整中文译本。
  • MDN — 使用 Fetch — Fetch API官方使用指南,包含请求配置、错误处理与实际用例。
  • The Pudding — 数据新闻与可视化叙事媒体,其作品大量运用JavaScript交互技术,可作为新闻前端实践的参照案例库。
  • Eloquent JavaScript(第4版) — 广受好评的JavaScript开源教材,第13-15章专门讲解DOM操作与浏览器事件,提供免费在线阅读。