1
1

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.js & axios】

Posted at

材料

  • PHP(7で動作確認)
  • Vue3
  • axios
  • 連動プルダウンにしたいデータ(DBでも連想配列でも)

連動部分を作る

data.php

<?php
$sushies = array(
    array(
        'sushi_type' => 0,
        'sushi_neta' => 'マグロ'
    ),
    array(
        'sushi_type' => 0,
        'sushi_neta' => 'サーモン'
    ),
    array(
        'sushi_type' => 0,
        'sushi_neta' => 'しめサバ'
    ),
    array(
        'sushi_type' => 1,
        'sushi_neta' => 'いくら'
    ),
    array(
        'sushi_type' => 1,
        'sushi_neta' => 'うに'
    ),
    array(
        'sushi_type' => 1,
        'sushi_neta' => 'コーンマヨ'
    ),
    array(
        'sushi_type' => 2,
        'sushi_neta' => 'かっぱ巻き'
    ),
    array(
        'sushi_type' => 2,
        'sushi_neta' => 'かんぴょう巻き'
    )
);
if (isset($_POST['sushi_type']) && is_numeric($_POST['sushi_type'])) {
    $sushi_type = (int)$_POST['sushi_type'];
    if ($sushi_type >= 0 || $sushi_type < 3) {
        // 検索結果のインデックスが入った配列が返ってる
        $indexes = array_keys(array_column($sushies, 'sushi_type'), $sushi_type);
    }
}
if (isset($indexes) && !empty($indexes)) {
    foreach ($indexes as $index) {
        $return_sushies[] = $sushies[$index]['sushi_neta'];
    }
} else {
    $return_sushies = array_column($sushies, 'sushi_neta');
}
echo json_encode($return_sushies);


ひな形をつくる

index.php

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

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://unpkg.com/vue@3.2.37"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <title>Linked Pulldown</title>
</head>

<body>
    <?php
    /**
     * htmlspecialcharsの短縮関数
     * 
     * @param string $text エスケープしたい文字
     * @return string エスケープ後の文字列
     */
    function h(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'utf-8');
    }
    $sushi_type_array = array('握り', '軍艦', '巻き寿司');
    // あとでVue.jsで使うので各所にIDを振っておく
    ?>
    <div id="sushi_zone">
        <select name="sushi_type" id="sushi_type">
            <?php foreach ($sushi_type_array as $key => $sushi_type) : ?>
                <option value="<?php echo h($key) ?>">
                    <?php echo h($sushi_type) ?>
                </option>
            <?php endforeach ?>
        </select>
        <select name="sushi_neta">
        </select>
    </div>
</body>

</html>

Vueでプルダウンの値を送る処理を書く

linked_pulldown.js

Vue.createApp({
    // divに指定したIDを、ここと最終行のmount()の中にセレクタで書く
    el: '#sushi_zone',
    data() {
        return {
            // 初期値設定
            selectedSushiType: 0,
            netas: "",
        }
    },
    methods: {
        // 処理内容。今回は寿司の握り方の値をdata.phpに送って結果を受け取る
        selected() {
            axios.defaults.headers.common = {
                'X-Requested-With': 'XMLHttpRequest',
            };
            const parameter = new URLSearchParams();
            // ここの第1引数が$_POST変数のインデックスになります。$_POST['sushi_type']
            parameter.append('sushi_type', this.selectedSushiType);
            axios.post('data.php', parameter)
                // echo json_encodeされたもののうちデータ部分がnetasという変数に入ります
                .then(res => this.netas = res.data)
                .catch(e => alert(e))
        },
    }
}).mount('#sushi_zone')

VueとHTMLをつなげる

index.php

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

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://unpkg.com/vue@3.2.37"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <title>Linked Pulldown</title>
</head>

<body>
    <?php
    /**
     * htmlspecialcharsの短縮関数
     * 
     * @param string $text エスケープしたい文字
     * @return string エスケープ後の文字列
     */
    function h(string $text): string
    {
        return htmlspecialchars($text, ENT_QUOTES, 'utf-8');
    }
    $sushi_type_array = array('握り', '軍艦', '巻き寿司');
    ?>
    <div id="sushi_zone">
        <!-- @change→要素が変わったときにselected()の中身を実行する。v-modelの指定忘れに注意 -->
        <select name="sushi_type" id="sushi_type" v-model="selectedSushiType" @change="selected">
            <?php foreach ($sushi_type_array as $key => $sushi_type) : ?>
                <option value="<?php echo h($key) ?>">
                    <?php echo h($sushi_type) ?>
                </option>
            <?php endforeach ?>
        </select>
        <!-- netaがさっきVueで受け取ったデータ -->
        <select name="sushi_neta">
            <option v-for="(neta, index) in netas" :value="index">
                {{ neta }}
            </option>
        </select>
    </div>
    <script src="linked_pulldown.js"></script>
</body>

</html>

とりあえず完成!

efa5bb7a17aa62e42837ca1d7cfa8cfe.gif

改善が必要な点

  • v-forがあるのにkey属性がない
    …Vue3から必須級になったようで。この記事の作成過程で知りました。indexをkeyにしてもこのindexは取得してきた値たちに対して連番振るやつなので、データベースから持ってくるのであれば主キーも引っ張り出してkey属性にあてがう必要がありますねこれ
  • 初期状態の画面がいまいち(例えば初期状態なら全部の寿司ネタ見れるとか)
    …プロトタイプだからいいかなと妥協した部分。気が向いたら直したりするかもしれません

その他事項

上に自分が書いた点以外で、「この書き方はよくない」とか「こうしたらもっと良くなる」とかありましたらコメント等でご指導いただけますと幸いです。
あ、htmlspecialcharsのラッパーは手癖で書いてるものです。こういうところでも書いておかないと肝心なところで忘れそうですので…

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?