在读这段代码之前,请确保你已经理解了JS基础部分(方法触发)相关的知识。
如果不清楚的话,可以跳转→[目录] JavaScript基础:方法触发相关查看。
首先,HTML部分增加了两个容器:
<input type="file" id="file-input">
<div id="image-container"></div>
然后,Script部分,我们首先声明两个常量:
const fileInput = document.getElementById('file-input');
const imageContainer = document.getElementById('image-container');
至于为什么读常量你不用管。这边即使你用var或者let读取也是一样的。
const 是 JavaScript 中的一个关键字,用于声明一个常量。声明的常量在声明后不能再被赋值,这与 let 或 var 声明的变量不同。
作用域:let 声明的变量具有块级作用域,而 var 声明的变量只具有函数作用域。
这意味着,在使用 let 声明变量时,该变量只在声明它的代码块中可见,在代码块外部不可见。而使用 var 声明变量时,该变量在函数内部可见,函数外部也可见。
通常来说,建议优先使用 let
声明变量,因为它可以避免一些常见的 JavaScript 问题,例如变量污染和意外的变量覆盖。但在某些情况下,使用 var
也是有用的,例如在函数作用域内共享变量或在 for 循环中声明计数器等。
const
声明的变量和 let
声明的变量一样,也具有块级作用域。这意味着 const
声明的变量只在声明它的代码块中可见,不能在代码块外部访问。与 let
不同的是,使用 const
声明的变量必须进行初始化,而且一旦初始化后,就不能再次赋值。这意味着 const
声明的变量是只读的。
另外注意,这里使用了ID选择器。
接着,我们直接调用fileInput里面的监听方法,监听change(),然后剩余的代码都在里面执行:
fileInput.addEventListener('change', function() {
//ToDo: Your code
});
ToDo部分:
const file = fileInput.files[0];
我们首先获取常量fileInput的0号元素,也就是第一个。(话说fileInput作为const本身就具有files属性?)
接着我们写一个if判定是否有文件且文件为Image,否则不执行:
if (file && file.type.startsWith('image/')){
//ToDo something
}
else
{
//Do nothing or 提示一下用户
}
ToDo something部分:
const reader = new FileReader();
我们需要再声明一个常量,它将是通过JS已存在的类FileReader()生成的。
然后,我们执行它的onload事件(如果不执行的话,代码也就是声明了一个变量而已,什么也没做):
const img = new Image();
img.src = reader.result;
img.onload = function() {
imageContainer.innerHTML = '';
imageContainer.appendChild(img);
}
我们再次实例化一个新的常量img,把img的src设定为刚才reader所得到的result。)
你问reader.result哪儿来的?
我只能说,以这个代码的逻辑,onload的一瞬间,reader就已经获取了这个控件所得到任何属性。
而const file本身并不是用于传递值的,仅仅是用来判定文件类型的。
那如果你说输出reader.result,你将会获得data属性,一个base64,以及后面紧跟着的base64码:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABDo......AAANSUhE
是的,它的src居然不会是真的src,而是一个数据流。
而且,既然得到的是数据流,后直接onload实例化,它这个img就可以直接放进之前获取赋值的const imageContainer 。
img.onload = function() {
//需要先把结果放到正确的容器里面
}
imageContainer现在是个常量,它已经获得了那个id名叫image-container的div标签。现在做的事情无非只是操纵它里面填充的内容:
imageContainer.innerHTML = '';
imageContainer.appendChild(img);
话说img可以直接填进来啊?这个img好像默认是一个img标签。
还剩最重要的一步:
reader.readAsDataURL(file);
这是 JavaScript FileReader API 中的一个方法,它可以将指定的文件对象读取为 Data URL 格式的字符串。
Data URL 是一种特殊的 URL,它包含了指定资源的数据内容,并且使用 Base64 编码进行了转换。在 Web 应用程序中,Data URL 常常用于在浏览器中显示图片或其他二进制文件。
当我们需要在浏览器中预览用户选择的图片或其他二进制文件时,可以使用 FileReader
对象读取文件内容,并将其转换为 Data URL 格式的字符串,然后将该字符串作为图片的 src
属性或其他元素的 background-image
属性的值,从而实现在页面中显示文件内容的效果。
这句话不写的话,图片是不会显示出来的。
(这里执行的是一个渲染,不写这个代码它不会去去读或生成Base64。)
(这个方法会先于onload执行,不管你放在什么位置。)
reader.readAsDataURL(file)
方法会立即开始读取文件并将其转换为 Data URL 字符串,这个过程是异步的。
当读取和转换完成后,FileReader
对象会触发 onload事件。
完整HTML代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>显示本地图片</title>
</head>
<body>
<input type="file" id="file-input">
<div id="image-container"></div>
<script>
const fileInput = document.getElementById('file-input');
const imageContainer = document.getElementById('image-container');
fileInput.addEventListener('change', function() {
const file = fileInput.files[0];
if (file && file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = function() {
const img = new Image();
img.src = reader.result;
img.onload = function() {
imageContainer.innerHTML = '';
imageContainer.appendChild(img);
}
}
reader.readAsDataURL(file);
} else {
imageContainer.innerHTML = '请选择一张图片文件';
}
});
</script>
</body>
</html>