涉及到的代码如下:
const urls = [
'http://192.168.15.149:3000/d/000000039/postgresql-database?orgId=1&refresh=10s&from=now-6h&to=now',
'http://192.168.15.149:3000/d/TgmJnqnnk/minio-dashboard?orgId=1&var-scrape_jobs=minio-cluster',
'http://192.168.15.149:3000/d/TgmJnnqn2k/minio-node-dashboard?orgId=1&var-DS_PROMETHEUS=DS_PROMETHEUS&var-scrape_jobs=minio-node&var-server=minio1:9000',
'http://192.168.15.149:3000/d/TgmJnqnnk2/minio-bucket-dashboard?orgId=1&var-scrape_jobs=minio-bucket',
'http://192.168.15.149:3000/d/rYdddlPWk/node-exporter-full?orgId=1&refresh=1m&var-ds_prometheus=DS_PROMETHEUS&var-job=node-exporter&var-nodename=10eb0cd53f3b&var-node=node-exporter:9100',
'http://192.168.15.66:2888/intelligenceVisual/standardization?visualModelType=0',
'http://www.baidu.com',
'http://www.baidu.com'
];
const tiles = urls.map(u => {
const a = document.createElement('a');
a.href = u;
a.className = 'tile';
const f = document.createElement('iframe');
f.src = u;
const label = document.createElement('span');
label.className = 'label';
label.textContent = new URL(u).hostname;//label标签显示内容做了截取
label.title = u;
a.appendChild(f);//<a>里面套<iframe>
a.appendChild(label);//<a>里面套<span>
container.appendChild(a);//<grid>里面套<a>
//grid内的各个<a>区域增加点击事件
a.addEventListener('click', e => {
e.preventDefault();
openModal(u);//调用弹出框页面函数
});
return { a, f };
});
map 是什么
- 数组方法,用于“把一个数组转成另一个数组”。
- 对原数组的每个元素调用一次回调函数,并用回调的返回值组成一个“新数组”。
- 语法要点:map 不修改原数组;如果回调不返回值,生成的新数组元素就是 undefined。
这段 map 在做什么
- 输入:urls(字符串数组,每个是一个页面地址)。
- 过程:对每个 url
- 创建一个可点击的格子 a(父元素)。
- 创建一个缩略图 iframe(子元素),设置 src 为该 url。
- 创建一个左下角标签 label,文本为该 url 的域名。
- 把 iframe 和 label 放进格子,再把格子加入网格容器。
- 绑定点击事件,阻止默认跳转,改为打开弹窗显示该 url。
- 输出:返回一个对象 {a, f},包含“格子元素”和“缩略图 iframe”的引用。最终得到 tiles 数组,长度与 urls 一致。
为什么用 map,而不是 forEach
- map 的“巧妙点”在于:一边“遍历构建 DOM”,一边“生成一个结构化的引用数组”,方便后续操作。
- 后续的 fitCover 用到了 tiles:tiles.forEach(({a, f}) => { … }),对每个格子计算缩放与居中。若用 forEach,就需要另建数组来保存 a 和 f。
- map 的返回值就是“派生数据模型”:把“原始数据(url)”自然地变成“视图模型({a,f})”。这种“数据 → 视图”的转换非常直观。
- 简洁与可读性:创建、注册事件、收集引用这三件事集中在同一块代码里完成,逻辑清晰。
对比示例
- 用 forEach 实现同样功能,需要手动维护引用数组:
const tiles = [];
urls.forEach(u => {
const a = document.createElement('a');
const f = document.createElement('iframe');
// ...同样的创建与绑定
tiles.push({ a, f });
});
- 用 map 更自然(把每个 url 映射为 {a,f}):
const tiles = urls.map(u => {
const a = document.createElement('a');
const f = document.createElement('iframe');
// ...同样的创建与绑定
return { a, f };
});
两者都能做到,但 map 强调“变换并返回结果”,forEach 强调“遍历产生副作用”。