Vue 2.0重構G買賣項目經驗分享

項目背景:

G買賣H5是運行在多端的遊戲交易平臺。基於產品層面的功能升級以及提升開發效率的需求,前段時間我用Vue和Webpack對項目進行了一次漸進式的重構。所謂漸進式,即每一個週期僅對部分頁面進行改造,不影響其餘業務的開展。此次我改造的是我買到的/我賣出的訂單列表以及訂單詳情。html

這次分享主要有如下幾個點:前端

  1. 核心技術
  2. 實現組件化
  3. 數據管理
  4. 代碼層面改善點
  5. 遇到的坑
  6. 持續優化點

核心技術

此次重構用到的核心技術是vue2.0和webpack1.0。接下來對它們進行簡要的介紹。vue

Vue.js是一套構建用戶界面的漸進式框架。 與其餘重量級框架不一樣的是,Vue 採用自底向上增量開發的設計。 Vue 的核心庫只關注視圖層,而且很是容易學習。具體能夠從官網學習它的用法。webpack

Webpack是當下最熱門的前端資源模塊化管理和打包工具,它能夠將不少鬆散的模塊按照依賴和規則打包成符合生產環境部署的前端資源,還能夠將按需加載的模塊進行代碼分割,等到實際須要的時候再異步加載。web

下圖是官方對Webpack的簡介,經過這幅圖看出,相互依賴的模塊文件,會被打包成一個或多個js文件,能夠減小HTTP的請求次數。ajax

Webpack的具體用法能夠參照 官網

這次重構用到的Vue版本是2.1.0,Webpack是1.13.2。vuex

目錄結構:緩存

gmmh5
  |-- build //構建目錄
  |    |-- build.js   
  |    |-- dev-client.js      
  |    |-- dev-server.js  
  |    |-- HashedModuleIdsPlugin.js 
  |    |-- utils.js  
  |    |-- webpack.base.conf.js  
  |    |-- webpack.dev.conf.js  
  |    |-- webpack.prod.conf.js  
  |-- config //配置文件
  |-- dist //打包後的文件
  |-- src //源碼目錄
  |    |--assets           // 靜態資源
  |    |--biz           // 頁面配置文件
  |    |--common           // 公共方法
  |    |--components           // 基礎組件
  |    |--constants             
  |    |--modules           // 業務組件
  |    |--pages           // 頁面
  |    |--utils           // 工具函數
複製代碼

如何實現組件化?

組件化的好處不一一列舉了,職責單一,易維護,可擴展...bash

首先我將這兩張頁面分別按功能和展示劃分了組件。app

以下圖的訂單列表頁面,頁面從上到下按照功能能夠劃分爲三個組件:選擇商品類型,切換交易狀態,以及渲染列表數據的組件

選擇商品類型select-type組件負責改變goodsType, 切換交易狀態change-state組件負責改變state, 兩個組件都將改變的參數傳到入口文件app.vue,由入口文件負責獲取列表數據,再將數據傳到list組件,負責展示列表數據。數據流動以下圖:

訂單詳情也是一樣的處理方法。

關於組件間的通信,父組件的數據經過prop下發到子組件中,子組件經過vue的$on, $emit 事件接口來與父組件通訊。兄弟組件或者層級比較深的組件,在目前沒有采用vuex的狀況下,使用EventBus進行通信。具體操做方法以下:

首先命名一個event-bus.js,建立一個新的全局Vue實例,命名爲EventBus而且導出該對象。

import Vue from 'vue'
var EventBus = new Vue()
export default EventBus
複製代碼

在組件A中同時引入Vue和EventBus。當這個組件中的方法「emitMethod」被調用時,它觸發了事件」EVENT_NAME」,而且傳遞了「payload」參數。

import Vue from 'vue';
import EventBus from 'event-bus'
Vue.component('component-a', {
  ...
  methods: {
    emitMethod () {
       EventBus.$emit('EVENT_NAME', payLoad);
    }
  }
});
複製代碼

在另一個組件B中,咱們能夠註冊一個監聽事件,來監聽由EventBus傳遞來的事件「EVENT_NAME」。

import Vue from 'vue';
import EventBus from './event-bus';
Vue.component(‘component-b’, {
  ...
  mounted () {
    EventBus.$on('EVENT_NAME', function (payLoad) {
      ...
    });
  }
});
複製代碼

這樣B組件就能夠監聽A組件觸發的事件,而不須要考慮過多的層級問題。

數據管理

處理訂單詳情複雜的部分在於它的頁面展現取決於商品類型與交易狀態值。

G買賣H5頁面有如下幾種商品類型,其中帳號還分爲手遊,端遊,外部寄售帳號。點券也包含撮合點券,普通點券的類型。實際處理的商品類型比下圖複雜。

每一個商品類型下有不一樣的狀態值,其中帳號的狀態值最多。商品類型和狀態值共同決定了頁面中內容的顯示:狀態說明的標題,頂部文字說明,交易圖標以及操做項按鈕。

爲了處理這類數據 ,不與頁面邏輯雜糅在一塊兒,我將其作成了配置表。部分代碼以下:

const account = {
  '1': {
    'title': '待付款',
    'topImg': imgState.wait,
    'topMsg': topMsgSource.fromFixTxtByFunc,
    'btns': [btn.cancel, btn.pay]
  },
  '2': {
    'title': '付款成功',
    'topImg': imgState.trade,
    'topMsg': topMsgSource.fromFixTxtByFunc,
    'btns': [btn.refund, btn.selectCheckType]
  },
  ...
}
複製代碼

account表明商品類型中的帳號類型。'1', '2'則是狀態值。

取值時在頁面中調用商品詳情的接口,獲取到數據detail,取出detail中的goods_type和state_to_out,即商品類型和商品交易狀態值。而後在配置config文件文件中取得對應的數據。譬如,取狀態說明的標題title:

const vm = this
let goods_type = vm.detail.goods_type
let state_to_out = vm.detail.state_to_out
title = vm.config[goods_type][state_to_out]["title"]

複製代碼

這樣的好處是一目瞭然,要進行任何的改動在配置表裏改動便可。

代碼層面改善點

減小重複的代碼

原先的代碼,存在的狀況是:一份代碼在多個地方複製,改動時常常不知道哪裏改了哪裏漏了。我將許多重複的代碼梳理一遍,抽象封裝重複的代碼邏輯。

譬如操做按鈕中的不少函數,調用了ajax以後都會刷新頁面,因而我將其抽出來單獨寫成一個函數:

operateRefresh(url, params) {
      //通用方法 -- ajax後刷新頁面
      const vm = this
      utils.get(url, params, (res) => {
        let data = res.data
        if (res.return_code === 0) {
          vm.refresh()
        } else {
          utils.toast(res.return_message)
        }
      })
}
複製代碼
單一職責原則編寫方法

單一職責就是一個對象(方法)只作一件事。 若是一個方法承擔了過多職責,那麼一個職責發生變化可能會影響其餘職責的實現,修改代碼就變得比較危險。

這次改造我將一些大的函數按功能細分紅一些小的功能函數。譬如列表頁在初始時要作的事情包括:判斷買單仍是賣單,獲取初始化的商品類型,調取接口獲取列表數據以及監聽其餘組件的事件:

created() {
    const vm = this
    // 判斷用戶是買家仍是賣家
    vm.judgeRole()
    // 從url獲取goods_type以及trade_mode
    vm.getUrlParams()
    // 獲取列表數據
    vm.getList()
    // 監聽事件
    vm.subscribeToEvent()
  }
複製代碼

遇到的坑

重構過程當中遇到的坑更可能是因爲對業務的不夠充分理解上,這回用Vue2.0來重構也遇到了一些Vue的坑。

因爲 Vue 會在初始化實例時對屬性執行 getter/setter 轉化過程,因此屬性必須在 data 對象上存在才能讓 Vue 轉換它,才能檢測到它的變化。Vue是不能檢測到屬性的添加或刪除的。在部分業務中我對數據屬性進行添加,以及修改,卻沒有引起Vue的從新渲染,在這個點上卡住了一些時間。後來閱讀了官方文檔,發現它可使用 Vue.set(object, key, value) 方法將響應屬性添加到嵌套的對象上,從而觸發組件的更新:

Vue.set(vm.someObject, 'b', 2)
複製代碼

另外,因爲Vue 異步執行 DOM 更新。只要觀察到數據變化,Vue 將開啓一個隊列,並緩衝在同一事件循環中發生的全部數據改變。若是同一個 watcher 被屢次觸發,只會一次推入到隊列中。若是想要在數據變化以後當即更新DOM,能夠在數據變化以後當即使用 Vue.nextTick(callback) 。

Vue.nextTick(function () {
	// 數據變化
})
複製代碼

持續優化點

業務完成了,我還整理了一些能夠持續優化的點:

  1. 性能。部分文件體積能夠近一步縮小,能夠更有效地利用緩存,提高首屏渲染速度。
  2. 體驗。提高下拉刷新的體驗以及添加頁面交互時的提示。
  3. 數據流。整合更多業務進來時,對數據流的結構設計要更加清晰。
  4. 組件化。基礎組件能夠更抽象化,利於複用。

總結

通過此次的重構,我對業務有了更深刻的瞭解和掌握,而且認識到在面對複雜的業務時,停下來思考清楚業務場景比動手寫代碼重要得多。

這次對Vue也有了更深刻的瞭解和掌握,也提醒了本身在平常開發中須要不斷提升編碼能力和代碼的質量。將來,更多業務整合到重構的新項目中,在其餘方面也須要不斷地優化和學習。

相關文章
相關標籤/搜索