vue.jsでcsvファイルのデータ抽出表示とオセロ

エクセルなどで使われるCSVファイルをブラウザで表示して見るツール
デモ：http://pie.karou.jp/zf.html

![index.png](https://qiita-image-store.s3.amazonaws.com/0/54926/b6c2d791-581c-37c3-a931-f7bd54f52b1e.png)

サンプルとして郵便番号と住所の書いてあるcsvファイルが
ちょうどよいので”郵便番号 csv”で検索してダウンロードする


全国のデータ  KEN_ALL_ROME.CSV 10.5MB
"0640941","北海道","札幌市　中央区","旭ケ丘","HOKKAIDO","SAPPORO SHI CHUO KU","ASAHIGAOKA"
1行がこんな感じで　12万行

***
1. csvファイルをinput fileで選択する
2. csvファイルはshiftJISが多くて文字化けするのでライブラリencoding.jsを使って対策する
3. 12万行も表示できないので30行だけ表示する（ファイルを開くのに5秒くらい）
4. and検索をするために

    ```
    Array.filter(function(v){
    return v.join("").indexOf("東京")>-1);
    }).filter(function(v){
    return v.join("").indexOf("新宿")>-1);
    });
    ```
これでデータ抽出すると1秒以下で697件見つけて表示される
***

```
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>csvファイル検索ツール</title>
<style>
h1{font-size: 16px;display:inline;}
p{display:inline;}
input[type=number]{width:80px;}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.7/vue.min.js"></script>
<script src="folder3/encoding.min.js"></script>
</head>
<body>
<div id="app">
   <h1>csvファイル 検索ツール（簡易オートフィルタ）</h1>
   <input type="file" @change="fileChange">
   <p>列幅調整はセル内でBackspace,←,→キー</p>
   <hr>
   検索文字:<input type="text" id="filter1">and<input type="text" id="filter2">
   行:<input type="number" id="maxGyou" step="10" min="10" value="30">
   <input type="button" @click="filterFn" value="抽出">
   ページ:
   <select v-model="index">
     <option v-for="n in pageLength" v-bind:value="n">{{n}} </option>
   </select> /{{ (pageLength==100)?"over": pageLength}}
   <input type="button" value="←" @click="plus(-1)">
   <input type="button" value="→" @click="plus(1)">
   一致数：{{ matchNum }}
   <hr>
   <div v-for="n in gyouNum" style="white-space: nowrap;">
      <input type="text" v-for="(v,i) in csvData[(index-1)*gyouNum + (n-1)]" :value="v" 
      @keyup.left="css(i,-25)" @keyup.right="css(i,50)" @keyup.delete="css(i,-1000)" 
      :style="{color : (colorArr[i] || 'black'), width: (widthArr[i] || 150) + 'px' }" readonly="readonly">
   </div>
</div>
<script>
var vm = new Vue({
   el: '#app',
   data: {
      index: 1,
      gyouNum: 30,
      fileData: [],
      csvData: [],
      widthArr: [],
      colorArr: [],
      matchNum: 0,
   },
   computed: {
      pageLength: function() {
         return Math.ceil(this.csvData.length / this.gyouNum);
      },
   },
   methods: {
      fileChange: function(e) {
         $("#filter1,#filter2").val("");
         var file = e.target.files[0];
         var reader = new FileReader();
         reader.onload = function(e) {
            var codes = new Uint8Array(e.target.result);
            var encoding = Encoding.detect(codes);
            var unicodeString = Encoding.convert(codes, {
               to: 'unicode',
               from: encoding,
               type: 'string'
            });
            var arr = unicodeString.trim().replace(/\"/g, "").split("\n");
            vm.fileData = arr.map(v => v.split(","));
            vm.filterFn();
         };
         reader.readAsArrayBuffer(file);
      },
      plus: function(x) {
         if (this.index + x <= 0 || this.index + x > this.pageLength) return;
         this.index += x;
      },
      css: function(x, y) {
         this.widthArr[x] = this.widthArr[x] || 150;
         this.widthArr[x] += y;
         if (this.widthArr[x] < 15) {
            this.widthArr[x] = 10;
            this.colorArr[x] = "white";
         } else {
            this.colorArr[x] = "black";
         }
         this.colorArr.push();
         this.widthArr.push();
      },
      filterFn: function() {
         this.index = 1;
         this.gyouNum = $("#maxGyou").val() - 0;
         var filter1 = $("#filter1").val().toLowerCase();
         var filter2 = $("#filter2").val().toLowerCase();
         var arr = this.fileData.filter(function(v) {
            return v.join("").toLowerCase().indexOf(filter1) > -1;
         }).filter(function(v, i) {
            return v.join("").toLowerCase().indexOf(filter2) > -1;
         });
         this.matchNum = arr.length;
         this.csvData = arr.filter(function(v, i) {
            return i < vm.gyouNum * 100;
         });
      },
   },
});
</script>
</body>
</html>
```

***
***

vue.jsで書いたオセロ
https://jsfiddle.net/af9b4bq3/

```
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.7/vue.min.js"></script>
<p>オセロ</p>
<div id="app">
  <p>白:{{ w }}, 黒:{{ b }}</p>
  <p>{{ ["白","黒"][wb] }}の手番</p>
  <div v-for="i in 8" class="container">
    <div v-for="j in 8" class="waku">
      <div :class="{ 'white': xy[i][j]==0, 'black': xy[i][j]==1 }" @click="oku(i, j)"></div>
    </div>
  </div>
  <p>
    <button @click="pass">pass</button>
  </p>
</div>
```

```
p {
  text-align: center;
}
div {
  min-width: 35px;
  min-height: 35px;
}
.container {
  display: flex;
  justify-content: center;
}
.waku {
  border: 1px solid black;
  background-color: green;
}
.white {
  border-radius: 35px;
  background-color: white;
}
.black {
  border-radius: 35px;
  background-color: black;
}
```

```
var vm = new Vue({
  el: '#app',
  data: {
    wb: 1,
    xy: [
      [3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
      [3, 2, 2, 2, 2, 2, 2, 2, 2, 3],
      [3, 2, 2, 2, 2, 2, 2, 2, 2, 3],
      [3, 2, 2, 2, 2, 2, 2, 2, 2, 3],
      [3, 2, 2, 2, 0, 1, 2, 2, 2, 3],
      [3, 2, 2, 2, 1, 0, 2, 2, 2, 3],
      [3, 2, 2, 2, 2, 2, 2, 2, 2, 3],
      [3, 2, 2, 2, 2, 2, 2, 2, 2, 3],
      [3, 2, 2, 2, 2, 2, 2, 2, 2, 3],
      [3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
    ],
  },
  computed: {
    w: function() {
      return (this.xy.join('').match(/0/g) || []).length;
    },
    b: function() {
      return (this.xy.join('').match(/1/g) || []).length;
    },
  },
  methods: {
    oku: function(x, y) {
      if (this.xy[x][y] != 2) return;
      var flag = false;
      for (var dx = -1; dx <= 1; dx++) {
        for (var dy = -1; dy <= 1; dy++) {
          if (dx == 0 && dy == 0) continue;
          var k = 1;
          while (this.xy[x + k * dx][y + k * dy] <= 1) {
            if (this.xy[x + k * dx][y + k * dy] == this.wb) {
              k = 1;
              while (this.xy[x + k * dx][y + k * dy] == 1 - this.wb) {
                flag = true;
                this.xy[x + k * dx][y + k * dy] = this.wb;
                k++;
              }
              break;
            }
            k++;
          }
        }
      }
      if (flag == false) return;
      this.xy[x][y] = this.wb;
      this.wb = 1 - this.wb;
      this.xy.push();
    },
    pass: function() {
      this.wb = 1 - this.wb;
    },
  },
});
```