推薦一個基於Vue 的 H5 快速開發模板

模板基於 vue-cli4 和 Vant-ui 搭建,進行大型 H5 項目開發最佳實踐方案,讓咱們來一探究竟javascript

模板地址 動動你可愛的小手點亮一顆 starcss

項目結構

本項目已經爲你生成了一個完整的開發框架,下面是整個項目的目錄結構。html

├── .github                    # git log
├── plop-templates             # 基本模板
├── public                     # 靜態資源
│   │── favicon.ico            # favicon圖標
│   └── index.html             # html模板
├── src                        # 源代碼
│   ├── assets                 # 靜態資源
│   ├── components             # 全局公用組件
│   ├── constants              # 常量
│   ├── core                   # 分層
│   ├── enum                   # 枚舉
│   ├── filters                # 全局 filter
│   ├── icons                  # 項目全部 svg icons
│   ├── lang                   # 國際化 language
│   ├── layout                 # 全局 layout
│   ├── router                 # 路由
│   ├── store                  # 全局 store 管理
│   ├── styles                 # 全局樣式
│   ├── utils                  # 全局公用方法
│   ├── pages                  # pages 全部頁面
│   ├── pwa                    # 漸進式Web應用
│   ├── App.vue                # 入口頁面
│   ├── main.js                # 入口文件 加載組件 初始化等
│   └── permission.js          # 權限管理
├── tests                      # 測試
├── .editorconfig              # 代碼風格
├── .env.xxx                   # 環境變量配置
├── .eslintrc.js               # eslint 配置項
├── .sentryclirc.js            # 前端異常日誌監控配置
├── .babel.config              # babel 配置
├── plopfile.js                # 基本模板配置
├── vue.config.js              # vue-cli 配置
├── postcss.config.js          # postcss 配置
└── package.json               # package.json
...
複製代碼

安裝

# 克隆項目
git clone https://github.com/push-over/vue-h5-template.git

# 進入項目目錄
cd vue-h5-template

# 安裝依賴
npm install

# 建議不要用 cnpm 安裝 會有各類詭異的bug 能夠經過以下操做解決 npm 下載速度慢的問題
npm install --registry=https://registry.npm.taobao.org

# 本地開發 啓動項目
npm start
複製代碼

TIP前端

強烈建議不要用直接使用 cnpm 安裝,會有各類詭異的 bug,能夠經過從新指定 registry 來解決 npm 安裝速度慢的問題。若仍是不行,可以使用 yarn 替代 npmvue

Windows 用戶若安裝不成功,很大機率是node-sass安裝失敗,解決方案java

另外由於 node-sass 是依賴 python環境的,若是你以前沒有安裝和配置過的話,須要自行查看一下相關安裝教程。node

啓動完成後會自動打開瀏覽器訪問 [http://localhost:9000, 你看到下面的頁面就表明操做成功了。python

接下來你能夠修改代碼進行業務開發了,本項目內建了典型業務模板、模擬數據、狀態管理、國際化、全局路由等等各類實用的功能來輔助開發android

經常使用命令

# 項目打包
npm run build:xxx

# 自動建立
npm run new

# 規範Git提交
npm run git-cz

# 生成CHANGELOG
npm run genlog
複製代碼

分層架構

目前前端的一個開發趨勢是以搭建單頁應用 (SPA) 爲主的。當應用體系比較大,或者你的應用業務邏輯足夠複雜的時候,會遇到各類各樣的問題,咱們隨便提兩點:webpack

  • 產品須要多人協做時,每一個人的代碼風格和對業務的理解不一樣,致使業務邏輯分佈雜亂無章

  • 對產品的理解停留在頁面驅動層面,致使實現的技術模型與實際業務模型出入較大,當業務需求變更時,技術模型很容易被摧毀

  • ...

針對上面所遇到的問題,咱們如下面這張架構圖作講解:

其中 視圖層/View 是你們接觸最多的,想必你們都很瞭解,就不在這裏介紹了,重點介紹其餘幾個層的含義:

Services 層

Services 層是用來對底層技術進行操做的,例如封裝 AJAX 請求,操做瀏覽器 CookieLocaStorageIndexedDB,操做 Native 提供的能力(如調用攝像頭等),以及創建 Websocket 與後端進行交互等。

Axios 封裝

.....

export default async function(options) {
  const { url } = options
  const requestOptions = Object.assign({}, options)

  try {
    const { data, data: { errno, errmsg }} = await instance.request(requestOptions)
    if (errno) {
      errorReport(url, errmsg, requestOptions, data)
      throw new Error(errmsg)
    }
    return data
  } catch (err) {
    errorReport(url, err, requestOptions)
    throw err
  }
}
複製代碼

IndexedDB

...

export class DBRequest {
  instance

  static getInstance() {
    if (!this.instance) {
      this.instance = new DBRequest()
    }
    return this.instance
  }
  async create(options = {}) {
    const { name, data } = options
    const db = await indexDB(name)
    return await db.add(name, data)
  }
    ...
}

複製代碼

.......

Entities 層

實體 Entity 是領域驅動設計的核心概念,它是領域服務的載體,它定義了業務中某個個體的屬性和方法。區分一個對象是不是實體,主要是看他是否有惟一的標誌符(例如 id)

經過上面的代碼能夠看到,這裏主要是以實體自己的屬性以及派生屬性爲主,固然實體自己也能夠具備方法,用於實現屬於實體自身的業務邏輯。

並非全部的實體都應該按上面那樣封裝成一個類,若是某個實體自己業務邏輯很簡單,就沒有必要進行封裝,例如本模板中的 Test 只是作個演示。

Interactors 層

Interactors 層是負責處理業務邏輯的層,主要是由業務用例組成

import { Request } from '@/utils/request'
import { CARDS } from '@/constants/api/test'

class TestHttpInteractor {
  service
  constructor(service) {
    this.service = service
  }
  async getTest() {
    try {
      const options = { url: CARDS }
      return await this.service.get(options)
    } catch (error) {
      throw error
    }
  }
  async createTest(data) {
    try {
      const optons = { url: CARDS, data }
      await this.service.post(optons)
    } catch (error) {
      throw error
    }
  }
    
	...
}

const testHttpInteractor = new TestHttpInteractor(Request.getInstance())
export default testHttpInteractor
複製代碼

經過上面的代碼能夠看到,Sevices 層提供的類的實例主要是經過 Interactors 層的類的構造函數獲取到,這樣就能夠達到兩層之間解耦,實現快速切換 service 的目的了,固然這個和依賴注入 DI 仍是有些差距的,不過已經知足了咱們的需求。

另外 Interactors 層還能夠獲取 Entities 層提供的實體類,將實體類提供的與實體強相關的業務邏輯和 Interactors 層的業務邏輯融合到一塊兒提供給 View 層,例如:

固然這種分層架構並非銀彈,其主要適用的場景是:實體關係複雜,而交互相對模式化,例如企業軟件領域。相反實體關係簡單而交互複雜多變就不適合這種分層架構了。

而後須要明確的是,架構和項目文件結構並非等同的,文件結構是你從視覺上分離應用程序各部分的方式,而架構是從概念上分離應用程序的方式。你能夠在很好地保持相同架構的同時,選擇不一樣的文件結構方式。沒有完美的文件結構,所以請根據項目的不一樣選擇適合你的文件結構。

佈局

頁面總體佈局是一個產品最外層的框架結構, 這裏使用了 vue-router 路由嵌套, 因此通常狀況下,你增長或者修改頁面只會影響 app-main這個主體區域。其它配置在 layout 中的內容如:底部導航都是不會隨着你主體頁面變化而變化的。

/foo                                  /bar
+------------------+                  +-----------------+
| layout           |                  | layout          |
| +--------------+ |                  | +-------------+ |
| | foo.vue      | |  +------------>  | | bar.vue     | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+
複製代碼

這裏在 app-main 外部包了一層 keep-alive 主要是爲了緩存 的,如不須要可自行去除。

樣式

CSS Modules

在樣式開發過程當中,有兩個問題比較突出:

  • 全局污染 —— CSS 文件中的選擇器是全局生效的,不一樣文件中的同名選擇器,根據 build 後生成文件中的前後順序,後面的樣式會將前面的覆蓋;
  • 選擇器複雜 —— 爲了不上面的問題,咱們在編寫樣式的時候不得不當心翼翼,類名裏會帶上限制範圍的標示,變得愈來愈長,多人開發時還很容易致使命名風格混亂,一個元素上使用的選擇器個數也可能愈來愈多,最終致使難以維護。

好在 vue 爲咱們提供了 scoped 能夠很方便的解決上述問題。 它顧名思義給 css 加了一個域的概念。

/* 編譯前 */
.example {
  color: red;
}

/* 編譯後 */
.example[_v-f3f3eg9] {
  color: red;
}
複製代碼

只要加上 style scoped 這樣 css 就只會做用在當前組件內了。

TIP

使用 scoped 後,父組件的樣式將不會滲透到子組件中。不過一個子組件的根節點會同時受其父組件的 scoped CSS 和子組件的 scoped CSS 的影響。這樣設計是爲了讓父組件能夠從佈局的角度出發,調整其子組件根元素的樣式。

目錄結構

vue-h5-template 全部全局樣式都在 @/src/styles 目錄下設置

├── styles
│   ├── _animation               # 按鈕樣式
│   ├── index.scss               # 全局通用樣式
│   ├── _mixin.scss              # 全局mixin
│   ├── _transition.scss         # 過渡效果
│   └── variables.scss           # 全局變量
複製代碼

一次完整的與服務器端交互

vue-h5-template 中,一個完整的前端 UI 交互到服務端處理流程是這樣的:

  1. UI 組件交互操做
  2. 調用統一管理的 api service 請求函數
  3. 使用封裝的 request.js 發送請求
  4. 獲取服務端返回
  5. 更新 data

request.js

其中,@/src/utils/request.js 是基於 Server目錄的 http 的二次封裝,便於統一處理 POST,GET 等請求方式。具體能夠參看項目代碼。

...
export class Request {
  instance

  static getInstance() {
    if (!this.instance) {
      this.instance = new Request()
    }
    return this.instance
  }

  async post(options = {}) {
    const { data } = await service({
      method: 'post',
      ...options
    })
    return data
  }
    ...
}

複製代碼

例子

定義接口地址統一管理 src/constants/api/test.js

export const CARDS = '/admin/cards'
複製代碼

請求方法 src/core/interactors/test-interactor.js

async getTest() {
  try {
    const options = { url: CARDS }
    return await this.service.get(options)
  } catch (error) {
    throw error
  }
}
複製代碼

請求方式 src/utils/request.js

async get(options = {}) {
   const { data } = await service({
     method: 'get',
     ...options
   })
   return data
}
複製代碼

TIP

目錄結構不要糾結,我的習慣而定

頁面使用 src/pages/test/index.vue

# 生命週期
async created() {
   if (this.id) {
     await this.handleGetTest()
   }
}

# 請求
async handleGetTest() {
  try {
    const test = await testInteractor.getTest(this.id)
    this.addressInfo = Object.assign({}, test)
  } catch (error) {
    console.log(error)
  }
}
複製代碼

可能你們會以爲很繁瑣,這麼多文件容易搞混,重複編寫代碼等等,不要着急,本模板配置了自動生成文件,上述除了視圖/View層這塊須要你手動去編寫代碼,其餘的咱們都會去一鍵生成,接下來咱們就來說講使用方法。

生成所需文件

在開發過程當中,不管咱們添加頁面也好仍是添加組件等等。都須要不停地新建 .vue文件(或者其餘框架或者html/js/css文件)

以Vue項目爲例, 咱們新建一個component 或 view 的時候,須要新建一個.vue文件,而後寫 <template>、<script>、<style>。最後寫咱們的業務代碼。若是使用 class 風格來寫 Vue 還須要在每一個頁面都引入 Vue 和Component

既然這種重複性的工做,並且並無實際的操做難度,咱們是學不到任何東西的,那有沒有什麼辦法能夠告別手敲呢, 在這裏給你們介紹一個插件 plop,它的使用方式比較簡單,在這裏我不作過多介紹了,你們能夠查閱文檔,或者直接拉取本模板進行查閱

本項目中我一個配置了5項,他們分別表明着什麼呢?

module.exports = function(plop) {
  plop.setGenerator('page', pageGenerator)        			// Page
  plop.setGenerator('component', componentGenerator)		// 組件
  plop.setGenerator('store', storeGenerator)				// vuex
  plop.setGenerator('interactor', interactorGenerator)		// 業務邏輯
  plop.setGenerator('db-interactor', dbInteractorGenerator)	//db業務邏輯
}
複製代碼

TIP

建立模板指令是 npm run new,記得屬於目錄或文件名稱哦

DSBridge

DSBridge的主要特色

  • DSBridge真正跨平臺,官方同時支持ios和android。
  • DSBridge支持同步調用。
  • 三端友好;不管是在ios、android或者web,使用起來都很是簡單優雅,這一點和WebViewJavascriptBridge相比,簡直就是藝術。
  • DSBridge爲國人項目,有詳細中文文檔和問題反饋渠道。

H5頁面與Native之間通訊

  • 跨平臺;同時支持ios和android。
  • 雙向調用;js能夠調用native, native能夠調用js
  • 不只支持異步調用,並且頁支持同步調用(dsbridge是惟一一個支持同步調用的javascript bridge)
  • 支持進度回調,屢次返回(經常使用於文件下載進度、計時器等)
  • Android支持騰訊x5內核
  • 三端易用;不管是前端仍是android或ios,使用都很是簡單,極大的下降集成/學習成本

環境變量與配置文件

env

# 移動端控制檯  開(yes) | 關(no)
VCONSOLE=no  

# 標題
VUE_APP_TITLE=CHINA-GOODS-H5

# 端口號
DEVSERVERPORT=9000

# 錯誤監控平臺
SENTRY_ENABLED=yes
SENTRY_DSN='https://b84aa04e3def4784a471f8032dc62fd4@sentry.io/3619515'
SENTRY_PLUGIN_ENABLED=no
複製代碼

settings

export const TITLE = ''      			// 標題
export const TOKEN_KEY = ''				// token-key
export const LANGUAGE_KEY = 'language'	// 國際化
...
複製代碼

ESLint .editorconfig

無論是多人合做仍是我的項目,代碼規範都是很重要的。這樣作不只能夠很大程度地避免基本語法錯誤,也保證了代碼的可讀性。

ESLint 全部的配置文件都在 .eslintrc.js 中。 本項目基本規範是依託於 vue 官方的 eslint 規則 eslint-config-vue 作了少量的修改。你們能夠按照本身的需求進行定製化配置。

代碼風格在 .editorconfig,你們能夠按照我的喜歡個性化修改。

圖標 SVG

若是你沒有在本項目 Icon 中找到須要的圖標,能夠到 iconfont.cn 上選擇並生成本身的業務圖標庫,再進行使用。或者其它 svg 圖標網站,下載 svg 並放到文件夾之中就能夠了。

生成圖標庫代碼

首先,搜索並找到你須要的圖標,將它採集到你的購物車裏,在購物車裏,你能夠將選中的圖標添加到項目中(沒有的話,新建一個),後續生成的資源/代碼都是以項目爲維度的。

如今本項目支持和推薦單獨導出 svg 的引入使用方式。下載方式以下圖:

下載完成以後將下載好的 .svg 文件放入 @/icons/svg 文件夾下以後就會自動導入。

更進一步優化本身的svg

已經配置指令,只須要執行相關指令就好:

npm run svgo
複製代碼

使用方式

<svg-icon icon-class="password" /> // icon-class 爲 icon 的名字
複製代碼

國際化

本項目集合了國際化 i18n 方案。經過 vue-i18n而實現。

因爲本項目 ui 框架使用了 Vant UI,因此國際化的同時也要將其國際化。同時將當前 lang 語言存在 cookie之中,爲了下次打開頁面能記住上次的語言設置。

export const VueVantLocales = (lang = getLocale()) => {
  switch (lang) {
    case 'zh':
      Locale.use('zh-CN', vantZhLocale)
      break
    case 'en':
      Locale.use('en-US', vantEnLocale)
      break
  }
}

export default new VueI18n({
  locale: getLocale(),
  fallbackLocale: getLocale(),
  messages
})
複製代碼

使用

Html 中使用:

// $t 是 vue-i18n 提供的全局方法
$t('heoll')
複製代碼

Js 中使用:

const options = [
  {
    value: '1',
    label: this.$t('i18nView.one')
  },
  {
    value: '2',
    label: this.$t('i18nView.two')
  }
]
複製代碼

樣式適配

因爲本模板是H5開發模板,因此必定要有樣式適配啦。對此目前主流方案有 vw 和 rem,咱們來使用一個工具來幫助咱們完成屏幕的適配,postcss-px-to-viewport,安裝以後咱們只須要在 postcss.config.js 配置便可,具體配置說明還請查閱文檔。

調試控制檯

在調試方面,本項目使用 vconsole 做爲手機端調試面板,功能至關於打開 PC 控制檯,能夠很方便地查看 Console, Network, Element、Storage 等關鍵調試信息。

錯誤監控平臺

對別的錯誤監控平臺也不太瞭解,只記得當時在寫 PHP 的時候有用過 sentry,因此本項目中就配置了它做爲錯誤監控平臺。同時使用了這個大佬的插件 編譯時自動在 try catch 中添加錯誤上報函數的 babel 插件,相關配置在 .sentryclirc 這個文件中,具體相關配置在你建立時就會給出提示。還不清楚的請查閱 配置sentry

[defaults]
url=https://sentry.io
org=組織名
project=項目名

[auth]
token=token
複製代碼

GIT 提交風格

代碼提交記錄是一個很好的代碼修改日誌。規範的代碼提交記錄,無論在平時代碼開發維護過程當中,仍是在定位 bug 或者回退版原本說都是極爲重要。

相關指令

npm run git-cz
複製代碼

詳細說明

1. Select the type of change that you're committing 選擇您要提交的更改類型 2. What is the scope of this change (e.g. component or file name): (press enter to skip) 更改的範圍是什麼(例如,組件或文件名):(按Enter跳過) 3. Write a short, imperative tense description of the change (max 61 chars) 撰寫簡短的命令式時態描述(最多61個字符) 4. Provide a longer description of the change: (press enter to skip) 提供更改的詳細說明:(按Enter跳過) 5. Are there any breaking changes? 有重大變化嗎? 6. Does this change affect any open issues? 此更改會影響任何未解決的問題嗎? - feat 新功能 - fix Bug 修復 - docs 文檔更新 - style 代碼的格式,標點符號的更新 - refactor 代碼重構 - perf 性能優化 - test 測試更新 - build 構建系統或者包依賴更新 - ci CI 配置,腳本文件等更新 - chore 非 src 或者 測試文件的更新 - revert commit 回退 複製代碼

生成 CHANGELOG.md

也已經配置相關指令:

npm run genlog
複製代碼

就會出現相似與這種的文件格式:

### Features

* 國際化 攔截器 完善模板 ([379b452](https://10.6.30.204/front/china-goods-h5/commits/379b4522f9c0c0a1c282281af68c92c1cca10858))
* 飛入購物車 ([f1a5f2d](https://10.6.30.204/front/china-goods-h5/commits/f1a5f2db2fe6e67e3b5801c26563ba9f089e470b))
複製代碼

PWA

PWA是Progressive Web App的英文縮寫, 翻譯過來就是漸進式加強WEB應用, 是Google 在2016年提出的概念,2017年落地的web技術。目的就是在移動端利用提供的標準化框架,在網頁應用中實現和原生應用相近的用戶體驗的漸進式網頁應用。

  • 能夠生成桌面小圖標,不須要打開瀏覽器,方便用戶訪問
  • 經過網絡緩存提高頁面訪問速度,達到漸進式的頁面甚至離線訪問,提高用戶體驗
  • 實現相似app的推送功能,生成系統通知推送給用戶

vue 最新腳手架中集成了 pwa 的插件,將 pwa 的實現變得更加的簡單,只須要在 vue.config.js 文件中配置 pwa 屬性就能夠自動生成對應的 service-worker.js 配置文件,在這不作過多介紹。

WebPack 配置

一些配置說明

# PWA 
pwa: {
    name: VUE_APP_TITLE,
    workboxPluginMode: 'InjectManifest',
    workboxOptions: {
      swSrc: resolve('src/pwa/service-worker.js')
    }
  }

# 別名
configureWebpack: {
    name: VUE_APP_TITLE,
    resolve: {
      alias: {
        '@': resolve('src')
      }
    }
  },
	
# 在樣式引入時,對於變量的引入,須要在每一個文件裏都要引入一遍,爲了不每次使用時都須要單獨引入一遍的問題,採用了style-resources-loader
  pluginOptions: {
    'style-resources-loader': {
      preProcessor: 'scss',
      patterns: [
        resolve('src/styles/_variables.scss'),
        resolve('src/styles/_mixins.scss')
      ]
    }
  },
      
# vconsole
config.plugin('VConsolePlugin')
 .use(new VConsolePlugin({
	filter: [],
	enable: DEV && VCONSOLE === 'yes'
 }))
.end()

# 引入 lodash  在頁面能夠直接使用 _.isString() ...
 config.plugin('ProvidePlugin')
  .use(new webpack.ProvidePlugin({
    _: 'lodash'
  }))
  .end()

# 設置 svg-sprite-loader
config.module
  .rule('svg')
  .exclude.add(resolve('src/icons'))
  .end()
config.module
  .rule('icons')
  .test(/\.svg$/)
  .include.add(resolve('src/icons'))
  .end()
  .use('svg-sprite-loader')
  .loader('svg-sprite-loader')
  .options({
    symbolId: 'icon-[name]'
  })
  .end()
      
# 提交 map 文件
config.plugin('sentryPlugin')
  .use(new SentryPlugin({
    release: version,
    include: path.join(__dirname, './dist/static/js'),
    urlPrefix: '~/vue-h5-template/statis/js',
    ignore: ['node_modules']
  }))
  .end()
複製代碼

相關插件

  • vconsole-webpack-plugin

  • @sentry/webpack-plugin

  • lodash-webpack-plugin

...

項目中還作了一些細節處理,詳情請拉取項目查看,謝謝觀看。以爲好能夠給顆 star 模板地址 ,會持續更新,有問題能夠留言或加我微信 gao1336650475

相關文章
相關標籤/搜索