使用typescript+vue 編寫電影資訊小專案!
為什麼要編寫這篇文章?一是對自己技術的磨練,二是給大家分享如何使用vue+typescript開發專案。
大佬就不要噴我的程式碼了。主要面向技術一般般的同學,沒有寫過typescript。當然我技術也是一般般。
正文:
我假設你已經熟練應用過vue全家桶(vue+router+vuex+axios[‘黑人問號臉?’])
另外先泡一杯咖啡!
在這裡我也不教你如何配置環境了直接開始正題,let's go!
第一階段配置專案並啟動
當前開發版本:

vue create projectName//projectName 是指你的專案名稱 複製程式碼
這裡可以選擇預設模板和和自己配置。

這裡我選擇的是第二個,然後又讓你選擇……

這裡的選擇可以按數字鍵選擇的
- Babel =====> 1
- TyepScript ====> 2
以次類推,所以你懂我意思吧
這裡選擇我們需要的幾個東東,然後愉快的回車把,喝一會咖啡等待專案安裝完成。

安裝完成之後我們先看下檔案目錄

細心的同學肯定發現了少了 build 和config 資料夾。那麼如果我配置webpack 怎麼辦?
新建一個 vue.config.js ofollow,noindex">不明白的同學可以點選這裡
那麼開始安裝我們需要的一些依賴!
npm i vant -S// ui框架 npm i babel-plugin-import -D// 使用 babel-plugin-import npm install --save-dev sass-loader// sass npm install --save-dev node-sass// sass-loader依賴於node-sass npm install --save vuex-class// 更方便使用vuex npm i axios -S// axios 複製程式碼
最後幾步
在配置檔案babel.config.js 中加上:
"plugins": [ ["import", { "libraryName": "vant", "libraryDirectory": "es", "style": true }] ] 複製程式碼
刪除已經無用的about.vue
在components中新建Header.vue 並寫入程式碼
<template> <div class="header"> <van-nav-bar title="首頁" /> </div> </template> <script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator'; import { NavBar } from 'vant'; @Component({ components: { [NavBar.name]: NavBar, }, }) export default class Header extends Vue { } </script> <style scoped> </style> 複製程式碼
App.vue的標籤後面寫入
<script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; import { NavBar } from 'vant'; import Header from '@/components/Header.vue'; @Component({ components: { Header }, }) export default class App extends Vue { } </script> 複製程式碼
刪除Home.vue的程式碼,寫入
<template> <div class="home"> <p>第一個vue+typescript應用</p> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; export default class Home extends Vue {} </script> 複製程式碼
應該是編輯器的bug,有些程式碼會提示bug,不過我們視終端和瀏覽器控制檯的報錯才是真正的報錯!
在控制檯輸入npm run serve

第二階段 封裝axios 和 使用vuex
在scr目錄下新建utils和store兩個資料夾
utils新建立request.ts
import * as axios from 'axios'; import store from '@/store'; import { Toast } from 'vant'; import { AxiosResponse, AxiosRequestConfig } from 'axios'; const baseURL = 'https://api.douban.com/v2/movie/'; const service = axios.default.create({ baseURL, timeout: 0, maxContentLength: 4000, }); service.interceptors.request.use((config: AxiosRequestConfig) => { return config; }, (error: any) => { Promise.reject(error); }); service.interceptors.response.use( (response: AxiosResponse) => { if (response.data.start !== 0) { Toast.fail('請求錯誤!'); } else { return response.data; } }, (error: any) => { return Promise.reject(error); }); export default service; 複製程式碼
新建ajax.ts
export interface AjaxResponse { code: number; data: any; message: string; } 複製程式碼
axios 簡單封裝完成。
vue.config 跨域設定vue官網webpack配置
module.exports = { configureWebpack: config => { }, devServer: { proxy: { '/api': { target: 'http://api.douban.com/v2', changeOrigin: true, ws: true, pathRewrite: {//一定要加上這個!!!!不然不能跨域,親身體驗! '^/api': '' } } } } } 複製程式碼
store 介面型別為了方便複用全部寫在store/interface.ts, 每個view元件對應一個資料夾。
store/home/index.ts
import { State } from '@/store/interface'; import { Commit } from 'vuex'; import { getMovieList } from '@/api/home'; const state: State = { movieList: [], }; const getters = { // tslint:disable-next-line:no-shadowed-variable movieList: (state: State) => state.movieList, }; const mutations = { }; const actions = { async movieList(context: { commit: Commit }, cate: string) { const res: any = await getMovieList(cate) .then( (response: any ) => response) // tslint:disable-next-line:no-console .catch((e: string) => console.error(e)); return res; }, }; export default { state, getters, mutations, actions, }; 複製程式碼
http請求程式碼則放在src/api下,同樣的每一個view元件對應一個檔案。
home.ts
import request from '@/utils/request'; // tslint:disable-next-line:only-arrow-functions export const getMovieList = function(cate: string) { return request({ url: '/api/movie/' + cate , method: 'GET', }); }; 複製程式碼
第三階段 首頁編寫
如何在vuex中使用點選此處
home.vue
<template> <div class="home"> <van-tabs v-model="active"> <van-tab title="正在熱映"> <div id="listMovieBox"> <div class="item" v-for="(item, index) in movieListData":key = 'index'> <a > <div class="movie-cover"> <img :src="item.images.small"width="88" height="110"> </div> <div class="movie-des"> <p class="title">{{item.title}}</p> <p class="genres"><span>類別:</span><span v-if="item.genres.length === 0">未知</span><span v-else-if="item.genres">{{item.genres}}</span></p> <p class="cast"> 主演:<span v-for="items in item.casts" style="margin-right: 4px;">{{ items.name}}</span> </p> <p class="director">導演:<span v-if="item.casts[1]">{{ item.casts[1].name }}</span></p> <p class="ratings">{{item.rating.average}} <span>分</span></p> </div> </a> </div> </div> </van-tab> <van-tab title="即將上映"> </van-tab> <van-tab title="Top250"> </van-tab> </van-tabs> </div> </template> <script lang="ts"> import { Component, Vue, Watch } from 'vue-property-decorator'; import {Action, Mutation, State} from 'vuex-class'; import { Tab, Tabs } from 'vant'; @Component({ components: { [Tab.name]: Tab, [Tabs.name]: Tabs, }, }) export default class Home extends Vue { private cate = 'in_theaters'; private active =0; private movieListData = []; @Action private movieList!: (cate: string) => any; private created() { this.movieList( this.cate ).then( (res: any) => { this.movieListData = res.subjects; }); } } </script> <style lang="sass"> #listMovieBox padding: 0 16px .item padding: 10px 0 border-bottom: 1px solid #eee a position: relative display: flex .movie-cover width: 88px flex: 0 height: 110px color: #000 .movie-des flex: 1 padding-left: 10px vertical-align: top .ratings position: absolute font-size: 20px font-weight: bold font-family: "Microsoft New Tai Lue" color: #FFB400 right: 0px top: 16px span font-size: 14px .title line-height: 1.5rem padding-top: 4px font-size: 16px .genres font-size: 12px color: #666 line-height: 24px .cast font-size: 12px width: 200px overflow: hidden white-space: nowrap text-overflow: ellipsis color: #666 line-height: 24px .director font-size: 14px color: #999 line-height: 26px </style> 複製程式碼
