2018.3.1更:
有贊·微商城(base杭州)部門招前端啦,最近的前端hc有十多個,跪求大佬扔簡歷,我直接進行內推實時反饋進度,有興趣的郵件 lvdada#youzan.com,或直接微信勾搭我 wsldd225 瞭解跟多
有贊開源元件庫·zanUI
初次接觸vue,刷完了堪稱經典的vue官網文件+vue-router文件+vuex文件+vue-cli文件,然後就開始刷專案了。這篇文章總結了專案實踐的一些思路。
首先看下專案的總覽圖(mockplus製作)
這個專案我負責的部分是一個控制檯的需求,使用者可以在這個模組進行佣金、訂單等專案的修改設定,可以看到第1張圖相當於控制檯首頁,頁面上有1、2、3、4、5個入口,其中1-4入口進入的頁面對應4個頁面,但是4個頁面主要結構相同,中間商品列表樣式資訊不同,為了簡略4圖歸為第二張圖。入口5對應第三張圖。
這幾個頁面需求並不複雜,大專案本身也是是基於zepto的,單單把這個模組拿出來抽離成單頁形式主要為了兩點考慮:
- 控制檯畢竟涉及操作dom的需求會很多,為了相容未來產品迭代的複雜需求。
- 控制檯從產品最終的形態上更像是一個獨立的應用,且使用者進入控制檯首頁後所有的操作就在當前單頁內進行操作,無需a連結跳轉,在體驗上也是很貼合使用者的。
基於以上兩點使用vue以及vue大禮包編寫了這個單頁模組。
vue-router路由控制
由入口而知一共有6個頁面(包含控制檯首頁),雖然是單頁模組,也是必須要符合通過url地址直接進入對應分頁的需求。在切換的過程中,留下url路由資訊也方便使用者進行後退操作。
首先是頂級路由的配置,六個頁面(元件)分別設定六個頂級路由。
// 在App.vue檔案中設定<router-view>
<template>
<div id="app">
<router-view keep-alive :style="{'padding-bottom': paddingBottom + 'rem'}"></router-view>
</div>
</template>
// 在main.js中配置路由
router.map({
'/': {
component: Index,
name: 'index'
},
'/commission': {
name: 'commission',
component: Commission
},
'/order': {
name: 'order',
component: Order
},
'/inventory': {
name: 'inventory',
component: Inventory
},
'/shop': {
name: 'shopList',
component: ShopList
},
'/qcode': {
name: 'qcode',
component: Qcode
}
})
路由查詢引數
由上圖具體的佣金頁面(元件)可以看到,這個頁面有兩個主要操作,一:搜尋,根據搜尋結果展示商品條目;二:翻頁,根據頁數展示商品條目。
原始的思路是搜尋與翻頁都在當前頁面(元件)操作,將非同步獲取的資料替換當前頁面的items陣列。Vue會將變化的資料與view繫結,同步重新整理view頁面。
這樣做有個缺陷,任何操作(搜尋、翻頁)都不會留下可追溯的路徑,假設有個場景:
使用者翻n頁,發現了一款商品點選進入詳情頁(外鏈,屬於大專案中的頁面),使用者返回佣金設定頁面時發現又從第一頁開始瀏覽了。
基於此類場景結合vue-router的路由查詢引數功能可以換一種實現方式。
點選搜尋不再在當前頁面(元件)非同步請求資料,而是通過$route物件進行路由跳轉。
this.$route.router.go({
name: 'index',
query: {
keyWord: 'searchWorld',
page: 1
}
})
根據上圖,搜尋n次,或者是點選翻頁n次,都會改變當前的url的查詢引數。實際上改變路由查詢引數,就相當於重新進入一次當前頁面(元件),Vue會識別計算是否重用當前元件,這種情況<router-view>並不會產生切換效果,因為即使查詢引數變化,當前頁面元件始終都是component: Commission
同一個元件。
這樣設計就留下了一系列的路徑,可供歷史回退。
那麼資料該如何獲取呢?
vue-router
有一個「切換控制流水線」的概念,即在不同路由切換的過程中會有不同的鉤子函式可以呼叫。
其中data
鉤子函式不管元件是否可以重用,在每次路由切換的時候都會觸發。
route: {
data (transition) {
this.$http.get('/api/test/test', {
params: {
keyword: this.keyWord,
page: this.currentPage,
pageSize: this.numberPerPage
}
}).then((response) => {
transition.next({
items: response.json().data.item.items,
listNumber: response.json().data.item.totalNum
})
}, (response) => {
// error
})
}
},
這樣實現了資料的獲取,引數部分依靠當前元件的$route
物件獲取。
vue 元件
上文已經提到的6大分頁其實就是6個元件,但是為了在開發環境下區分資源,將這6個元件放在了views檔案下內。
|
|-src
| |
| |-components
| |-views
| | |-Index.vue
| | |-Commission.vue
| | |-Order.vue
| | |-...
common components(通用業務元件)
由上圖可知可以將1.title 2.搜尋欄 3.confirm 4.toast 5.分頁器 6.loading等待封裝成全域性元件。在main.js
中進行註冊。
import Toast from './components/common/Toast'
Vue.component('c-toast', Toast);
...
...
商品列表也可以抽離成元件,但是在每個分頁裡的商品列表是不同的,所以每個分頁裡的商品列表都獨立抽離成元件,並註冊在對應的分頁元件裡。
import ListCommission from '../components/ListCommission'
export default {
name: 'commission',
components: {
ListCommission
}
}
vuex 狀態管理
控制檯這個模組狀態並不複雜,多數狀態的傳遞都只發生在父元件和子元件這種上下層級的關係之間。
比如Commission元件(佣金分頁)中的ListCommission元件(佣金頁的商品列表元件)之間的狀態傳遞就只發生在這兩級之間。
// Commission.vue
<template>
<list-commission :visible="listNumber > 0" v-if="!$loadingRouteData" :items="items"></list-commission>
</template>
其中items
狀態屬於父元件,會傳遞到ListCommission
元件內供其view展示。這種狀態稱為「元件本地狀態」,元件本身管理自己的狀態。
但是現在有這麼一個功能點,生成二維碼模組需要使用一個完整url路徑,這個路徑需要根據測試、線上環境的不同對應.net/.com
。這個狀態也許還有許多不同層級的元件需要使用,那麼這樣的狀態就適合用vuex去管理。
1.首先在store中定義狀態初始值
const state = {
suffix: '.net'
}
2.在根元件App.vue中觸發action
let suffix = window.location.hostname.indexOf('showjoy.net') > -1 ? '.net' : '.com';
export const setGlobalSuffix = function ({dispatch}, suffix) {
dispatch('SET_GLOBAL_SUFFIX', suffix);
}
this.setGlobalSuffix(suffix);
3.觸發dispatch
SET_GLOBAL_SUFFIX (state, suffix) {
state.suffix = suffix;
}
4.get狀態
export function getSuffix (state) {
return state.suffix;
}
只要在相應元件中定義了getSuffix的getters,就可以在相應的元件中呼叫這個函式,獲取suffix狀態。此時suffix狀態可稱為「應用層級狀態」。應用層級狀態不屬於任何特定的元件,但每個元件都可以監視其變化並響應式的更新DOM。
suffix
狀態只是一個簡單的例子,像上圖所示,當同級元件之間或者是不同直系關係的父子元件之間需要進行狀態的變更,依賴「元件本地狀態」將難以維護。
比如Commission元件
需要改變Order元件
的一個狀態,如果不借助vuex,那麼需要顯示的編寫事件將狀態分發到上層元件App,Order元件需要監聽這個事件。狀態變更一多,那維護將是噩夢。
對我以上的理解有疑問和意見的歡迎找我私聊~微博-寫前端的暹羅