RN 组定义组件
背景
自定义RN native Component,js绑定事件与native通信
CheckBox
遵循微信小程序的规范,实现组件,首先我们来看一下微信小程序的规范
checkboxGroup
多项选择器,内部由多个checkbox
组成。
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
onbindchange | EventHandle |
<checkbox-group/> 中选中项发生改变是触发 change 事件,detail = {value:[选中的checkbox的value的数组]} |
checkbox
多选项目。
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
value | String |
<checkbox/> 标识,选中时触发<checkbox-group/> 的 change 事件,并携带 <checkbox/> 的 value |
|
disabled | Boolean | false | 是否禁用 |
checked | Boolean | false | 当前是否选中,可用来设置默认选中 |
color | Color | checkbox的颜色,同css的color |
微信小程序语法兼容
由于RN框架的自身特性,说明两点:
1、小程序中的组件命名为"-",而我们使用的RN框架并不支持这种命名方式,大概率还是由于我没有吃透RN的用法,总之目前为止没有方案可以支持"-"命名,所以统一改成了驼峰。
2、change事件,RN中必须要加"on"前缀,所以,更改了规范,EventHandle的属性名都加了前缀
NSString *RCTNormalizeInputEventName(NSString *eventName)
{
if ([eventName hasPrefix:@"on"]) {
eventName = [eventName stringByReplacingCharactersInRange:(NSRange){0, 2} withString:@"top"];
} else if (![eventName hasPrefix:@"top"]) {
eventName = [[@"top" stringByAppendingString:[eventName substringToIndex:1].uppercaseString]
stringByAppendingString:[eventName substringFromIndex:1]];
}
return eventName;
}
上方代码片段是截取RN框架中的RCTEventDispatcher.m,片段描述了处理eventName的"诡异"操作,估计是为了代码规范特定加的。
开展组件代码
目标
我们的成果是这样的,很常规的一个CheckBox

怎么使用
<SCheckboxGroup onbindchange={this.onclick}>
<SLabel>
<SText selectable={false}>国家选择</SText></SLabel>
<SLabel>
<SCheckbox value='中国' />
<SText selectable={false}>中国</SText></SLabel>
<SLabel>
<SCheckbox value='新加坡' />
<SText selectable={false}>新加坡</SText></SLabel>
<SLabel>
<SCheckbox value='马来西亚' />
<SText selectable={false}>马来西亚</SText></SLabel>
</SCheckboxGroup>
组件组织结构
一个RN原生组件,包含两部分,native代码和js桥接代码,native代码实现了具体的view、各种事件,js桥接代码实现了对native组件的封装,属性以及事件的包装,最终能被js业务代码所使用
组件代码究竟怎么写
因为CheckBox有组的概念,所以checkbox实际包含了checkboxGroup和checkbox两个组件
从业务逻辑上区分,checkboxGroup负责处理事件,checkbox负责视图和事件的触发
CheckboxGroup
SMPCheckboxGroup.h
#import <UIKit/UIKit.h>
#import <React/RCTComponent.h>
@interface SMPCheckboxGroup : UIView
@property (nonatomic, copy) RCTBubblingEventBlock onbindchange;
- (void)addValue:(NSString *)value;
- (void)removeValue:(NSString *)value;
@end
这边定义了两个方法addValue和removeValue,group里面添加和删除元素
onbindchange是当勾选时候触发的事件,会传递到js业务层。
SMPCheckboxGroup.m
#import "SMPCheckboxGroup.h"
@interface SMPCheckboxGroup()
@property (nonatomic,strong) NSMutableArray *values;
@end
@implementation SMPCheckboxGroup
- (SMPCheckboxGroup *)init{
if (self = [super init]) {
self.values = [NSMutableArray arrayWithCapacity:1];
}
return self;
}
- (void)didMoveToSuperview{
[self drawCheckBox];
}
- (void)drawCheckBox{
self.backgroundColor = [UIColor clearColor];
}
- (void)addValue:(NSString *)value{
[self.values addObject:value];
[self sendBoxValueToJs];
}
- (void)removeValue:(NSString *)value{
[self.values removeObject:value];
[self sendBoxValueToJs];
}
- (void)sendBoxValueToJs{
if (_onbindchange) {
self.onbindchange(@{@"detail":@{@"value":self.values}});
}
}
- (void)drawRect:(CGRect)rect{
[super drawRect:rect];
}
@end
属性values用来存储勾选的值,是一个数组
不管对元素的添加和删除都要触发sendBoxValueToJs ,向js发消息。发消息的原理其实就是通过block
SMPCheckboxGroupManager.h
#import <React/RCTViewManager.h>
@interface SMPCheckboxGroupManager : RCTViewManager
@end
1、命名是有规范的,必须要xxxManager结尾,在写js桥接程序的时候会提到为什么非得这么写
SMPCheckboxGroupManager.m
#import "SMPCheckboxGroup.h"
#import "SMPCheckboxGroupManager.h"
@implementation SMPCheckboxGroupManager
RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(onbindchange, RCTBubblingEventBlock)
#pragma mark init
- (UIView *)view{
SMPCheckboxGroup *view = [[SMPCheckboxGroup alloc] init];
return view;
}
@end
1、RCT_EXPORT_MODULE() 导出module的预处理,必须要写
2、RCT_EXPORT_VIEW_PROPERTY ,导出事件和属性,js才能使用。第一个参数是属性名,第二个是类型
js桥接
import PropTypes from "prop-types";
import React from "react";
import { requireNativeComponent } from "react-native";
class SCheckboxGroup extends React.Component {
_onbindchange = (event) => {
if (!this.props.onbindchange) {
return;
}
this.props.onbindchange(event.nativeEvent);
}
render() {
return <SMPSCheckboxGroup {...this.props} onbindchange={this._onbindchange}
/>;
}
}
SCheckboxGroup.propTypes = {
onbindchange: PropTypes.func,
};
var SMPSCheckboxGroup = requireNativeComponent("SMPCheckboxGroup", SCheckboxGroup);
export default SCheckboxGroup;
1、propTypes属性列表
2、requireNativeComponent方法中,"SMPCheckboxGroup"名称是取自SMPCheckboxGroupManager,规定将Manager去掉的字符串传入第一个参数。
checkbox
原理都与checkboxGroup相似,但如果是radio的话,就稍微复杂一点。radio是选择唯一性,需要排他。
1、捕捉到radio的点击
2、查到当前radio所属的radiogroup
3、遍历radiogrou下面所有的radio
3、排他,将出了当前值意外的都更改为未选中状态
查到同一radiogroup下面的所有radio
- (UIView *)getFatherSRadioGroup:(UIView *)view
{
if (view==nil) {
return nil;
}
if ([view.superview isKindOfClass:NSClassFromString(@"SMPRadioGroup")]) {
return view.superview;
}else{
return [self getFatherSRadioGroup:view.superview];
}
}
遍历radiogroup下面所有的radio
//遍历父视图的所有子视图,包括嵌套的子视图
-(void)TraverseAllSubviews:(UIView *)view array:(NSMutableArray *) array{
for (UIView *subView in view.subviews) {
if (subView.subviews.count) {
if ([subView isKindOfClass:NSClassFromString(@"SMPRadio")]) {
[array addObject:subView];
}else{
[self TraverseAllSubviews:subView array:array];
}
}
NSLog(@"%@",subView);
}
}
排他,将出了当前值意外的都更改为未选中状态
- (void)changeOtherBrothers:(NSArray *)array
{
for (UIView *v in array) {
if ([v isKindOfClass:NSClassFromString(@"SMPRadio")] && v != self) {
SMPRadio *radio = (SMPRadio *)v;
radio.RadioChecedColor.backgroundColor = [UIColor whiteColor];
radio.selectedRadio = NO;
}
}
}
网友评论