上一篇文章記錄了在RN中如何響應(yīng)Hover事件,現(xiàn)在,我想仿照RN中<TouchableHighlight>標(biāo)簽實(shí)現(xiàn)<HoverBoard>,目的是為了不在具體UI代碼中進(jìn)行業(yè)務(wù)邏輯代碼的頻繁copy,最終的效果基本如下:
<FlatList
data={[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]}
keyExtractor={() => ++i}
numColumns={6}
style={{paddingHorizontal: 15,}}
renderItem={({item}) => (
<HoverBoard
onHoverChanged={this._onHoverChanged}
>
<Image source={require('./img/icon.jpg')} style={{width: 150, height: 150}}/>
<Title ref="text"/>
</HoverBoard>
)}
/>
<HoverBoard>在加載之后會(huì)計(jì)算每個(gè)子節(jié)點(diǎn)的實(shí)際位置,然后監(jiān)聽Hover事件,在發(fā)現(xiàn)自身狀態(tài)發(fā)生變化時(shí),會(huì)回調(diào)“this._onHoverChanged”方法來更新界面。
簡單說一下實(shí)現(xiàn)背景,在Android中有很多的監(jiān)聽器,可以很簡單的實(shí)現(xiàn)類似FlatList組件中子節(jié)點(diǎn)狀態(tài)的回調(diào),但是看了一段時(shí)間的RN或者說JavaScript,發(fā)現(xiàn)這件事情做起來好像有些麻煩(好吧,我承認(rèn)目前對(duì)JS還不太在行。。)。
我為什么一定要這樣做呢,簡略的說一下探索的過程,最初我采用類似下面的方式實(shí)現(xiàn)FlatList的子節(jié)點(diǎn):
<View>
<Image source={require('../img/icon.jpg')} style={{width: len, height: len}}/>
<Text ref="text" style={styles.text}>
({this.state.left}, {this.state.right}), ({this.state.top}, {this.state.bottom})
</Text>
</View>
后來發(fā)現(xiàn),在現(xiàn)有的設(shè)備上,子節(jié)點(diǎn)每次整體刷新需要接近20ms的時(shí)間,這真的是無法忍受。因?yàn)楫吘怪皇菍?shí)現(xiàn)Demo,所以我嘗試單獨(dú)刷新<Text>標(biāo)簽,在經(jīng)過了一番折騰之后,發(fā)現(xiàn)這樣做確實(shí)讓效率提高了十倍以上。
從以往的開發(fā)經(jīng)驗(yàn)中可以得到一點(diǎn):子節(jié)點(diǎn)的布局肯定不會(huì)如上面那樣簡單,換句話說,它肯定是一個(gè)"Component"。
我肯定不愿意讓多余的業(yè)務(wù)邏輯插入到這個(gè)"View"中,閱讀了一下<TouchableHighlight>的源碼,發(fā)現(xiàn)渲染部分的代碼是醬嬸的:
render: function() {
return (
<View
... ...>
{React.cloneElement(
React.Children.only(this.props.children),
{
ref: CHILD_REF,
}
)}
{... ...}
</View>
);
}
經(jīng)過了一番折騰,發(fā)現(xiàn)這段代碼的意思應(yīng)該是將源代碼中的該組件的子節(jié)點(diǎn)克隆并轉(zhuǎn)換成界面上UI元素,“React.Children.only”方法目前還不是非常理解,大致理解為修改單獨(dú)元素的屬性。
在折騰代碼的時(shí)候,發(fā)現(xiàn)自己對(duì)于“this.refs”和“this.props.children”的區(qū)別鬧不明白了,現(xiàn)在的理解是“this.refs”代表的應(yīng)該是界面顯示之后的節(jié)點(diǎn)對(duì)象,而“this.props.children”應(yīng)該是指源代碼中書寫的該標(biāo)簽的子節(jié)點(diǎn)集,好吧,我知道這么說也還是有點(diǎn)繞。
最終通過下面的代碼回調(diào)到外部:
_hoverListener = (msg) => {
let {x: hx, y: hy} = msg;
let inHover = hx >= this.left && hx <= this.right && hy >= this.top && hy <= this.bottom;
const isChanged = this._inHover != inHover;
if (isChanged) {
this.props.onHoverChanged && this.props.onHoverChanged(this.refs.text, inHover);
this._inHover = inHover;
}
}