amtoaer

晓风残月

叹息似的渺茫,你仍要保存着那真!
github
x
telegram
steam
nintendo switch
email

馬原毛概刷題ツール(WEB VERSION)

試験前に急いでマ原刷題ツールを作成し、試験後に時間ができたので、マ原毛概刷題ツールに拡張し、ランダム刷題、試験シミュレーション、間違いノートなどの機能を追加しました。しかし、正直なところ、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 の中級知識を持っていることを前提としています。フロントエンド開発を始めたばかりの場合、フレームワークを最初のステップとして使用するのは最良のアイデアではないかもしれません —— 基礎知識をしっかりと身につけてから来てください!以前に他のフレームワークの使用経験があれば役立ちますが、必須ではありません。

私はフロントエンドの知識が全くなかったので、まずfreecodecampHTMLの基礎と最初の数回のCSSを学び(CSSの内容は本当に多すぎる!)、その後廖雪峰教程JavaScriptの関数部分を学びました。そして、公式ドキュメントを参考にしながら開発を始めました。


まずwebpackの雛形を使用してvueプロジェクトを作成し、次にmuse-uiコンポーネントライブラリをインストールして取り込みました。

  1. ルーティング

    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
        }
      ]
    })
    
  2. コンポーネント

    • App.vueに共通のトップバー、サイドバーなどの内容を書き、ルートの変化を監視してタイトルを変更します。

    • index.vueabout.vueは純粋なHTML/CSSで作成されています。

    • temp.vueは刷題方法を選択するためのものです。

    • order.vueは順序刷題インターフェースで、mu-paginationを使用してページングを行い、exam.vueは試験シミュレーションインターフェースで、mu-load-moreを使用して問題部分を読み込みます。

    • question.vueは単位問題で、order.vueexam.vueの子コンポーネントで、propsnumの変化を監視し、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リソースを読み込むことができないため、ginhttpsを追加する必要があることがわかりました。

調べたところ、一般的な方法はサブドメインと無料証明書を申請することですが、私はそんなに面倒なことをしたくなかったので、ちょうど手元にhttpsのドメインがあったので、nginxの現在のserverブロックにリバースプロキシを設定しました:

location /api{
        proxy_pass http://localhost:8080;
}

その後、github pagesでこのアドレスをリクエストしましたが、間にnginxがあるせいか、再びクロスオリジンの問題が発生し、一時的に解決方法が見つからなかったため、やむを得ずフロントエンドもnginxにデプロイしました。問題は解決しました(唯一の問題は私のサーバーが未登録のため、ポートを手動で入力してアクセスする必要があることです)。

参考#

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。