多业务平台思考与研究

其实业务里经常会有这样的需求,就是经常同一个网站有时候你需要支持不同的渠道或不同的国家,不同的渠道或国家如果只是文案上的不同,其实依靠一些库等手段,我们很容易实现其区分,但往往复杂的是逻辑上的不同,随着国家或渠道等的变化,往往在业务逻辑上,页面组成上会有很多的不同和相同。
在接触到这种需求的时候,其实经常是随着业务的修改,去添加相应的代码,但现在回头看的时候,真的要再去修改就已经变得很复杂了,于是就开始思考如果再有这样的需求怎样去实现是比较好的想法。
其实简化去思考,这种区分可以分为渲染时候的不同和方法上的不同,因为我项目现在主要是react,所以我也主要是从react的实现角度去出发的。
在视图上的不同主要想到的是去使用一个组件,对需要进行区分的组件进行包裹:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const Platform = (props) => {
const nowPlatform = React.useContext(PlatformContext)

if(props.except) {
let exceptArr = props.except.split(",")
if(exceptArr.indexOf(nowPlatform) >= 0){
return null
}else{
return props.children
}
}else if(props.only){
let onlyArr = props.only.split(",")
if(onlyArr.indexOf(nowPlatform) >= 0){
return props.children
}else{
return null
}
}
}

去使用:

1
2
3
4
5
6
7
import Pl from './Platform'
<Pl only="dev,pre">开发</Pl>
<Pl except="dev,pre">不是开发</Pl>
<button>切换
<Pl only="dev,pre">不是开发</Pl>
<Pl except="dev,pre">开发</Pl>
</button>

然后接下来就是方法层的问题,往往这样一个页面会有很多共同的方法,还有很多特殊的方法,所以想到的就是使用高阶组件对其去进行包裹。
对于公共的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const withCommon = (WrappedComponent: any) => {
return class CommonProps extends React.Component<any, any> {
constructor(props) {
super(props)
}
commonFunction() {
console.log(‘this is common’)
}

render() {

return (
<WrappedComponent
commonFunction = {this.commonFunction}
{…this.props}
/>
)
}
}
}

对于特殊的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
export default (WrappedComponent: any, props:any) => {
return class DevProps extends React.Component<any, any> {
constructor(props, context) {
super(props, context)
}
devFunction() {
console.log(“this is dev function”)
}
switchPlatform(){
changePlatform(‘pro’)
}
render() {
return (
<WrappedComponent
devFunction = {this.devFunction}
switchPlatform={this.switchPlatform.bind(this)}
{…this.props}
{…props}
/>
)
}
}
}

然后在使用的index里面将这两个高阶组件导入,并compose在一起,就在组件内得到这些方法了。
但我当时遇到了一个问题,就是如果平台很多,而且需要考虑到动态切换的情况,即在编译的时候我是不知道是哪个平台的,这样的话一个个高阶组件不停的去包裹,页面的结构简直看起来像一个粽子了。。。所以需要能够根据平台的不同,去取到那个平台对应的特殊的高阶组件。
一开始我一直在纠结怎么在compose这个函数里去取值判断,后来想其实就是个动态取组件的问题。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function withSp() {
return class extends React.Component<any, any> {
components: any
constructor(props) {
super(props)
this.components = {
dev: withDev(commonRender, props),
pro: withPrd(commonRender, props),
};
}

render() {
const Specific = this.components[this.props.global.platform];
return <Specific {…this.props}/>
}
}
}

这样就能动态的去拿到对应的高阶组件和方法了。
总觉得这个问题也许还会有更好的方法,希望以后还能继续去优化吧。