携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情[1]
上篇文章从0搭建vue3组件库:Upload文件上传组件[2]已经实现基本的文件上传组件,本篇文章将为Upload
组件加入拖拽上传(drag)的功能。
定义props
首先在types.ts
中定义一个drag
来控制是否使用拖拽上传
import { ExtractPropTypes } from 'vue'
export const uoloadType = {
multiple: Boolean,
accept: String,
drag: Boolean
}
export type LinkProps = ExtractPropTypes<typeof uoloadType>
区域样式
在upload.vue
中通过判断用户是否传入drag
来控制拖拽区域的显示与隐藏,并且为拖拽区域定义一些样式。部分代码省略,文章最后会贴最终完整代码
-
upload.vue
部分代码
<div @click="fileUpload" v-if="!props.drag">
<slot />
</div>
<div class="k-upload-dragger" v-else>
<div class="k-upload-content">
<Icon class="k-upload-icon" name="folder-close" />
<div class="k-upload-dragger-text">将文件拖到此处或<em>点击上传</em></div>
</div>
</div>
-
style/index.less
部分代码
.k-upload-dragger {
background-color: #fff;
border: 1px dashed #d9d9d9;
border-radius: 6px;
box-sizing: border-box;
width: 360px;
height: 180px;
display: flex;
cursor: pointer;
align-items: center;
justify-content: center;
&:hover {
border: 1px dashed #409eff;
}
.k-upload-content {
text-align: center;
color: #606266;
.k-upload-icon {
font-size: 20px;
}
em {
color: #409eff;
font-style: normal;
}
}
}
然后在本地测试项目examples
下的app.vue中引入
<template>
<div class="upload-demo">
<k-upload @getFilesList="getFilesList" drag multiple accept="image/*"></k-upload>
</div>
</template>
<script lang="ts" setup>
const getFilesList = (files: File[]) => {
console.log(files)
}
</script>
<style lang="less">
.upload-demo {
width: 400px;
}
</style>
注意这里为了调试方便,已经全局导入了kitty-ui
库了。对应的main.ts
:
import { createApp } from 'vue'
import App from './app.vue'
const app = createApp(App)
import kittyui from "kitty-ui"
app.use(kittyui)
app.mount('#app')
启动项目,便可以看到下面的效果

拖拽实现
接下来要做的就是将文件拖进来获取到文件列表以及点击上传。其中点击上传很简单,只需要绑定和上面一样的事件即可
-
upload.vue
部分代码
<div @click="fileUpload" v-if="!props.drag">
<slot />
</div>
<div class="k-upload-dragger" @click="fileUpload" v-else>
<div class="k-upload-content">
<Icon class="k-upload-icon" name="folder-close" />
<div class="k-upload-dragger-text">将文件拖到此处或<em>点击上传</em></div>
</div>
</div>
实现拖拽上传可以借助drop
事件。在组件生命周期onMounted
中获取到拖拽区域的dom
,然后监听它的drop
事件。
首先给拖拽区域一个ref
属性
<div class="k-upload-dragger" ref="fileArea" @click="fileUpload" v-else>
<div class="k-upload-content">
<Icon class="k-upload-icon" name="folder-close" />
<div class="k-upload-dragger-text">将文件拖到此处或<em>点击上传</em></div>
</div>
</div>
然后在组件创建完成后进行事件监听
const fileArea = ref()
onMounted(() => {
fileArea.value.addEventListener('drop', (e: any) => {
e.preventDefault();
console.log(e)
}, false)
fileArea.value.addEventListener('dragover', (e: any) => {
e.preventDefault();
}, false)
})
注意 这里需要阻止dragover
的默认事件,不然drop
是不生效的.此时我们将文件拖拽到这个区域后我们可以看到控制台打印很多东西,而我们只需要e.dataTransfer.files
即可(不知道为什么控制台上显示files的长度为0,但是实际代码中却可以获取到)

获取到文件之后把文件名字渲染到下面的列表中,并且将文件列表传给用户,同时我们做个限制,如果没有传入drag
则不监听这两个事件
const fileArea = ref()
onMounted(() => {
if (!props.drag) return
fileArea.value.addEventListener('drop', (e: any) => {
e.preventDefault();
filesList.value.push(...Array.from(e.dataTransfer.files as FileList))
emits('getFilesList', filesList.value)
}, false)
fileArea.value.addEventListener('dragover', (e: Event) => {
e.preventDefault();
}, false)
})
最终拖拽完毕的效果为

最后我们再加两个事件dragenter
和dragleave
来判断文件是否拖到这个区域从而展示不同样式
-
template
部分代码
<div v-else class="k-upload-dragger" :class="{ ['k-upload-draggerenter']: isEnter }" ref="fileArea"
@click="fileUpload">
<div class="k-upload-content">
<Icon class="k-upload-icon" :name="isEnter ? 'file-open' : 'folder-close'" />
<div class="k-upload-dragger-text">将文件拖到此处或<em>点击上传</em></div>
</div>
</div>
-
script
部分代码
const fileArea = ref()
const isEnter = ref(false)
onMounted(() => {
if (!props.drag) return
fileArea.value.addEventListener('drop', (e: any) => {
e.preventDefault();
filesList.value.push(...Array.from(e.dataTransfer.files as FileList))
emits('getFilesList', filesList.value)
}, false)
fileArea.value.addEventListener('dragover', (e: Event) => {
e.preventDefault();
}, false)
fileArea.value.addEventListener('dragenter', (e: Event) => {
isEnter.value = true
e.preventDefault();
}, false)
fileArea.value.addEventListener('dragleave', (e: Event) => {
isEnter.value = false
e.preventDefault();
}, false)
})
此时文件进入的效果

写在最后
到这里Upload
组件拖拽上传的功能基本已经实现,如果大家对vue3组件库搭建感兴趣的话,欢迎大家关注 公众号合集 “vue3组件库” 将持续更新一些组件的实现。
完整代码
完整代码点击 阅读原文 获取,最后希望大家给个👍
原文始发于微信公众号(web前端进阶):从0搭建vue3组件库:实现Upload组件文件拖拽上传
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/232530.html