仿"米丫天氣App"-Vue項目總結

032bd3557a5abcd0000018c1b74486e.jpg

前言

先說說寫這個項目的動機。以前工做的時候,雖然作過很多項目,可是由於簽了保密協議,無法把代碼放出來。後來跳槽的時候,拿不出一個完整的我的項目,只能把平時寫的一些小demo拿出來遛遛。因此打算寫一個本身的項目。
這個項目仿的是「米丫天氣」APP。也不知道會不會侵權,反正先放上來再說。功能部分其實很簡單,只是通常的數據獲取,還有用戶管理這一塊的功能。主要是經過這個項目來練習一個完整的項目所須要考慮到的地方。例如:項目文件架構,邏輯組件和公共組件應該如何安排;vuex部分該怎樣劃分和組合;router部分該怎樣配置;前臺和後臺應該若是關聯。
目前項目還有很多bug,先發了,後面再慢慢優化。
這篇文章將把我作這個項目的過程和一些想法描述出來,給本身總結一下。固然,若是能夠幫助到也在寫vue的朋友就更好了。

技術棧

  • vue
  • vue-router
  • vuex
  • axios
  • stylus
  • easy-mock

項目連接:weather-webappcss

項目結構

按字母順序vue

  1. api:請求數據時使用到的方法
  2. assets:靜態資源。主要包括一些圖標和全局樣式之類的文件
  3. components:公共組件
  4. router:路由配置
  5. store:集中數據管理(vuex)
  6. tools:工具函數
  7. view:邏輯頁面組件
  8. App.vue:根組件
  9. main.js:入口文件
這裏稍微提一下css的解決方案。
以前一直都在使用sass,只是node-sass很難安裝成功,因此就改用stylus。二者的差異我感受不是很大。另外是 .vue文件中的 style部分,即便添加 scoped屬性,仍是會有可能發生衝突。例如父子組件的樣式中都擁有同一個類名,這時就會發生衝突。目前正在打算準備使用 css-modules

從路由開始吧

對於路由,各位寫過vue的朋友應該都不陌生了。這裏主要講一下路由的結構,我把它理解爲「分層」,也就是router-view組件的位置。以前在看一個ui框架的時候(忘了是啥框架了),留意到它的頁面分層的概念。大概是這樣的:
1.遮罩層(loading之類的) 2.交互層(模態框什麼的) 3.消息提示層(本項目中的toast組件) 4.主內容界面 5.嵌套的子路由
目前就只想到這些了。node

另外是router.js文件的寫法。在本項目中,我把全部的路由寫在同一個文件,是由於路由比較少,若是在路由結構多而複雜的項目,這種寫法會很頭疼。建議的寫法是將各個邏輯模塊的路由分開,最後在主路由裏引入。大概是這樣的:react

// router/module-a.js

const View1 = () => import('@/view/view-1')
const View2 = () => import('@/view/view-2')

export default [
  { path: '/home/module-a/view-1', name: 'view-1', component: View1 },
  { path: '/home/module-a/view-2', name: 'view-2', component: View2 }
]
// router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import ModuleA from './module-a'

Vue.use(Router)

const router = new Router({
  routes: [
    ...ModuleA
  ]
})

export default router

噢,對了。以前還在sf找到一個小技巧:如何在切換路由時,修改瀏覽器標籤的標題。ios

router.beforeEach((to, from, next) => {
  window.document.title = to.meta.title || '米丫天氣'
  next()
})

注意:我試過把title寫在路由屬性中而不是meta裏,發現是不可行(多寫一層也沒啥大問題)。git

來講說store

在項目的store裏面,只有modules,沒有根層的state,這個主要是受redux的一些影響吧。把全部須要緩存的數據放在一個store樹裏面,每一個模塊單獨控制。另外在store/index.js裏面會看到setState這個方法。這個也是受react的影響(this.setState 方法),也是一個小技巧吧。vuex裏面提到mutations只處理同步的操做,actions處理異步操做。那麼基本上每一個action都會commit一個或者多個mutation。而mutation是應該只修改一個state仍是多個?這個問題根據不一樣的業務邏輯會有不一樣的結果。因此定義了setState這個通用的方法。至於action的寫法,本項目裏的寫法我感受仍是有點問題的。下面是最近找到的關於async函數的寫法:web

async function getSomething() {
    try{
       const result = await apiGetSomething()
       if(result.status === 'ok') {
           // some code
       }
    } catch(err) { console.error(err) }
}

關於這種寫法目前還在思考中,後續會進行修改。vue-router

api文件

上述提到的action裏使用到請求數據的api方法。api方法都會返回一個promise對象,同時也是一個異步函數。
說到api就要提一下easy-mock。這個網站是基於mock.js,能夠很方便生成自定義接口,就算你不會後臺,也能夠很快速簡單的編輯本身想要的接口。使用方法嘛,仍是直接看官方教程吧。
由於本項目要使用的數據比較簡單,因此接口部分沒有什麼好說的了。vuex

資源文件

assets部分的圖標會被看成依賴,引用的時候使用import引入,而後還不能直接使用,必須放到配置項裏面,通常是放在data
而後是style,這裏主要是配置全局樣式變量,例如主題色之類的。
具體方法:
build/utils.js的generateLoaders中修改.
添加全局變量的文件配置redux

const stylusOptions = {
  import: [path.join(__dirname, '../src/assets/style/theme.styl')],
  paths: [path.join(__dirname, '../src/assets/style/'), path.join(__dirname, '../')]
}

其中的theme.styl定義全局變量的文件

修改stylus的配置

stylus: generateLoaders('stylus', stylusOptions),
styl: generateLoaders('stylus', stylusOptions)

公共組件

基本上我把能夠單獨提出來的內容都寫成公共組件。另外單獨寫了一個index.js文件。裏面將全部的公共組件引入而後打包導出,這樣在使用的時候就能夠少寫不少代碼,這個技巧是以前看vux-ui裏面的組件定義學到的。

// components/index.js

const TabBar = () => import('./TabBar')
const AddressBar = () => import('./AddressBar')
const TmpPanel = () => import('./TmpPanel')
// ...
export { TabBar, AddressBar, TmpPanel //... }
// 邏輯頁面引入
import { TabBar, AddressBar, TmpPanel } from '@/components'

待續。。。

相關文章
相關標籤/搜索