需求:通过按钮的点击事件控制另一个输出框/按钮的点击

news2024/11/16 14:07:20

目录

第一章 接到需求

第二章 了解需求

第三章 解决需求 

第四章 优化代码

第五章 解决问题


第一章 接到需求

  • 最近开发的时候遇到这么一个事,技术经理是个全栈,已经把接口生成了,而且前端页面也写好了一个初稿,操作什么的功能基本上已经布局好了,如下:

经理说需求了:这里有两个按钮,一个是导入文件的,一个是导入机构的,你看看怎么把这按钮功能实现,把excel文件导入进去,后台的接口已经写好了 

第二章 了解需求

  • 然后小编接到需求了,clone下代码,根据路由找到对应的页面代码(注释的部分是小编已经写好的代码):

  •  发现这里就是两个按钮,然后设置了权限一些其他配置。
  • (注意事项:我们很多人有的时候为了语义化一些特别容易出现一个问题:就是会用到关键字,比如小编一开始看这个代码的时候,上面写的是@click="import(scope.row.id)",好家伙,不细看不知道,代码一跑吓一跳,直接控制台报错,一定要留意,import是关键字,我们不要直接定义!!!语义化命名不要命名到关键字!!!
  • 好了,接下来进入正题:当我们拿到这么一个需求,首先我们分析一下,很明显,我们拿到的需求是一个上传文件的功能实现,平常我们上传文件很多时候会用到element、antd等等一些框架类的东西来实现这么一个功能。那么问题来了,我们这里就只有按钮,样式、布局都确定了,而且不管我们怎么点击,都没反应。那么接下来我们考虑的是不是给按钮添加点击事件 -> 调出本地文件管理器 -> 点击我们需要上传的文件 -> 上传成功拿到文件的二进制流 -> 准备上传的参数 -> 像后端发送请求 -> 后端返回成功/失败的数据 -> 前端拿到数据进行处理,那么难点在哪呢:一个按钮,怎么能调出本地的文件管理器呢,又怎么知道我们点击文件上传了呢,对于用很多组件的我们来说可能就麻烦了,去找组件啥啥啥,但是小编觉得,是的,组件或许能帮我们实现这么个需求,但是我们难道没有别的方法了吗?
  • 原生标签:input!!!小编回忆,最开始学习html的时候有个标签input,小编也不绕圈了,设置type="file"就是文件上传的按钮!!

  • 回忆一下,看如下文档:

HTML input type 属性 | 菜鸟教程

第三章 解决需求 

  • 好了,用到的工具有了,现在的问题在于如何解决我们利用导入的按钮操作文件上传的按钮?
  • 思路:小编为按钮与input都绑定唯一识别的ref(vue)/id(正常的html页面)以及click点击事件,原生js会告诉我们,当我们绑定id时,获取到DOM之后,我们能通过DOM.click获取到DOM上绑定的点击事件。问题解决!
  • 大家根据小编的代码理解逻辑:(小编会逐步解释的) 

html: 

// 这里是element-ui的button组件
<el-button 
    v-if="hasPermission('book:book:import')" // 通过权限控制图标显示隐藏(可忽略)
    type="text" //button的type(可忽略)
    icon="el-icon-import" // 图标类名(可忽略)
    size="small" // 尺寸
    @click="toImportBookList(scope.row.id)"> // 按钮的点击事件,传的参数是该行数据的id
    导入</el-button>
// 原生的input
<input 
    type="file" // 上传文件的类型
    accept=".xls,.xlsx" // 限制上传的文件格式
    :ref="`upload-book-list-file-${scope.row.id}`"  // 唯一识别的ref,利用id使得渲染时ref不重名
    style="display: block" // 控制该标签的显示隐藏
    @click="importBookList(scope.row.id)"> // 该标签的点击事件

js:(注意一定要理解思路,而不是直接拷贝代码)

export default {
  methods: { // vue:方法
    toImportBookList (id) { // 按钮的点击事件
      const bookListFileUplodDom = this.$refs[`upload-book-list-file-${id}`] // 通过$refs获取对应的input标签
      bookListFileUplodDom.click() // 注意这句代码,他就是通过dom调用自身的点击事件
    },
    importBookList (id) { // input标签的点击事件
      const _this = this
      const bookListFileUplodDom = this.$refs[`upload-book-list-file-${id}`] // 通过$refs获取input标签
      bookListFileUplodDom.addEventListener('change', function (e) { // input标签监听事件,当input发生变化时说明文件要么上传了,要么删除了,上传成功执行如下代码
        const file = bookListFileUplodDom.files[0] // 该方法只针对input、type="file"或者图片,才能使用他获取到file的二进制流
        const formBody = new FormData() // 这里的formData小编就不多说了,已经用到很多次了,小编会有单独的详细的文章做讲解
        formBody.append('file', file)
        formBody.append('id', id)
        this.loading = true // 添加加载中(可忽略)
        bookService.importBook(formBody).then(({data}) => { // 这里是发送请求系列信息,仅供参考
          this.$message.success({ // 请求成功后返回信息
            dangerouslyUseHTMLString: true,
            message: data
          })
          this.refreshList() // 刷新列表
        }).catch(err => { // 出错了则捕获错误
          this.loading = false // 隐藏加载中
          console.log('出错了', err)
        })
      }, false)
    }
  }
}

第四章 优化代码

  • 使用e.stopPropagation()

阻止事件冒泡,使用addEventListener,三个参数,第三个参数小编设置了false,表示的是事件冒泡,由里向外触发,子元素的点击事件触发之后,之后还会触发父元素的点击事件,从而导致我们点击事件执行到不需要执行的事件,触发顺序:children -> parent -> body,添加e.stopPropagation()就只会执行我们点击的标签的点击事件。代码如下:

bookListFileUplodDom.addEventListener('change', function (e) {
  e.stopPropagation() // 阻止冒泡事件(注意该方法写在代码前面)
  ……(其余代码逻辑)
}, false)
  • addEventListener我们注册的监听'change'函数有两种情况:当上传文件成功时,input变化了,会执行代码,然后向发送请求,当然,当我们删除文件时,文件都为空了,还需要执行代码,向后端发请求吗?所以需要我们判断一下,当删除文件时,不执行代码,不向后端发送请求

 

 通过输出可以看到,删除文件时,file拿到的值是undefined,那么我们就能通过判断来解决该问题了,代码如下:

bookListFileUplodDom.addEventListener('change', function (e) {
  e.stopPropagation() // 阻止冒泡事件(注意该方法写在代码前面)
  const file = bookListFileUplodDom.files[0]
  if(file){ // 只有当file有数据时才执行如下逻辑
    ……(其余代码逻辑)
  }
}, false)
  •  addEventListener注册了还需要removeEventListener移除事件,如何removeEventListener移除呢,在哪移除呢,解决方法在下一章节

第五章 解决问题

  • 查看问题,不如不添加removeEventListener的效果,当我们执行多次导入时,也就相当于注册了很多个addEventListener('change',function(e){})事件,就会造成当我们只执行一次有效操作时,多个监听开始执行,导致最终前端会发送多个相同的请求

 

  • (这里直接给出小编的最终解决完成的源代码,如果大家进一步知道原理,小编会在下一篇文章中说明原因,做详细的解释!)
  • 原理看该文章

js基础:addEventListener与removeEventListener使用时,涉及的问题(包括事件捕获、冒泡,removeEventListener不生效问题)-CSDN博客

<script>

let bookListHandler = null // 定义一个自变量的等待赋值(移除监听函数使用)

export default {

  methods: {
    toImportBookList (id) {
      const bookListFileUplodDom = this.$refs[`upload-book-list-file-${id}`]
      bookListFileUplodDom.removeEventListener('change', bookListHandler, false) // 每次调用函数执行移除上一次的添加的监听
      bookListFileUplodDom.click()
    },
    importBookList (id) {
      const _this = this
      const bookListFileUplodDom = this.$refs[`upload-book-list-file-${id}`]
      console.log('bookListFileUplodDom', bookListFileUplodDom)
      bookListHandler = function (e) { // 将执行的监听函数赋值
        e.stopPropagation()
        _this.getBookList(id, bookListFileUplodDom)
      }
      bookListFileUplodDom.addEventListener('change', bookListHandler, false) // 添加监听事件
    },
    getBookList (id, bookListFileUplodDom) {
      const file = bookListFileUplodDom.files[0]
      console.log('file', file)
      if (file) {
        const formBody = new FormData()
        formBody.append('file', file)
        formBody.append('id', id)
        this.loading = true
        bookService.importBook(formBody).then(({data}) => {
          this.$message.success({
            dangerouslyUseHTMLString: true,
            message: data
          })
          this.refreshList()
        }).catch(err => {
          this.loading = false
          console.log('出错了', err)
        })
      }
    },
  }
}
</script>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL数据库——SQL语法

Structured Query Language&#xff08;结构化查询语言&#xff09;&#xff0c;简称SQL&#xff0c;是用于操作关系型数据库的标准编程语言。SQL提供了一种与数据库交互的方式&#xff0c;可以用于查询、插入、更新和删除数据库中的数据。 1. SQL通用语法 SQL语句可以写在一…

【PID学习笔记11】连续系统的数字PID

写在前面 从本文开始将一块学习数字PID控制及其MATLAB仿真。本文重点介绍连续系统的数字PID控制仿真。 一、数字PID总览 基于刘金琨编著的《先进PID控制MATLAB仿真&#xff08;第4版&#xff09;》参考文献内容&#xff0c;我们一起学习以下数字式PID控制。 二、连续系统的…

c 实现jpeg中的ALI(可变长度整数转换)正反向转换

用于DC的ALI表&#xff1a;DIFF 就是前后两个8X8块DC的差值&#xff0c;ssss就是DIFF值用二进制表示的位数 亮度&#xff0c;与色度的DC都是这种处理的。两个相邻的亮度与亮度比差&#xff0c;色度与色度比差产生DIFF, 扫描开始DIFF等于0。 用于AC ALI表&#xff1a;表中的AC…

Leetcode—16.最接近的三数之和【中等】

2023每日刷题&#xff08;六十四&#xff09; Leetcode—16.最接近的三数之和 实现代码 class Solution { public:int threeSumClosest(vector<int>& nums, int target) {sort(nums.begin(), nums.end());int s 0;int diff INT_MAX / 2;int n nums.size();int a…

宣布推出 ML.NET 3.0

作者&#xff1a;Jeff Handley 排版&#xff1a;Alan Wang ML.NET 是面向 .NET 开发人员的开源、跨平台的机器学习框架&#xff0c;可将自定义机器学习模型集成到 .NET 应用程序中。ML.NET 3.0 版本现已发布&#xff0c;其中包含大量新功能和增强功能&#xff01; 此版本中的深…

比 style gan 更好的 style gan2

上一篇博客介绍了style gan 原理&#xff0c;但是 style gan 的结果会有水珠伪影&#xff0c;作者实验后发现是 Adain 导致的&#xff0c;AdaIN对每一个feature map的通道进行归一化&#xff0c;这样可能破坏掉feature之间的信息。当然实验证明发现&#xff0c;去除AdaIN的归一…

轻量级购物小程序H5产品设计经典样例

主要是看到这个产品设计的不错值得借鉴特记录如下&#xff1a; 不过大多数购物app都大致相同&#xff0c;这个算是经典样例&#xff0c;几乎都可以复制&#xff0c;我第一次使用&#xff0c;感觉和顺畅。看上去产品是经过打磨的&#xff0c;布局非常好。内容也很丰富。支持异业…

SpringCloud 分布式事务

一.介绍 首先我们看一个项目中的下单业务整体流程&#xff1a; 由于订单、购物车、商品分别在三个不同的微服务&#xff0c;而每个微服务都有自己独立的数据库&#xff0c;因此下单过程中就会跨多个数据库完成业务。而每个微服务都会执行自己的本地事务&#xff1a; 交易服务&…

uniapp-安卓APP开发时使用手机调试

调试 1. 手机打开开发者模式: 华为手机举列-->设置-->关于手机-->版本号&#xff0c;多次连续点击“版本号”&#xff0c;就会提示已打开开发者模式 2. 华为手机举列-->设置-->系统和更新-->开发人员选项-->打开 USB调试&#xff0c;进入调试模式 3. 先…

路由器设置代理IP教程,http代理怎么固定IP地址?

路由器设置代理IP教程 一、确定代理IP地址 首先&#xff0c;你需要确定你要使用的代理IP地址。你可以从代理服务提供商处获取代理IP地址和端口号。 二、登录路由器管理界面 在浏览器中输入路由器的IP地址&#xff0c;输入账号和密码&#xff0c;进入路由器的管理界面。 三、设置…

k8s集群1.23.0版本部署说明

1.部署 k8s1.23.0版本与1.26.0版本的部署基本差不多&#xff0c;只不过k8s 1.23版本不需要部署cri-docker&#xff0c;所以只需要在1.26.0版本部署的基础上不要cri-docker的部署即可 参考&#xff1a;kubeadm部署k8s 1.26.0版本高可用集群_kubeadm 高可用集群-CSDN博客 搭建…

xcode无线真机调试详细图文步骤

步骤一、 步骤二&#xff1a; 步骤三&#xff1a; 配置完到这里&#xff0c;点击真机右键&#xff0c;菜单栏并未出现connect via ip address 选项&#xff0c;也没出现无线连接的小地球图标&#xff0c;别慌&#xff0c;接着进行下一步操作即可。 步骤四&#xff1a; 1.打开…

【C++】对象特性:无参有参构造函数,拷贝构造函数,析构函数

目录 对象的初始化和清理1.1 构造函数和析构函数1.2 构造函数的分类及调用1.3 拷贝构造函数调用时机1.4 构造函数调用规则1.5 深拷贝与浅拷贝 对象的初始化和清理 生活中我们买的电子产品都基本会有出厂设置&#xff0c;在某一天我们不用时候也会删除一些自己信息数据保证安全。…

个人用户的数据之美:数据可视化助力解读

数据可视化是一种强大的工具&#xff0c;不仅可以为企业和专业人士提供见解&#xff0c;也对个人用户带来了许多实际的帮助。下面我就以一个数据可视化从业者的视角&#xff0c;来谈谈数据可视化对个人用户的益处&#xff1a; 首先对于个人用户来说&#xff0c;数据可视化可以让…

代码规范-代码注释,及注释辅助工具

文章目录 代码规范-代码注释&#xff0c;及注释辅助工具1.常见代码块注释提示标签2.JSDoc3.注释格式 参考&#xff1a;https://knightyun.github.io/2020/03/13/js-comment-format 代码规范-代码注释&#xff0c;及注释辅助工具 1.常见代码块注释提示标签 descfileauthorpara…

【python与机器学习2】激活函数

目录 1 什么是激活函数&#xff1f; activation function 1.1 阈值 1.2 激活函数a(x) &#xff0c;包含偏置值θ 1.3 激活函数a(x) &#xff0c;包含偏置值b 2 激活函数1: 单位阶跃函数 2.1 函数形式 2.2 函数图形 2.3 函数特点 2.4 代码实现这个 单位阶跃函数 3 激活…

GaussDB数据库表创建行访问控制策略

目录 一、前言 二、GaussDB中的行访问控制 1、CREATE ROW LEVEL SECURITY POLICY语法 2、ALTER ROW LEVEL SECURITY POLICY语法 3、ROW LEVEL SECURITY策略与适配SQL语法关系 三、GaussDB中的行访问控制策略示例 1、实现GaussDB行访问控制的一般步骤 2、行访问控制策略…

使用深度学习的微光图像和视频增强:综述

1INTRODUCTION 微光图像增强&#xff08;LLIE&#xff09;旨在提高在光照较差的环境中捕获的图像的感知或可解释性。该领域的最新进展主要是基于深度学习的解决方案&#xff0c;其中采用了许多学习策略、网络结构、损失函数、训练数据等。在本文中&#xff0c;我们提供了一个全…

用 SpringBoot+Redis 解决海量重复提交问题

1 前言 在实际的开发项目中,一个对外暴露的接口往往会面临很多次请求&#xff0c;我们来解释一下幂等的概念&#xff1a;**任意多次执行所产生的影响均与一次执行的影响相同 。**按照这个含义&#xff0c;最终的含义就是 对数据库的影响只能是一次性的&#xff0c;不能重复处理…