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
是 “指向它”(建立关联),如超链接、样式表。