簡體   English   中英

從文本文件讀取而不使用javascript中的事件

[英]Reading from text file without using event in javascript

當觸發並選擇文件時,以下工作有效,但在這種情況下,我什至不想使用該事件,我希望從路徑中自動加載文件並逐行讀取。

<input type="file" id="fileinput" />
<script>
function readSingleFile(evt){

    //Retrieve the first (and only!) File from the FileList object
    var f = evt.target.files[0]; 

    if(f){
        var r = new FileReader();
        r.onload = function(e) { 
            var contents = e.target.result;
            // Some code
        }
        r.readAsText(f);
    }else{ 
        alert("Failed to load file");
    }
}
document.getElementById('fileinput').addEventListener('change', readSingleFile, false);
<script>

從用戶操作系統加載文件必須由某種形式的用戶事件觸發,除了從canvas元素獲取文件對象外(可以直接生成)。

正如MDN的摘錄所述:

可以從用戶使用元素選擇文件后返回的FileList對象,拖放操作的DataTransfer對象或HTMLCanvasElement上的mozGetAsFile()API中獲取文件對象。

允許網頁在沒有用戶干預或未獲得明確許可的情況下從用戶計算機加載任何文件的能力確實是一件危險的事情。 但是,根據您可以對文件(或主機環境)執行的操作,您確實可以選擇一些方法。


通過AJAX / XHTTP加載文件

我包括通過file://協議使用的源代碼,因此是在本地下載jQuery的原因,而不是使用任何等效的熱鏈接。 為了對此進行測試,您只需要下載jQuery並將其保存在與該HTML文件相同的目錄中,顯然可以創建一個textfile.txt或更改代碼以指向另一個文件。

注意:除非您從本地運行file://協議中的代碼,否則文件路徑應保留在您的Web根目錄中,並且可以從同一主機下的Web服務器進行訪問。 如果您通過file://協議運行,則只要瀏覽器有權訪問該文件,就可以從計算機上的任何位置加載文件,並且您仍然可以通過file://訪問。

以這種方式(或我在頁面上提到的其他任何一種方式)加載文件與在問題中加載文件的方式有很大的不同。 通過文件選擇器對話框加載文件是從用戶自己的計算機中獲取文件。 而通過AJAX(或通過腳本/ iframe標簽)加載文件是從服務器上獲取文件。 這是否使您的目標失敗,將取決於您使用它的目的。 最好是通過這種方法來完成文本文件的加載,在下面您會發現一些具有其優點的其他輔助方法,但也有很多缺點。

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Load a text file</title>
<script src="jquery.js"></script>
<script>
  jQuery 
    .ajax({
      url: 'textfile.txt',
      dataType: 'text'
    })
    .error(function(){
      console.warn('An error occurred whilst loading the file', arguments);
    })
    .done(function(res){
      jQuery.each(res.split(/\r?\n/g), function(i, v){
        jQuery('#output').append('<p>' + v + '</p>');
      });
    })
  ;
</script>
</head>
<body>
  <h1>Fileload</h1>
  <div id="output"></div>
</body>
</html>


通過腳本標簽加載文件

此選項要求您將文本文件修改為由少量JavaScript包裹,然后再使用普通腳本標記導入其內容。 與AJAX不同,它不受跨域阻止,即stackoverflow.com可以從gamedev.stackexchange.com請求文件。 該方法還具有占地面積小的優點。

注意:現在,在實現CORS時,AJAX請求可以可靠地解決跨域問題。 但是,這通常涉及對服務器端的一些控制。

此方法的缺點是,您必須修改文本文件,將文本文件解析為JavaScript(這意味着某些高階字符可能會使較舊的解析器混亂),並且您正在濫用Function.toString() 如果您不願意為多行hack使用注釋,您可以很容易地修改文本文件以使用字符串連接的正確方式實現多行字符串 但是一旦這樣做,加載諸如純文本文件之類的東西就已經相去甚遠。

文本文件的內容

(typeof loadfile != 'undefined') && loadfile(function(){/*
Place your text file contents here.
We are abusing the JavaScript comment facility
to achieve multiline strings without too much
modification to your original text file.
*/});

主頁中的腳本

<script>
/**
 * This function is responsible for receiving the function
 * sent by your text file
 */
function loadfile(content){
  var text = String(content && content.toString()),
      p1 = text.indexOf('/*')+2,
      p2 = text.lastIndexOf('*/')
  ;
  console.log(text.substring(p1, p2));
};
</script>
<script src="your-text-file.txt.js"></script>


通過iframe加載文件

在AJAX流行之前,如果沒有可用的服務器端,此選項幾乎可以使用。 與AJAX相比,它實際上沒有任何好處,但事實是,如果使用輪詢來監視iframe准備就緒的時間,則用於管理iframe的代碼會更小且跨瀏覽器更可靠。 使用AJAX,通常最好依靠庫(如jQuery)來處理不同環境之間的差異。

但是,這表示AJAX為您提供了更多的功能,並且提供了有關事件發生時的更多交互反饋(具有對事件的更好支持)。 依賴輪詢可能較慢/不可靠,但這是iframe的唯一選擇,因為並非所有瀏覽器都支持觸發正確的事件,尤其是在處理意外的數據類型時。

這是我用來整理和更新的腳本,僅用於說明要點。 這個版本依賴於Object.create 因此 ,如果您想在較舊的瀏覽器中使用它,則需要使用polyfill 但是正如我已經說過很多次……如果可以,請改用AJAX,如果不能,則可能需要重新考慮您的方法。

/**
 * Textfile
 *
 * Allows the loading of a textfile via an iframe or script tag.
 *
 * Loading via script tag:
 *
 *  textfile.load({
 *    type: 'script',
 *    path: 'textfile.txt.js'
 *  })
 *    .fail(function(){
 *      console.log('an error occured!');
 *    })
 *    .done(function(res){
 *      console.log('file loaded', res);
 *    })
 *  ;
 *
 * loading via iframe:
 *
 *  textfile.load({
 *    type: 'iframe',
 *    path: 'textfile.txt'
 *  })
 *    .fail(function(){
 *      console.log('an error occured!');
 *    })
 *    .done(function(res){
 *      console.log('file loaded', res);
 *    })
 *  ;
 *
 * NOTE: When loading via a script tag, your text file must be in the
 * following format:
 */
(typeof textfile != 'undefined') && textfile.injected('NAME OF YOUR FILE', function(){/*
This is example text content
you can have as many lines as
you want.
*/});
/**
 * Once your text file is wrapped with the above the textfile code
 * will be notified that the file has been loaded, and it will also
 * allow you to have multiline text more easily in JavaScript.
 *
 * <NAME OF YOUR FILE> should be replaced with your filename to load
 * for example textfile.txt.js
 */
var textfile = (function(){

  var tf = {

    shared: {},

    create: function(config){
      return tf.prep.apply(Object.create(tf), arguments);
    },

    prep: function(config){
      this.config = config;
      this.tag = !this.config.inline
        ? document.documentElement
        : document.scripts[document.scripts.length-1]
      ;
      this.tid = setTimeout(this.bind(this.timeout), this.config.timeout || 5 * 1000);
      this.iid = setInterval(this.bind(this.polling), 100);
      this.loader = this.config.type === 'script'
        ? this.script()
        : this.frame()
      ;
      this.loader.src = this.config.path;
      !this.config.inline
        ? this.tag.appendChild(this.loader)
        : this.tag.parentNode && this.tag.parentNode.insertBefore(this.loader, null)
      ;
      return this;
    },

    script: function(element){
      if ( element ) { return element; }
      element = document.createElement('script');
      element.type = 'text/javascript';
      return element;
    },

    frame: function(element){
      if ( element ) { return element; }
      element = document.createElement('iframe');
      element.style.position = 'fixed';
      element.style.right = '100%';
      element.style.bottom = '100%';
      element.style.width = '1em';
      element.style.height = '1em';
      return element;
    },

    tidyup: function(){
      this.loader && this.loader.parentNode.removeChild(this.loader);
      return this;
    },

    loaded: function(res){
      this.trigger('done', res);
      this.tidyup();
      return this;
    },

    failed: function(){
      this.trigger('fail');
      this.tidyup();
      return this;
    },

    on: function(name, listener){
      !this.listeners && (this.listeners = {});
      !this.listeners[name] && (this.listeners[name] = []);
      this.listeners[name].push(listener);
      return this;
    },

    off: function(name, listener){
      if ( this.listeners && this.listeners[name] ) {
        for ( var a=this.listeners[name], i=a.length-1; i>=0; i-- ) {
          if ( a[i] === listener ) {
            this.listeners[name].splice(i, 1);
          }
        }
      }
      return this;
    },

    trigger: function(name, data, context){
      if ( this.listeners && this.listeners[name] ) {
        for ( var i=0, a=this.listeners[name], l=a.length; i<l; i++ ) {
          if ( a[i] && a[i].call ) {
            a[i].call( context || this, data );
          }
        }
      }
      return this;
    },

    bind: function(method, args, context){
      !context && args && !args.length && (context = args);
      !context && (context = this);
      args && (args = Array.prototype.slice.call(args));
      return function(){
        return (args
          ? method.apply(context, args.concat(Array.prototype.slice.call(arguments)))
          : method.apply(context, arguments)
        );
      };
    },

    fail: function(listener){ return this.on('fail', listener); },
    done: function(listener){ return this.on('done', listener); },

    timeout: function(){
      clearInterval(this.iid);
      this.failed();
    },

    polling: function(){
      var obj, text, ex;
      if ( this.config.type === 'iframe' ) {
        try { text = ((obj=this.loader.contentWindow) && obj.document.documentElement.textContent) ||
                     ((obj=this.loader.contentWindow) && obj.document.documentElement.innerText) ||
                     ((obj=this.loader.contentDocument) && obj.documentElement.textContent) ||
                     ((obj=this.loader.contentDocument) && obj.documentElement.innerText); 
        } catch (ex) {}
      }
      else {
        text = this.loader.textContent || 
               this.loader.text || 
               this.loader.innerHTML || 
               this.shared.loaded && this.shared.loaded[this.config.path]
        ;
      }
      if ( text && text.split ) {
        this.loaded(text);
        clearInterval(this.tid);
        clearInterval(this.iid);
      }
    },

    injected: function(script, content){
      var text = String(content && content.toString()),
          p1 = text.indexOf('/*')+2,
          p2 = text.lastIndexOf('*/')
      ;
      !this.shared.loaded && (this.shared.loaded={});
      this.shared.loaded[script] = text.substring(p1, p2);
    },

    load: function(config){
      return config && config.split
        ? tf.create({ path: config })
        : tf.create(config)
      ;
    }

  };

  return tf;

})();

如果您已經知道文件的路徑,則只需使用onload事件調用函數。 使用jQuery,您可以使用$(function(){});。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM