Taro 集成 小程序、Android、iOS 项目
Text 组件
-
Text 组件,在 react native 中,Text 组件布局不是 inline 的,而是 block 的。而 react native 中无法使用 inline、inline-block 等布局,只能通过 flex 布局进行实现。
Q&A
-
当一段文本中文字需要样式,如果只是简单的字体样式不同
可以使用 Text 组件包裹 Text 组件进行设置,这样设置 Text 组件不会保持一行宽度,以类似 span 标签的形式进行展示,但是 Text 组件同样不能设置宽高,padding,margin 等属性,也不生效。
-
当这段文字中有块级元素(如 Button 等),则需要通过 flex 布局来实现。
如下:
<View className="flexRow"> <View className="btn">Button</View> <Text>Text</Text> </View>但当文本过长需要换行时,就会遇到宽度不够的问题,导致换行无效。flex 布局将文字按钮被分为两块区域,因此就需要进行一些特殊处理。
<View className="flexRow flexWrap"> <View className="btn">Button</View> {"假设这是一段很长的文字".split("").map((item, index) => { return <Text key={index}>{item}</Text>; })} </View>
-
Text 保持一行,在微信、支付宝小程序中有较大差异,设置 one-line 在支付宝中不生效,需要设置 numberOfLines={1},但还不能设置 one-line className 样式,否知不显示省略号
<Text className="one-line-wx" numberOfLines={1}> 假设这是一段很长很长的文字 </Text>// 处理微信小程序的省略号 // 因为支付宝小程序 text 组件设置 number-of-lines 后 // 同时设置 one-line 导致省略号不显示 .one-line-wx { /* #ifdef weapp */ white-space: nowrap; text-overflow: ellipsis; overflow: hidden; /* #endif */ }
-
弹窗问题
-
react native 中 position 只能设置 absolute、relative。react native 默认为 relative 定位,而且若设置 absoulte,想定位到根节点顶部、底部也十分困难。
因此,大多数弹窗都直接设置在页面层,当在子组件中设置弹窗时,就会非常麻烦,代码逻辑也十分混乱。因此出现了一个库 react-native-root-siblings,用于解决这个问题。
但是我当前开发需求还需要再小程序中运行,所以没能直接使用该库。仔细看了下这个库的代码,了解其实现思路,自己写一个弹窗控制器,实现功能。
react-native-root-siblings 实现思路:依旧是将组件渲染到最外层,通过一个数组来管理组件的显示与隐藏,在根组件循环遍历渲染。
因此,想着通过 createContext + reducer 来控制数组,这样在不同组件中也能够使用管理弹窗的方法。
const initialState = { siblings: [] }; const RootSiblingsContext = React.createContext(initialState); const reducer = (state, action) => { switch (action.type) { case "add": return [...state, action.payload]; case "remove": return state.filter((item) => item.key !== action.payload); default: return state; } }; export { RootSiblingsContext, reducer };RootSiblingsManager.jsx:const { siblings, dispatch } = useReducer(reducer, initialState); export default const RootSiblingsManager = (props) => { return ( <RootSiblingsContext.Provider value={{ siblings, dispatch }}> {props.children} {state.siblings.map((item, index) => ( <Fragment key={index}>{item.element}</Fragment> ))} </RootSiblingsContext.Provider> ); }; export const withRootSiblingsManagerWrapper = (Component) => { return (props) => ( <RootSiblingsManager> <Component {...props} /> </RootSiblingsManager> ); };补充问题
当上面的在不同页面使用时,最上面的导航栏是不会被弹窗遮住的,是因为
app.rn.jsx设置的问题。<> <StatusBar {...props} /> {props.children} </>改为
<RootSiblingsManager> <StatusBar {...props} /> {props.children} </RootSiblingsManager>这样设置的组件就会直接显示在最顶层,和页面是同级的。 因此
app.rn.jsx中的<StatusBar />就可以正常被遮住,在 IOS 中,滚动也不会出现穿透的情况。但这样写在 Android 中,却会遇到另外一个问题,弹窗打开时,通过手势及按键返回时,弹窗不会消失。
在通过查看不同的 App 后,发现在 Android 中,弹窗打开时,使用手势及按键返回,会执行关闭弹窗,没有返回到下一页的逻辑。可能是劫持了返回按键的逻辑,只有在满足一定条件时,才会执行返回逻辑。
接下来就是尝试如何实现弹窗的返回逻辑。
还记得上面说过的 弹窗组件和页面组件同层吗?在这就隐藏着具体实现逻辑。 只需将弹窗组件最外层包裹一层组件,并实现返回逻辑。
import {BackHandler} from "react-native"; const { state, dispatch } = useContext(RootSiblingsManagerContext) useEffect(() => { // Android 全局弹窗拦截返回键 const onBackPress = () => { if(state.siblings.length > 0) { dispatch({ type: ACTION_TYPE.POP, payload: null }) return true } return false } const subscription = BackHandler.addEventListener('hardwareBackPress', onBackPress) return () => { subscription.remove() } }, [state.siblings])
布局问题 Flexbox
占据剩余空间 flex: 1,在小程序中 flex: 1,当高度超出剩余高度时,高度会继续增加,为解决该问题还需给该元素设置 overflow: auto;
<View className="flexColumn">
<View className="xxx">NavBar</View>
<View className="flex1 overflowAuto">
<View>Content</View>
</View>
</View>
flex 布局内设置 Text 组件,会影响 Text 组件默认功能,可以给 Text 组件设置宽高及 borderRadius 等,且具体高度会被其他子元素影响。
获取真实宽高
因该项目中使用的是标准 750px 布局,因此获取真实 1px 高度只需通过将 真实屏幕宽度 / 750 就能获取真实 1px 像素值
const realPx = function () {
return Taro.getSystemInfoSync().windowWidth / 750;
};
弹窗中键盘弹起导致弹窗顶部超出
问题是因为 CoverPopWindow 组件的设置是通过 position: absoulte 实现,当键盘弹起时,窗口大小发生变化,因此 CoverPopWindow 高度缩小,内部的弹窗内容也因此发生位置变化。 之后考虑到 CoverPopWindow 高度发生变化,导致该问题,因此采用 ScrollView 组件重新实现 CoverPopWindow 组件。当键盘弹起时,CoverPopWindow 依旧能够包裹住弹窗内容,这样就可以滚动查看剩余内容。然后发现当这样实现时,弹窗内容不会在键盘弹起时超出屏幕,但是此时还可以滚动弹窗查看内容,因此再次禁用 ScrollView 的滚动,就可以完美解决弹窗中唤起键盘问题。