点击按钮更新href下载文件时出现无限下载循环的问题排查
解决按钮触发文件下载时的无限循环问题
尝试实现点击按钮下载文件,步骤如下:
- 点击按钮调用API获取文件Buffer Data
- 将Buffer转换为base64 URL,更新
<a>元素的href属性 - 函数内部触发
<a>元素的点击事件
该方法能成功下载文件,但会出现无限下载的情况。
原代码
调用方式
<button v-on:click="this.getImage([imageID, imageName], $event)"><a>View scoresheet</a></button>
函数代码
getImage: async function(info, event){ fetch('endpoint' + String(info[0]) + "/" + String(info[1]) , { method: 'GET', }) .then(response => response.json()) .then(async result => { var image_data = await result.image_buffer.data var imgSrc = "data:image/jpg;base64," + btoa( image_data.reduce((data, byte) => data + String.fromCharCode(byte), '') ); event.target.href = imgSrc event.target.download = 'image.jpg' event.target.click() }) },
问题原因
- DOM结构不符合规范:按钮内部嵌套
<a>标签违反HTML语义,会导致事件冒泡干扰。 - 事件循环触发:当调用
event.target.click()时:- 若
event.target是按钮元素,点击会再次触发绑定的getImage方法,形成无限循环; - 若
event.target是内部的<a>元素,其点击事件会冒泡到父级按钮,再次触发getImage,导致无限下载。
- 若
解决办法
方案1:使用隐藏的独立<a>元素(推荐)
修改DOM结构,将用于下载的<a>元素单独隐藏,避免事件冒泡干扰:
<button v-on:click="getImage([imageID, imageName])">View scoresheet</button> <!-- 隐藏的下载专用a标签 --> <a ref="downloadLink" style="display: none;"></a>
修改函数代码,通过Vue的ref获取隐藏元素触发下载:
getImage: async function(info){ try { const response = await fetch(`endpoint${info[0]}/${info[1]}`, { method: 'GET' }); const result = await response.json(); const image_data = result.image_buffer.data; const imgSrc = "data:image/jpg;base64," + btoa( image_data.reduce((data, byte) => data + String.fromCharCode(byte), '') ); const downloadLink = this.$refs.downloadLink; downloadLink.href = imgSrc; downloadLink.download = 'image.jpg'; downloadLink.click(); } catch (error) { console.error('下载失败:', error); } },
方案2:临时阻止事件冒泡
若不想调整DOM结构,可在触发<a>点击时阻止事件冒泡,避免触发按钮的点击事件:
getImage: async function(info, event){ fetch('endpoint' + String(info[0]) + "/" + String(info[1]) , { method: 'GET', }) .then(response => response.json()) .then(async result => { var image_data = await result.image_buffer.data var imgSrc = "data:image/jpg;base64," + btoa( image_data.reduce((data, byte) => data + String.fromCharCode(byte), '') ); // 精准获取内部的a元素 const aElement = event.currentTarget.querySelector('a'); aElement.href = imgSrc; aElement.download = 'image.jpg'; // 单次阻止事件冒泡 aElement.addEventListener('click', function(e) { e.stopPropagation(); }, { once: true }); aElement.click(); }) },
内容的提问来源于stack exchange,提问作者doozy
相关产品推荐
相关产品推荐

