從0開始,手把手教你用Vue開發一個答題App
阿新 • • 發佈:2020-07-08
## 專案演示
[專案演示](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)