紧跟潮流
大前端和全栈是以后前端的一个趋势,懂后端的前端,懂各端的前端更加具有竞争力,以后可以往这个方向靠拢。
这边整理了一个对标“阿里 50W”年薪企业高级前端工程师成长路线,由于图片太大仅展示一小部分
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
其中,object 参数指 用于创建 URL 的 File 对象、Blob 对象或者 MediaSource 对象。
对于我们的 input[type=file]
而言, input.files[0]
可以获取到当前选中文件的 File 对象。示例代码如下:
<input id="inputFile" type="file" accept="image/*">
<img src="" id="previewImage" alt="图片预览">
<script>
const $ = document.getElementById.bind(document);
const $inputFile = $('inputFile');
const $previewImage = $('previewImage');
$inputFile.addEventListener('change', function() {
const file = this.files[0];
$previewImage.src = file ? URL.createObjectURL(file) : '';
}, this);
</script>
具体用法可以参考 MDN上的 URL.createObjectURL(),
2. 使用 FileReader 预览
FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。同理的,我们也可以通过 input.files[0]
获取到当前选中的图片的 File
对象。
特别注意,FileReader 和 是异步读取文件或数据的!
下面是使用 FileReader 预览图片的示例:
<input id="inputFile" type="file" accept="image/*">
<img src="" id="previewImage" alt="图片预览">
<script>
const $ = document.getElementById.bind(document);
const $inputFile = $('inputFile');
const $previewImage = $('previewImage');
$inputFile.addEventListener('change', function() {
const file = this.files[0];
const reader = new FileReader();
reader.addEventListener('load', function() {
$previewImage.src = reader.result;
}, false);
if (file) {
reader.readAsDataURL(file);
}
}, false)
</script>
会发现, FileReader 会相对复杂一些.
更多关于 FileReader
的用法 ,可以参考 MDN 文档 FileReader
两种方法的对比
我个人更加倾向于使用 URL.createObjectURL()
。主要原先它的 API 简洁,同步读取,并且他返回的是一个 URL
,比 FileReaer
返回的base64 更加精简。兼容性上,两者都差不多,都是在 WD
的阶段。性能上的对比, 在 chrome 上, 选择了一张 2M 的图片, URL.createObjectURL()
用时是 0 , 而 FileReader
用时 20ms 左右。0 感觉不太合理,虽然这个方法立刻就会返回一个 URL ,但是我猜测实际上这个 URL 指定的内容还没有生成好,应该是异步生成的,然后才渲染出来的。所以并没有很好的办法来对比他们的性能。
如果想要学习更多关于图片预览,可以阅读以下两篇文章:
- 使用FileReader实现前端图片预览
- js图片/视频预览 - URL.createObjectURL()
裁剪图片
关于图片的裁剪,很自然的会想到使用 canvas
,确实是要通过 canvas
, 但是如果全部我们自己来实现,可能需要做比较多的工作,所以为了省力,我们可以站在巨人的肩膀上。比较优秀的图片裁剪库是 cropperjs , 该库可以对图片进行缩放、移动和旋转。
cropperjs
的详细配置这里就不展开了 ,需要的可以自己去看文档就好。下面我们就以这个库为基础,实现一个裁剪人脸的例子:
<input id="inputFile" type="file" accept="image/*">
<img class="preview-image" id="previewImage" src="" alt="">
<!-- cropper裁剪框 -->
<div class="cropper" id="cropper">
<div class="inner">
<div class="face-container">
<img class="cropper-image" id="cropperImage">
</div>
<div class="tips">请将面部区域置于人脸框架内</div>
<div class="toolbar">
<div class="btn" id="confirm">确认</div>
</div>
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.min.js"></script>
<style>
.preview-image,
.cropper-image {
max-width: 100%;
}
.cropper {
display: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: #ccc;
font-size: 0.27rem;
text-align: center;
}
.inner {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.face-container {
position: relative;
width: 320px;
height: 320px;
margin: 50px auto;
}
.cropper-modal {
background: url('https://ok.166.net/gameyw-misc/opd/squash/20191028/152551-m37snfsyu1.png') center no-repeat;
background-size: 100% 100%;
opacity: 1;
}
.cropper-bg {
background: none;
}
.cropper-view-box {
opacity: 0;
}
.tips {
font-size: 16px;
}
.toolbar {
display: flex;
justify-content: center;
margin: 50px 0;
}
.btn {
width: 150px;
line-height: 40px;
font-size: 20px;
text-align: center;
color: #fff;
background: #007fff;
}
</style>
<script>
const $ = document.getElementById.bind(document);
const $cropper = $('cropper');
const $inputFile = $('inputFile');
const $previewImage = $('previewImage');
const $cropperImage = $('cropperImage');
const $confirmBtn = $('confirm')
let cropperInstance = null;
// 选择图片后,显示图片裁剪框
$inputFile.addEventListener('change', function() {
const file = this.files[0];
if (!file) return;
$cropperImage.src = URL.createObjectURL(file);
showCropper();
}, false);
// 点击确认按钮,将裁剪好的图片放到 img 标签显示。
$confirmBtn.addEventListener('click', function() {
const url = cropperInstance.getCroppedCanvas().toDataURL("image/jpeg", 1.0);
$cropper.style.display = 'none';
$previewImage.src = url;
}, false);
function showCropper() {
$cropper.style.display = 'block';
cropperInstance && cropperInstance.destroy();
cropperInstance = new Cropper($cropperImage, {
viewMode: 1,
aspectRatio: 1,
autoCropArea: 1,
dragMode: 'move',
guides: false,
highlight: false,
cropBoxMovable: false,
cropBoxResizable: false
});
}
</script>
效果图如下:
上传
前面的操作已经完成了图片上传前的准备,包括选择图片、预览图片、编辑图片等,那接下来就可以上传图片了。上面的例子中,使用了 cropperInstance.getCroppedCanvas()
方法来获取到对应的 canvas
对象 。有了 canvas
对象就好办了,因为 canvas.toBlob()
方法可以取得相应的 Blob
对象,然后,我们就可以把这个 Blob
对象添加到 FromData
进行无刷新的提交了。大概的代码如下:
function uploadFile() {
cropperInstance.getCroppedCanvas().toBlob(function(blob) {
const formData = new FormData();
formData.append('avatar', blob);
fetch('xxxx', {
method: 'POST',
body: formData
});
});
}
这段代码并不能真正执行,因为我们还没有对应的后端服务器。如果想要尝试上传图片的朋友,可以参考一下这篇文章 写给新手前端的各种文件上传攻略,从小图片到大文件断点续传,由于篇幅原因,这里就不展开啦。
后记
关于图片上传的介绍,差不多不到些结束了。但是之前在 iPhone 和 小米 手机上,遇到一个奇怪的问题:就是我使用前置摄像头自拍出来的照片,选择之后 ,会自逆时针旋转 90 度,比如像下图:
拍照的时候明明就是正着拍的,为什么预览就会变成横着了呢?当时第一次遇到这个问题的时候,也觉得好奇怪。后来查了一下,得知这是因为拍照时,相机都会记录拍照的角度信息,可能 iPhone 前置摄像头记录的角度信息和其他的有点不一样,而 iPhone 自己的相册在浏览照片时,自动纠正了角度 ,而浏览器却没有纠正,所以才会出现这个旋转。
为了解决这个问题,需要使用 EXIF 这个库来处理。
我刚刚试了一下,发现我的 iPhone 现在竟然不会有这个问题了,大概是半年前,当时在做一个需求时,自拍的图片会发生这种旋转,有可能是 iOS 系统升级后, 已经修复了这个问题。而现在身边又没有小米手机, 所以也不好复现。还好,当时我保存了一张会自动旋转的图片。大家可以到这里下载:
https://ok.166.net/gameyw-misc/opd/squash/20191028/170829-f5t38i0d9k.png
这图片下载后,用电脑的图片查看器打开是正常的,但是,在浏览器中,选择这个图片后,使用 URL.createObjectURL()
或 FileReader
来预览就会发生旋转。甚至直接 img 标签引入也会逆时针旋转了 90 度,比如:
<img src="https://ok.166.net/gameyw-misc/opd/squash/20191028/170829-f5t38i0d9k.png">
数据结构与算法
这一块在笔试、面试的代码题中考核较多,其中常考的数据结构主要有:数组、链表、队列、栈、Set、Map、哈希表等,不同数据结构有不同的方法以及储存原理,这些算是技术岗的必备知识。算法部分主要分为两大块,排序算法与一些其他算法题。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
排序算法根据考频高低主要有:快速排序、归并排序、堆排序、冒泡排序、插入排序、选择排序、希尔排序、桶排序、基数排序、Timsort这十种,这类考核点要么是算法的时间、空间复杂度、稳定度,要么是直接手写代码,故在理解算法原理的同时,对JS语言版的排序算法代码也要加强记忆。
- 二叉树层序遍历
- B 树的特性,B 树和 B+树的区别
- 尾递归
- 如何写一个大数阶乘?递归的方法会出现什么问题?
- 把多维数组变成一维数组的方法
- 知道的排序算法 说一下冒泡快排的原理
- Heap 排序方法的原理?复杂度?
- 几种常见的排序算法,手写
- 数组的去重,尽可能写出多个方法
- 如果有一个大的数组,都是整型,怎么找出最大的前 10 个数
- 知道数据结构里面的常见的数据结构
- 找出数组中第 k 大的数组出现多少次,比如数组【1,2, 4,4,3,5】第二大的数字是 4,出现两次,所以返回 2
- 合并两个有序数组
- 给一个数,去一个已经排好序的数组中寻找这个数的位 置(通过快速查找,二分查找)
什么问题?
- 把多维数组变成一维数组的方法
- 知道的排序算法 说一下冒泡快排的原理
- Heap 排序方法的原理?复杂度?
- 几种常见的排序算法,手写
- 数组的去重,尽可能写出多个方法
- 如果有一个大的数组,都是整型,怎么找出最大的前 10 个数
- 知道数据结构里面的常见的数据结构
- 找出数组中第 k 大的数组出现多少次,比如数组【1,2, 4,4,3,5】第二大的数字是 4,出现两次,所以返回 2
- 合并两个有序数组
- 给一个数,去一个已经排好序的数组中寻找这个数的位 置(通过快速查找,二分查找)
[外链图片转存中…(img-O1o4TCpe-1715226586091)]