LoginSignup
41
38

More than 5 years have passed since last update.

Vue.jsでCSVをインポート

Last updated at Posted at 2019-02-02

結構記事があるので余裕だと思ったら躓きまくったので残しておこうと思います.

目指すもの

Image from Gyazo

CSVファイルをドラッグアンドドロップ もしくは 選択してアップロードして, そのCSVファイルを自由に読み取れるようにするまでです.

簡単な流れを説明すると

ファイルアップロード => パース => dataにぶちこむ => 表示

といった感じです.

[f:id:ustrgm:20181223003622p:plain]

script

vueファイルのCSVを読み込む部分はこんな感じになってます.

CSV.vue

<script>
export default {
  data: function() {
    return {
      // CSVファイルのヘッダー部を定義しておきます
      headers: [
        {
          text: "Code",
          align: "left",
          sortable: false,
          value: "code"
        },
        { text: "Name", align: "left", value: "name" },
        { text: "WorkerType", align: "left", value: "workerType" }
      ],
      workers: []
    };
  },
  methods: {
    fileChange: function(e) {
      const file = e.target.files[0];
      const reader = new FileReader();
      const workers = [];

      const loadFunc = () => {
        const lines = reader.result.split("\n");
        lines.forEach(element => {
          const workerData = element.split(",");
          if (workerData.length != 3) return;
          const worker = {
            code: workerData[0],
            name: workerData[1],
            workerType: workerData[2]
          };
          workers.push(worker);
        });
        this.workers = workers;
      };

      // onloadはreadAsBinaryStringでファイルを読み込んだ後に実行されます.
      reader.onload = loadFunc;

      reader.readAsBinaryString(file);
    }
  }
};
</script>

うまくいかないパターン

最初以下のように書いてました

      // onloadはreadAsBinaryStringでファイルを読み込んだ後に実行されます.
      reader.onload =() => {
        const lines = reader.result.split("\n");
        lines.forEach(element => {
          const workerData = element.split(",");
          if (workerData.length != 3) return;
          const worker = {
            code: workerData[0],
            name: workerData[1],
            workerType: workerData[2]
          };
          workers.push(worker);
        });
        this.workers = workers;
      };

これで行けそうな気がしたのですが, this がFileReaderを指すためうまくいきません.

workersとかも更新されません.

上記のように関数を作っておいてそれを渡すようにします.

ちなみにスコープ外の値を操作するのに作成する関数をクロージャといいます.クロージャ

躓いたのはここだけでしたが, ほとんど記事はonloadに直接関数を入れ込んでいるのでthisを使って値を変えようとする場合はうまくいかないです.

また, ローカル変数を作って最後に代入しているのは, 配列のpush関数を使っても再レンダリングがおこらないためです. (値そのものを書き換えるときにsetterが呼ばれ, vueは再レンダリングします)

全体

vuetifyを使ってますがこんな感じにテーブルにして表現することができます.

CSV.vue

<template>
  <div>
    <h1>CAVインポート</h1>
    <input @change="fileChange" type="file" id="file_input_expense" name="file_input_expense">
    <v-data-table :headers="headers" :items="workers" class="elevation-1">
      <template slot="items" slot-scope="props">
        <td class="text-xs-right">{{ props.item.code }}</td>
        <td class="text-xs-right">{{ props.item.name }}</td>
        <td class="text-xs-right">{{ props.item.workerType }}</td>
      </template>
    </v-data-table>
  </div>
</template>

<script>
export default {
  data: function() {
    return {
      headers: [
        {
          text: "Code",
          align: "left",
          sortable: false,
          value: "code"
        },
        { text: "Name", align: "left", value: "name" },
        { text: "WorkerType", align: "left", value: "workerType" }
      ],
      workers: []
    };
  },
  methods: {
    fileChange: function(e) {
      const file = e.target.files[0];
      const reader = new FileReader();
      const workers = [];

      const loadFunc = () => {
        const lines = reader.result.split("\n");
        lines.forEach(element => {
          const workerData = element.split(",");
          if (workerData.length != 3) return;
          const worker = {
            code: workerData[0],
            name: workerData[1],
            workerType: workerData[2]
          };
          workers.push(worker);
        });
        this.workers = workers;
      };

      reader.onload = loadFunc;

      reader.readAsBinaryString(file);
    }
  }
};
</script>

まとめ

vueというよりほぼJSでしたがこれでCSV読み込んで色々できます!

41
38
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
38