1. 程式人生 > >從0開始,手把手教你用Vue開發一個答題App

從0開始,手把手教你用Vue開發一個答題App

## 專案演示 [專案演示](https://kamiba.gitee.io/vue-quiz-app-show-version/) ## 專案原始碼 [專案原始碼](https://gitee.com/kamiba/vue-quiz) ## 教程說明 本教程適合對Vue基礎知識有一點了解,但不懂得綜合運用,還未曾使用Vue從頭開發過一個小型App的讀者。本教程不對所有的Vue知識點進行講解,而是手把手一步步從0到1,做出一個完整的小專案。目前網上的教程不是隻有零散的知識點講解;就是丟擲一個開源的大專案,初級讀者下載下來後,執行起來都很費勁,更談不上理解這個專案是如何一步步開發出來的了。本教程試圖彌補這個空白。 ## 1. 專案初始化 ### 1.1使用 Vue CLI 建立專案 > 如果你還沒有安裝 VueCLI,請執行下面的命令安裝或是升級: > > ```sh > npm install --global @vue/cli > ``` 在命令列中輸入以下命令建立 Vue 專案: ``` vue create vue-quiz ``` ``` Vue CLI v4.3.1 ? Please pick a preset: > default (babel, eslint) Manually select features ``` default:預設勾選 babel、eslint,回車之後直接進入裝包 manually:自定義勾選特性配置,選擇完畢之後,才會進入裝包 選擇第 1 種 default. 安裝結束,命令提示你專案建立成功,按照命令列的提示在終端中分別輸入: ``` # 進入你的專案目錄 cd vue-quiz # 啟動開發服務 npm run serve ``` 啟動成功,命令列中輸出專案的 http 訪問地址。 開啟瀏覽器,輸入其中任何一個地址進行訪問 ![image-20200707121732592](https://gitee.com/kamiba/images4mk2/raw/master/image-20200707121732592.png) 如果能看到該頁面,恭喜你,專案建立成功了。 ### 1.2 初始目錄結構 專案建立好以後,下面我們來了解一下初始目錄結構: ![image-20200707122944401](https://gitee.com/kamiba/images4mk2/raw/master/image-20200707122944401.png) ### 1.3 調整初始目錄結構,實現遊戲設定頁面 預設生成的目錄結構不滿足我們的開發需求,所以需要做一些自定義改動。 這裡主要處理下面的內容: - 刪除初始化的預設檔案 - 新增調整我們需要的目錄結構 刪除預設示例檔案: - src/components/HelloWorld.vue - src/assets/logo.png 修改package.json,新增專案依賴: ``` "dependencies": { "axios": "^0.19.2", "bootstrap": "^4.4.1", "bootstrap-vue": "^2.5.0", "core-js": "^3.6.5", "vue": "^2.6.11", "vue-router": "^3.1.5" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.4.0", "@vue/cli-plugin-eslint": "~4.4.0", "@vue/cli-plugin-router": "~4.4.0", "@vue/cli-service": "~4.4.0", "babel-eslint": "^10.1.0", "eslint": "^6.7.2", "eslint-plugin-vue": "^6.2.2", "vue-template-compiler": "^2.6.11" }, ``` 然後執行yarn install,安裝依賴。 修改專案入口檔案main.js,引入bootstrap-vue。 ``` import Vue from 'vue' import App from './App.vue' import router from './router' import BootstrapVue from 'bootstrap-vue' import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' Vue.config.productionTip = false Vue.use(BootstrapVue) const state = { questions: [] } new Vue({ router, data: state, render: h => h(App) }).$mount('#app') ``` 定義一個state物件來共享答題資料(答題頁面和結果頁面共享) ``` const state = { questions: [] } ``` src目錄下新增eventBus.js訊息匯流排,用來在元件間傳遞訊息,程式碼如下: ``` import Vue from 'vue' const EventBus = new Vue() export default EventBus ``` 修改App.vue,css樣式略,請參考原始碼。 ``` ``` 新增components/Navbar.vue,定義導航部分。 ![image-20200707125506858](https://gitee.com/kamiba/images4mk2/raw/master/image-20200707125506858.png) ``` ``` src目錄下新增router/index.js,定義首頁路由。 ``` import Vue from 'vue' import VueRouter from 'vue-router' import MainMenu from '../views/MainMenu.vue' Vue.use(VueRouter) const routes = [ { name: 'home', path: '/', component: MainMenu } ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) export default router ``` src下新增views/MainMenu.vue,MainMenu主要包含GameForm元件。 ``` ``` 新增src/components/GameForm.vue,實現遊戲初始設定。 ![image-20200707125814786](https://gitee.com/kamiba/images4mk2/raw/master/image-20200707125814786.png) ``` ``` GameForm元件,主要通過axios發起獲取全部題目分類請求: ``` axios.get('https://opentdb.com/api_category.php') ``` 新增src/components/LoadingIcon.vue,在非同步請求資料未返回時,渲染等待圖示。 ``` ``` 新增src/assets/ajax-loader.gif等待動畫檔案,請參考專案原始碼。 ### 1.4 執行專案 ``` yarn run serve ``` ![image-20200707130702456](https://gitee.com/kamiba/images4mk2/raw/master/image-20200707130702456.png) ## 2. 答題頁面開發 ![image-20200708083506391](https://gitee.com/kamiba/images4mk2/raw/master/image-20200708083506391.png) ### 2.1 修改路由 修改router/index.js: ``` import Vue from 'vue' import VueRouter from 'vue-router' import MainMenu from '../views/MainMenu.vue' import GameController from '../views/GameController.vue' Vue.use(VueRouter) const routes = [ { name: 'home', path: '/', component: MainMenu }, { name: 'quiz', path: '/quiz', component: GameController, props: (route) => ({ number: route.query.number, difficulty: route.query.difficulty, category: route.query.category, type: route.query.type }) } ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) export default router ``` ### 2.2 答題頁面 新增views/GameController.vue 本頁面是本專案最重要的模組,展示問題,和處理使用者提交的答案,簡單解析一下: 1.fetchQuestions函式通過請求遠端介面獲得問題列表。 2.setQuestions儲存遠端迴應的問題列表到本地陣列。 3.onAnswerSubmit處理使用者提交的選項,呼叫nextQuestion函式返回下一問題。 ``` ``` 新增\src\mixins\shuffleMixin.js 打亂問題答案,因為遠端返回的答案有規律。mixins是混入的意思,可以混入到我們的某個頁面或元件中,補充頁面或元件功能,便於複用。 ``` const ShuffleMixin = { methods: { shuffleArray: (arr) => arr .map(a => [Math.random(), a]) .sort((a, b) => a[0] - b[0]) .map(a => a[1]) } } export default ShuffleMixin ``` 新增src/components/Question.vue ``` ``` 新增src/components/QuestionBody.vue ![image-20200708083544511](https://gitee.com/kamiba/images4mk2/raw/master/image-20200708083544511.png) ``` ``` 執行: ``` yarn run serve ``` 啟動成功: ![image-20200708083506391](https://gitee.com/kamiba/images4mk2/raw/master/image-20200708083506391.png) 如果能看到該頁面,恭喜你,專案到此成功了。 ### 2.3 至此專案目錄結構 如果你走丟,請下載原始碼進行對比: ![image-20200708084009828](https://gitee.com/kamiba/images4mk2/raw/master/image-20200708084009828.png) ## 3 實現最終結果展示頁面 ![image-20200708084853745](https://gitee.com/kamiba/images4mk2/raw/master/image-20200708084853745.png) 再次修改router/index.js ``` import Vue from 'vue' import VueRouter from 'vue-router' import MainMenu from '../views/MainMenu.vue' import GameController from '../views/GameController.vue' import GameOver from '../views/GameOver' Vue.use(VueRouter) const routes = [ ... { name: 'result', path: '/result', component: GameOver } ] ... ``` 新增src/views/GameOver.vue: ``` ``` 新增src\components\Answer.vue ``` ``` ### 3.1 執行專案 ``` yarn run serve ``` ![](https://gitee.com/kamiba/images4mk2/raw/master/image-20200708084853745.png) ### 3.2 專案結構 ![image-20200708085222248](https://gitee.com/kamiba/images4mk2/raw/master/image-20200708085222248.png) ## 專案總結 很感謝您和豆約翰走到了這裡,至此我們一個小型的Vue專案,全部開發完畢,下一期,豆約翰會帶大家見識一箇中型的專案,咱們循序漸進,一起加油。 ## 最後 為了將來還能找到我 ![](https://gitee.com/kamiba/images4mk2/raw/master/468490-7ffff01f715dcbfb.png)