試験前に急いでマ原刷題ツールを作成し、試験後に時間ができたので、マ原毛概刷題ツールに拡張し、ランダム刷題、試験シミュレーション、間違いノートなどの機能を追加しました。しかし、正直なところ、python
のコマンドラインプログラムはあまり使いやすくないので、ウェブ版に変更することを考えました。現在このプロジェクトは github でオープンソースになっています(それ以前はフロントエンドに触れたことがなかったので、いくつかの不足があるかもしれません)。
バックエンド#
バックエンドはgo
の軽量ウェブフレームワークgin
を使用しています。コードはこちら!
現在のディレクトリのmayuan.json/maogai.json
を読み込み、異なるルートに基づいて異なる結果を返します:
アクセスアドレス | 返却結果 |
---|---|
/$subject/position/ | 該当 subject の位置が num の問題を返す |
/$subject/random/ | 該当 subject のランダムな問題を返す |
/$subject/random/radio | 該当 subject のランダムな単選択問題を返す |
/$subject/random/checkbox | 該当 subject のランダムな多選択問題を返す |
フロントエンド#
フロントエンドはvue.js
を使用し、学習する際に公式ドキュメントで次の文を見つけました:
公式ガイドは、あなたが HTML、CSS、JavaScript の中級知識を持っていることを前提としています。フロントエンド開発を始めたばかりの場合、フレームワークを最初のステップとして使用するのは最良のアイデアではないかもしれません —— 基礎知識をしっかりと身につけてから来てください!以前に他のフレームワークの使用経験があれば役立ちますが、必須ではありません。
私はフロントエンドの知識が全くなかったので、まずfreecodecamp
でHTML
の基礎と最初の数回のCSS
を学び(CSS
の内容は本当に多すぎる!)、その後廖雪峰教程
でJavaScript
の関数部分を学びました。そして、公式ドキュメントを参考にしながら開発を始めました。
まずwebpack
の雛形を使用してvue
プロジェクトを作成し、次にmuse-ui
コンポーネントライブラリをインストールして取り込みました。
-
ルーティング
import Vue from 'vue' import Router from 'vue-router' import index from '../components/index' import temp from '../components/temp' import exam from '../components/exam' import order from '../components/order' import about from '../components/about' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'index', component: index }, { path: '/マ原', name: 'mayuan', component: temp }, { path: '/毛概', name: 'maogai', component: temp }, { path: '/マ原/順序刷題', name: 'mayuanorder', component: order }, { path: '/毛概/順序刷題', name: 'maogaiorder', component: order }, { path: '/マ原/試験シミュレーション', name: 'mayuanexam', component: exam }, { path: '/毛概/試験シミュレーション', name: 'maogaiexam', component: exam }, { path: '/について', name: 'about', component: about } ] })
-
コンポーネント
-
App.vue
に共通のトップバー、サイドバーなどの内容を書き、ルートの変化を監視してタイトルを変更します。 -
index.vue
とabout.vue
は純粋なHTML/CSS
で作成されています。 -
temp.vue
は刷題方法を選択するためのものです。 -
order.vue
は順序刷題インターフェースで、mu-pagination
を使用してページングを行い、exam.vue
は試験シミュレーションインターフェースで、mu-load-more
を使用して問題部分を読み込みます。 -
question.vue
は単位問題で、order.vue
とexam.vue
の子コンポーネントで、props
のnum
の変化を監視し、getQuestion()
を呼び出して対応する問題を読み込み、単選択か多選択かを判断します。選択肢を選ぶ際にはifRight()
を使用して答えが正しいかどうかを判断します。// ifRight ifRight: function () { let answer if (this.isRadio === false) {// 多選択は答えの配列をソートして文字列に結合 answer = this.yourAnswer.sort().join("") } else {// 単選択はそのまま取得 answer = this.yourAnswer } if (answer === this.question["Answer"]) { this.isRight = true let that = this if (this.timer) clearTimeout(this.timer) this.timer = setTimeout(function () {// 2秒間通知を表示 that.isRight = false }, 2000) } else { this.isRight = false } } // getQuestion getQuestion () { this.yourAnswer=[] // 親コンポーネントのpathと現在のnumに基づいてリクエストするアドレスを取得 if (this.type === "/マ原/順序刷題") { this.url = "https://.../api/mayuan/position/" + (this.num - 1) } else if (this.type === "/毛概/順序刷題") { this.url = "https://.../api/maogai/position/" + (this.num - 1) } else if (this.type === "/マ原/試験シミュレーション") { if (this.num <= 40) { this.url = "https://.../api/mayuan/random/radio" } else { this.url= "https://.../api/mayuan/random/checkbox" } } else if (this.type === "/毛概/試験シミュレーション") { if (this.num <= 40) { this.url = "https://.../api/maogai/random/radio" } else { this.url = "https://.../api/maogai/random/checkbox" } } axios// axiosを使用してAPIから問題を取得 .get(this.url) .then(response => { this.question = response.data if (this.question['Answer'].length > 1) {// 単選択か多選択かを判断 this.isRadio = false } else { this.isRadio = true } }) }
-
デプロイ#
デプロイ時にいくつかの問題に直面しました。
最初にローカルでデバッグしていると、問題を読み込むことができないことに気付きました。chrome console
のエラーメッセージを確認したところ、バックエンドがクロスオリジンを設定していないためだとわかり、バックエンドのルートに次のように追加しました:
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
デバッグは正常に行われましたが、github pages
にデプロイすると、再び読み込めないことがわかりました。エラーメッセージを確認すると、https
のウェブページではhttp
リソースを読み込むことができないため、gin
にhttps
を追加する必要があることがわかりました。
調べたところ、一般的な方法はサブドメインと無料証明書を申請することですが、私はそんなに面倒なことをしたくなかったので、ちょうど手元にhttps
のドメインがあったので、nginx
の現在のserver
ブロックにリバースプロキシを設定しました:
location /api{
proxy_pass http://localhost:8080;
}
その後、github pages
でこのアドレスをリクエストしましたが、間にnginx
があるせいか、再びクロスオリジンの問題が発生し、一時的に解決方法が見つからなかったため、やむを得ずフロントエンドもnginx
にデプロイしました。問題は解決しました(唯一の問題は私のサーバーが未登録のため、ポートを手動で入力してアクセスする必要があることです)。