4
4

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 3 years have passed since last update.

わぁい!どうぶつの森 カブ損益ツールをVueで作ったよー!

Posted at

#Tl;DR

  • Vue Cliを使ってどうぶつの森 カブ損益ツールを作ったよ
  • できあがったのはこちらだよ
  • GitHubはこれだよ

##あなた誰?
はじめまして。葉月ゆき(@peridot_snow08)、初投稿です。
フロント未満コーダー以上の存在でエンジニアをやりつつ都内でほそぼそしてます。

##何やったの?
前から興味があったVueで簡単などうぶつの森 カブ損益ツールを作りました!
ss.png

きっとまだ不完全だと思われる部分もあるけど、公開はできた!
なのでやってきたことを振り返ろうと思います。

##振り返り
###各値の入力と結果の表示
始めにここを作ったので、数値入力と結果が親子関係になってないです。
見返すと、親子関係にしたほうがよかったかなぁって思います。

BellInput.vue
<template lang="pug">
  div.bellInput
    div.trade
      .buyKabu.kabuPrice
        label(for='buyBell') 買値
        div.kabuPriceInput
          input#buyBell(type='number', v-model.number='buyPrice' placeholder="100")
          span ベル
      .sellKabu.kabuPrice
        label(for='sellBell') 売値
        div.kabuPriceInput
          input#sellBell(type='number', v-model.number='sellPrice' placeholder="100")
          span ベル
    .kabuNumber 
      label(for='kabuNumber') 購入数
      .kabuPriceInput
        input#kabuNumber(type='number', v-model.number='kabuNumber' placeholder="100")
        span カブ
    h2.result 購入結果
    table
      tr
        td.first 購入合計
        td 
          span.priceTxt {{buyTotal | numberGrouping}}
          span ベル
      tr
        td.first 買取合計
        td 
          span.priceTxt {{sellTotal | numberGrouping}}
          span ベル
      tr.borderNone
        td.first カブ損益
        td 
          span(:class="{active : kabuTotal < 0}").priceTxt {{kabuTotal | numberGrouping}}
          span ベル
    Tanukichi(:kabuTotal="kabuTotal")
    StrageBtn(:buy="buyPrice" :sell="sellPrice" :total="kabuNumber")
</template>

<script>
import Tanukichi from './Tanukichi.vue'
import StrageBtn from './StrageBtn.vue'
export default {
  name: 'BellInput',
  components: {
    Tanukichi,
    StrageBtn
  },
  data(){
    return {
       buyPrice: '',
       sellPrice: '',
       kabuNumber:'',
    }
  },
  mounted() {
    if(localStorage.length > 0) {
      this.buyPrice = localStorage.getItem('buy')
      this.sellPrice = localStorage.getItem('sell')
      this.kabuNumber = localStorage.getItem('total')
    }
  },

  computed: {
    buyTotal(){
      return this.buyPrice * this.kabuNumber
    },
    sellTotal(){
      return this.sellPrice * this.kabuNumber
    },
    kabuTotal(){
      return this.sellTotal - this.buyTotal
    },
  },
  filters: {
    numberGrouping(price){
      return price = price.toLocaleString()
    }
  }

}
</script>

各値はv-model、結果computedで計算し、Filterを使って3桁区切りをしています。
computedで桁区切りを行うと型変換が起こってしまうため、propsで渡すと文字列として渡してしまいます。
これだと後で支障きたすため、Filterを使いマスタッシュの中で桁区切りを行ってます。
コードの見たわしが若干悪くなるけど、地味に便利だったので採用。
各計算結果と入力値は使うので、propsで子Componentに渡してあげてます。

###たぬきちのアドバイス
各値を入力すると、たぬきちがアドバイスをくれます。
たぬきち曰くプラマイ0は運命らしいです。

BellInput.vue
<template lang="pug">
  div.tanukichi
    p.name たぬきち
    vue-typer(
      :text="tanukichiTalk"
      :repeat='0'
    )
</template>

<script>
/* eslint no-irregular-whitespace: ["error", {"skipTemplates": true}] */
import { VueTyper } from 'vue-typer'
export default {
  name: 'Tanukichi',
  components: {
    VueTyper
  },
  props: {
    kabuTotal: {
      type: Number
    }
  },
  data() {
    return {
      tanukichiTalk:`数値を入力をしてだなも。\n3つの数字をいれると、自動的に金額がでるだなも!`
    }
  },
  watch: {
    kabuTotal(newTotal){
      if(newTotal > 0){
        this.tanukichiTalk = `今 カブを売ると儲けでるだなも!\n売り値が上がるともっと儲けることができるから、もう少し待ってみるだなも。`
      } else if( newTotal < 0) {
        this.tanukichiTalk = `あわわわ! 損がでちゃただなも!\n明日になったらカブ価が回復するかも…\n今は売らずに待つのがよいだなも!`
      } else {
        this.tanukichiTalk = `プラスマイナス0だなも。\n損をしなくて済むから今売るといいだなも!`
      }
    }
  },
}
</script>

パッ切替わると味気がないので、ちゃんと会話ウィンドウっぽく喋ってくれるように、タイピングエフェクトにはVueTyperを使いました。
株価の損益の結果の値を親からもらい、たぬきちのセリフを変えてます。
セリフの切り替えをmethodsでやろうとしましたが、処理が重くなりそうなので、watchで処理。

###ヘルプのモーダル
ヘルプの部分を押すと、ヘルプのモーダルが開きます。
Componentを別にし、App.vue経由でModalを表示させるかを制御してます。

Header.vue
<template lang="pug">
  transition(name="modal")
    div
      div.modalOverlay
        span.modalCloseBtn
        div.modalContents
          div.useHead 使い方
          ul.howToUse
            li 買値・売値・購入数の3つを入力すると、購入結果に自動で計算結果が出力されます。購入結果がマイナスになると、損益が赤く表示されます。
            li 【結果を保存する】のボタンを押すと、ブラウザに買値・売値・購入数の入力値が保存され、次回アクセス時に自動で挿入されます。
            li 【保存データを破棄】を押すとブラウザに保存されたデータは破棄されます。入力結果はそのまま残りますので、日曜日のタイミングなどに使うといいかもです。
          p 開発の要望などは<a href="https://twitter.com/peridot_snow08" target="_blank">葉月ゆき</a>のTwitterにてお寄せください。
          button(@click="modalClose") ヘルプを閉じる
</template>

<script>
export default {
  name:'Modal',
  methods: {
    modalClose(){
      this.$emit('modalClose')
    }
  },
}
</script>
App.js
<template lang="pug">
  div#app
    Header(@modalOpen = 'toggleModalFlag')
    BellInput
    Modal(v-if="modalFlag" @modalClose = 'toggleModalFlag')
</template>

<script>
import Header from './components/Header.vue'
import BellInput from './components/BellInput.vue'
import Modal from './components/Modal.vue'
export default {
  name: 'App',
  components: {
    Header,
    BellInput,
    Modal
  },
  data(){
    return {
      modalFlag: false
    }
  },
  methods: {
    toggleModalFlag(){
      this.modalFlag = !this.modalFlag
    }
  },
}
</script>

子から親へは基本イベントしか渡せないというので、Headerでクリックイベントを発火させて、App.jsの切り替えメソッドに伝搬させ、それをpropで真偽値を渡すということをしてます。
クローズのときもApp.jsの切り替えメソッドまでは同じ。

こんなことをやりつつ、損益ツールは動かして作りました。
ただ…モーダルを表示時にactive-enterが入らないのでトランジションが動きません…。

##完成した感想
基礎を叩き込むまで随分時間はかかってしまいましたが、理解をするとこんなにも便利フレームワークがあるのか!一気に世界が開けた気がしました。特にデータバインディングの利便性はとってもすごい。
ツール自体まだ甘いところはありますが、インプットだけではと思い、こんなツールを作った次第です。誰かの役に経てばいいな。
Vue自体に特に大きな制約もないため、これからどんどんいろんなものを作って行きたいと思います。

##最後に
お友達がいないのでお友達募集中です。
Twitterやってるので、お友達になってください…

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?