vue部分:
<tag-input
id="uploadTag"
ref="uploadTag"
v-model="fileNameList"
size="small"
@input="removeFile"
></tag-input>
逻辑部分:
页面加载时监听拖拽事件,监听后将文件放置下发fileList参数列表中
mounted() {
setTimeout(() => {
this.$nextTick(() => {
if (this.$refs.uploadTag) {
let dropEle = this.$refs.uploadTag.$el
// 禁止拖拽文件后打开文件
dropEle.addEventListener('drop', e => {
e.preventDefault();
e.stopPropagation();
}, false)
dropEle.addEventListener('dragover', e => {
e.preventDefault();
e.stopPropagation();
}, false)
dropEle.addEventListener('dragleave', e => {
e.preventDefault();
e.stopPropagation();
}, false)
// 处理拖拽文件的逻辑
dropEle.addEventListener('drop', e => this.watchFileUpload(e))
}
})
}, 1000)
}
// 拖拽上传
private watchFileUpload(e) {
e.preventDefault();
e.stopPropagation();
var df = e.dataTransfer;
var dropFiles = []; // 拖拽的文件,会放到这里
var dealFileCnt = 0; // 读取文件是个异步的过程,需要记录处理了多少个文件了
var allFileLen = df.files.length; // 所有的文件的数量,给非Chrome浏览器使用的变量
// 检测是否已经把所有的文件都遍历过了
function checkDropFinish() {
dealFileCnt++;
}
if (df.items !== undefined) {
// Chrome拖拽文件逻辑
for (var i = 0; i < df.items.length; i++) {
var item = df.items[i];
if (item.kind === "file" && item.webkitGetAsEntry().isFile) {
var file = item.getAsFile();
dropFiles.push(file);
}
}
} else {
// 非Chrome拖拽文件逻辑
for (var i = 0; i < allFileLen; i++) {
var dropFile = df.files[i];
if (dropFile.type) {
dropFiles.push(dropFile);
checkDropFinish();
} else {
try {
var fileReader = new FileReader();
fileReader.readAsDataURL(dropFile.slice(0, 3));
fileReader.addEventListener('load', function (e) {
console.log(e, 'load');
dropFiles.push(dropFile);
checkDropFinish();
}, false);
fileReader.addEventListener('error', function (e) {
console.log(e, 'error,不可以上传文件夹');
checkDropFinish();
}, false);
} catch (e) {
console.log(e, 'catch error,不可以上传文件夹');
checkDropFinish();
}
}
}
}
dropFiles.forEach(item => {
this.fileList.push(item)
})
this.fileNameList = this.fileList.map(item => {
if (item.name) {
return item.name
}
if (item.fileName) {
return item.fileName
}
});
}
删除当前文件:
// 附件删除 下拉框
private removeFile(nameList, name) {
// 记录删除的附件信息
this.fileList.splice(this.fileList.findIndex(item => item.fileName === name || item.name === name), 1)
this.fileNameList = this.fileList.map(item => item.name || item.fileName);
}
封装的tag-input组件:
<template>
<div
class="yh-input-tag input-tag-wrapper"
ref="InputTag"
@click="foucusTagInput"
>
<el-tag
v-for="(tag, idx) in innerTags"
:key="tag"
:size="size"
:closable="!readonly"
:disable-transitions="false"
@close="remove(tag, idx)"
>{{ tag }}</el-tag
>
<input
:readonly="readonly || readonlyIpt"
class="tag-input"
:class="[size ? 'yh-input-tag--' + size : '']"
:style="widthStyle"
:placeholder="isplaceholder"
v-model="newTag"
@keydown.delete.stop="removeLastTag"
@keydown="addNew"
@blur="blurTagInput"
/>
</div>
</template>
<script>
export default {
name: 'InputTag',
props: {
value: {
type: Array,
default: () => []
},
addTagOnKeys: {
type: Array,
default: () => [13, 188, 9]
},
readonly: {
type: Boolean,
default: false
},
// 输入框只读
readonlyIpt: {
type: Boolean,
default: false
},
size: String,
placeholder: {
type: String,
default: '请输入'
}
},
inject: {
elForm: {
default: ''
},
elFormItem: {
default: ''
}
},
data () {
return {
newTag: '',
innerTags: [...this.value],
currentTag: null,
widthStyle: {
minWidth: '10px'
}
}
},
computed: {
isplaceholder () {
let str = ''
if(this.value?.length > 0) {
this.$nextTick(() => {
if (this.$refs.yhInputTag) {
this.$refs.InputTag.style.padding = '0'
}
})
str = ''
} else {
this.$nextTick(() => {
if (this.$refs.yhInputTag) {
this.$refs.InputTag.style.padding = '0 15px'
}
})
str = this.placeholder
}
return str
},
// 表单禁用关联
inputDisabled() {
return this.disabled || (this.elForm || {}).disabled;
}
},
watch: {
value: {
handler(newVal, oldVal) {
if (this.elForm && oldVal !== undefined && newVal !== oldVal) {
this.elForm.validateField(this.elFormItem.prop)
}
if (newVal) {
this.innerTags = [...newVal]
}
},
deep: true,
immediate: true
}
},
methods: {
foucusTagInput () {
if (this.readonly || this.readonlyIpt || !this.$el.querySelector('.tag-input')) {
return
} else {
this.$el.querySelector('.tag-input').focus()
this.widthStyle = {
minWidth: '10px'
}
}
},
blurTagInput (e) {
this.addNew(e)
this.widthStyle = {
width: '0px'
}
},
addNew (e) {
if (e && (!this.addTagOnKeys.includes(e.keyCode)) && (e.type !== 'blur')) {
return
}
if (e) {
e.stopPropagation()
e.preventDefault()
}
let addSuucess = false
if (this.newTag.includes(',')) {
this.newTag.split(',').forEach(item => {
if (this.addTag(item.trim())) {
addSuucess = true
}
})
} else {
if (this.addTag(this.newTag.trim())) {
addSuucess = true
}
}
if (addSuucess) {
this.tagChange()
this.newTag = ''
}
},
addTag (tag) {
tag = tag.trim()
if (tag && !this.innerTags.includes(tag)) {
this.innerTags.push(tag)
return true
}
return false
},
remove (tag, index) {
this.innerTags.splice(index, 1)
this.currentTag = tag
this.tagChange()
},
removeLastTag () {
if (this.newTag) {
return
}
this.innerTags.pop()
this.tagChange()
},
tagChange () {
this.$forceUpdate()
this.$emit('input', JSON.parse(JSON.stringify(this.innerTags)), this.currentTag)
}
}
}
</script>
<style scoped>
.input-tag-wrapper {
position: relative;
font-size: 14px;
background-color: #fff;
background-image: none;
border-radius: 4px;
border: 1px solid #DCDFE6;
box-sizing: border-box;
color: #575757;
display: inline-block;
cursor: text;
outline: none;
padding: 0 15px;
transition: border-color .2s cubic-bezier(.645,.045,.355,1);
width: 100%;
line-height: normal;
&:hover{
border-color: #C5C6C7;
}
&:focus{
border-color: #d32f2f;
}
.el-tag{
box-sizing: border-box;
border-color: transparent;
margin: 2px 0 2px 6px;
background-color: #f0f2f5;
display: inline-flex;
max-width: 100%;
align-items: center;
}
}
.tag-input {
background: transparent;
border: 0;
font-size: 14px;
outline: none;
padding-left: 0;
height: 26px;
&::placeholder {
color: #C8C9CA;
}
}
.yh-input-tag--mini{
height: 26px;
line-height: 26px;
.tag {
height: 16px;
}
}
.yh-input-tag--small{
height: 30px;
line-height: 30px;
.tag {
height: 20px;
}
}
.yh-input-tag--medium{
height: 34px;
line-height: 34px;
.tag {
height: 24px;
}
}
// 表单标签选择器必填样式
.el-form-item.is-error .input-tag-wrapper,
.el-form-item.is-error .input-tag-wrapper:focus {
border-color: #bc1126 !important;
}
</style>
最后实现的效果:
可支持手动拖拽上传