0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

VueとuseFuseをつかって東京都府中市の粗大ゴミシール料金検索をつくりました

Posted at

概要

府中市の粗大ゴミを出すときに必要なシール料金の検索サイトをVue3で作りました。

CleanShot 2023-06-04 at 22.16.01.gif

環境

  • Vue3 (Composition API)

背景

以前、下記を作っていました。

しかし、herokuの有料化にともない、無料で運用するのが難しくなりました。

改めて、検索対象を見たところ、Algolia使うほどではなかったので、サーバー不要でクライアントだけで検索できるようにVue3で書き直しました。

結果、netlifyで公開し、無料で運用できました。

ソース

解説

データは、東京都府中市が公開しているデータを使っています。
CSVで公開されていましたので、importしやすいように加工して使っています。
加工したCSVはこちらです。

data/fuchu-gomi.csv
key,品目,料金,ふりがな
1,アイエイチ(IH)クッキングヒーター(1口),200円,あいえいち(IH)くっきんぐひーたー(1くち)
2,アイスボックス(高さと幅の合計90cm未満),200円,あいすぼっくす(たかさとはばのごうけい90cmみまん)

csvを読み取る

csvを読み取るためには、csvをassetとして扱い、csvのurlを参照してcsvをPapaParseでimportしました。

Viteでassetsに含めるための設定は以下の通りです。

vite.config.ts
  assetsInclude: ['**/*.csv']

共通オプション | Vite

JS からインポートすると、解決された URL 文字列が返されます

ということなので、importするとurlが取得できます。

components/SearchPageBody.vue
import csvUrl from '@/data/fuchu-gomi.csv';

csvが保存されているurlを元にして、PapaParseでimportするのは以下の通り。

Papa.parse(url, {
	download: true,
	// rest of config ...
})

実際は以下の通り。

src/composables/useGomiFeeCsv.ts
const importFromUrl = (csvUrl: string, callback: (gomiFees: GomiFee[]) => void) => {
    Papa.parse(csvUrl, {
      download: true,
      header: true,
      complete: (results: ParseResult<GomiFeeRow>) => {
        gomiFees.value = results.data.map((row) => {
          return gomiFeeRow2GomiFee(row);
        });
        callback(gomiFees.value);
      },
    });
  };
src/components/SearchPageBody.vue
import csvUrl from '@/data/fuchu-gomi.csv';
importFromUrl(csvUrl, (_gomiFees: GomiFee[]) => {
  gomiFees.value = _gomiFees;
});

データを検索する

検索はFuseを使いました。

What is Fuse.js? | Fuse.js

実際は、VueUseでcomposable useFuse | VueUse経由です。

src/components/SearchResultSearch.vue
<script setup lang="ts">
import { useFuse } from '@vueuse/integrations/useFuse';

const { results } = useFuse(searchText, props.gomiFees, {
  fuseOptions: {
    keys: ['name', 'furigana'],
  },
  resultLimit: 10,
  matchAllWhenSearchEmpty: false,
});

const onInputSearchText = (e: any) => {
  searchText.value = e.target.value;
};
</script>

<template>
  <div>
    <div>
      <input type="text" placeholder="検索" @input="onInputSearchText" />
    </div>
    <div class="card">
      <div v-for="result in results" :key="result.item.key" class="card-item">
        <label>{{ result.item.name }}</label>
        <div>
          {{ result.item.furigana }}
        </div>
        <div>
          {{ result.item.fee }}
        </div>
      </div>
    </div>
  </div>
</template>

その他

csvを置き換えれば、他の市町村にも対応できます。

感想

Ruby on Railsだとサーバー代が高くて、書いてもなかなか公開できなかった。しかし、JavaScript onlyで作ると、サーバーを無料運用が現実的に可能になる。

無料で運用できる結果、色々作り放題ですので、個人開発が楽しくなりました。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?