实验目的
- 了解前端页面组成及html、css、JavaScript分工;
- 熟悉MVVM设计模式;
- 掌握JavaScript中函数的使用
- 掌握异步编程中promise的使用
- 掌握模块化导入导出技术
- 掌握前端调试技术
实验过程
通过制作一个前端网页,完成HTML、CSS和JavaScript相关语法的学习,并了解MVVM架构模式及模块化开发。
实验步骤
- 创建一个名为studentModel.js文件,提供学生信息数据。该模块首先定义学生数据,并模拟异步获取数据fetchStudents,最后通过模块导出获取学生数据方法。代码如下:
javascript
// 学生数据模型模块
const studentModule = (function() {
// 私有学生数据,使用字面量定义对象数组
const students = [
{
id: 'S001',
firstName: '小明',
lastName: '张',
age: 20,
major: '计算机科学',
grade: 85,
gpa: 3.7,
email: 'zhangxiaoming@example.com'
},
{
id: 'S002',
firstName: '小红',
lastName: '李',
age: 21,
major: '数学',
grade: 92,
gpa: 3.9,
email: 'lixiaohong@example.com'
},
{
id: 'S003',
firstName: '小刚',
lastName: '王',
age: 19,
major: '物理',
grade: 78,
gpa: 3.2,
email: 'wangxiaogang@example.com'
}
];
// 模拟异步获取数据
function fetchStudents() {
return new Promise((resolve) => {
// 模拟网络延迟,使用扩展运算符
setTimeout(() => {
resolve([...students]);
}, 800);
});
}
// 公开的API
return {
getStudents: fetchStudents
};
})();
// 导出模块
export const { getStudents } = studentModule;
代码中首先定义学生对象数组,其次模拟异步获取数据函数,该函数返回了一个Promise对象;最后通过模块导出getStudents 方法,体现面向对象的封装性
2 创建一个名为student.html的网页文件,展示学生信息。并将CSS和JavaScript代码集中存放Body元素底部。这种将不同类型的文件进行集中存放,便于代码的后期维护。代码如下:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学生信息管理系统</title>
</head>
<body>
<div class="container">
<h1>学生信息管理系统</h1>
<div id="student-container">
<div class="loading">正在加载学生数据...</div>
</div>
</div>
<script type="module">
import { getStudents } from './studentModel.js';
// 通过异步访问,获取要显示的数据,async代表函数内部包含了异步处理
async function displayStudents() {
try {
const students = await getStudents();
console.log("异步数据读取完成",students );
// 以上代码获取的students可以想象为MVVM中的M,
// 以下代码对获取的M加工,并将其渲染到页面(V)中
const processedStudents = processStudentData(students);
renderStudents(processedStudents);
console.log("数据已经渲染到页面",processedStudents)
} catch (error) {
document.getElementById('student-container').innerHTML =
`<div class="error">加载学生数据失败: ${error.message}</div>`;
}
}
function processStudentData(students) {
return students.map(student => {
return {
// ...扩展运算,将student对象解析为单个属性,与下面加工属性合并为一个新的对象
...student,
fullName: `${student.lastName} ${student.firstName}`,
gradeLevel: getGradeLevel(student.grade),
gpaStatus: student.gpa >= 3.5 ? '优秀' : student.gpa >= 2.5 ? '良好' : '需提高'
};
});
}
function getGradeLevel(grade) {
if (grade >= 90) return 'A';
if (grade >= 80) return 'B';
if (grade >= 70) return 'C';
if (grade >= 60) return 'D';
return 'F';
}
// 将数据渲染到页面
function renderStudents(students) {
const container = document.getElementById('student-container');
container.innerHTML = '';
if (students.length === 0) {
container.innerHTML = '<div class="error">没有找到学生数据</div>';
return;
}
students.forEach(student => {
const card = document.createElement('div');
card.className = 'student-card';
card.innerHTML = `
<h3>${student.fullName}</h3>
<div class="student-info">
<div class="info-item">
<span class="info-label">学号:</span> ${student.id}
</div>
<div class="info-item">
<span class="info-label">年龄:</span> ${student.age}
</div>
<div class="info-item">
<span class="info-label">专业:</span> ${student.major}
</div>
<div class="info-item">
<span class="info-label">年级:</span> ${student.gradeLevel}
</div>
<div class="info-item">
<span class="info-label">GPA:</span> ${student.gpa} (${student.gpaStatus})
</div>
<div class="info-item">
<span class="info-label">邮箱:</span> ${student.email}
</div>
</div>
`;
container.appendChild(card);
});
}
// 初始化加载数据
displayStudents();
</script>
<style>
/* 标签选择器 */
body {
font-family: 'Arial', sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
/* 类选择器 */
.container {
max-width: 1000px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
h1 {
color: #2c3e50;
text-align: center;
margin-bottom: 30px;
}
.student-card {
border: 1px solid #ddd;
border-radius: 5px;
padding: 15px;
margin-bottom: 15px;
background-color: #f9f9f9;
}
/* 后代选择器,其中.student-card是祖先元素,h3是后代元素 */
.student-card h3 {
margin-top: 0;
color: #3498db;
}
.student-info {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
.info-item {
margin-bottom: 5px;
}
.info-label {
font-weight: bold;
color: #7f8c8d;
}
.loading {
text-align: center;
padding: 20px;
font-style: italic;
color: #7f8c8d;
}
.error {
color: #e74c3c;
text-align: center;
padding: 20px;
}
</style>
</body>
</html>
代码中HTML是页面骨架,CSS是修饰器,JavaScript代码完成互动。由MVVM模式角度,可以认为HTML为V(视图),studentModel.js中的数据看做为M(模型),JavaScript代码为VM,V和M不发生直接耦合,VM将二者联系起来,当M发生变化时,仅变化VM中代码,当V发生变化时,也仅限于VM代码的变化。这种架构模式符合迪米特法则------不和陌生人讲话,即V和M是陌生人
- 浏览页面,由于使用浏览器访问文件时,会报跨域错误,因此需要安装Web服务器,再浏览页面。执行步骤如下:
按win+R,输入CMD,打开命令行窗口,在命令行窗口输入:node -v,验证是否安装node.js,如果没有安装,先安装node.js
NPM包含在node.js,在命令行窗口输入命名:npm install anywhere -g;安装anywhere静态服务器(类似tomcat)。
在命令行窗口,进入上述html所在目录,输入命令:anywhere -p 10009;启动服务器,启动后弹出界面如下:

点击student.html文件,显示页面如下:

- 页面调试
按F12,打开调试页面。选中第一个选项卡,在此可以查看DOM元素,调整相关样式,界面如下:

选中console可以查看控制台上输出,以便调试代码。界面如下:

点击网络选项卡(network),可以查看网络请求,界面如下:
