仅使用Javascript(无服务器端)下载文本区域内容作为文件

31

我被要求创建一个“下载”按钮,将同一页上的文本区域内容作为文件下载,并显示浏览器的“另存为...”对话框。复制/粘贴可以完成这项工作,但这是一个“要求”。

目前,我只是将文本区域的内容发布到服务器,并使用Content-disposition: attachment返回它们。是否有办法仅使用客户端Javascript实现这一点?

9个回答

31

这可能是你要找的内容: http://thiscouldbebetter.wordpress.com/2012/12/18/loading-editing-and-saving-a-text-file-in-html5-using-javascrip/

它使用浏览器的下载对话框,但仅支持FF和Chrome,也许现在还有更多的浏览器?


   function saveTextAsFile(textToWrite, fileNameToSaveAs)
    {
     var textFileAsBlob = new Blob([textToWrite], {type:'text/plain'}); 
     var downloadLink = document.createElement("a");
     downloadLink.download = fileNameToSaveAs;
     downloadLink.innerHTML = "Download File";
     if (window.webkitURL != null)
     {
      // Chrome allows the link to be clicked
      // without actually adding it to the DOM.
      downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
     }
     else
     {
      // Firefox requires the link to be added to the DOM
      // before it can be clicked.
      downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
      downloadLink.onclick = destroyClickedElement;
      downloadLink.style.display = "none";
      document.body.appendChild(downloadLink);
     }
    
     downloadLink.click();
    }
<textarea id=t>Hey</textarea><br>
<button onclick=saveTextAsFile(t.value,'download.txt')>Download</button>


虽然这理论上回答了问题,但最好在此处包含答案的基本部分,并提供参考链接。 - John Dvorak
今天不再需要检查webkitURL了。http://caniuse.com/#search=URL 似乎Edge仍然不支持此功能。 - Wolfgang Blessen
1
错误:destroyClickedElement未定义。从互联网复制代码对健康不利。 - crisc2000

10

我在这里找到了一个简单的解决方案:https://codepen.io

My text area:<br />
<textarea rows='10' cols='80' id='myTextArea' ></textarea>

<br /><br />

Download button: <br />
<input value='download' type='button'
onclick='doDL(document.getElementById("myTextArea").value)' />


<script type='text/javascript'>
function doDL(s){
    function dataUrl(data) {return "data:x-application/text," + escape(data);}
    window.open(dataUrl(s));
}
</script>

希望这有所帮助。


您正在使用无效的内容类型;application/octet-stream不具有相同的效果吗? - Julian Reschke
@CyrLop -- 你在这里发布的答案很棒.... 你知道是否有一种方法可以硬编码一个文件名,以便保存对话框打开时,用户可以编辑一个文件名,但例如是当前日期 -- yyyymmdd.txt? - tamak
@tamak,请看下面基于此答案的回复。 - bbarker

9
你可以尝试使用window.location = "data:application/octet-stream,"+text,但这种方法无法提供一个机制,让你建议一个文件名。而且IE对数据URI的最大长度有很小的限制,这可能会成为一个问题。

2
甚至在IE6中都不可能实现。 - Rakesh Pai

7
有一些JavaScript库可以通过小型嵌入式SWF文件来完成这种操作。例如这个

1
在我看来,这更像是对问题的回答。我的意思是,它帮助了我,谢谢 :) - Iulius Curt
这个库有没有其他类似的库? - Husman

4
可以使用这个跨浏览器JavaScript实现HTML5中的saveAs函数:https://github.com/koffsyrup/FileSaver.js 如果您只想保存文本,则上述脚本在所有浏览器中(包括所有版本的IE)均可使用,无需SWF。

4
你可以使用 data: URI 并给它一个文件名,同时仍然下载文本。试试这个:

document.getElementById("download").onclick = function(){
  var l = document.createElement("a");
  l.href = "data:text/plain;charset=UTF-8," + document.getElementById("dload-txt").value;
  l.setAttribute("download", document.getElementById("dload-fn").value);
  l.click();
}
textarea { width: 200px; height: 75px }
input { width: 200px }
<textarea placeholder="Enter text to download" id="dload-txt"></textarea><br/>
<input placeholder="Enter file name to download as" id="dload-fn"/><br/><br/>
<button id="download">Download</button>

这在大多数浏览器中都有效。

它的作用是从文本区和输入框中获取必要的数据,创建一个链接,该链接的 href 设置为 data:text/plain;UTF-8,<textarea data>,并设置 download 属性为由 <input> 元素设置的名称。然后点击该链接,将下载文本。

这里唯一不兼容所有浏览器的是:

  1. 用于将数据存储为链接的 data: URI。CanIUse 上的 data: URIs

  2. 使用 click() 函数来点击链接。CanIUse 上的 HTMLElement.click()

  3. 用于表示下载的 download 属性。CanIUse 上的 download 属性

所以基本上:

  • 不在IE中工作
  • 不在Opera Mini中工作
  • 不在早期版本的Firefox、Chrome、Safari、Opera和iOS Safari中工作
否则,在所有主要浏览器中都可以正常工作,并且不需要任何Blob对象。 CanIUse上的Blob构建 CanIUse上的Blob URL

这个效果出奇的好 - 绝佳的解决方案。 - deadroxy

3
基于@Cyrlop的答案和https://stackoverflow.com/a/41948732/3096687,这提供了一种指定文件名的方法:
            function doDownload(str) {
              function dataUrl(data) {
                return "data:x-application/xml;charset=utf-8," + escape(data);
              }
              var downloadLink = document.createElement("a");
              downloadLink.href = dataUrl(str);
              downloadLink.download = "foo.xml";

              document.body.appendChild(downloadLink);
              downloadLink.click();
              document.body.removeChild(downloadLink);
            }

@Superphonic的解决方案可能更好,如果你不介意在你的JavaScript中包含更多字节。

有没有办法让它提示用户进行另存为操作? - schizoid04

1

通过创建一个框架,编写内容,然后在IE中调用document.execCommand('saveas', ...),在Mozilla中使用nsIFilePicker进行一些操作,这可能是可能的,但我相信这需要一些特殊的权限(比如成为浏览器本身的一部分)。


确实可能,并且不需要特殊权限.. 请参见此处:http://jsfiddle.net/YhdSC/1/ (仅限IE :/) - Shadow The Spring Wizard
是的,权限部分更多涉及Firefox。 - Andrey Shchekin

-2

简短的回答:这是不可能的。 你必须将其POST到服务器,并从服务器响应可以是“Content-disposition: attachment”。


这个答案是客观错误的,因为我亲自测试并成功得到了其中一个答案。 - schizoid04
不确定这个回答为什么会被归类为VLQ队列 - 它确实是一个回答(只是可能是错误的)。[错误的回答并不等同于非常低质量的回答。] (https://meta.stackoverflow.com/questions/345023/are-blatantly-wrong-answers-very-low-quality) - EJoshuaS - Stand with Ukraine

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