如果项目中,因为各种因素导致无法用UI组件完成文件上传,需要用原生input标签完成可以采用如下方式
功能如下
- 1.input介绍
- 2.修改上传input样式
- 3.多个文件上传(批量上传+多次累计上传)
- 4.图片删除
- 5.图片大图查看
一.input上传介绍
type:设置为file才能有上传功能
accept:允许上传的文件类型
multiple:批量上传(一次上传多张)想要上传多个文件需要在选择文件时,按住Ctrl进行多选
贴出html代码:
<input id="upload-input" type="file" class="file" multiple accept="image/jpg,image/png" />
二.修改input样式
文件上传input的默认样式如图
针对input标签设置一些样式不会起作用(比如去掉黑色边框之类的),所以我们采用如下方式:
- 先隐藏type = "file"的元素,添加一个type="button"的元素
- 把上传按钮的样式写到type="button"的元素上
- 在type="button"的元素上绑定点击事件
代码如下:
1.html 部分
<div class="demo-upload-btn">
<!--上传input-->
<input id="upload-input" type="file" class="file" multiple accept="image/jpg,image/png" />
<!--加一个相机图标-->
<div class="camera"></div>
<!--点击上传的按钮-->
<input type="button" class="btn" @click="clickFile" />
</div>
2.JS部分
<script>
clickFile (type) {
const input = document.querySelector('#file' + type)
input.click()
}
</script>
3.css部分
<style lang="less">
.demo-upload-btn {
position: relative;
width: 60px;
height: 60px;
background: #fff;
border: 1px dashed #d7dde4;
border-radius: 4px;
text-align: center;
overflow: hidden;
transition: border-color 0.2s ease;
.file { // 将type="file"隐藏
display: none;
}
.btn { //type="button"设置样式
position: absolute;
top: 0;
left: 0;
width: 60px;
height: 60px;
background: rgba(0, 0, 0, 0);
z-index: 10;
border: none;
cursor: pointer;
}
.camera {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 28px;
cursor: pointer;
background-image: '你的icon';
}
}
</style>
然后上传的样式变成了
三.多个文件上传
1.获取文件上传的数据
给input="file"的标签加上input的change事件,获取上传后的文件数据
html 部分
<div class="demo-upload-btn">
<!--上传input-->
<input id="upload-input" type="file" class="file" multiple accept="image/jpg,image/png" @change="handleSuccess" />
<!--加一个相机图标-->
<div class="camera"></div>
<!--点击上传的按钮-->
<input type="button" class="btn" @click="clickFile" />
</div>
JS部分
<script>
handleSuccess1 (e) {
// 因为上传过程为实例,这里模拟添加 url
console.log(e.target.files) //拿到了上传的文件,是个数组
}
</script>
打印如下
如果是批量上传多张,FileList会是多条数据
2.实现在本地显示上传的文件/图片
HTML部分
<div class="demo-upload-box">
<div class="demo-upload-image-box" v-if="imageUrlArr && imageUrlArr.length">
<!--循环展示上传后的图片-->
<div class="demo-upload-image" v-for="(item,index) in imageUrlArr" :key="index">
<img :src="item">
<div class="demo-upload-box-cover">
<!--图片查看大图-->
<div class="ios-eye-outline" @click.native="handleView(item)"></div>
<!--图片删除-->
<div class="ios-trash-outline" @click.native="handleRemove(item)"></div>
</div>
</div>
</div>
<!--图片上传-->
<div class="demo-upload-btn">
<input ref="uploadInput1" type="file" multiple id="file" accept="image/jpg,image/png" class="file" @change="handleSuccess">
<div type="camera"></div>
<input type="button" class="btn" @click="clickFile" />
</div>
</div>
JS部分
// urlList作为公共变量,可以实现批量上传+多次累计上传
var urlList = []
handleSuccess1 (e) {
// 因为上传过程为实例,这里模拟添加 url
let file = e.target
for (let i = 0; i < file.files.length; i++) {
urlList.push(window.URL.createObjectURL(file.files.item(i)))
}
this.imageUrlArr = urlList
}
如图:
三.图片删除和查看大图
因为input中的files是只读,不能直接删除某一项,所以需要用一个变量接收上传的文件信息,所以上传方法和删除方法改造如下:
//公共变量记录上传文件:filesData
handleSuccess (e) {
let file = e.target
for (let i = 0; i < file.files.length; i++) {
this.imageUrlArr.push(window.URL.createObjectURL(file.files.item(i)))
this.filesData.push(file.files[i])
}
},
// 删除上传的案例图
handleRemove (index) {
this.imageUrlArr.splice(index, 1)
this.filesData.splice(index, 1)
this.$forceUpdate()
}
// 查看大图
handleView (index) {
this.bigPicSrc = this.imageUrlArr[index]
}
三.完整代码
<template>
<div class="updata-component">
<div class="demo-upload-box">
<div class="demo-upload-image-box" v-if="imageUrlArr && imageUrlArr.length">
<div class="demo-upload-image" v-for="(item,index) in imageUrlArr" :key="index">
<img :src="item">
<div class="demo-upload-box-cover">
<Icon type="ios-eye-outline" @click.native="handleView(index)"></Icon>
<Icon type="ios-trash-outline" @click.native="handleRemove(index)"></Icon>
</div>
</div>
</div>
<div class="demo-upload-btn">
<input :ref="name" type="file" :multiple="multiple" :accept="accept" class="file" @change="handleSuccess">
<Icon type="camera"></Icon>
<input type="button" class="btn" @click="clickFile" />
</div>
</div>
<!-- 查看大图 -->
<div class="big-pic" v-if="bigPicSrc" @click.self="bigPicSrc = ''">
<img class="" :src="bigPicSrc" />
</div>
</div>
</template>
<script>
export default {
props: {
multiple: {
type: Boolean,
default: () => {
return false
}
},
accept: {
type: String,
default: () => {
return 'image/jpg,image/png'
}
},
name: {
type: String,
default: () => {
return 'uploadInput'
}
}
},
data () {
return {
bigPicSrc: '',
imageUrlArr: [],
filesData: []
}
},
methods: {
// 文件上传接收
handleSuccess (e) {
let file = e.target
for (let i = 0; i < file.files.length; i++) {
this.imageUrlArr.push(window.URL.createObjectURL(file.files.item(i)))
this.filesData.push(file.files[i])
}
},
clickFile () {
const input = this.$refs[this.name]
input.click()
},
// 删除上传的案例图
handleRemove (index) {
this.imageUrlArr.splice(index, 1)
this.filesData.splice(index, 1)
this.$forceUpdate()
},
// 查看大图
handleView (index) {
this.bigPicSrc = this.imageUrlArr[index]
}
}
}
</script>
<style scoped lang="less">
.updata-component {
.demo-upload-box {
display: flex;
.demo-upload-image-box {
display: flex;
}
.demo-upload-image {
width: 60px;
height: 60px;
text-align: center;
line-height: 60px;
border-radius: 4px;
position: relative;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
margin-right: 4px;
.demo-upload-box-cover {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0);
}
&:hover {
.demo-upload-box-cover {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.3);
}
.demo-upload-box-cover .ivu-icon {
color: #fff;
font-size: 20px;
cursor: pointer;
margin: 0 2px;
}
}
}
.demo-upload-btn {
position: relative;
width: 60px;
height: 60px;
background: #fff;
border: 1px dashed #d7dde4;
border-radius: 4px;
text-align: center;
overflow: hidden;
transition: border-color 0.2s ease;
.file {
display: none;
}
.btn {
position: absolute;
top: 0;
left: 0;
width: 60px;
height: 60px;
background: rgba(0, 0, 0, 0);
z-index: 10;
border: none;
cursor: pointer;
}
.ivu-icon-camera {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 28px;
cursor: pointer;
}
}
}
.big-pic {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 9999;
img {
position: absolute;
width: 700px;
height: auto;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
}
</style>
<style lang="less">
.ivu-form .ivu-form-item-label {
font-size: 14px;
color: #45484c;
}
</style>