LoginSignup
17
2

More than 3 years have passed since last update.

Laravel + Vue.jsでクイズを作った

Last updated at Posted at 2019-12-18

作ることになったきっかけ

以前からLaravelのアウトプットとして何か作りたいと思っていたのですが、なかなかネタが思い浮かばずずっと先延ばしになっていました。
そんなある日、趣味の競馬観戦でレースの条件(開催月や距離、競馬場)が自分の記憶のものとかなり変わっていることが度々あり、自分の脳内番組表(競馬の開催スケジュールのこと)のアップデートが必要だと感じました。
そこでLaravelと、ついでにVue.jsも使ってクイズを作ることにしました。

ざっくり仕様

  • レースはGI、GⅡ、GⅢのようにグレードが定められているので、そのグレードごとにカテゴリー分けして、トップページで挑戦するカテゴリーを選択します。
  • 問題は全10問。1つの画面で開催月、距離、競馬場を選択して解答します。
  • 「回答する」ボタンをクリックすると、答えと解説が表示されます。
  • 「次の問題へ」をクリックすると、次の問題が出題されます。 10問目まで解答が終わると、結果画面が表示されます。

出題〜解答までの動き

今回はシンプルに問題の出題のみ行うので、テーブルはproblemsテーブル1つのみです。
せっかくなら画面遷移のないSPAにしたいので、コンポーネントとしてトップページ、出題ページ、結果ページの3つのVueファイルを作成します。
簡単に処理の流れを書くと、
1. fetchItemで問題をテーブルからランダムに1件取得、開発ツールからのカンニングを防ぐため、idとレース名のみ取得。
2. fetchAnswerで該当の問題をidで検索、答え合わせをする。このとき、出題済みの問題がまた出題されないようにprocessed_flgをtrueにします。
3. fetchNewItemで次の問題を取得。

ProblemCpntroller.php
    public function index($category)
    {
        DB::table('problems')->update(['processed_flg' => false]);
        $query = Problem::query();
        $query->where('category', '=', $category);
        $problem['count'] = $query->where('processed_flg', '=', false)->count();

        if($query->exists()){
            $query->select('id', 'title')->get();
            $problem = $query->inRandomOrder()->first();
            return $problem;
        }
    }
    public function fetchNewItem(Request $request)
    {
        $category = $request->input('category');
        $query = Problem::query();
        $query->where('category', '=', $category);
        $query->where('processed_flg', '=', false);

        if($query->exists()){
            $query->select('id', 'title')->get();
            $problem = $query->inRandomOrder()->first();
            return $problem;
        }
    }
    public function fetchAnswer(Request $request)
    {
        $id = $request->input('id');
        $problem = Problem::find($id);
        $problem->processed_flg = true;
        $problem->save();
        return $problem;
    }
Problem.vue
methods: {
        async fetchItem() {
            this.is_question = true
            const response = await window.axios.get(`/api/ploblems/category/${this.category}`)

            this.problem = response.data.title
            this.is_answer = false
            this.answer.id = response.data.id
        },
        async fetchNewItem() {
            if(this.counter === 9) {
                this.next_message = '結果発表'
            } else if(this.counter === 10) {
                this.$router.push({ name: 'result', params: { score: this.score } })
            }
            this.errors = {}
            this.answer = {}
            this.counter++
            this.is_question = true
            const response = await window.axios.get('/api/ploblems/category/', {params: {category: this.category}})

            this.problem = response.data.title
            this.is_answer = false
            this.answer.id = response.data.id

        },
        async fetchAnswer() {
            const answer = await window.axios.get('/api/ploblems/', {params: {id: this.answer.id}})
            this.get_answer = answer.data
            this.is_answer = true
            this.is_question = false
            if(this.answer.month !== this.get_answer.month) {
                this.errors.month = true
            }
            if(this.answer.distance !== this.get_answer.distance) {
                this.errors.distance = true
            }
            if(this.answer.place !== this.get_answer.place) {
                this.errors.place = true
            }

            if(!this.errors.month && !this.errors.month && !this.errors.place) {
                this.score++
            }
        }

実際の動き

raceq_ .gif

作ってみた感想

時間の関係で、とにかく動くことを優先してしまったので、リファクタリングの余地ありありになってしまいました。
答え合わせのときの表示も、もっと分かりやすく表示させたかったですね。
でもこうしてアウトプットをすることで、自分の理解の浅い部分を洗い出すことができました。今後も作ってみたい物はあるので、LaravelやVue.jsに限らずいろいろ挑戦したいです!

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