封装上传文件组件(axios,onUploadProgress,取消请求)

目录

定时模拟进度条

方法

A.axios

B.xhr

取消请求​​​​​​​

完整代码

A.自定义上传组件

B.二次封装组件

情况

增加cancelToken不生效,刷新页面

进度条太快->设置浏览器网速

定时模拟进度条

    startUpload() {
        if (!this.file) return;

        const totalSize = this.file.size;
        let uploadedSize = 0;

        const interval = setInterval(() => {
            if (uploadedSize >= totalSize) {
                clearInterval(interval);
                // this.state_tip = STATE_TIPS.get('上传成功');
            } else {
                uploadedSize += 1024;
                this.progress = Math.round((uploadedSize / totalSize) * 100);
            }
        }, 200);
    }

方法

A.axios

 uploadQuery() {
        if (!this.file) return;
        this.state_tip = STATE_TIPS.get('上传中');
        this.progress = 0;
        // headers = {'Content-Type': 'multipart/form-data'}
        const formData = new FormData()
        formData.append('file', this.file)
        axios.post(this.uploadPath, formData, {
            headers: {
                "X-Requested-With": "XMLHttpRequest",
            },
            onUploadProgress: (progressEvent: ProgressEvent) => {
                console.log("onUploadProgress");
                if (progressEvent.lengthComputable) {
                    this.progress = Math.round(
                        (progressEvent.loaded / progressEvent.total) * 100
                    );
                    console.log(this.progress);
                }
            },
        }).then((res: any) => {
            if (res && res.code == 200) {
                this.uploadExel = res.data;
                this.state_tip = STATE_TIPS.get('上传成功');
                console.log(this.uploadExel);
                this.$emit("update:uploadExel", this.uploadExel);
            } else {
                this.state_tip = STATE_TIPS.get('其他');
                this.state_tip.tip = res.msg || '请取消上传,更换符合模板要求的文件';
            }
        }).catch((error: any) => {
            this.state_tip = STATE_TIPS.get('上传失败');
        }).finally(() => {
            this.uploaded = true;
            this.$emit("update:uploaded", this.uploaded);
        });
    }

B.xhr

   uploadQuery(file: File) {
        // headers = {'Content-Type': 'multipart/form-data'}
        const formData = new FormData()
        formData.append('file', file)
        const xhr = new XMLHttpRequest();
        xhr.open("POST", this.uploadPath, true);

        xhr.upload.onprogress = (event) => {
            if (event.lengthComputable) {
                this.uprogress = Math.round((event.loaded / event.total) * 100);
            }
        };

        xhr.onload = () => {
            console.log(xhr);
            
            if (xhr.status === 200) {
                const res = JSON.parse(xhr.responseText);
                console.log(res);
                console.log(res.code);
                if (res.code === 200) {
                    this.uploadExel = res.data;
                    this.state_tip = "上传成功";
                    this.uploaded = true;
                    console.log(this.uploadExel);
                    this.$emit("update:uploaded", this.uploaded);
                    this.$emit("update:uploadExel", this.uploadExel);
                } else {
                    // 处理上传失败情况
                    this.state_tip = "上传失败";
                }
            }
        };

        xhr.onerror = () => {
            // 处理上传出错情况
            this.state_tip = "上传出错";
        };

        xhr.send(formData);
        // request.post(this.uploadPath, formData).then((res: any) => {

        //     if (res.code == 200) {
        //         this.uploadExel = res.data;
        //         this.state_tip = STATE_TIPS.get('上传成功');
        //         this.uploaded = true;
        //         this.$emit("update:uploaded", this.uploaded);
        //         this.$emit("update:uploadExel", this.uploadExel);
        //     } else {

        //     }
        // })
    }

取消请求​​​​​​​

完整代码

<UploadComp :uploadPath="PATH" :fileLogPath="PATH.replace('uploadExcel?wpReleId=','getOtherIndexFileLog/')" :uploaded.sync="uploaded" :uploadExel.sync="uploadExel" @cancelUpload="cancelUpload" />
            <!-- <SingleUploadComp :uploadPath="PATH" :uploaded.sync="uploaded" :uploadExel.sync="uploadExel" @cancelUpload="cancelUpload" /> -->

A.自定义上传组件

<template>
    <div class="upload-list-dragger" :uploadPath="uploadPath" :fileLogPath="fileLogPath">
        <div v-if="!file" @click="openFileInput" @dragenter="onDragEnter" @dragover="onDragOver" @drop="onDrop"
            :class="{ 'drag-over': isDragOver }">
            <input type="file" ref="fileInput" style="display: none;" @change="onFileChange" :accept="format" />
            <div class="custom-drag-style">
                <img src="@/assets/img/upload.png" class="upload-icon" />
                <div class="upload-click-drag">点击或拖拽上传文件</div>
                <!-- 使用正则表达式替换所有点号 -->
                <div class="upload-tip">请上传{{ format.replace(/\./g, "") }}格式文件,上传多份文件时以最后一次为准</div>
            </div>
        </div>
        <div v-else class="custom-upload-card">
            <img class="upload-card-icon" src="@/assets/img/excel.png" />
            <div class="upload-card-state">
                <div>
                    <span class="file-name">{{ file.name }}</span>
                    <span class="cancel-upload" @click="cancelUpload"><mds-icon type="line-close" /></span>
                </div>
                <div class="progress-bar" :style="{ width: progress + '%', backgroundColor: state_tip.color }"></div>
                <div class="span-container">
                    <span :style="{ color: state_tip.state === '上传中' ? '#A8ACB3' : state_tip.color }">{{
                        state_tip.tip
                    }}</span>
                    <span v-if="state_tip.state === '上传中'">{{ progress + '%' }}</span>
                    <span v-if="state_tip.state === '上传失败'" class="span-operate" underline
                        @click="restartUpload">重新上传</span>
                    <span v-if="state_tip.state === '上传成功'" class="span-operate" underline
                        @click="downloadQuery">下载结果明细</span>
                </div>
            </div>
        </div>
    </div>
</template>
  
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';
import request from '@/utils/request'
import axios, { Canceler } from 'axios';
const STATE_TIPS = new Map([['其他', { state: '其他', color: 'orange', tip: '' }], ['上传中', { state: '上传中', color: '#1564FF', tip: '文件上传解析中…' }], ['上传失败', { state: '上传失败', color: '#DD2100', tip: '上传失败,请重新上传' }], ['上传成功', { state: '上传成功', color: '#00AF5B', tip: '上传成功!' }]])
@Component({
    components: {}
})
export default class UploadComp extends Vue {
    @Prop({ required: true }) private uploadPath!: string
    @Prop({ required: true }) private fileLogPath!: string
    @Prop({ default: '.xls' }) private format!: string //形如".xls,.csv,.xlsx"

    uploadExel: any = {
        succList: []
    }
    uploaded: boolean = false;

    file: File | null = null;
    source = axios.CancelToken.source();

    progress = 0;
    isDragOver = false;
    data() {
        return {
            state_tip: {},
            
        }
    }
    created() {
        console.log(this.fileLogPath);
    }
    onFileChange(event: Event) {
        const target = event.target as HTMLInputElement;
        this.fileValidator(target.files);//可能为null
    }
    fileValidator(files: FileList | undefined | null) {
        if (files && files.length > 0) {
            // 上传多份文件时以最后一次为准
            const file = files[0];
            if (this.isValidFormat(file)) {
                this.file = file;
                console.log(this.file);
                this.uploadQuery();
            } else {
                alert(`请上传${this.format.replace(/\./g, "")}格式文件。`);
            }
        } else {
            alert(`请上传文件!`);
        }
    }
    uploadQuery() {
        if (!this.file) return;
        this.state_tip = STATE_TIPS.get('上传中');
        this.progress = 0;
        // headers = {'Content-Type': 'multipart/form-data'}
        const formData = new FormData()
        formData.append('file', this.file)
        // 在合适的地方定义取消令牌和取消函数
        const CancelToken = axios.CancelToken;

         // 判断上一次的请求是否还在继续,如果还在继续,则取消上一次的请求
       if(this.source.token._listeners!=undefined )
        {
            this.source.cancel("取消请求")
            this.source = axios.CancelToken.source()
        }

        request.post(this.uploadPath, formData, {
            onUploadProgress: (progressEvent: ProgressEvent) => {
                console.log("Upload progress:", progressEvent);
                this.progress = Math.round((progressEvent.loaded / progressEvent.total) * 100);
                console.log("进度:", this.progress);
            },
            cancelToken:this.source.token,
        }).then((res: any) => {
            if (res && res.code == 200) {
                this.uploadExel = res.data;
                this.state_tip = STATE_TIPS.get('上传成功');
                console.log(this.uploadExel);
                this.$emit("update:uploadExel", this.uploadExel);
                this.uploaded = true;
                this.$emit("update:uploaded", this.uploaded);
            } else {
                this.state_tip = STATE_TIPS.get('其他');
                this.state_tip.tip = res.msg || '请取消上传,更换符合模板要求的文件';
            }
        }).catch((error: any) => {
            this.state_tip = STATE_TIPS.get('上传失败');
        })
    }
    downloadQuery() {
        request.get(this.fileLogPath).then((res: any) => {
            var aLink = document.createElement("a");
            aLink.style.display = "none";
            aLink.href = res.data[0].fileUrl
            document.body.appendChild(aLink);
            aLink.click();
            document.body.removeChild(aLink);
        })
    }
    cancelUpload() {
        console.log("取消上传")
        this.state_tip = STATE_TIPS.get('其他');
        this.progress = 0;
        this.file = null;
        if (this.uploaded) {
            this.$emit('cancelUpload', this.uploadExel.fileLogId)
        }else{
            this.source.cancel("请求已被取消")
            this.source = axios.CancelToken.source()
        }
    }

    restartUpload() {
        this.uploadQuery();
    }
    openFileInput() {
        const fileInput = this.$refs.fileInput as HTMLInputElement;
        fileInput.click();
    }
    // 拖动文件进入上传区域
    onDragEnter(event: DragEvent) {
        // 防止浏览器默认的拖放行为
        event.preventDefault();
        this.isDragOver = true;
    }
    // 拖动文件在上传区域中移动
    onDragOver(event: DragEvent) {
        //防止浏览器默认的拖放行为
        event.preventDefault();
    }
    // 放置拖动的文件
    onDrop(event: DragEvent) {
        event.preventDefault();
        this.isDragOver = false;
        this.fileValidator(event.dataTransfer?.files)//可能为undefined
    }
    isValidFormat(file: File) {
        const supportedFormats: string[] = this.format.split(','); // 将 format 字符串拆分成数组
        const fileExtension = '.' + file.name.split('.').pop(); // 获取文件名的扩展名
        return supportedFormats.some((supportedFormat: string) => {
            return fileExtension === supportedFormat;
        });
    }
}
</script>
  
<style>
.upload-list-dragger {
    width: 800px;
    height: 160px;
    border: 1px dashed rgba(206, 212, 224, 1);
    border-radius: 4px;
    display: flex;
    align-items: center;
}

.upload-list-dragger:hover {
    background-color: #eef8ff;

}

.custom-drag-style {
    height: 140px;
    width: 780px;
    background-color: #fff;
    flex-wrap: wrap;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    cursor: pointer;

    .upload-icon {
        width: 24px;
        height: 24px;
    }

    .upload-click-drag {
        width: 144px;
        height: 24px;
        font-family: PingFangSC-Regular;
        font-size: 16px;
        font-weight: 400;
        line-height: 24px;
        color: rgba(69, 71, 77, 1);
        text-align: left;
        display: block;
    }

    .upload-tip {
        height: 24px;
        font-family: PingFangSC-Regular;
        font-size: 14px;
        font-weight: 400;
        line-height: 24px;
        color: rgba(168, 172, 179, 1);
        text-align: left;
        display: block;
    }
}

.custom-upload-card {
    display: flex;
    align-items: center;
    height: 71px;

    .upload-card-icon {
        width: 71px;

    }

    .upload-card-state {
        height: 100%;
        display: flex;
        flex-direction: column;
        justify-content: space-around;

        .file-name {
            font-family: PingFangSC-Regular;
            font-size: 16px;
            font-weight: 400;
            line-height: 16px;
            color: rgba(69, 71, 77, 1);
            text-align: left;
            margin-right: 12px;
        }

        .cancel-upload {
            cursor: pointer;
        }

        .progress-bar {
            height: 8px;
            border-radius: 8px;
        }

        /* 进度条看作是由两个嵌套的<div>元素构成,外部的.progress-bar元素和内部的<div> */
        .progress-bar div {
            width: 638px;
            height: 8px;
            background-color: rgba(228, 231, 237, 1);
            border-radius: 8px;
        }

        .span-container {
            width: 690px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            font-family: PingFangSC-Regular;
            font-size: 14px;
            font-weight: 400;
            line-height: 24px;

            .span-operate {
                color: #1564FF;
                cursor: pointer;
            }
        }
    }

}
</style>
  

B.二次封装组件

<template>
  <mds-upload ref="uploadRef" :path="uploadPath" name="file" :beforeUpload="onBeforeUpload"
    :getUploadParams="getUploadParams" :disabled="false" :multiple="false" :accept="format" :onComplete="onUploadComplete"
    :onError="onUploadError" :onChange="onListChange" listType="imgCard" :limit="1" :dragable="true">
    <template v-slot:dragStyle>
      <div class="custom-drag-style">
        <img src="@/assets/img/upload.png" class="upload-icon" />
        <div class="upload-click-drag">点击或拖拽上传文件</div>
        <!-- 使用正则表达式替换所有点号 -->
        <div class="upload-tip" slot="tip">请上传{{ format.replace(/\./g, "") }}格式文件,上传多份文件时以最后一次为准</div>
      </div>
    </template>
  </mds-upload>
</template>
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator'
@Component({
  components: {}
})
export default class SingleUploadComp extends Vue {
  @Prop({ required: true })  private uploadPath!: boolean
  @Prop({ default: '.xls' }) private format!: string //形如".xls,.csv,.xlsx"
  uploadExel: any = {
    succList: []
  }
  uploaded:boolean= false
   onBeforeUpload(files: File[], callback: (files: File[]) => void) {
    callback(files)
  }
  
   getUploadParams(file: File, callback: (data: any) => void) {
    const formData = new FormData()
    formData.append('file', file)
    const cbData = {
      data: formData,
      withCredentials: true
    }
    callback(cbData)
    this.$refs.uploadRef.$el.querySelector('.upload-list-dragger').style.display = "none";
  }
  /**
   * @param res 响应结果
   * @param oriFile 原始文件
   */
   onUploadComplete(res: any, oriFile: File) {
    const errEle = this.$refs.uploadRef.$el.querySelector('.mds-upload-card-data-error')
    if (res.data.code == 200) {
      this.uploadExel = res.data.data;
      this.$emit("update:uploadExel", this.uploadExel); 
      errEle.innerHTML = "上传成功!";
      this.uploaded = true;
      this.$emit("update:uploaded", this.uploaded); 
    } else {
      errEle.innerHTML = res.data.msg;
      errEle.style.color = "orange";
    }
  }
   onUploadError(err: any, oriFile: File) {
    const errEle = this.$refs.uploadRef.$el.querySelector('.mds-upload-card-data-erro')
    errEle.innerHTML = "上传失败,请重新上传";
  }
   onListChange(uploadList: any[]) {
    console.log('on list change')
    if (uploadList.length == 0) {
      if (this.uploaded) {
        console.log("取消上传")
        this.$emit('cancelUpload', this.uploadExel.fileLogId)
      }
      this.$refs.uploadRef.$el.querySelector('.upload-list-dragger').style.display = "block";
    }
  }
}  
</script>
<style lang="scss" scoped>
::v-deep .upload-list-dragger {
  // position: relative;
  width: 800px;
  height: 160px;
  border: 1px dashed rgba(206, 212, 224, 1);
  border-radius: 4px;

  .custom-drag-style:hover {
    background-color: #eef8ff;
  }

  .custom-drag-style {
    height: 140px;
    background-color: #fff;
    flex-wrap: wrap;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    cursor: pointer;

    .upload-icon {
      width: 24px;
      height: 24px;
    }

    .upload-click-drag {
      width: 144px;
      height: 24px;
      font-family: PingFangSC-Regular;
      font-size: 16px;
      font-weight: 400;
      line-height: 24px;
      color: rgba(69, 71, 77, 1);
      text-align: left;
      display: block;
    }

    .upload-tip {
      width: 326px;
      height: 24px;
      font-family: PingFangSC-Regular;
      font-size: 14px;
      font-weight: 400;
      line-height: 24px;
      color: rgba(168, 172, 179, 1);
      text-align: left;
      display: block;
    }
  }
}

::v-deep .mds-upload-card {
  position: relative;
  width: 800px;
  height: 160px;
  border: 1px dashed rgba(206, 212, 224, 1) !important;
  border-radius: 4px;
}

::v-deep .mds-upload-card:hover .mds-upload-card-eyes {
  display: none;
}

::v-deep .mds-upload-card-icon {
  width: 71px;
  height: 71px;
  display: block;

  &::before {
    content: '';
    display: block;
    width: 71px;
    height: 71px;
    background: url('../../../assets/img/excel.png');
    background-size: 71px 71px;
    z-index: 9999;
  }
}

::v-deep .mds-upload-card-data-name {
  width: 114px;
  height: 24px;
  font-family: PingFangSC-Regular;
  font-size: 16px;
  font-weight: 400;
  line-height: 24px;
  color: rgba(69, 71, 77, 1);
  text-align: left;
}

::v-deep .mds-upload-card-data {
  .mds-upload-card-data-error {
    color: #00AF5B;
    height: 24px;
    font-family: PingFangSC-Regular;
    font-size: 14px;
    font-weight: 400;
    line-height: 24px;
    text-align: left;
  }

  .mds-upload-card-data-size {

    height: 24px;
    font-family: PingFangSC-Regular;
    font-size: 14px;
    font-weight: 400;
    line-height: 24px;
    text-align: left;
  }
}
</style>

情况

增加cancelToken不生效,刷新页面

进度条太快->设置浏览器网速

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/64014.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

flink kafka消费者如何处理kafka主题的rebalance

背景&#xff1a; 我们日常使用kafka客户端消费kafka主题的消息时&#xff0c;当消费者退出/加入消费者组&#xff0c;kafka主题分区数有变等事件发生时&#xff0c;都会导致rebalance的发生&#xff0c;此时一般情况下&#xff0c;如果我们不自己处理offset&#xff0c;我们不…

Vue3+Vite+Pinia+Naive后台管理系统搭建之九:layout 动态路由布局

前言 如果对 vue3 的语法不熟悉的&#xff0c;可以移步Vue3.0 基础入门&#xff0c;快速入门。 1. 系统页面结构 由 menu&#xff0c;面包屑&#xff0c;用户信息&#xff0c;页面标签&#xff0c;页面内容构建 ​ 2. 创建页面 创建 src/pages/layout.vue 布局页 创建 sr…

python 封装sql 增删改查连接MySQL

select * from Teacher limit 10 连接字符串配置MysqlConfig.py class MysqlConfig:HOST 192.168.56.210PORT 3306USER rootPASSWORD 1qaz0987654321DBStudentDBCHARSET utf8封装增删改查MysqlConnection.py Author: tkhywang 2810248865qq.com Date: 2023-06-19 15:44:48 Las…

VMware Workstation及CentOS-7虚机安装

创建新的虚机&#xff1a; 选择安装软件&#xff08;这里选的是桌面版&#xff0c;也可以根据实际情况进行选择&#xff09; 等待检查软件依赖关系 选择安装位置&#xff0c;自主配置分区 ​​​​​​​ 创建一个普通用户 安装完成后重启 点击完成配置&#xff0c;进入登陆界面…

Vue3 列表渲染简单应用

去官网学习→列表渲染 | Vue.js 运行示例&#xff1a; 代码&#xff1a;HelloWorld.vue <template><div class"hello"><h1>Vue 列表渲染</h1><p v-for"item in dataList">{{item}}</p><p v-for"(item,index)…

ros tf

欢迎访问我的博客首页。 tf 1. tf 命令行工具1.1 发布 tf1.2 查看 tf 2.参考 1. tf 命令行工具 1.1 发布 tf 我们根据 cartographer_ros 的 launch 文件 backpack_2d.launch 写一个 tf.launch&#xff0c;并使用命令 roslaunch cartographer_ros tf.launch 启动。该 launch 文件…

认识所有权

专栏简介&#xff1a;本专栏作为Rust语言的入门级的文章&#xff0c;目的是为了分享关于Rust语言的编程技巧和知识。对于Rust语言&#xff0c;虽然历史没有C、和python历史悠远&#xff0c;但是它的优点可以说是非常的多&#xff0c;既继承了C运行速度&#xff0c;还拥有了Java…

zookeeper的部署

一 先下载zookeeper 二 解压包 三 修改配置文件 四 把配好文件传到其他的节点上面 五 在每个节点的dataDir指定的目录下创建一个 myid 的文件 六 配置zook的启动脚本 七 设置开机自启 八 分别启动 九查看当前状态service zookeeper status 十 总结 一 先下载zookeeper …

Vue常见的事件修饰符

1.prevent:阻止默认事件(常用) 2. stop:阻止事件冒泡(常用) 3. once:事件只触发一次(常用) 4.captrue:使用事件的捕捉模式(不常用) 5.self:只有event.target是当前操作的元素时才触发事件(不常用) 6.passive:事件的默认行为立即执行&#xff0c;无需等待事件回调执行完毕(不常用…

网关 GateWay 的使用详解、路由、过滤器、跨域配置

一、网关的基本概念 SpringCloudGateway网关是所有微服务的统一入口。 1.1 它的主要作用是&#xff1a; 反向代理&#xff08;请求的转发&#xff09; 路由和负载均衡 身份认证和权限控制 对请求限流 1.2 相比于Zuul的优势&#xff1a; SpringCloudGateway基于Spring5中…

Go微服务实践 - Rpc核心概念理解

概述 从0研究一下Golang已经Golang的微服务生态体系&#xff0c;Golang的微服务首先要从Rpc开始&#xff0c;在升级到Grpc&#xff0c;详细介绍这些技术点都在解决什么技术问题。 Rpc Rpc (Remote Procedure Call) 远程过程调用&#xff0c;简单的理解是一个节点请求另一个节…

集成学习算法是什么?如何理解集成学习?

什么是集成学习&#xff1f; 集成学习通过建立几个模型来解决单一预测问题。它的工作原理是生成多个分类器/模型&#xff0c;各自独立地学习和作出预测。这些预测最后结合成组合预测&#xff0c;因此优于任何一个单分类的做出预测。 机器学习的两个核心任务 任务一&#xff1…

【JavaEE】Spring Boot - 日志文件

【JavaEE】Spring Boot 开发要点总结&#xff08;3&#xff09; 文章目录 【JavaEE】Spring Boot 开发要点总结&#xff08;3&#xff09;1. 日志有什么作用2. 日志格式2.1 日志框架原理 3. 日志的打印3.1 System.out.println3.2 使用日志框架3.3 日志级别3.3.1 设置默认日志显…

自监督去噪:Noise2Self原理分析及实现 (Pytorch)

文章地址:https://arxiv.org/abs/1901.11365 代码地址: https://github.com/czbiohub-sf/noise2self 要点   Noise2Self方法不需要信号先验信息、噪声估计信息和干净的训练数据。唯一的假设就是噪声在测量的不同维度上表现出的统计独立性&#xff0c;而真实信号表现出一定的…

Vue Router 的query和params的区别?

区别一&#xff1a; &#xff08;1&#xff09;query相当于get请求&#xff0c;页面跳转的时候可以在地址栏看到请求参数 &#xff08;2&#xff09;params相当于post请求&#xff0c;参数不会在地址栏中显示&#xff0c;所以用params传值相对安全 &#xff08;简记&#xff1…

C++ | C++11新特性(上)

目录 前言 一、列表初始化 二、声明 1、auto 2、decltype 3、nullptr 三、STL容器的变化 四、右值引用与移动语义 1、左值与左值引用 2、右值与右值引用 3、右值引用与左值引用的比较 4、右值引用的场景及意义 &#xff08;1&#xff09;做参数 &#xff08;2&a…

Python连接Hive实例教程

一 Python连接hive环境实例 经在网络查询相关的教程&#xff0c;发现有好多的例子&#xff0c;发现连接底层用的的驱动基本都是pyhive和pyhs2两种第三方库的来连接的 hive,下面将简介windows 10 python 3.10 连接hive的驱动程序方式&#xff0c;开发工具&#xff1a;pycharm …

layui之layer弹出层的icon数字及效果展示

layer的icon样式 icon如果在信息提示弹出层值(type为0)可以传入0-6&#xff0c;icon与图标对应关系如下&#xff1a; 如果是加载层&#xff08;type为3&#xff09;可以传入0-2&#xff0c;icon与图标对应关系如下&#xff1a;

基于fpga的电子时钟

文章目录 前言实验手册一、实验目的二、实验原理1&#xff0e;理论原理2&#xff0e;硬件原理 三、系统架构设计四、模块说明1&#xff0e;模块端口信号列表按键消抖模块&#xff08;key&#xff09;计数器模块&#xff08;counter&#xff09;蜂鸣器乐谱模块(music)蜂鸣器发声…

有没有好用的在线画图工具推荐?

绘画是设计师最常见的工作之一&#xff0c;设计师对在线绘画工具的要求越来越高&#xff0c;市场上也出现了各种在线绘画工具&#xff0c;让设计师不知道如何选择高质量的在线绘画工具&#xff0c;一个好的在线绘画工具不仅可以让你轻松绘画&#xff0c;而且可以让你的工作效率…