我可以在JavaScript中以编程方式为文件输入元素触发“点击”事件吗?


261

我想以<input type="file">编程方式在标签上触发click事件。

仅调用click()似乎没有任何作用,或者至少它没有弹出文件选择对话框。

我一直在尝试使用侦听器捕获事件并重定向事件,但是我无法像某些人单击它那样实际地执行事件。


1
您触发的点击事件必须在用户启动的点击事件中调用,否则将无法正常工作。
Umagon '16

Answers:


79

你可以这样做,在所有的浏览器,IE理应不会允许它,但Mozilla和Opera没有。

当您在GMail中编写邮件时,“附加文件”功能是针对IE和支持该功能的任何浏览器的一种方法,然后针对Firefox和不支持该功能的浏览器的另一种方法。

我不知道为什么你不能做到这一点,但有一点安全风险,并且不允许你在任何浏览器做的,是编程设置HTML文件元素的文件名。


1
德拉特 好吧,我当然理解它是可利用的。这在任何地方都有记录吗?我想它将由每个浏览器实现吗?
user28655

更新了我的答案,使其比以前的答案更正确-要旨是相同的,但澄清应该有所帮助。这个家伙遇到了同样的问题:bytes.com/forum/thread542877.html
杰森·邦廷

谢谢上帝,FF5允许此点击
rshimoda 2011年

2
为了澄清以上评论:Chrome最近更改为检查文件input元素是否可见。click如果可以看到该元素,则触发该方法将起作用,包括在控制台中。
jwadsa​​ck 2012年

2
@Otvazhnii-老兄,这个答案(你说的是错误的)已经10岁了-毫不奇怪,它是不正确的!(我不确定,我相信你的意思)。:P
杰森邦廷

257

我整天都在寻找解决方案。这些是我得出的结论:

  1. 出于安全原因,Opera和Firefox不允许触发文件输入。
  2. 唯一方便的替代方法是创建一个“隐藏”文件输入(使用不透明度,而不是“隐藏”或“显示:无”!),然后在其下方创建按钮。通过这种方式可以看到按钮,但在用户单击时实际上会激活文件输入。

希望这可以帮助!:)

<div style="display: block; width: 100px; height: 20px; overflow: hidden;">
<button style="width: 110px; height: 30px; position: relative; top: -5px; left: -5px;"><a href="javascript: void(0)">Upload File</a></button>
<input type="file" id="upload_input" name="upload" style="font-size: 50px; width: 120px; opacity: 0; filter:alpha(opacity=0);  position: relative; top: -40px;; left: -20px" />
</div>

6
这个解决方案效果很好。不知道为什么它被忽视和未升级。*并不是问题的确切要求,但这是一个很好的解决方法。您是否发现它与任何浏览器都不兼容?我没有时间花所有10多种相关口味进行测试。
叶夫根尼·辛金

1
谢谢你的回答,太棒了:D
mario.tco 2011年

不错的解决方案。也适用于android移动浏览器。
gstroup 2012年

1
这是不正确的,请参阅下面的迪迪埃回应。程序化点击必须来自用户操作上下文-就像另一个按钮的点击处理程序一样。然后工作正常,不需要溢出元素。
抽烟

1
唯一的问题是,如果要在悬停时更改按钮样式,则不能。这意味着如果您希望它看起来像应用程序中的所有其他按钮,那您就不能这样做。
文森特

68

您可以在任何浏览器上触发click(),但是某些浏览器需要该元素可见并集中。这是一个jQuery示例:

$('#input_element').show();
$('#input_element').focus();
$('#input_element').click();
$('#input_element').hide();

它可以与hide之前的hide一起工作,click()但是我不知道是否在不调用show方法的情况下可以工作。我从未在Opera上尝试过此功能,而是在IE / FF / Safari / Chrome上进行了测试,并且可以正常工作。我希望这将有所帮助。


51
感谢分享。以防万一您不知道-您可以在jQuery中使用链接:$(...).show().focus().click().hide();:)
pimvdb 2011年

1
@pimvdb:据我测试,您的解决方案仅适用于Chrome。
晃龙

1
@HoàngLong:您是说连锁还是Florin Mogos的解决方案?我不认为链接将对跨浏览器产生任何影响。
pimvdb 2011年

1
@HoàngLong它适用于IE 8和9,最新的Chrome,Safari和Firefox。
Sami Samhuri

2
奇怪。如我所测试,它在Ubuntu中的Chrome下无法正常工作。
sandrew 2011年

29

这是可能的:在FF4 +,Opera?,Chrome下:但是:

  1. inputElement.click()应该从用户操作上下文中调用!(不是脚本执行上下文)

  2. <input type="file" />应该是可见的(inputElement.style.display !== 'none')(您可以使用可见性或其他方式隐藏它,但不能使用“显示”属性来隐藏它)


这为我解决了。我必须将javascript添加到onclick属性,而不是绑定到事件。
jasonlfunk

1
提出唯一合理的解决方案。溢出方法很丑陋。
2014年

哈!我知道这一定与上下文有关!我观察到inputElement.click()从keydown事件(连接文件的快捷方式)中进行调用是可行的,但是在超时或ajax回调中进行调用则无效。已投票。
brettjonesdev

9
顺便说一句,在“用户操作上下文”和“脚本执行上下文”上是否还有其他资源?我在搜索时看到的所有内容都与执行上下文和this。:/
brettjonesdev

@bretjonesdev我认为这意味着它需要在用户启动的事件处理程序中执行,例如单击事件处理程序,而不是promise,超时或任何其他非用户启动的事件。
Alex Guerra

10

对于那些了解您必须在链接上覆盖不可见形式但又懒得写的人,我为您编写了它。好吧,对我而言,但不妨分享一下。欢迎发表评论。

HTML(某处):

<a id="fileLink" href="javascript:fileBrowse();" onmouseover="fileMove();">File Browse</a>

HTML(您不关心的地方):

<div id="uploadForm" style="filter:alpha(opacity=0); opacity: 0.0; width: 300px; cursor: pointer;">
    <form method="POST" enctype="multipart/form-data">
        <input type="file" name="file" />
    </form>
</div>

JavaScript:

function pageY(el) {
    var ot = 0;
    while (el && el.offsetParent != el) {
        ot += el.offsetTop ? el.offsetTop : 0;
        el = el.offsetParent;
    }
    return ot;
}

function pageX(el) {
    var ol = 0;
    while (el && el.offsetParent != el) {
        ol += el.offsetLeft ? el.offsetLeft : 0;
        el = el.offsetParent;
    }
    return ol;
}

function fileMove() {
    if (navigator.appName == "Microsoft Internet Explorer") {
        return; // Don't need to do this in IE. 
    }
    var link = document.getElementById("fileLink");
    var form = document.getElementById("uploadForm");
    var x = pageX(link);
    var y = pageY(link);
    form.style.position = 'absolute';
    form.style.left = x + 'px';
    form.style.top = y + 'px';
}

function fileBrowse() {
    // This works in IE only. Doesn't do jack in FF. :( 
    var browseField = document.getElementById("uploadForm").file;
    browseField.click();
}



7

如果您希望该click方法在Chrome,Firefox等上运行,请对输入文件应用以下样式。它会被完全隐藏,就像您做一个display: none;

#fileInput {
    visibility: hidden;
    position: absolute;
    top: 0;
    left: -5000px;
}

就这么简单,我测试了它的工作原理!


我最喜欢这种方式,因为如果某些旧版浏览器被隐藏,它们将不会对inputElement.click()执行任何操作。
尼克,

为什么不只将height和设置width0
所罗门·乌科

5
$(document).one('mousemove', function() { $(element).trigger('click') } );

当我遇到类似问题时为我工作,这是常规的eRube Goldberg。


4

解决方案

让我添加到这个旧帖子中,我曾经使用过一个有效的解决方案,该解决方案可以在所有新旧浏览器中的80%或更多使用。

解决方案既复杂又简单。第一步是利用CSS并通过“ under-elements”掩盖输入文件的类型,因为它的不透明度为0。下一步是使用JavaScript根据需要更新其标签。

HTML 如果您想要一种快速的方法来访问特定元素,则只需插入ID,但是这些类是必需的,因为它们与设置整个过程的CSS有关

<div class="file-input wrapper">
    <input id="inpFile0" type="file" class="file-input control" />
    <div class="file-input content">
        <label id="inpFileOutput0" for="inpFileButton" class="file-input output">Click Here</label>
        <input id="inpFileButton0" type="button" class="file-input button" value="Select File" />
    </div>
</div>

CSS 请记住,颜色和字体样式等完全是您的偏爱,如果您使用此基本CSS,则始终可以随心所欲地使用后端标记来标记样式,这在最后列出的jsFiddle中显示。

.file-test-area {
    border: 1px solid;
    margin: .5em;
    padding: 1em;
}
.file-input {
    cursor: pointer !important;
}
.file-input * {
    cursor: pointer !important;
    display: inline-block;
}
.file-input.wrapper {
    display: inline-block;
    font-size: 14px;
    height: auto;
    overflow: hidden;
    position: relative;
    width: auto;
}
.file-input.control {
    -moz-opacity:0 ;
    filter:alpha(opacity: 0);
    opacity: 0;

    height: 100%;
    position: absolute;
    text-align: right;
    width: 100%;
    z-index: 2;
}
.file-input.content {
    position: relative;
    top: 0px;
    left: 0px;
    z-index: 1;
}
.file-input.output {
    background-color: #FFC;
    font-size: .8em;
    padding: .2em .2em .2em .4em;
    text-align: center;
    width: 10em;
}
.file-input.button {
    border: none;
    font-weight: bold;
    margin-left: .25em;
    padding: 0 .25em;
}

JavaScript 纯正,但是,某些更旧(已淘汰)的浏览器可能仍会遇到问题(例如Netscrape 2!)

var inp = document.getElementsByTagName('input');
for (var i=0;i<inp.length;i++) {
    if (inp[i].type != 'file') continue;
    inp[i].relatedElement = inp[i].parentNode.getElementsByTagName('label')[0];
    inp[i].onchange /*= inp[i].onmouseout*/ = function () {
        this.relatedElement.innerHTML = this.value;
    };
};

工作jsFiddle示例


4

有用 :

出于安全原因,在Firefox和Opera上,您无法触发对文件输入的点击,但可以使用MouseEvents模拟:

<script>
click=function(element){
    if(element!=null){
        try {element.click();}
        catch(e) {
            var evt = document.createEvent("MouseEvents");
            evt.initMouseEvent("click",true,true,window,0,0,0,0,0,false,false,false,false,0,null);
            element.dispatchEvent(evt);
            }
        }
    };
</script>

<input type="button" value="upload" onclick="click(document.getElementById('inputFile'));"><input type="file" id="inputFile" style="display:none">

1
请注意,createEvent()initMouseEvent()现在已被弃用。
Alexis Wilke

4

我知道这已经很老了,所有这些解决方案都是针对具有实际价值的浏览器安全预防措施的黑客。

就是说,到目前为止,fileInput.click()在当前的Chrome(36.0.1985.125 m)和当前的Firefox ESR(24.7.0)中均可运行,但在当前的IE(11.0.9600.17207)中则无效。在按钮顶部覆盖具有不透明度0的文件字段是可行的,但是我希望将link元素用作可见触发器,并且悬停下划线在任何浏览器中都无法正常工作。它闪烁然后消失,可能是浏览器在思考是否确实应用了悬停样式。

但是我确实找到了在所有这些浏览器中都可以使用的解决方案。我不会声称已经测试了每种浏览器的每个版本,也不知道它将永远持续工作,但是现在看来可以满足我的需求。

很简单:将文件输入字段放在屏幕外(位置:绝对;顶部:-5000px),在其周围放置标签元素,然后触发对标签的单击,而不是文件字段本身。

请注意,链接确实需要编写脚本才能调用标签的click方法,它不会自动执行此操作,就像单击标签元素内的文本时一样。显然,link元素捕获了单击,并且没有将其传递到标签。

还要注意,由于该字段不在屏幕上,因此这不提供显示当前所选文件的方法。我想在选择文件后立即提交,所以这对我来说不是问题,但是如果您的情况有所不同,则需要采用某种不同的方法。


好的,在按钮标签上,onclick =“ filetag.click()”不适用于IE 9和10(但适用于IE 11,Firefox 4/10/26/27/28,Chrome / Chromium 31/32/33 / 36,Safari 7,Opera 23)。但是,如果您将标签用于=“ id-of-file-input”(不带onlick),则它适用于IE 9/10/11。
luigifab 2014年

4

JS小提琴:http : //jsfiddle.net/eyedean/1bw357kw/

popFileSelector = function() {
    var el = document.getElementById("fileElem");
    if (el) {
        el.click();  
    }
};

window.popRightAway = function() {
    document.getElementById('log').innerHTML += 'I am right away!<br />';
    popFileSelector();
};

window.popWithDelay = function() {
    document.getElementById('log').innerHTML += 'I am gonna delay!<br />';
    window.setTimeout(function() {
        document.getElementById('log').innerHTML += 'I was delayed!<br />';
        popFileSelector();
    }, 1000);
};
<body>
  <form>
      <input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)" />
  </form>
  <a onclick="popRightAway()" href="#">Pop Now</a>
    <br />
  <a onclick="popWithDelay()" href="#">Pop With 1 Second Delay</a>
    <div id="log">Log: <br /></div>
</body>


3

该代码对我有用。这是您要做什么?

<input type="file" style="position:absolute;left:-999px;" id="fileinput" />
<button  id="addfiles" >Add files</button>

<script language="javascript" type="text/javascript">
   $("#addfiles").click(function(){
      $("#fileinput").click();
   });
</script>

3

我的jQuery和jQuery-ui Safari浏览器解决方案:

$("<input type='file' class='ui-helper-hidden-accessible' />").appendTo("body").focus().trigger('click');

注意:不适用于Firefox 38(chrome 38)。trigger('click')仅在用户交互事件上下文中有效-事件处理程序。
阿米特G

3

这是解决此问题的纯JavaScript解决方案。在所有浏览器上均可正常运行

<script>
    function upload_image_init(){
        var elem = document.getElementById('file');
        if(elem && document.createEvent) {
           var evt = document.createEvent("MouseEvents");
           evt.initEvent("click", true, false);
           elem.dispatchEvent(evt);
        }
    }
</script>

2

有一些方法可以将事件重定向到控件,但是不要期望自己能够轻松地将事件触发到控件,因为出于(良好)安全原因,浏览器将尝试阻止事件。

如果您只需要在用户单击某些内容时显示文件对话框,例如,因为您希望更好看的文件上传按钮,那么您可能想看看Shaun Inman提出了什么

我已经能够通过创造性地将焦点移入和移出按键,按键和按键事件之间的控件来实现键盘触发。YMMV。

我的真诚建议是,不要管它,因为这是浏览器不兼容之痛的世界。较小的浏览器更新也可能会在没有任何警告的情况下阻止欺骗,并且您可能必须不断重新发明hack才能使其正常运行。


2

我之前对此进行了研究,因为我想创建一个自定义按钮,该按钮将打开文件对话框并立即开始上传。我只是注意到一些可能使之成为可能的东西-当您单击上载的任何位置时,Firefox似乎都会打开对话框。因此,可以执行以下操作:

  1. 创建一个文件上传和一个单独的元素,其中包含要用作按钮的图像
  2. 排列它们以使其重叠,并使文件元素背景和边界透明,因此按钮是唯一可见的
  3. 添加Javascript,以在单击按钮/文件输入时使IE打开对话框
  4. 选择文件后,使用onchange事件提交表单

这只是理论上的,因为我已经使用了另一种方法来解决该问题,但它可能会起作用。


2

我有一个<input type="button">看不见的标签。我所做的是将"onClick"事件附加到任何类型的可见组件上,例如标签。这是通过使用Google Chrome浏览器的开发人员工具或Mozilla Firefox的Firebug并通过右键单击“编辑HTML”命令来完成的。在这种情况下,请指定以下脚本或类似内容:

如果您有JQuery:

$('#id_of_component').click();

如果不:

document.getElementById('id_of_component').click();

谢谢。


2

嘿,这个解决方案有效。下载,我们应该使用MSBLOB

$scope.getSingleInvoicePDF = function(invoiceNumberEntity) {
   var fileName = invoiceNumberEntity + ".pdf";
   var pdfDownload = document.createElement("a");
   document.body.appendChild(pdfDownload);

   AngularWebService.getFileWithSuffix("ezbillpdfget",invoiceNumberEntity,"pdf" ).then(function(returnedJSON) {
       var fileBlob = new Blob([returnedJSON.data], {type: 'application/pdf'});
       if (navigator.appVersion.toString().indexOf('.NET') > 0) { // for IE browser
           window.navigator.msSaveBlob(fileBlob, fileName);
       } else { // for other browsers
           var fileURL = window.URL.createObjectURL(fileBlob);
           pdfDownload.href = fileURL;
           pdfDownload.download = fileName;
           pdfDownload.click();      
       }
   });
};

对于AngularJS甚至普通的javascript。


1

现在,这在Firefox 4中将成为可能,但需要注意的是,它被视为弹出窗口,因此只要有弹出窗口就将被阻止。


2
实际上,firefox4大大改善了文件上传的状态。我的麻烦是如何在Google Chrome浏览器中执行相同的操作。
erick2red 2011年

1

这是对我有用的解决方案: CSS:

#uploadtruefield {
    left: 225px;
    opacity: 0;
    position: absolute;
    right: 0;
    top: 266px;
    opacity:0;
    -moz-opacity:0;
    filter:alpha(opacity:0);
    width: 270px;
    z-index: 2;
}

.uploadmask {
    background:url(../img/browse.gif) no-repeat 100% 50%;
}
#uploadmaskfield{
    width:132px;
}

带有“小” JQuery帮助的HTML:

<div class="uploadmask">
    <input id="uploadmaskfield" type="text" name="uploadmaskfield">
</div>
<input id="uploadtruefield"  type="file" onchange="$('#uploadmaskfield').val(this.value)" >

只要确保maskfied被真正的上载字段完全覆盖即可。



1

我发现如果input(file)在表单之外,则触发click事件将调用文件对话框。


1

希望这对某人有帮助-我花了2个小时将头撞向它:

在IE8或IE9中,如果您以任何方式触发使用javascript打开文件输入(相信我,我已经尝试了所有方法),它不会让您使用javascript提交表单,只会无声地失败。

通过常规的提交按钮提交表单可能有效,但可以调用form.submit();。将无声地失败。

我不得不求助于我的选择文件按钮覆盖一个有效的透明文件输入。


另外,您可以将文件输入包装在标签中,以便在IE中可以获取标签的可单击区域以覆盖整个按钮区域,而仅使用文件输入标签,在IE中只有一半是可单击的。
加拉太书

1

这为我工作:

<script>
    function sel_file() {
        $("input[name=userfile]").trigger('click');
    }  
</script>

<input type="file" name="userfile" id="userfile" />

<a href="javascript:sel_file();">Click</a>

1

这不是不可能的:

var evObj = document.createEvent('MouseEvents');
evObj.initMouseEvent('click', true, true, window);  
setTimeout(function(){ document.getElementById('input_field_id').dispatchEvent(evObj); },100);

但是以某种方式,它只有在通过点击事件调用的函数中才有效。

因此,您可能需要进行以下设置:

的HTML:

<div onclick="openFileChooser()" class="some_fancy_stuff">Click here to open image chooser</div>
<input type="file" id="input_img">

JavaScript:

    function openFileChooser() {
      var evObj = document.createEvent('MouseEvents');
      evObj.initMouseEvent('click', true, true, window);  
      setTimeout(function()
      { 
        document.getElementById('input_img').dispatchEvent(evObj);      
      },100);      
    }

createEvent()initMouseEvent()被弃用。您必须立即使用CustomEvent()...
Alexis Wilke

0

您可以使用

<button id="file">select file</button>
<input type="file" name="file" id="file_input" style="display:none;">
<script>
$('#file').click(function() {
        $('#file_input').focus().trigger('click');
    });
</script>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.