从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 获取,最后希望大家给个👍



目录
打赏
0
0
0
0
16
分享
相关文章
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
183 64
创建vue3项目步骤以及安装第三方插件步骤【保姆级教程】
这是一篇关于创建Vue项目的详细指南,涵盖从环境搭建到项目部署的全过程。
168 1
|
3月前
|
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
150 58
vue3使用pinia中的actions,需要调用接口的话
通过上述步骤,您可以在Vue 3中使用Pinia和actions来管理状态并调用API接口。Pinia的简洁设计使得状态管理和异步操作更加直观和易于维护。无论是安装配置、创建Store还是在组件中使用Store,都能轻松实现高效的状态管理和数据处理。
146 3
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
76 8
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
64 1
|
2月前
|
vue使用iconfont图标
vue使用iconfont图标
152 1
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
ry-vue-flowable-xg:震撼来袭!这款基于 Vue 和 Flowable 的企业级工程项目管理项目,你绝不能错过
基于 Vue 和 Flowable 的企业级工程项目管理平台,免费开源且高度定制化。它覆盖投标管理、进度控制、财务核算等全流程需求,提供流程设计、部署、监控和任务管理等功能,适用于企业办公、生产制造、金融服务等多个场景,助力企业提升效率与竞争力。
68 12
Vue中的class和style绑定
在 Vue 中,class 和 style 绑定是基于数据驱动视图的强大功能。通过 class 绑定,可以动态更新元素的 class 属性,支持对象和数组语法,适用于普通元素和组件。style 绑定则允许以对象或数组形式动态设置内联样式,Vue 会根据数据变化自动更新 DOM。

热门文章

最新文章