LoginSignup
6
6

More than 3 years have passed since last update.

value を変えずに input に3桁カンマを振る

Posted at

value を変えずに input に3桁カンマを振る

「数値に3桁カンマを振りたい」って要望は結構あって、ググると js で value 自体をゴリゴリいじる実装が多いですが、今回はちょっと違ったアプローチをしてみます。

コード

<html lang="ja">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>

<style>
    /* number-input と number-overlap をまとめるコンテナ */
    .number-container {
        position: relative;
    }

    /* カンマ区切りにしたい input 要素 */
    .number-input {
        position: relative;
    }
    /* 普段は z-index:1 で number-overlap の後ろに居る。色は被ってしまうので transparent */
    .number-input:not(:focus) {
        z-index: 1;
        color: transparent;
    }
    /* フォーカス中は z-index:3 で number-overlap の前に来る。色も戻す */
    .number-input:focus {
        z-index: 3;
        color: #555;
    }

    /* number-input に覆い被さる要素。 pointer-events:none でクリックを透過させる */
    .number-overlap {
        position: absolute;
        top: 1px;
        left: 0px;
        display: inline-block;
        background: transparent;
        width: 100% !important;

        pointer-events: none;
        z-index: 2;
    }
</style>
<script>
    $(function () {
        // フォーカスを抜けたり値が変わったりしたら覆い被さっているテキストをカンマ区切りにする
        $('#hoge').on('blur change input', function () {
            const $this = $(this);
            if ($this.val() !== '') {
                $this.next().text((+$this.val()).toLocaleString());
            }
        });
    });
</script>

<form class="form-inline">
    <div class="form-group">
        <div class="number-container">
            <input type="text" id="hoge" name="hoge" class="form-control number-input" placeholder="自動でカンマが付きます">
            <span class="number-overlap form-control"></span>
        </div>
    </div>
</form>

</body>
</html>

殴り書きしたのでかなり荒いですが、コメントを読めば何をしているかは分かると思います。
一応説明を加えると下記のような感じです。

.number-container

position で要素を重ね合わせる必要があるので、そのためのコンテナです。
それ以上の意味は特にありません。

.number-input

input に付与します。
普段は z-index で後述の .number-overlap の後ろに隠れていますが、フォーカスすると前面に出てきます。

.number-overlap

実際に3桁カンマの文字列が設定される要素です。
普段は z-index で前述の .number-input に被さっていますが、フォーカスされると後ろに引っ込みます。
pointer-events:none なのでクリックを透過します。これが今回のキモです。これによって「被さっているんだけど後ろの要素がクリック(フォーカス)できる」が実現できます。

javascript

フォーカスとか見え方とかは css だけで完結しますが、「カンマを振る処理そのもの」はどうしても js の力を借りる必要があるのでそれをしています。
できれば html + css だけでやりたい・・・。

注意点

ただし上記はかなりサボっています。実際はいろいろ調整しないと使い物になりません。

まず .number-overlap のスタイルは number-input に完全に合わせる必要があります(padding や font-size など多岐にわたる。合わせないとすぐズレる)。
上記は bootstrap を使っていますが form-controlinput に限定されないので流用してるだけです。しっかりやろうとすると結構めんどくさいです。
実際、上記は chrome で確認しましたが、他のブラウザではズレたりします。そういった微調整が必須になります。

また、個人的に数値入力は type=number を使うことが多いです。さらに右寄せにしたいですが、スピンボタンがくっつくのでブラウザごとの調整が必要です(幅がブラウザごとに全く異なります)。
正直かなり大変なので、いっその事スピンボタンは消したほうが良いです。

js サイドも上のコードだと数値以外を入れると NaN になるので、もっといろいろな分岐が必要です。
NaN は type=number でサボったり出来ますが e の罠があったりして、正直「ロケール指定ができる type=number があればいいのに・・・」と思います。

まとめ

注意点で記載した所が調整・クリアできれば変換の面倒をまったく見なくて済むようになるので結構有用だと思います。
(js で値をゴリゴリいじるのはなんか好かん)。

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