JS相关知识7.0
JavaScript图片、文件夹上传到后台是什么类型
在 JavaScript 中,图片和文件夹上传到后台时,通常使用 multipart/form-data 格式。这种格式允许将文件和其他表单数据一起上传。以下是详细说明:
1. 文件上传的类型
multipart/form-data:用于上传文件和其他表单数据。
通过
<form>表单或FormData对象实现。
application/json:- 通常用于上传文本数据,不适合直接上传文件。
2. 使用 <form> 表单上传
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" multiple>
<button type="submit">Upload</button>
</form>说明:
enctype="multipart/form-data":指定表单数据编码类型。multiple:允许选择多个文件。
3. 使用 FormData 对象上传
const fileInput = document.querySelector('input[type="file"]');
const formData = new FormData();
fileInput.addEventListener('change', function() {
for (const file of fileInput.files) {
formData.append('files', file); // 添加文件到 FormData
}
fetch('/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
});说明:
FormData:用于构建表单数据,支持文件上传。append:将文件添加到FormData中。
4. 文件夹上传
<input type="file" name="files" webkitdirectory multiple>说明:
webkitdirectory:允许选择文件夹(仅支持部分浏览器)。multiple:允许选择多个文件夹。
5. 后台处理
- Node.js(使用
multer中间件):
const express = require('express');
const multer = require('multer');
const app = express();
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.array('files'), (req, res) => {
console.log(req.files); // 上传的文件信息
res.json({ message: 'Upload successful' });
});
app.listen(3000, () => console.log('Server running on port 3000'));说明:
multer:用于处理multipart/form-data格式的文件上传。upload.array('files'):处理多个文件上传。
总结
| 类型 | 描述 | 适用场景 |
|---|---|---|
| multipart/form-data | 用于上传文件和表单数据 | 文件上传、文件夹上传 |
| FormData | 用于构建表单数据,支持文件上传 | 通过 JavaScript 动态上传文件 |
| multer | Node.js 中间件,处理文件上传 | 后台接收和处理文件 |
通过 multipart/form-data 格式和 FormData 对象,可以方便地实现文件和文件夹的上传功能。
Window.write和document.innerhtml区别
window.write 和 document.innerHTML 是 JavaScript 中用于操作页面内容的两种方法,但它们的行为和用途有显著区别。以下是它们的详细对比:
1. window.write
定义:
window.write是document.write的别名,用于向文档中写入内容。
行为:
如果文档已经加载完成,调用
document.write会清空整个文档并重新写入内容。如果文档正在加载中,
document.write会将内容插入到当前文档流中。
document.write('<h1>Hello, World!</h1>');优点:
- 简单易用,适合快速测试。
缺点:
会清空已加载的文档,导致页面内容丢失。
不推荐在现代 Web 开发中使用。
2. document.innerHTML
定义:
document.innerHTML是Element.innerHTML的误写,正确用法是element.innerHTML,用于获取或设置元素的 HTML 内容。
行为:
获取或设置指定元素的内部 HTML 内容。
不会影响其他元素或文档结构。
document.getElementById('myDiv').innerHTML = '<p>Hello, World!</p>';优点:
精确控制特定元素的内容。
不会影响文档的其他部分。
缺点:
- 直接操作 HTML 字符串可能导致安全问题(如 XSS 攻击)。
3. 对比
| 特性 | document.write | element.innerHTML |
|---|---|---|
| 作用对象 | 整个文档 | 特定元素 |
| 行为 | 清空文档或插入内容 | 获取或设置元素的 HTML 内容 |
| 影响范围 | 影响整个文档 | 仅影响指定元素 |
| 安全性 | 低,可能导致内容丢失 | 低,可能导致 XSS 攻击 |
| 适用场景 | 快速测试,不推荐用于生产环境 | 动态更新页面内容 |
总结
document.write:用于向文档中写入内容,但会清空已加载的文档。
不推荐在现代 Web 开发中使用。
element.innerHTML:用于获取或设置特定元素的 HTML 内容。
适合动态更新页面内容,但需注意安全问题。
根据具体需求选择合适的方法,可以提高代码的可维护性和安全性。
JavaScript中call和apply的区别
在 JavaScript 中,call 和 apply 都是用于显式绑定函数执行时的 this 值的方法。它们的主要区别在于 传递参数的方式。
call方法
作用:调用函数,并显式指定函数内部的
this值,同时以 参数列表 的形式传递参数。语法:
javascriptfunc.call(thisArg, arg1, arg2, ...);thisArg:函数运行时this的值。arg1, arg2, ...:传递给函数的参数列表。
示例:
javascriptfunction greet(name, age) { console.log(`Hello, ${name}! You are ${age} years old.`); console.log(this); // { country: "USA" } } const context = { country: "USA" }; greet.call(context, "Alice", 25); // 输出: // Hello, Alice! You are 25 years old. // { country: "USA" }
apply方法
作用:调用函数,并显式指定函数内部的
this值,同时以 数组或类数组 的形式传递参数。语法:
javascriptfunc.apply(thisArg, [argsArray]);thisArg:函数运行时this的值。argsArray:传递给函数的参数数组(或类数组对象)。
示例:
javascriptfunction greet(name, age) { console.log(`Hello, ${name}! You are ${age} years old.`); console.log(this); // { country: "Canada" } } const context = { country: "Canada" }; greet.apply(context, ["Bob", 30]); // 输出: // Hello, Bob! You are 30 years old. // { country: "Canada" }
call和apply的区别
| 特性 | call | apply |
|---|---|---|
| 参数传递方式 | 以参数列表 的形式传递 | 以数组或类数组 的形式传递 |
| 适用场景 | 参数数量固定时使用 | 参数数量不固定或动态时使用 |
- 使用场景
(1) call 的使用场景
- 当参数数量固定且较少时,使用
call更直观。
function add(a, b) {
return a + b;
}
const result = add.call(null, 2, 3); // 5(2) apply 的使用场景
- 当参数数量不固定或动态时,使用
apply更方便。
function sum() {
return Array.from(arguments).reduce((acc, val) => acc + val, 0);
}
const numbers = [1, 2, 3, 4];
const result = sum.apply(null, numbers); // 10- 实际应用
(1) 借用方法
- 使用
call或apply可以借用其他对象的方法。
const obj1 = { name: "Alice" };
const obj2 = { name: "Bob" };
function greet() {
console.log(`Hello, ${this.name}!`);
}
greet.call(obj1); // Hello, Alice!
greet.call(obj2); // Hello, Bob!(2) 处理类数组对象
- 使用
apply可以将类数组对象(如arguments或NodeList)转换为数组。
function logArguments() {
const args = Array.prototype.slice.call(arguments);
console.log(args);
}
logArguments(1, 2, 3); // [1, 2, 3]总结
call:适合参数数量固定的场景,参数以列表形式传递。apply:适合参数数量不固定或动态的场景,参数以数组形式传递。- 两者都可以显式绑定
this值,是 JavaScript 中灵活调用函数的重要工具。
JavaScript添加 删除 替换 插入到某个节点的方法
在 JavaScript 中,操作 DOM 节点(添加、删除、替换、插入)是常见的任务。以下是常用的方法及其示例:
- 添加节点
(1) appendChild()
将一个节点添加到指定父节点的子节点列表的末尾。
语法:
javascriptparentNode.appendChild(childNode);示例:
javascriptconst parent = document.getElementById("parent"); const newChild = document.createElement("div"); newChild.textContent = "New Child"; parent.appendChild(newChild);
(2) insertBefore()
将一个节点插入到指定父节点的某个子节点之前。
语法:
javascriptparentNode.insertBefore(newNode, referenceNode);示例:
javascriptconst parent = document.getElementById("parent"); const newChild = document.createElement("div"); newChild.textContent = "New Child"; const referenceChild = document.getElementById("child"); parent.insertBefore(newChild, referenceChild);
- 删除节点
(1) removeChild()
从父节点中移除指定的子节点。
语法:
javascriptparentNode.removeChild(childNode);示例:
javascriptconst parent = document.getElementById("parent"); const child = document.getElementById("child"); parent.removeChild(child);
(2) remove()
直接从 DOM 中移除当前节点。
语法:
javascriptnode.remove();示例:
javascriptconst child = document.getElementById("child"); child.remove();
- 替换节点
(1) replaceChild()
用新节点替换父节点中的某个子节点。
语法:
javascriptparentNode.replaceChild(newNode, oldNode);示例:
javascriptconst parent = document.getElementById("parent"); const oldChild = document.getElementById("child"); const newChild = document.createElement("div"); newChild.textContent = "New Child"; parent.replaceChild(newChild, oldChild);
(2) replaceWith()
用新节点替换当前节点。
语法:
javascriptoldNode.replaceWith(newNode);示例:
javascriptconst oldChild = document.getElementById("child"); const newChild = document.createElement("div"); newChild.textContent = "New Child"; oldChild.replaceWith(newChild);
- 插入节点
(1) insertAdjacentElement()
在相对于当前元素的指定位置插入一个新元素。
语法:
javascriptelement.insertAdjacentElement(position, newElement);参数:
position:插入位置,可以是以下值之一:"beforebegin":在当前元素之前插入。"afterbegin":在当前元素的第一个子元素之前插入。"beforeend":在当前元素的最后一个子元素之后插入。"afterend":在当前元素之后插入。
示例:
javascriptconst target = document.getElementById("target"); const newElement = document.createElement("div"); newElement.textContent = "New Element"; target.insertAdjacentElement("beforeend", newElement);
(2) insertAdjacentHTML()
在相对于当前元素的指定位置插入 HTML 字符串。
语法:
javascriptelement.insertAdjacentHTML(position, htmlString);示例:
javascriptconst target = document.getElementById("target"); target.insertAdjacentHTML("beforeend", "<div>New Element</div>");
总结
| 操作 | 方法 | 描述 |
|---|---|---|
| 添加 | appendChild() | 在父节点末尾添加子节点 |
insertBefore() | 在指定子节点前插入新节点 | |
| 删除 | removeChild() | 移除指定子节点 |
remove() | 直接移除当前节点 | |
| 替换 | replaceChild() | 用新节点替换指定子节点 |
replaceWith() | 用新节点替换当前节点 | |
| 插入 | insertAdjacentElement() | 在指定位置插入新元素 |
insertAdjacentHTML() | 在指定位置插入 HTML 字符串 |
通过掌握这些方法,可以灵活地操作 DOM 节点,实现动态的页面更新和交互。
清除浮动有哪些方法,哪种方法最优
清除浮动是解决父元素高度塌陷问题的关键方法。以下是常用的清除浮动方案及其优缺点分析,最后会给出最优方案建议:
一、清除浮动的常见方法
1. 空 div + clear: both
<div class="parent">
<div class="float-left"></div>
<div class="float-left"></div>
<div style="clear: both;"></div> <!-- 清除浮动的空 div -->
</div>- 优点:简单直接,兼容性好。
- 缺点:添加无意义的空标签,破坏 HTML 语义化。
2. 父元素设置 overflow 属性
.parent {
overflow: auto; /* 或 overflow: hidden */
}- 原理:触发 BFC(块级格式化上下文),强制父元素包裹浮动内容。
- 优点:代码简洁,无需额外标签。
- 缺点:可能隐藏内容(
overflow: hidden)或显示滚动条(overflow: auto)。
3. 伪元素法(.clearfix)
.clearfix::after {
content: "";
display: block;
clear: both;
}
/* 兼容旧浏览器(可选) */
.clearfix {
zoom: 1;
}<div class="parent clearfix">
<div class="float-left"></div>
<div class="float-left"></div>
</div>- 优点:语义化好,无冗余标签,广泛使用。
- 缺点:需为父元素添加额外类名。
4. 父元素浮动(不推荐)
.parent {
float: left; /* 父元素自身浮动 */
}- 缺点:可能导致布局连锁反应,影响其他元素。
5. 使用 display: flow-root(现代方案)
.parent {
display: flow-root;
}- 原理:直接创建 BFC,无需副作用。
- 优点:语义清晰,无冗余代码。
- 缺点:兼容性稍差(不支持 IE11 及以下)。
二、最优方案推荐
推荐方案:伪元素法(.clearfix)
- 原因:
- 语义化:无需添加无意义的空标签。
- 兼容性:支持所有浏览器(搭配
zoom: 1兼容 IE6/7)。 - 灵活性:可复用
.clearfix类,适合复杂项目。
替代方案:display: flow-root(现代项目首选)
- 条件:
- 项目无需支持 IE11 及以下浏览器。
- 希望代码更简洁,无副作用。
三、各方案对比表
| 方法 | 语义化 | 兼容性 | 副作用 | 代码简洁性 |
|---|---|---|---|---|
空div + clear | ❌ | ✅ | 添加空标签 | ❌ |
overflow | ✅ | ✅ | 内容截断/滚动条 | ✅ |
伪元素法(.clearfix) | ✅ | ✅ | 无 | ✅ |
| 父元素浮动 | ✅ | ✅ | 布局连锁反应 | ❌ |
display: flow-root | ✅ | ⚠️ | 无(需兼容性处理) | ✅ |
四、总结
- 传统项目:使用 伪元素法(
.clearfix),兼容性好且无副作用。 - 现代项目:优先选择
display: flow-root,代码简洁高效。 - 避免使用:空
div和父元素浮动,前者破坏语义,后者导致布局问题。
根据项目需求选择最适合的方案即可!
DOM怎样添加、移除、移动、复制、创建和查找节点
以下是 JavaScript 中 DOM 节点操作的常见方法,涵盖创建、添加、移除、移动、复制和查找节点的详细说明及示例:
一、创建节点
- 创建元素节点
// 创建新的 <div> 元素
const newDiv = document.createElement('div');- 创建文本节点
// 创建文本内容
const newText = document.createTextNode('Hello World!');- 创建带属性的节点
const newImg = document.createElement('img');
newImg.src = 'image.jpg';
newImg.alt = '示例图片';二、添加节点
- 追加到父节点末尾
const parent = document.getElementById('parent');
parent.appendChild(newDiv); // 将 newDiv 添加到 parent 末尾- 插入到指定位置
const referenceNode = document.getElementById('child1');
parent.insertBefore(newDiv, referenceNode); // 在 referenceNode 前插入- 直接插入 HTML(现代方法)
parent.insertAdjacentHTML('beforeend', '<p>插入的内容</p>');
// 可选位置:'beforebegin', 'afterbegin', 'beforeend', 'afterend'三、移除节点
- 通过父节点移除子节点
parent.removeChild(childNode); // 传统方法- 直接移除自身(现代方法)
childNode.remove(); // 直接调用节点的 remove() 方法四、移动节点
- 移动现有节点到新位置
const newParent = document.getElementById('newParent');
newParent.appendChild(childNode); // 从原位置移除,添加到新位置- 示例:交换两个节点的位置
const node1 = document.getElementById('node1');
const node2 = document.getElementById('node2');
const parent = node1.parentNode;
parent.insertBefore(node2, node1); // 将 node2 移到 node1 前面五、复制节点
- 浅拷贝(不复制子节点)
const clonedNode = node.cloneNode(false); // 只复制节点本身- 深拷贝(复制节点及其子节点)
const clonedNode = node.cloneNode(true); // 复制节点及所有子节点六、查找节点
- 通过 ID 查找
const element = document.getElementById('myId');- 通过类名查找
const elements = document.getElementsByClassName('myClass'); // 返回动态集合- 通过标签名查找
const elements = document.getElementsByTagName('div'); // 返回动态集合- 通过 CSS 选择器查找
// 返回第一个匹配元素
const element = document.querySelector('.myClass');
// 返回所有匹配元素(静态集合)
const elements = document.querySelectorAll('div.highlight');- 层级关系查找
// 父节点
const parent = node.parentNode;
// 子节点集合(包含文本节点)
const children = node.childNodes;
// 仅元素子节点
const elementChildren = node.children;
// 前后兄弟节点
const nextSibling = node.nextElementSibling;
const prevSibling = node.previousElementSibling;七、综合示例
<div id="container">
<p class="text">原始段落</p>
</div>// 创建新节点
const newParagraph = document.createElement('p');
newParagraph.textContent = '新段落';
// 添加到容器末尾
document.getElementById('container').appendChild(newParagraph);
// 移除原始段落
const oldParagraph = document.querySelector('.text');
oldParagraph.remove();
// 复制节点并插入到前面
const clonedParagraph = newParagraph.cloneNode(true);
document.getElementById('container').prepend(clonedParagraph);八、最佳实践
- 优先使用
querySelector和querySelectorAll:更灵活且支持复杂选择器。 - 操作前检查节点是否存在:避免
null错误。javascriptconst node = document.getElementById('myId'); if (node) { node.remove(); } - 批量操作使用文档片段:减少重绘次数。javascript
const fragment = document.createDocumentFragment(); for (let i = 0; i < 10; i++) { const div = document.createElement('div'); fragment.appendChild(div); } document.body.appendChild(fragment);
通过掌握这些方法,你可以高效地操作 DOM 节点,实现动态的页面交互!
src与href的区别
在 HTML 中,src(Source)和 href(Hypertext Reference)是两个常见的属性,但它们的用途和行为有本质区别:
1. 核心定义
src表示 “引入资源”,用于替换当前元素的内容或直接嵌入外部资源。 常见场景:<script>、<img>、<iframe>、<audio>、<video>。html<script src="app.js"></script> <!-- 加载并执行 JS --> <img src="image.jpg"> <!-- 加载并显示图片 -->href表示 “建立关联”,用于定义当前文档与外部资源的链接关系。 常见场景:<a>、<link>、<area>。html<a href="page.html">链接</a> <!-- 跳转到其他页面 --> <link href="style.css" rel="stylesheet"> <!-- 关联 CSS 文件 -->
2. 关键区别
| 特性 | src | href |
|---|---|---|
| 作用 | 直接嵌入资源,替换当前元素内容 | 建立关联,不替换当前内容 |
| 加载行为 | 阻塞性加载(如 JS 会阻塞 HTML 解析) | 非阻塞性加载(如 CSS 并行加载) |
| 语义 | 资源是当前文档的一部分 | 资源与当前文档是关联关系 |
| 典型标签 | <script>、<img>、<iframe> | <a>、<link>、<area> |
3. 具体场景分析
(1) <script> 标签
- 使用
src引入外部 JS 文件,文件内容会替代标签内的代码:html<!-- 正确 --> <script src="app.js"></script> <!-- 错误:同时写 src 和内部代码时,内部代码会被忽略 --> <script src="app.js"> console.log("这段代码不会执行!"); </script>
(2) <link> 标签
- 使用
href关联 CSS 文件,浏览器会加载但不会替换标签本身:html<link href="style.css" rel="stylesheet">
(3) <a> 标签
- 使用
href定义超链接,点击后跳转到目标 URL:html<a href="https://example.com">访问网站</a>
(4) <img> 标签
- 使用
src加载图片资源,图片会替代<img>标签的位置:html<img src="photo.jpg" alt="示例图片">
4. 加载行为差异
src的阻塞性: 浏览器遇到src属性时会暂停解析 HTML,直到资源加载并执行完成(如 JS 文件)。html<!-- 页面会等待 app.js 加载执行完成后,再继续渲染 --> <script src="app.js"></script>href的非阻塞性: 浏览器遇到href属性时会并行加载资源,不会阻塞 HTML 解析(如 CSS 文件)。html<!-- 页面继续渲染,同时加载 style.css --> <link href="style.css" rel="stylesheet">
5. 常见误区
(1) 混淆 <link> 和 <script>
- 错误:html
<link src="style.css"> <!-- 应用 href,而非 src --> <script href="app.js"></script> <!-- 应用 src,而非 href -->
(2) 误用 <a> 标签的 src
- 错误:html
<a src="page.html">点击</a> <!-- 应用 href -->
总结
| 场景 | 使用 src | 使用 href |
|---|---|---|
| 资源类型 | 直接嵌入内容(JS、图片、框架等) | 关联外部资源(CSS、超链接等) |
| 是否替换元素内容 | 是 | 否 |
| 加载行为 | 阻塞 | 非阻塞 |
| 典型标签 | <script>、<img>、<iframe> | <a>、<link>、<area> |
简单记忆:
src是 “拿来用”(替换当前内容),如脚本、图片。href是 “指向它”(建立关联),如超链接、样式表。