我正在参加「掘金·启航计划」
前言
本期是对JS的File对象、DataTransfer对象、Clipboard API,URL.createObjectURL(file) 或 FileReader.readAsDataURL(file)的了解和使用,并基于其基础上,实现实现复制粘贴上传,拖拽上传点击打开文件管理器上传图片,并滚轮实现改变图片的大小的功能。
JS的File对象
在 HTML 文档中 <input type="file"> 标签每出现一次,一个 FileUpload 对象就会被创建。
该元素包含一个文本输入字段,用来输入文件名,还有一个按钮,用来打开文件选择对话框以便图形化选择文件。该元素的 value 属性保存了用户指定的文件的名称,但是当包含一个 file-upload 元素的表单被提交的时候,浏览器会向服务器发送选中的文件的内容而不仅仅是发送文件名。
dataTransfer对象
拖放事件 拖放的过程中被拖放的对象被称为源对象,过拖放过程中间经过的其他对象被称为过程对象,最终到达的对象称作目标对象。 在所有的拖放事件中都提供了一个数据传输对象dataTransfer,主要是用于在源对象和目标对象之间传递数据。
Clipboard API
剪贴板Clipboard API提供了响应剪贴板命令(剪切、复制和粘贴)与异步读写系统剪贴板的能力。 获取权限之后,才能访问剪贴板内容;如果用户没有授予权限,则不允许读取或更改剪贴板内容。
URL.createObjectURL()
简单来说:URL.createObjectURL()处理后生成了一个临时的链接,直接赋值给src就行。
FileReader.readAsDataURL(file)
FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容, 使用 File 或 Blob 对象指定要读取的文件或数据。简单来说:异步读取指定的Blob中的内容,一旦完成,会返回一个data: URL格式的字符串以表示所读取文件的内容。
这些简单了解一下即可,剩下的主要是实战,废话不多说,直接上代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>上传图片</title>
<link rel="stylesheet" href="./uploadPic.css">
<link rel="stylesheet" href="./font/iconfont.css">
<link rel="stylesheet" href="../Task2/font2/iconfont.css">
<link rel="stylesheet" href="./font next-pre/iconfont.css">
<script src="./uploadPic.js"></script>
</head>
<body id="scroll">
<div class="previewBox">
<div id="preBtn"><span class="iconfont icon-pre"></span></div>
<div id="nextBtn"><span class="iconfont icon-next"></span></div>
<div class="preview">
<div id="closeBtn"><span class="iconfont icon-close"></span></div>
<div class="picBox">
<img src="https://ts1.cn.mm.bing.net/th/id/R-C.a902a2666359a8cdfdb4a5073d402423?rik=%2fOAi8FFhylA5IQ&riu=http%3a%2f%2fimg.ewebweb.com%2fuploads%2f20191203%2f19%2f1575371671-fMmhxsnHNX.jpg&ehk=R7dew66vN%2bgvvyJL3I8BL00tsQwYL%2bv8PIqeUSKgzk4%3d&risl=&pid=ImgRaw&r=0" alt="" id="previewPic">
</div>
</div>
</div>
<input type="file" id="openFile">
<div id="openBtn">点击上传图片</div>
<div id="picWall" contenteditable="true">
<div class="pic">
<img class="upPic" src="https://ts1.cn.mm.bing.net/th/id/R-C.a902a2666359a8cdfdb4a5073d402423?rik=%2fOAi8FFhylA5IQ&riu=http%3a%2f%2fimg.ewebweb.com%2fuploads%2f20191203%2f19%2f1575371671-fMmhxsnHNX.jpg&ehk=R7dew66vN%2bgvvyJL3I8BL00tsQwYL%2bv8PIqeUSKgzk4%3d&risl=&pid=ImgRaw&r=0" alt="">
<div class="shadowBox">
<div class="previewBtn"><span class="iconfont icon-fangdajing1-xianxing"></span></div>
<div class="deleteBtn"><span class="iconfont icon-lajixiang"></span></div>
</div>
</div>
</div>
</body>
</html>
CSS
.previewBox {
display: none;
position: fixed;
top: 0;
left: 0;
z-index: 100;
width: 100%;
height: 100vh;
background-color: rgba(63, 60, 60, 0.7);
}
.previewBox #preBtn {
position: absolute;
left: 196px;
top: 200px;
width: 40px;
height: 70px;
color: aliceblue;
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
background-color: #dcc6f5;
line-height: 70px;
text-align: center;
cursor: pointer;
}
.previewBox #preBtn span {
font-size: 18px;
}
.previewBox #nextBtn {
position: absolute;
right: 196px;
top: 200px;
width: 40px;
height: 70px;
color: aliceblue;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
background-color: #dcc6f5;
line-height: 70px;
text-align: center;
cursor: pointer;
}
.previewBox #nextBtn span {
font-size: 30px;
}
.previewBox .preview {
position: relative;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
width: 470px;
height: 450px;
padding: 10px;
padding-top: 30px;
background-color: aliceblue;
}
.previewBox .preview .picBox {
max-width: 470px;
max-height: 450px;
overflow: hidden;
}
.previewBox .preview #previewPic {
width: 200px;
height: 200px;
}
.previewBox .preview #closeBtn {
position: absolute;
right: 10px;
top: 5px;
cursor: pointer;
}
#openFile {
display: none;
}
#openBtn {
width: 120px;
height: 80px;
margin: 10px auto;
border-radius: 10px;
border: 1px solid #bcff5f;
background-color: #84dcbf;
color: white;
font-size: 18px;
line-height: 80px;
text-align: center;
cursor: pointer;
}
#picWall {
display: flex;
flex-wrap: wrap;
align-self: flex-start;
width: 640px;
height: 600px;
margin: 60px auto;
border: 1px solid skyblue;
padding: 20px;
padding-right: 10px;
outline: none;
}
#picWall .pic {
position: relative;
width: 150px;
height: 150px;
border-radius: 8px;
margin-right: 10px;
margin-bottom: 10px;
}
#picWall .pic:hover .shadowBox {
transition: 0.3s;
background-color: rgba(82, 76, 76, 0.5);
}
#picWall .pic:hover .shadowBox span {
transition: 0.3s;
opacity: 1;
}
#picWall .pic img {
width: 150px;
height: 150px;
border-radius: 8px;
}
#picWall .pic .shadowBox {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
width: 150px;
height: 150px;
border-radius: 8px;
background-color: rgba(81, 76, 76, 0);
}
#picWall .pic .shadowBox span {
opacity: 0;
cursor: pointer;
color: white;
}
#picWall .pic .shadowBox span:nth-child(1) {
margin-right: 10px;
}
JS
window.onload = function(){
// $符号操作dom
function $(vArg) {
//通过获取css选择器第一位符号判断
switch (vArg[0]) {
case "#":
return document.getElementById(vArg.substring(1));
break;
case ".":
return elementByClassName(document,vArg.substring(1))
break;
default:
//对参数前五个字符进行判断
var str =vArg.substring(0,5);
if (str == "name=") {
return document.getElementsByName(vArg.substring(5))
} else {//tagName
return document.getElementsByTagName(vArg)
}
break;
}
}
function elementByClassName(parent,classStr) {
var nodes = parent.getElementsByTagName('*');
var result = [];
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].className == classStr) {
result.push(nodes[i]);
}
}
return result;
}
// 获取打开文件按钮
var openBtn = $("#openBtn")
// 获取input标签
var openFile = $("#openFile")
// 获取图片墙
var picWall = $("#picWall")
// 获取删除图片按钮
var deleteBtn = $(".deleteBtn")
// 获取图片盒子
var pic = $(".pic")
// 获取预览按钮
var previewBtn = $(".previewBtn")
// 获取关闭预览页面按钮
var closeBtn = $("#closeBtn")
// 获取预览图片
var previewPic = $("#previewPic")
// 获取预览图片页面
var previewBox = $(".previewBox")[0]
// 获取上传的图片
var upPic = $(".upPic")
// body元素
var scroll = $("#scroll")
// 获取上一张图片按钮
var nextBtn = $("#nextBtn")
var preBtn = $("#preBtn")
// 获取下一张图片按钮
updateFun()
// 点击打开上传图片
openBtn.onclick = function(){
openFile.click()
}
openFile.onchange = function(){
var newUrl = window.URL.createObjectURL(this.files[0])
picWall.innerHTML += `
<div class="pic">
<img class="upPic" src=${newUrl} alt="">
<div class="shadowBox">
<div class="previewBtn"><span class="iconfont icon-fangdajing1-xianxing"></span></div>
<div class="deleteBtn"><span class="iconfont icon-lajixiang"></span></div>
</div>
</div>
`
updateFun()
}
//被拖拽元素在目标元素上移动时触发,必须阻止默认事件,否则拖拽不生效
picWall.ondragover = () => false
/* 阻止图片默认拖拽链接--start*/
document.ondragover = () => false
/* 阻止图片默认拖拽链接--end*/
document.ondrop = () => false
picWall.ondrop = (e) => {
let file = e.dataTransfer.files[0];//获取上传的文件
let reader = new FileReader();//创建FileReader读取文件
//读取成功后触发函数
reader.onload = () => {
var newUrl = reader.result;//图片地址
console.log(newUrl)
picWall.innerHTML += `
<div class="pic">
<img class="upPic" src=${newUrl} alt="">
<div class="shadowBox">
<div class="previewBtn"><span class="iconfont icon-fangdajing1-xianxing"></span></div>
<div class="deleteBtn"><span class="iconfont icon-lajixiang"></span></div>
</div>
</div>
`
updateFun()
};
//设置读取方式 ,这里读取的结果会在 reader.onload回调中reader显示
reader.readAsDataURL(file)
}
// 照片墙粘贴触发事件
picWall.onpaste = function(e){
var data = e.clipboardData.items[0].getAsFile()
e.preventDefault()
console.log(data)
var Url = window.URL.createObjectURL(data)
picWall.innerHTML += `
<div class="pic">
<img class="upPic" src=${Url} alt="">
<div class="shadowBox">
<div class="previewBtn"><span class="iconfont icon-fangdajing1-xianxing"></span></div>
<div class="deleteBtn"><span class="iconfont icon-lajixiang"></span></div>
</div>
</div>
`
updateFun()
}
function imgMove(img) {
// 图片坐标信息
let imgTop = 0;
let imgLeft = 0;
// 鼠标坐标信息
let mx = 0;
let my = 0;
// 图片拖动开始前
img.ondragstart = e => {
// 初始化鼠标坐标信息
mx = e.clientX;
my = e.clientY;
}
// 图片拖动中
img.ondrag = function(e){
cancelHandler(e)
if (e.clientX <= 277 || e.clientX >= 746 || e.clientY <= 36 || e.clientY >= 483) {
return
}
console.log(e.clientY)
imgTop = imgTop + e.clientY - my;
imgLeft = imgLeft + e.clientX - mx;
mx = e.clientX;
my = e.clientY;
img.style.transform = `translate(${imgLeft}px,${imgTop}px)`
}
}
function updateFun(){
var deleteBtn = $(".deleteBtn")
var pic = $(".pic")
var previewBtn = $(".previewBtn")
var upPic = $(".upPic")
var picSize = 200
var index = 0
// 绑定关闭预览图片界面
closeBtn.onclick = function(){
previewBox.style.display = 'none'
scroll.style.overflow= "visible"
}
for (let t = 0; t < deleteBtn.length; t++) {
// 绑定删除图片事件
deleteBtn[t].onclick = function(){
picWall.removeChild(pic[t])
}
// 绑定预览图片事件
previewBtn[t].onclick = function(){
previewBox.style.display = 'block'
previewPic.style.height = '200px'
previewPic.style.width = '200px'
previewPic.src = upPic[t].src
index = t
scroll.style.overflow= "hidden"
previewPic.style.transform = `translate(0,0)`
}
}
// 绑定滚轮缩放照片事件
previewPic.onwheel = function(e){
// console.log(e.deltaY/125)
picSize += -(e.deltaY/125)*50
// if(picSize >= 450) picSize = 450
if(picSize <= 150) picSize = 150
previewPic.style.height = picSize + 'px'
previewPic.style.width = picSize + 'px'
if(parseFloat(previewPic.style.height)>450){
imgMove(previewPic)
}else{
previewPic.style.transform = `translate(0,0)`
}
}
// 返回上一张图片
preBtn.onclick = function(){
if(index === 0){
index = upPic.length - 1
}else{
index --
}
previewPic.style.height = '200px'
previewPic.style.width = '200px'
if(parseFloat(previewPic.style.height)>450){
imgMove(previewPic)
}
previewPic.style.transform = `translate(0,0)`
previewPic.src = upPic[index].src
}
// 下一张图片
nextBtn.onclick = function(){
if(index === upPic.length - 1 ){
index = 0
}else{
index ++
}
previewPic.style.height = '200px'
previewPic.style.width = '200px'
if(parseFloat(previewPic.style.height)>450){
imgMove(previewPic)
}
previewPic.style.transform = `translate(0,0)`
previewPic.src = upPic[index].src
}
}
//封装了一个取消默认事件的函数,用来兼容老IE
function cancelHandler(event){
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
}