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

Vue.jsで計算機アプリを作る

Last updated at Posted at 2021-09-29

image.png

はじめに

Vue.jsでアプリを作る課題が出たので、せっかくなので記録として残しておく。
計算機アプリって基本的なイメージだけど、いまいち参考になるものがなかったので。。。
他の方の少しでも参考になれば良いかなと思います。


image.png

内容

Vue.jsを使って計算機アプリケーションを作ることになりました。
計算機としての機能があれば問題なしです。
シンプルな計算機を作成していきます。

シンプルな計算機の機能

そもそも電卓の機能とは何かを考える。

  • 四則演算ができる(足し算とか掛け算とかですね)今回は%は除きます。
  • 入力と計算結果が画面に表示される
  • Cを押したら数字がキャンセルされる
  • ACを押したら全部消える
  • .を押すと小数を入力できて、計算できる

こんなところでしょうか。
(今回は%は省きます。電卓の%は60の後に%のように入力すると0.6と60%の意味になります)

ちょっと調べてみたら電卓にはまだまだ知らない便利機能がたくさんあるようです。
そもそも電卓って最近買わなくなりましたよね。。。

誰も教えてくれない電卓の機能

image.png

それは置いておいてVue.jsでプロジェクトを作成していきます。

計算機アプリを作成する

それではVue CLIを使いながら計算機アプリを作成します。
Vue CLIはアプリケーション開発に必要なツールやライブラリを簡単に構築できるコマンドラインインターフェイスです。

Vue CLIでプロジェクトを作成する。

ターミナル
% vue create calculator

vue create アプリ名コマンドを打つと
image.png

この画面が出ますが、今回はVuexなどは使わないのでDefault ([Vue 2] babel, eslint)で作成していきます。

🎉  Successfully created project calculator.
👉  Get started with the following commands:

 $ cd calculator
 $ yarn serve

作成できました。
確認のためローカルサーバーを立ち上げます。

Image from Gyazo

Vue.jsの画面が表示されました。

次にcomponents内に新しくCalculator.vueを作成します。
Image from Gyazo

次にApp.vueを少し変更してCalculator.vueを呼び出せるようにします。

App.vue
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <calculator />
  </div>
</template>
<script>
import Calculator from './components/Calculator.vue'

export default {
  name: 'App',
  components: {
    Calculator
  }
}
</script>

簡単に計算機画面を作る

まずは数字など、入力するボタンや表示画面を簡単に作成します。
今回はこんな感じのシンプルな計算機を作成します。

image.png

単純にやると寂しい感じなのでCSSフレームワークのBlumaBluma Swatchを使います。
簡単にCDNで今回はやってみます。
public下にあるindex.htmlのheadタグにコピペしてください。

index.html
<!DOCTYPE html>
<html lang="">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
  <link rel="stylesheet" href="https://unpkg.com/bulmaswatch/lumen/bulmaswatch.min.css">
  <title>
    <%= htmlWebpackPlugin.options.title %>
  </title>
</head>

その後に単純にbuttonタグで適当に作成して、
Image from Gyazo
こんな感じのそれっぽいのが出来上がりました。

計算機能を作成する

それでは次に本体である計算機能を作ります。

Calculator.vue
<template>
  <div class="calc">
    <h1 class="title">calculator</h1>
    <div class="result box" style="text-align: right">
      {{showNum}}
    </div>
    <div class="clear">
      <button @click="clearCurrent" class="button is-danger is-medium">
        C
      </button>
      <button @click="clearAll" class="button is-danger is-medium">AC</button>
    </div>
    <div class="buttons columns">
      <div class="number-buttons colum is-one-third">
        <button
          v-for="num in buttons.num"
          :key="num"
          class="button is-dark"
          @click="selectNumber(num)"
        >
          {{ num }}
        </button>
      </div>
      <div class="column">
        <button
          v-for="operator in buttons.operator"
          :key="operator"
          class="button is-primary is-medium"
          @click="selectOparator(operator)"
        >
          {{ operator }}
        </button>
      </div>
    </div>
    <div class="">
      <button
        @click="showResult"
        class="button is-success is-medium equal-button"
      >
        =
      </button>
    </div>
  </div>
</template>

<script src="https://cdn.jsdelivr.net/npm/decimal.js-light@2.5.0/decimal.min.js"></script>

<script>

export default {
  data() {
    return {
      buttons: {
        num: [
          "7",
          "8",
          "9",
          "4",
          "5",
          "6",
          "1",
          "2",
          "3",
          "0",
          "00",
          ".",
          "+/-"
        ],
        operator: ["+", "-", "×", "÷"]
      },
      isInsertNumber: true, // 数字入力中かどうかを判断
      isResult: false, // =を押した後かどうかを判断
      currentOperator: "", // 現在選択中の演算子
      currentNumber: "0", // 現在選択中の数字
      numArray: [], // 押した数字の配列を格納する
      opeArray: [] // 押した演算子の配列を格納する
    };
  },
  computed: {
    // 状態によって 合計値 or 入力値 を出し分ける
    showNum() {
      let result;
      // 数字が入力中なら次の入力値を出力して
      if (this.isInsertNumber) {
        let text = String(this.currentNumber);
        let newText = text.replace(/^0{1,}([^.])/, "$1");
        result = newText;
      } else {
        // そうでないならtotalメソッドの結果を返す
        result = this.total();
      }
      return result;
    }
  },
  methods: {
    // reduceメソッドを使い、全ての計算結果を出す
    total() {
      return this.numArray.reduce((prev, next, index) => {
        return this.setTotalNum(prev, next, index - 1);
      });
    },
    // 前後の数字を演算子ごとに計算して値を返す
    // decimal.js-lightを使用して誤差によるエラーを回避
    setTotalNum(prev, next, index) {
      if (this.opeArray[index] === "+") {
        let plus = new Decimal(prev).plus(next);
        return plus
      } else if (this.opeArray[index] === "-") {
        let minus = new Decimal(prev).minus(next)
        return minus
      } else if (this.opeArray[index] === "÷") {
        let division = new Decimal(prev).div(next)
        return division
      } else if (this.opeArray[index] === "×") {
        let multiplication = new Decimal(prev).times(next)
        return multiplication;
      }
    },
    // 数字ボタンを押した時
    selectNumber(num) {
      // 正負を逆にする
      if (num === "+/-") {
        if (!this.isInsertNumber) return;
        this.currentNumber = -1 * this.currentNumber;
        return;
      }
      // = を押した直後、一度数字をリセットして次の計算をする
      if (this.isResult) {
        this.currentNumber = "0";
        this.isResult = false;
      }
      // 数字以外が入力された場合は演算子の配列に今の演算子をpushして数字0にし、次の数字を入力できるようにする
      if (!this.isInsertNumber) {
        this.opeArray.push(this.currentOperator);
        this.currentNumber = "0";
        this.isInsertNumber = true;
      }
      // 小数点は1つまでしか入力できない
      if (num === "." && this.currentNumber.indexOf(".") > -1) {
        return;
      }
      this.currentNumber += num;
    },
    // 演算子ボタンを押した時
    selectOparator(operator) {
      if (this.isInsertNumber) {
        this.numArray.push(Number(this.currentNumber));
        this.isInsertNumber = false;
      }
      this.currentOperator = operator;
    },
    // =を押した時に動くメソッド
    showResult() {
      // 数字入力時 かつ current演算子有り かつ まだ=ボタンを押していないとき
      // 入力された数字、演算子をリセットし、currentNumberにtotalメソッドで計算結果を返す
      if (this.isInsertNumber && this.currentOperator && !this.isResult) {
        this.numArray.push(Number(this.currentNumber));
        this.currentOperator = "";
        this.currentNumber = this.total();
        this.numArray = [];
        this.opeArray = [];
        this.isResult = true;
      }
    },
    // cを押した時
    clearCurrent() {
      this.currentNumber = 0;
      this.isInsertNumber = true;
    },
    // acを押した時
    clearAll() {
      this.numArray = [];
      this.opeArray = [];
      this.currentNumber = 0;
      this.currentOperator = "";
      this.isInsertNumber = true;
    }
  }
};
</script>

**javascriptは小数点の計算で誤差が出るみたいなので、ライブラリを入れて防止します。 たまに計算を試していると、数字じゃなくて`3.5e-8`みたいな表示が出ることがあるんですが 改善方法わかる方いたら教えていただけたらありがたいです。**

CSSで見た目を整えていきます。

Calculator.vue
<style>
.calc {
  width: 380px;
  padding: 20px 0;
  margin: 10px auto;
  background-color: rgba(122, 196, 199, 0.808);
  border-radius: 20px;
  box-shadow: 8px 5px rgba(62, 150, 145, 0.6);
}

.title {
  font-size: 20px;
  color: rgb(235, 227, 128);
  text-shadow: 1px 1px rgb(105, 95, 95);
}
.result {
  width: 250px;
  font-size: 30px;
  font-weight: bold;
  margin: 0 auto;
  padding: 8px 10px;
  border: 1px solid;
  background-color: rgb(248, 165, 165);
  color: rgb(231, 220, 220);
  /* 数字が表示できない桁数になったら...で表示 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.clear {
  width: 300px;
  margin: 10px auto;
  display: flex;
}

.clear button {
  margin: 0 5px;
}

.buttons {
  width: 300px;
  margin: 0 auto 0;
}

.number-buttons button {
  width: 30%;
  margin: 0 0 5px;
  font-size: 15px;
}

.op-buttons button {
  width: 22%;
}

.equal-button {
  margin: 0 auto 0;
  width: 260px;
}
p {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
</style>

index.htmlにはCDNでdecimal.js-lightというjavascriptのライブラリを読み込んでいます。

index.html
<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
  <link rel="stylesheet" href="https://unpkg.com/bulmaswatch/lumen/bulmaswatch.min.css">
  <script src="https://cdn.jsdelivr.net/npm/decimal.js-light@2.5.0/decimal.min.js"></script>
  <title>
    <%= htmlWebpackPlugin.options.title %>
  </title>
</head>

**実行してみましょう。**
ターミナル
% yarn run serve

yarn run v1.22.10
warning ../../package.json: No license field
$ vue-cli-service serve
 INFO  Starting development server...
98% after emitting CopyPlugin

 DONE  Compiled successfully in 4472ms                        9:56:59


 App running at:
  - Local:   http://localhost:8080/ 
  - Network: http://10.2.105.137:8080/

 Note that the development build is not optimized.
 To create a production build, run yarn build.

image.png

完成

こんな感じの計算機になりました。
Image from Gyazo

せっかくなのでHerokuでデプロイしてみました

実際に動かしてみたい方はこちらからどうぞ

Vue.jsでつくった電卓アプリ 「Calculator」

おわりに

いろいろと調べながらコードを読み込みながらどうにかできました。
細かい説明はしていないところと、まだまだ改善できるところはあるので随時気づいたら更新していきます。

参考サイト

2
0
3

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
2
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?