js 實(shí)現(xiàn)文件上傳樣式詳情
1、概述


這個(gè)js包括按鈕樣式,列表樣式、帶有刪除、添加、放大(使用的是自帶的放大功能,提供有API來(lái)放入你的彈窗來(lái)進(jìn)行展示)
| 可監(jiān)聽(tīng)的事件 | Value | wdaasd |
|---|---|---|
| onlargeClickCallBack | 如果想使用自己的彈窗,只需要監(jiān)聽(tīng)這個(gè)函數(shù),拿到返回值給你的彈窗的img->href進(jìn)行賦值即可 | imgFile對(duì)象(包括這個(gè)被點(diǎn)擊圖片的全部信息)that(這個(gè)js的全局唯一對(duì)象,可以在這里面拿到你所有的值) |
| ondialogBeforeClose | 自帶的彈窗被關(guān)閉的回調(diào) | object 返回值是一個(gè)對(duì)象 對(duì)象.event -> 被執(zhí)行的事件的源事件 對(duì)象.imgFile -> 被點(diǎn)擊關(guān)閉彈窗時(shí),目前彈窗上展示的圖片對(duì)象信息 |
| onaddImgList | 每添加一個(gè)圖片的回調(diào) | file -> 文件對(duì)象 that -> (這個(gè)js的全局唯一對(duì)象,可以在這里面拿到你所有的值) |
2、創(chuàng)建對(duì)象的參數(shù)
| 參數(shù) | 含義 |
|---|---|
| maxFileLength | 最大可以存在的文件個(gè)數(shù) 默認(rèn)值:2 |
| maxFileSize | 每個(gè)文件單獨(dú)最大的文件大小 默認(rèn)值:1024 (1M) |
| fileSuffix | 允許上傳的文件后綴 默認(rèn)值:['mp4', 'mp3', 'word', 'pdf', 'ppt', 'excel', 'jpg', 'png'] |
| StopDialog | 是否阻止打開(kāi)自帶的默認(rèn)彈窗 默認(rèn)值:false |
| shadeDialogStyle | 如果打開(kāi)自帶彈窗的選項(xiàng),那么這個(gè)控制打開(kāi)的彈窗高寬多少默認(rèn)值:[null, null],默認(rèn)為null為自適應(yīng),如果想要設(shè)置百分比和px 請(qǐng)直接改變數(shù)組[0,1],數(shù)組第一項(xiàng)代表寬,第二項(xiàng)代表高 |
| showBtnImgStyle | 是否開(kāi)啟按鈕樣式 默認(rèn)值:false |
使用代碼示例:
<div class="hj-file">
<input type="file" file="" class="hj-file-input">
<div class="hj-box hj-append-item">
<div class="append-item margin-class">
<div class="img-push">
<img src="./img/push.png" alt="">
</div>
</div>
</div>
<!-- 在不開(kāi)啟按鈕樣式時(shí),這個(gè)外層div可以刪除 -->
<div class="hj-btn-box hj-hidden">
<div class="hj-btn">
選擇圖片
</div>
</div>
<!-- 文件信息列表 -->
<div class="hj-file-list">
</div>
</div>
var file = new File({
maxFileLength: 2,
maxFileSize: 1024,
fileSuffix: ['mp4', 'mp3', 'word', 'pdf', 'ppt', 'excel', 'png', 'jpg'],
StopDialog: false,
showBtn: false
});
initHJFile(file);
3、監(jiān)聽(tīng)例子
//如果不想使用自帶的彈窗,可以選擇監(jiān)聽(tīng)file對(duì)象的onlargeClickCallBack函數(shù)
file.callBack.onlargeClickCallBack = function (img, that) {}
file.callBack.ondialogBeforeClose = function (event) {}
file.callBack.onaddImgList = function () {}
4、使用方法

項(xiàng)目目錄如上圖所示
如果要使用,只需要把js放入你的項(xiàng)目路徑下,然后把img放到你的static目錄(靜態(tài)資源路徑)。
這里js里面默認(rèn)引入的圖標(biāo)是 ./ 的相對(duì)路徑,請(qǐng)自行搜索然后進(jìn)行更改為你項(xiàng)目的文件路徑
上圖項(xiàng)目示例為可直接打開(kāi)查看的完整包,后文有下載地址
5、源代碼
此源代碼為不包括圖標(biāo)的源代碼,全部在一個(gè)html頁(yè)面里面
<!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>Document</title>
</head>
<style>
* {
padding: 0;
margin: 0;
}
body {
width: 100vw;
height: 100vh;
/* display: flex;
justify-content: center;
align-items: center; */
}
/* .box {
width: 600px;
} */
.hj-file {
width: 100%;
/* height: 100%; */
}
.hj-file-input {
display: none;
}
.hj-box {
display: flex;
flex-wrap: wrap;
}
.append-item {
width: 150px;
height: 150px;
border: 1px dashed #b1b5bb;
border-radius: 5px;
background-color: #fbfdff;
display: flex;
align-items: center;
margin: 10px;
justify-content: center;
}
.image-item {
width: 150px;
height: 150px;
border-radius: 5px;
margin: 10px;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid #eaedf1;
position: relative;
background-size: 100% 100%;
background-repeat: no-repeat;
transition: 1s;
animation: translaters 1s;
}
.image-item-delete {
animation: bottom-translaters .7s;
}
@keyframes translaters {
0% {
opacity: .2;
transform: translate(0, -50%);
}
100% {
opacity: 1;
transform: translate(0);
}
}
@keyframes bottom-translaters {
0% {
opacity: 1;
transform: translate(0, 0);
}
100% {
opacity: .2;
transform: translate(0, 50%);
}
}
.img-push img {
width: 60px;
height: 60px;
}
.append-item:hover {
border-color: #00d2fc;
}
.margin-class {
margin-bottom: 20px;
}
.first {
background-image: url('./img/66.jpg');
}
.z-index-promote {
z-index: 3;
}
.largeImg img {
cursor: pointer;
width: 30px;
height: 30px;
transition: .6s;
display: none;
}
.deleteImg img {
cursor: pointer;
width: 40px;
height: 40px;
display: none;
}
.image-item:hover::before {
content: "";
z-index: 2;
background-color: #42393999;
width: 100%;
position: absolute;
height: 100%;
border-radius: 5px;
transition: .6s;
animation: transparency linear .6s;
}
.image-item:hover .largeImg img {
display: block;
animation: transparency linear .6s;
}
.image-item:hover .deleteImg img {
display: block;
animation: transparency linear .6s;
}
@keyframes transparency {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.hj-shade {
width: 100vw;
height: 100vh;
background-color: #302d2d99;
position: fixed;
overflow: hidden;
z-index: 1978;
display: flex;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
justify-content: center;
align-items: center;
animation: hj-shade-sacle .5s;
}
@keyframes hj-shade-sacle {
0% {
transform: translate(-50%, -50%) scale(0%);
}
100% {
transform: translate(-50%, -50%) scale(100%);
}
}
@keyframes hj-shade-hidden {
0% {
transform: translate(-50%, -50%) scale(100%);
}
100% {
transform: translate(-50%, -50%) scale(0%);
}
}
.hj-shade-hidden {
animation: hj-shade-hidden .5s;
}
.hj-shade {
overflow: auto;
}
.hj-shade .hj-box {
width: 60%;
height: 80%;
padding: 20px 10px 10px 10px;
background-size: 100% 100%;
background-color: white;
}
.hj-shade .hj-box .hj-img {
width: 100%;
overflow: auto;
height: 100%;
}
.hj-file-list .hj-file-list-item {
background-color: white;
color: #8cacb3;
display: flex;
line-height: 2;
font-size: 0.8em;
}
.hj-file-list .hj-file-list-item:hover {
background-color: #00d2fc70;
color: white;
}
.hj-file-list .hj-file-list-item .hj-left {
width: 30%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.hj-file-list .hj-file-list-item .hj-left span {
margin-left: 20px;
cursor: pointer;
}
.hj-file-list .hj-file-list-item .hj-right {
width: 30%;
display: flex;
align-items: center;
justify-content: end;
}
.hj-file-list .hj-file-list-item .hj-right span {
margin-right: 20px;
}
.hj-file-list .hj-file-list-item .hj-right img {
width: 20px;
height: 20px;
cursor: pointer;
}
@keyframes hj-list-hidden {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.hj-list-hidden {
animation: hj-list-hidden .7s;
}
.hj-btn-box {
margin-bottom: 25px;
}
.hj-btn-box .hj-btn {
margin-left: 20px;
cursor: pointer;
background-color: #009efa;
width: 30%;
line-height: 2;
border-radius: 4px;
color: white;
font-size: 1.2em;
text-align: center;
}
.hj-hidden {
display: none;
}
</style>
<body>
<div class="box">
<div class="hj-file">
<input type="file" file="" class="hj-file-input">
<div class="hj-box hj-append-item">
<div class="append-item margin-class">
<div class="img-push">
<img src="./img/push.png" alt="">
</div>
</div>
</div>
<div class="hj-btn-box hj-hidden">
<div class="hj-btn">
選擇圖片
</div>
</div>
<div class="hj-file-list">
</div>
</div>
</div>
<script>
// File構(gòu)造函數(shù)
function File(obj) {
// 文件總個(gè)數(shù)
this.fileLength = 0;
// 文件數(shù)組
this.fileList = [];
// 對(duì)象參數(shù)配置文件
this.config = {
// 最大文件個(gè)數(shù)
maxFileLength: obj.maxFileLength || 2,
// 最大文件大小
maxFileSize: obj.maxFileSize || 1024,
// 允許的文件后綴
fileSuffix: obj.fileSuffix || ['mp4', 'mp3', 'word', 'pdf', 'ppt', 'excel', 'jpg', 'png'],
// 是否阻止默認(rèn)打開(kāi)彈窗
StopDialog: obj.StopDialog || false,
// 彈窗的樣式 寬 高
shadeDialogStyle: obj.shade || [null, null],
// 是否開(kāi)啟按鈕樣式
showBtnImgStyle: obj.showBtn || false,
};
// fileDom中存儲(chǔ)的唯一的dom節(jié)點(diǎn)
this.dom = {
// input 文件選中輸入框dom
inputDom: null,
// append-item 添加點(diǎn)擊dom
imageItemDom: null,
// 要向hj-append-item節(jié)點(diǎn)后面追加圖片的dom
appendItemDom: null,
// 要向hj-file-list節(jié)點(diǎn)后面添加圖片列表的dom
appendListDom: null,
};
// 事件處理對(duì)象
this.event = {
// append-item點(diǎn)擊事件處理
imageItemClick: () => {
this.dom.inputDom.click();
},
// input 文件選中輸入框選擇完圖片之后事件處理
changeLoadFile: (file) => {
this.method.filterFile(file.target.files);
},
// 圖片刪除事件
imgDeleteClick: (id) => {
for (let index = 0; index < this.fileList.length; index++) {
if (this.fileList[index].id == id) {
let _before = this.fileList.slice(0, index == this.fileList.length ? index - 1 :
index);
let _after = this.fileList.slice(index + 1);
_before = _before.concat(_after);
// 刪除圖片
this.method.deleteImg(id);
setTimeout(() => {
this.fileList[index].dom.remove();
this.fileList[index].listDom.remove();
this.fileLength--;
this.fileList = _before;
}, 600);
break;
}
}
1
},
// 圖片放大事件
imgLargeClick: (id) => {
let imgFile = this.privateUtils.foreachFileListToId(id);
console.log(imgFile);
this.callBack.onlargeClickCallBack(imgFile, this);
if (this.config.StopDialog) return;
let hjShadeDiv = document.getElementsByClassName('hj-shade');
if (hjShadeDiv.length != 0) return;
let div = document.createElement('div');
div.className = 'hj-shade';
let div2 = document.createElement('div');
div2.className = 'hj-box';
let img = document.createElement('img');
img.className = 'hj-img';
img.src = imgFile.base64;
div2.appendChild(img);
div.addEventListener('click', (event) => {
this.callBack.ondialogBeforeClose({
event: event,
imgFile: imgFile,
});
div.className = div.className + ' hj-shade-hidden';
setTimeout(() => {
document.body.removeChild(div);
}, 500);
})
// 防止在按鈕模式下,會(huì)出現(xiàn)第一次沒(méi)有加載完成,高長(zhǎng)為0的不正常情況
img.onload = () => {
div.appendChild(div2);
document.body.appendChild(div);
this.privateUtils.computeDialogWH(img, div2);
}
},
},
this.method = {
// 過(guò)濾圖片
filterFile: (list) => {
for (let index = 0; index < list.length; index++) {
let size = parseInt(list[index].size / 1024);
let suffix = list[index].name.substring(list[index].name
.lastIndexOf('.') + 1);
// 是否符合后綴
let isTrue = false;
// 判斷文件大小
if (size > this.config.maxFileSize) {
console.log("文件太大");
break;
}
for (let j = 0; j < this.config.fileSuffix.length; j++) {
if (suffix == this.config.fileSuffix[j]) {
isTrue = true;
break;
}
}
if (isTrue) {
let id = parseInt(Math.random() * 100000);
this.fileList.push({
id: id,
file: list[index],
base64: '',
dom: '',
listDom: '',
});
console.log(this.fileList);
this.method.streamToImgBase64(list[index], id);
} else {
console.log("文件后綴不符合");
}
}
},
// 處理圖片展示
streamToImgBase64: (file, id) => {
var fileReader = new FileReader();
fileReader.onload = (data) => {
this.method.appendImage(data.target.result, id);
}
fileReader.readAsDataURL(file);
},
// 追加圖片到dom節(jié)點(diǎn)中
appendImage: (url, id) => {
let div = document.createElement('div');
div.className = 'image-item margin-class';
div.style.backgroundImage = 'url(' + url + ')';
for (let index = 0; index < this.fileList.length; index++) {
if (this.fileList[index].id == id) {
this.fileList[index].dom = div;
this.fileList[index].base64 = url;
break;
}
}
// 創(chuàng)建刪除dom,全部使用addEventListener
let largeDom = document.createElement('div');
largeDom.className = 'largeImg z-index-promote';
largeDom.innerHTML = `<img src="./img/big.png" alt="">`;
largeDom.addEventListener('click', () => {
this.event.imgLargeClick(id);
})
let deleteDom = document.createElement('div');
deleteDom.className = 'deleteImg z-index-promote';
deleteDom.innerHTML = `<img src="./img/delete.png" alt="">`;
deleteDom.addEventListener('click', () => {
this.event.imgDeleteClick(id);
})
div.appendChild(largeDom);
div.appendChild(deleteDom);
this.dom.appendItemDom.appendChild(div);
this.fileLength++;
// 添加圖片列表
this.method.addImgList(id);
},
// 刪除圖片
deleteImg: (id) => {
for (let index = 0; index < this.fileList.length; index++) {
if (this.fileList[index].id == id) {
let item = this.fileList[index];
let cless = item.dom.getAttribute('class');
let clessList = item.listDom.getAttribute('class');
this.fileList[index].dom.setAttribute("class", cless + " image-item-delete");
this.fileList[index].listDom.setAttribute("class", clessList + " hj-list-hidden ")
break;
}
}
},
// 添加圖片列表
addImgList: (id) => {
let file = this.privateUtils.foreachFileListToId(id);
this.callBack.onaddImgList(file, this);
let div = document.createElement('div');
div.className = ' hj-file-list-item '
let div$left = document.createElement('div');
let div$right = document.createElement('div');
let file$img = document.createElement('img');
let fileSize = this.privateUtils.computeFileSize(file.file.size);
file$img.src = './img/delete-balck.png';
div$left.className = ' hj-left ';
div$right.className = ' hj-right ';
div$left.innerHTML = `<span>${file.file.name}</span>`
div$right.innerHTML = `<span>${fileSize}</span>`;
div$left.addEventListener('click', () => {
this.event.imgLargeClick(id);
})
file$img.addEventListener('click', () => {
this.event.imgDeleteClick(id);
})
div$right.appendChild(file$img);
div.appendChild(div$left);
div.appendChild(div$right);
for (let index = 0; index < this.fileList.length; index++) {
if (id == this.fileList[index].id) {
this.fileList[index].listDom = div;
break;
}
}
this.dom.appendListDom.appendChild(div);
},
}
// 暴露的監(jiān)聽(tīng)Api
this.callBack = {
// 阻止默認(rèn)自帶的打開(kāi)彈窗
onlargeClickCallBack: (img, that) => {},
// 自帶的彈窗被關(guān)閉時(shí)的回調(diào)
// {event: 點(diǎn)擊的源事件對(duì)象 imgFile: 被關(guān)閉的那張圖片的全局file對(duì)象信息}
ondialogBeforeClose: (object) => {},
// 每一次添加圖片列表時(shí)的回調(diào)
onaddImgList: (file, that) => {},
},
this.privateUtils = {
foreachFileListToId: (id) => {
for (let index = 0; index < this.fileList.length; index++) {
if (id == this.fileList[index].id) {
return this.fileList[index];
}
}
},
computeFileSize: (size) => {
let result = parseInt(size / 1024);
if (result < 1024) {
return result + '.KB';
} else if (result >= 1024) {
return parseInt(result / 1024) + ".MB";
}
},
// 計(jì)算彈窗的高度和長(zhǎng)度
computeDialogWH: (img, dom) => {
let w = this.config.shadeDialogStyle[0];
let h = this.config.shadeDialogStyle[1];
let w2 = img.naturalWidth;
let h2 = img.naturalHeight;
if (w2 > window.innerWidth * 0.9) {
w2 = window.innerWidth * 0.7;
h2 = window.innerHeight * 0.7;
}
dom.style.width = w == null ? w2 + "px" : w;
dom.style.height = h == null ? h2 + "px" : h;
}
}
}
var file = new File({
maxFileLength: 2,
maxFileSize: 1024,
fileSuffix: ['mp4', 'mp3', 'word', 'pdf', 'ppt', 'excel', 'png', 'jpg'],
StopDialog: false,
showBtn: false
});
initHJFile(file);
// 如果不想使用自帶的彈窗,可以選擇監(jiān)聽(tīng)file對(duì)象的onlargeClickCallBack函數(shù)
file.callBack.onlargeClickCallBack = function (img, that) {}
file.callBack.ondialogBeforeClose = function (event) {}
file.callBack.onaddImgList = function () {}
// 加載初始信息,比如dom節(jié)點(diǎn)的添加
function initHJFile(file) {
console.log(file);
let input_dom = document.getElementsByClassName('hj-file-input')[0];
let imageItem_dom = document.getElementsByClassName('append-item')[0];
let appendItem_dom = document.getElementsByClassName('hj-append-item')[0];
let appendList_dom = document.getElementsByClassName('hj-file-list')[0];
file.dom.inputDom = input_dom;
file.dom.imageItemDom = imageItem_dom;
file.dom.appendListDom = appendList_dom;
if (file.config.showBtnImgStyle) {
// 開(kāi)啟按鈕模式
appendItem_dom.style.display = 'none';
let btn = document.getElementsByClassName('hj-btn-box');
console.log(btn);
if (btn.length != 0) {
btn[0].className = 'hj-btn-box';
btn[0].children[0].addEventListener('click', file.event.imageItemClick);
} else {
console.log("沒(méi)有找到btn Class");
throw new Error('未定義按鈕模式所需的HTML')
}
}
file.dom.appendItemDom = appendItem_dom;
file.dom.imageItemDom.addEventListener('click', file.event.imageItemClick);
file.dom.inputDom.addEventListener('change', file.event.changeLoadFile)
}
</script>
</body>
</html>
到此這篇關(guān)于js 實(shí)現(xiàn)文件上傳樣式詳情的文章就介紹到這了,更多相關(guān)js 實(shí)現(xiàn)文件上傳樣式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS前端面試數(shù)組扁平化手寫flat函數(shù)示例
這篇文章主要為大家介紹了JS前端面試數(shù)組扁平化手寫flat函數(shù)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
微信小程序之滾動(dòng)視圖容器的實(shí)現(xiàn)方法
這篇文章主要介紹了微信小程序之滾動(dòng)視圖容器的實(shí)現(xiàn)方法的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家掌握這部分內(nèi)容,需要的朋友可以參考下2017-09-09
微信小程序 本地?cái)?shù)據(jù)存儲(chǔ)實(shí)例詳解
這篇文章主要介紹了微信小程序 本地?cái)?shù)據(jù)存儲(chǔ)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04
直觀詳細(xì)的typescript隱式類型轉(zhuǎn)換圖文詳解
這篇文章主要為大家介紹了直觀詳細(xì)的typescript隱式類型轉(zhuǎn)換圖文詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
微信小程序 scroll-view組件實(shí)現(xiàn)列表頁(yè)實(shí)例代碼
這篇文章主要介紹了微信小程序 scroll-view組件實(shí)現(xiàn)列表頁(yè)實(shí)例代碼的相關(guān)資料,scroll-view組件介紹scroll-view是微信小程序提供的可滾動(dòng)視圖組件,其主要作用是可以用來(lái)做手機(jī)端經(jīng)常會(huì)看到的上拉加載 ,需要的朋友可以參考下2016-12-12
微信小程序 天氣預(yù)報(bào)開(kāi)發(fā)實(shí)例代碼源碼
這篇文章主要介紹了微信小程序 天氣預(yù)報(bào)開(kāi)發(fā)實(shí)例代碼源碼的相關(guān)資料,這里含有源碼,需要的朋友可以參考下2017-01-01
微信小程序 頁(yè)面滑動(dòng)事件的實(shí)例詳解
這篇文章主要介紹了微信小程序 頁(yè)面滑動(dòng)事件的實(shí)例詳解的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10
在微信小程序中渲染HTML內(nèi)容3種解決方案及分析與問(wèn)題解決
在開(kāi)發(fā)微信小程序時(shí)我們會(huì)在小程序內(nèi)加入純HTML代碼,且HTML中包括圖片,視頻,甚至是事件,微信小程序?yàn)槲覀兲峁┝?種解決方法,但它們的功能與實(shí)現(xiàn)方式與最終效果并不理想2020-01-01
詳解JavaScript中數(shù)組的相關(guān)知識(shí)
這篇文章主要介紹了JavaScript中中數(shù)組的相關(guān)知識(shí),是JS入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-07-07

