1.虽然Taro是类 React DSL,但在很DOM、BOM api上都不支持,需要整个项目重构,工量较大
2.现有功能还在迭代,停掉功能迭代 or 重构完再补
3.由于兔小巢的宿主环境是各种第三方APP,重构后测试工作量、上线风险都挺大
MultiPlatformPlugin
,这个插件主要是提供一个根据编译环境读取对应后缀名文件的能力。Home/index
这个路径 读取的是Home/index.jsx
这个文件Home/index
这个路径 读取的是Home/index.weapp.jsx
这个文件// Home.jsx
import React, { Component } from 'react';
export default class Home extends Component {
componentDidMount() {
this.loadData()
}
loadData(){
// ...
}
render(){
// ...
}
}
小程序根据刚介绍的MultiPlatformPlugin
插件功能,去创建在同目录想的同名不同后缀文件作为小程序入口,这样可以保证小程序有自己的逻辑开发空间,不污染原代码。
// 小程序Home页面 Home.weapp.jsx
import React from 'react';
import HomeBase from './Home.jsx';
class Home extends HomeBase {}
业务逻辑重写
1.方法内部实现逻辑不一致
// 小程序Home页面 Home.weapp.jsx
// loadData方法不一致时
import React from 'react';
import HomeBase from './Home.jsx';
class Home extends HomeBase {
loadData(){
// 小程序独有的loadData方法
// ...doSomething
}
}
// 小程序Home页面 Home.weapp.jsx
// loadData方法小程序不需要时
import React from 'react';
import HomeBase from './Home.jsx';
class Home extends HomeBase {
loadData(){}
}
3.小程序需要定制业务逻辑
解决方案,入口处或对应生命周期增加方法引入,在小程序页定制
// 小程序Home页面 Home.weapp.jsx
// 小程序需要定制业务逻辑
import React from 'react';
import HomeBase from './Home.jsx';
class Home extends HomeBase {
componentDidMount() {
super.componentDidMount && super.componentDidMount();
this.foo();
}
foo() {
// ...
}
}
Txc/index.js
文件// Txc/index.js
const Txc = {
...window,
...document
}
export default Txc
在相同位置对小程序端进行单独处理
// Txc/index.weapp.js
import Taro from '@tarojs/taro';
const Txc = {
localStorage: {
getItem(key){
return Taro.getStorageSync(key)
},
// ...
},
location: {
// ...
set href(url) {
Taro.navigateTo({ url });
},
// ...
},
// ...,
};
这个过程有点像monkey patch ,有一些地方需要单独封装像 location.href。有些地方需要hack处理,比如屏幕尺寸获取小程序需要调用特有api,还有设备信息获取 等等,基本就是一些苦力活, 这里我是以页面为粒度去做patch,把这个页面用到的dom、bom api封装完了就提测一个页面然后上线,因此对于移动端来说基本是无影响的。
使用方式:
1.引入工具
// Home.jsx
// 兼容dom、bom api
import Txc from 'components/txc'
// ...
foo(){
// window.localStorage.getItem('foo')
Txc.localStorage.getItem('foo')
}
// ...
// Home.jsx
import React, { Component } from 'react';
import Txc from 'components/txc'
export default class Home extends Component {
render(){
return (
<Txc.div >home</Txc.div>
)
}
}
// Txc/index.js
// 存放块元素
const blockElements = ['div', 'p','h1','section']
// 存放行内元素
const inlineElements = ['span','i','em']
// 所有元素
const allElements = ['button', 'input', 'img', ...blockElements, ...inlineElements]
// Txc/index.js
const Txc = {
...window,
...document
}
allElements.forEach(type => {
Txc[type] = React.forwardRef((props, ref) => {
return React.createElement(type, { ...props, ref })
});
});
export default Txc
小程序端需要按照上面设计的映射规则做实现, 以下做一些简单的代码演示
// Txc/index.weapp.js
import React from 'react'
import { View, Image, Text } from '@tarojs/components';
// 存放块元素
const blockElements = ['div', 'p','h1','section']
// 存放行内元素
const inlineElements = ['span','i','em']
// 所有元素
const allElements = ['button', 'input', 'img', ...blockElements, ...inlineElements]
const Txc = {
...
}
allElements.forEach(type => {
Txc[type] = React.forwardRef((props, ref) => <TxcItem type={type} {...props} ref={ref} />);
});
const TxcItem = React.forwardRef(({ type, ...props }, ref) => {
const params = {
...props,
ref,
classNames: `txc-${type}`
}
if (blockElements.some(item => item === type)) {
return <View {...params} />
}
if (inlineElements.some(item => item === type)) {
return <Text {...params} />
}
if ('img' === type) {
return <Image {...params} />
}
...
})
export default Txc
import React from 'react';
import HomeBase from './Home.jsx';
// 小程序单独引入样式文件处理
import './style.weapp.css'
class Home extends HomeBase {}