首先簡要的介紹一下問題,我們公司大部分項目都是使用umi+Ant Design Pro 構(gòu)建(下面的Pro都指代它),因?yàn)閳鼍暗牟煌覀兛偸且鶕?jù)不同的場景區(qū)分和抽離布局組件,在Pro中的layouts文件夾里面已經(jīng)為我們提供了不同場景的布局組件。
大部分頁面包含了通用的導(dǎo)航、側(cè)邊欄、頂部通知、頁面標(biāo)題等元素,這時候我們會使用BasicLayout作為布局組件,使用如下:
{
path: '/org',
component: '../layouts/SecurityLayout',
routes: [
{
path: '/',
component: '../layouts/BasicLayout',
authority: [],
routes: [
{
path: '/org/dashboard',
name: 'dashboard',
component: './dashboard'
},
{
path: '/org/department',
name: 'department',
component: './department',
hideInMenu: true
},
{
path: '/org/user',
name: 'user',
component: './user/list'
},
{
component: './404'
}
]
}
]
},
這時候問題就出現(xiàn)了,/org/department頁面的布局不是BasicLayout,而是BlankLayout。那怎么辦?
剛開始這種頁面不多,直接就在BasicLayout中的render函數(shù)中判斷l(xiāng)ocation.pathname的值,直接return一個children,代碼如下:
if (['/org/department'].indexOf(pathname) > -1) {
return <div>{children}</div>
}
從此不優(yōu)雅的代碼開始瘋狂的增長,想象一下當(dāng)有十幾個頁面出現(xiàn)這種情況的時候。
下面我們就用裝飾器模式,優(yōu)雅的解決這個問題。如果對裝飾器比較陌生的同學(xué)可以看這里Javascript 中的裝飾器
先實(shí)現(xiàn)一個裝飾器,一個高階組件ExcludeLayout:
import React, { Component } from 'react';
import BlankLayout from './BlankLayout';
function ExcludeLayout(opt) {
return function(WrappedComponent) {
return class extends Component {
render() {
const {
children,
location = {
pathname: '',
},
} = this.props;
const { routes } = opt;
const { pathname } = location;
if (routes.indexOf(pathname) > -1) {
return <BlankLayout {...this.props} />
}
return (
<WrappedComponent {...this.props} />
);
}
}
}
}
export default ExcludeLayout;
上面這個高階函數(shù)其實(shí)就是進(jìn)行路由的挾持,如果pathname在我們傳入的opt.routes路由數(shù)組中,我們就使用BlankLayout布局組件。下面看一下ExcludeLayout裝飾器去裝飾BasicLayout組件:
@ExcludeLayout({
routes: ['/org/department']
})
class BasicLayout extends Component {
.......
.......
}
// 非class定義的使用
BasicLayout = ExcludeLayout({
routes: [`/org/department`]
})(BasicLayout);
以上就用裝飾模式,優(yōu)雅的解決上面的問題。
實(shí)際開發(fā)場景下還有很多地方可以用到裝飾器,當(dāng)代碼寫好看起來就討厭的時候,就可以思考思考是否有上面優(yōu)雅的實(shí)現(xiàn)方式。