以编程方式触发“选择文件”对话框。

124

我有一个隐藏的文件输入元素。是否可以在按钮的点击事件中触发它的“选择文件”对话框?

15个回答

167

如果你想要自己的上传文件按钮而不是使用 <input type="file" />,你可以这样做:

<input id="myInput" type="file" style="visibility:hidden" />
<input type="button" value="Show Dialog" onclick="$('#myInput').click();" />

请注意我使用了visibility: hidden而不是display: none。这是因为在非显示的文件输入框上无法调用点击事件。


对于基本情况来说很简单,但不兼容许多浏览器。请注意最好的方法是将此解决方案与在opacity:0下将文件输入元素覆盖在按钮上的方式相结合,正如Xeon06的答案中所提到的那样。 - SquareCat
14
更新:在现代浏览器中,您甚至可以单击不在DOM中的输入框。太棒了! - Adria
8
我刚刚尝试了在一个display:none的输入框上使用click(),它起作用了。 - Daniel Cheung
18
没错,在2015年,使用click()来点击一个display: none的元素是可行的!;) 这些年发生了多大的变化。 - ffxsam
1
你可以使用 hidden 属性代替 style="visibility:hidden"<input id="myInput" type="file" hidden>(https://www.w3schools.com/tags/att_global_hidden.asp) - cespon

134

这里大多数答案缺少有用的信息:

是的,你可以使用jQuery/JavaScript编程方式点击输入元素,但只有在属于由用户启动的事件处理程序中才能这样操作!

例如,如果您在ajax回调中以编程方式点击按钮,则不会发生任何事情,但如果您将相同的代码行放入由用户引发的事件处理程序中,则它将起作用。

P.S. 如果在程序化点击之前使用debugger;关键字,它将破坏浏览窗口...至少在Chrome 33中...


正如@LouisBataillard所指出的那样:原始事件处理程序不仅需要由用户启动;它必须是一个特定的点击事件。这是他提供的演示:[链接](http://jsfiddle.net/UQfaZ/1/) - Souhaieb Besbes
1
你可以点击动态生成的元素。在 jQuery 中,代码如下:$(staticElementParent).on("click", "dynamicChild", function(){}) - Daniel Cheung
1
谢谢!!!我一直在JavaScript控制台中测试所有这些答案,我都快疯了! - jdkealy
8
我已经艰难地花了半个小时来编写程序并调出一个文件输入窗口。没有其他人说过,如果事件不是由用户启动的话,这是不可能的……你应该得到很多个“赞”。 - Umagon
2
从Chrome 62开始,debugger;关键字不再中断编程点击。 - Chris W.
显示剩余3条评论

75

仅供参考,这里有一种不需要 JavaScript 的替代方案。这是一个小技巧,利用了标签的点击行为可以将焦点设置到相关联的输入框上。

你需要一个带有正确 for 属性(指向输入框)的 <label>,可选地使用按钮样式(使用 Bootstrap,可以使用 btn btn-default)。当用户点击标签时,对话框会打开,例如:

<!-- optionnal, to add a bit of style -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"/>

<!-- minimal setup -->
<label for="exampleInput" class="btn btn-default">
  Click me
</label>
<input type="file" id="exampleInput" style="display: none" />


3
我喜欢这个,不想在我的Angular项目中包含完整的jQuery,它运行得很好 :) - Starscream1984
1
这种行为在所有现代浏览器中都可靠吗? - JoshuaDavid
这个功能完全不需要使用JS,而是利用浏览器本身的行为。结合onDrop事件,实现一个功能丰富的文件上传非常棒! - Yanick Rochon
我不得不调整CSS,但最终它起作用了 - 也就是说,在所有浏览器中,“display:none”不适用于文件输入可见性。 (但可以使用0的不透明度等) - floer32
如果您不希望意外点击它,请添加pointer-events: none;。请参阅https://zellwk.com/blog/hide-content-accessibly/,了解各种选项的可访问性影响的讨论。 - s6mike

15

我不确定浏览器如何处理对 type="file" 元素的点击(出于安全方面的考虑),但这应该能够起作用:

$('input[type="file"]').click();
我已在Chrome、Firefox和Opera中测试过这个JSFiddle,它们都显示了文件浏览对话框。

5
这似乎只在“调用”事件本身是点击事件时才有效。例如,基于“悬停”事件打开文件对话框似乎是不可能的:http://jsfiddle.net/UQfaZ/1/ - Louis B.
你知道如果输入不在DOM中,如何使用Selenium进行测试吗? - Sebastien Lorber

8

现在这样的混合解决方案可以提供最佳的体验。

let fileHandle;
async function fileOpen() {
    [fileHandle] = await window.showOpenFilePicker();
    const file = await fileHandle.getFile();
    console.log(await file.text());
}
// The advantage of this is fileHandle can be used to save to
// the opened file itself later, read more on this in https://web.dev/file-system-access/


// in April 2021, window.showOpenFilePicker still not support in Safari
// so one should have this around also
function legacyFileOpen() {
    var input = document.createElement('input');
    input.type = 'file';
    input.onchange = function () {
        input.files[0].arrayBuffer().then(function (arrayBuffer) {
            console.log(new TextDecoder().decode(arrayBuffer));
        });
    }
    input.click();
}

对于使用混合方法的任何人,您可以通过类似以下方式进行检查,以查看是否支持“现代”fileOpen,并根据API的可用性决定调用哪个实现。export const supportsShowOpenFilePicker = 'showOpenFilePicker' in window && typeof window.showOpenFilePicker === 'function'; - rcbevans

4
最佳解决方案,适用于所有浏览器...甚至移动设备。
<div class="btn" id="s_photo">Upload</div>

<input type="file" name="s_file" id="s_file" style="opacity: 0;">';

<!--jquery-->

<script>
    $("#s_photo").click(function() {
        $("#s_file").trigger("click");
    });
</script>

隐藏输入文件类型会导致浏览器出现问题,不过透明度是最好的解决方案,因为它并不是隐藏,而是不显示。 :)

1
你应该提到这需要一个 jQuery 引用。 - Brino
不透明度涉及一个完全无关的概念 - 如果它不影响您的布局与“透明”元素,则只是幸运。该元素应该存在,但不可见,因此visibility:hidden应该是更好的选择。 - conny
visibility: hidden 仍会影响布局。你需要使用 display: none - jobukkit

4

我将input[type=file]包装在一个label标签中,然后根据您的喜好样式化label并隐藏input

<label class="btn btn-default fileLabel" data-toggle="tooltip" data-placement="top" title="Upload">
    <input type="file">
    <span><i class="fa fa-upload"></i></span>
</label>

<style>
    .fileLabel input[type="file"] {
        position: fixed;
        top: -1000px;
    }
</style>

纯CSS解决方案。


只需设置<input type="file" hidden>即可消除应用CSS样式的需要。 - Sylvain Lesage

3
原生的方法是需要创建一个<input type="file">元素,然后模拟点击,很遗憾这是唯一的方法。
有一个小巧的插件(自我推广),可以省去每次都要这样做的烦恼:file-dialog
fileDialog()
    .then(file => {
        const data = new FormData()
        data.append('file', file[0])
        data.append('imageName', 'flower')

        // Post to server
        fetch('/uploadImage', {
            method: 'POST',
            body: data
        })
    })

1

确保在REACT中使用绑定来获取组件属性

class FileUploader extends Component {
  constructor (props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
   onChange=(e,props)=>{
    const files = e.target.files;
    const selectedFile = files[0];
    ProcessFileUpload(selectedFile,props.ProgressCallBack,props.ErrorCallBack,props.CompleatedCallBack,props.BaseURL,props.Location,props.FilesAllowed);
  }
   handleClick = () => {
    this.refs.fileUploader.click();
  }
  render()
  {
  return(
      <div>
        <button type="button" onClick={this.handleClick}>Select File</button>  
        <input type='file' onChange={(e)=>this.onChange(e,this.props)} ref="fileUploader" style={{display:"none"}} />
      </div>)
  }
}

1
以编程方式浏览文件。


function browseFile(accept) {
    const promise = resolvingPromise();
    const input = document.createElement('input');
    input.type = "file";
    input.accept = accept;
    input.onchange = function (e) {
        const files = e.target.files;
        promise.resolve(files);
    }
    setTimeout(function () {
        click(input);
    }, 0);
    return promise;
}

function click(node) {
    try {
        node.dispatchEvent(new MouseEvent('click'))
    } catch (e) {
        const evt = document.createEvent('MouseEvents')
        evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null)
        node.dispatchEvent(evt);
    }
}



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接