从0搭建vue3组件库:实现Upload组件文件拖拽上传

简介: 从0搭建vue3组件库:实现Upload组件文件拖拽上传

image.png


上篇文章从0搭建vue3组件库:Upload文件上传组件已经实现基本的文件上传组件,本篇文章将为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')

启动项目,便可以看到下面的效果

image.png


拖拽实现



接下来要做的就是将文件拖进来获取到文件列表以及点击上传。其中点击上传很简单,只需要绑定和上面一样的事件即可

  • 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,但是实际代码中却可以获取到)

image.png

获取到文件之后把文件名字渲染到下面的列表中,并且将文件列表传给用户,同时我们做个限制,如果没有传入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)
})

最终拖拽完毕的效果为

image.png

最后我们再加两个事件dragenterdragleave来判断文件是否拖到这个区域从而展示不同样式

  • 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)
})

此时文件进入的效果

image.png


写在最后



到这里Upload组件拖拽上传的功能基本已经实现,如果大家对vue3组件库搭建感兴趣的话,欢迎大家关注 从零搭建Vue3组件库专栏 将持续更新一些组件的实现。


完整代码



完整代码点击 kitty-ui 获取,最后希望大家给个👍



相关文章
|
2月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
163 64
|
2月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
57 8
|
2月前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
2月前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
20天前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
110 1
|
1月前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
2月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
56 1
vue学习第一章
|
2月前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
52 1
|
2月前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
46 1
vue学习第四章
|
2月前
|
JavaScript 前端开发 算法
vue学习第7章(循环)
欢迎来到瑞雨溪的博客,一名热爱JavaScript和Vue的大一学生。本文介绍了Vue中的v-for指令,包括遍历数组和对象、使用key以及数组的响应式方法等内容,并附有综合练习实例。关注我,将持续更新更多优质文章!🎉🎉🎉
40 1
vue学习第7章(循环)