有贊·微商城(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組件需要監聽這個事件。狀態變更一多,那維護將是噩夢。