1.0.31 • Published 5 years ago

react-remote v1.0.31

Weekly downloads
1
License
ISC
Repository
-
Last release
5 years ago

安装 npm i react-remote

官网 www.react-remote.com

为什么使用remote

react-remote 致力于提供丰富的逻辑功能和和自由拆解的外观组件。同时,还包含一套前端常用的工具库

  • 逻辑和外观(DOM结构)分离,自由定制外观却仍能复用逻辑。

    不论组件的外观设计多么精美,在大部分商业项目中,设计师也很少会直接使用,事实上同一个设计师每次设计组件外观都大相径庭,即使这些组件功能完全一致。

传统的解决方法有两种:

  • 重写逻辑和外观——缺点:大量的重复代码,很多“复制粘贴”正是由此而来
  • 先隐藏默认外观,再添加新外观元素——缺点:增加了隐藏默认外观的工作量,增加了页面上元素

既然只有外观改变,为什么不能只重写外观?既然默认外观用不上,为什么不能直接丢弃默认外观? remote组件库出发点即在于此,通过逻辑和外观的解构,组件逻辑类和组件外观类完全分离,通过skinClass属性关联。当需要使用新的外观时,你只需要从0开始写外观类,然后把外观类设置为skinClass属性的值,无需重写逻辑,也无需先隐藏默认外观。

当然,remote的默认皮肤也足以满足大部分后台需求

  • 接口名称统一

    当你用了一两个remote的组件后,几乎就能猜到其它组件的属性和接口名称。例如label表示短小文字,text表示大段文字,value表示当前值,selectedValue表示选中值…… 在每个组件中,相同功能的属性都具有一样的名称。不仅如此,remote的所有事件处理函数,都和原生js事件一样,有且只有一个event参数。

  • 强大的工具包

    事实上,除了组件库,remote还包含一套工具库,例如:可设置限制区域的元素拖动器、获取元素相对窗口/相对页面的位置和占用区域、支持循环引用的深拷贝…… 更多工具包,还会不断以合理易用的形式添加进来

概述

一个完整的组件包含三部分 1. 组件类——定义组件的数据、逻辑功能 2. 皮肤类——定义组件的外观DOM结构,包含拥有的元素、层级关系、和组件类数据的联系 3. 样式类——CSS文件,定义皮肤类中DOM结点的样式

开始使用react-remote

下面以输入框为例,进行组件的创建、属性修改、事件监听

  1. 创建组件

    <TextInput  ref='tb' text='第一段文字'/>
  2. 读取和设置属性——使用组件时,有两种方法可设置组件属性。

    //通过props传递
    <TextInput ref='tb' text={this.state.text} />
    this.setState({text:'一段新的文字'});
    
    //获取组件实例并设置属性
    this.refs.tb.text = '一段新的文字';

    如果组件的值只需要在最后提交时使用,则不必和传统react代码一样,在state中保存属性,只需要在最后使用时,通过下面的代码读取组件值即可

    this.refs.tb.text;

    特别需要注意的是,上面的代码并不意味着在react-remote中,props变得可写了。

    text本质是TextInput的属性,是this.text而不是this.props.text;只不过,react-remote把props做为传递属性的工具而已

  3. 添加事件监听,react-remote所有事件函数的参数都只有一个:event。event可能是原生JS事件对象、RemoteEvent类实例、RemoteEvent子类的实例

    在props中设置事件处理函数,此方法会替换掉之前使用props设置的处理函数

    <TextInput ref='tb' text='第一段文字' changeHandler={this.tb_changeHandler}/>

    如果添加监听后,希望之前的事件处理函数仍然保留,需要使用addEventListener函数监听事件

    this.refs.tb.addEventListener(RemoteEvent.CHANGE, this.tb_changeHandler);

    事件处理函数的参数只有一个,是下面三种对象的一种:原生JS事件对象、RemoteEvent类实例、emoteEvent子类的实例

    tb_changeHandler = (event)=>{
    	//currentTarget为添加事件处理函数的对象
    	let currentTarget = event.currentTarget;    
    		
    	//target为发出事件的对象
    	let target = event.target;			
    }

自定义CSS样式

remote的组件都默认提供了一组外观状态属性,例如Button类包含下面的状态

  • 'unable' 不可用的状态
  • 'down' 鼠标/手指 按下的状态
  • 'over' 鼠标移上但是未按下的状态(移动端无此状态)
  • '' 默认状态

组件的class名称通常为:组件名称 + 状态名称,例如:button-unable。可通过修改css来改变组件样式

每种组件包含的外观状态,可参考API文档中每个组件的 _getCurrentSkinStatus() 方法

自定义皮肤

如果修改css无法满足外观需求(例如文本框有多层图片),可以通过创建自定义皮肤实现外观。 1. 创建皮肤类:MyTextInputSkin.js

创建皮肤类,有两点要注意
+ this.getClassByStatus(preName)——此方法传入样式前缀名称,返回结果为'前缀-组件状态'(例如 button-unable),用于设置不同状态下className的值
+ this.target——表示组件本身,如果组件提供的皮肤状态无法满足样式需要,可使用this.target的任意属性来进行状态判断和计算
```
class MyTextInputSkin extends SkinBase{
	render(){

		//myTextInput 表示className前缀。最终生成的className值为:myTextInput、myTextInput-unable等
		return (
			<div className={this.getClassByStatus('myTextInput')}>	
				<img sr='1.jpg' className='img1'/>
				<img sr='2.jpg' className='img2'/>
				<img sr='3.jpg' className='img3'/>

				//this.target表示组件本身
				<input ref='inputNode' type='text' placeholder={this.target.placeholder} className='myInput'/>
			</div>
		);
	}
}
```
  1. 创建皮肤类的样式文件:MyTextInputSkin.less

    .myTextInput{
    	.img1{
    		//img1的css样式
    	}
    	.img2{
    		//img2的css样式
    	}
    	.img3{
    		//img3的css样式
    	}
    	.myInput{
    		//myInput的css样式
    	}
    }
    
    .myTextInput-unable{
    	//组件不可用时的样式
    }
  2. 设置组件的皮肤类

    //jsx语法设置
    <TextInput ref='tb' text={this.state.text} skinClass={MyTextInputSkin}/>
    
    //js语法设置
    this.refs.tb.skinClass = MyTextInputSkin;

自定义组件

如果你需要基于react-remote组件库定义你自己的组件,请阅读此段内容。

组件类

  • 默认属性—— 在_initProperty() 方法中设置组件默认属性值
  • 默认皮肤—— _getDefaultSKinClass() 方法定义组件的默认皮肤类
  • 绘制组件——组件本身只包含一层容器,真正的组件结构在皮肤类中进行
  • 初始化皮肤——在_initSkin()函数中对皮肤进行初始化, 例如属性设置、事件监听、render皮肤中的容器(例如,list的子项渲染到皮肤的container容器中)
  • 销毁皮肤——在_unstallSkin()函数中对皮肤使用的资源进行销毁,尤其是事件监听

除非你十分确定,否则自定义组件应继承自 SkinnableComponent

皮肤类

皮肤类用于定义组件的外观,详情请参考上一节: 自定义皮肤。皮肤类的基类是SkinBase

创建自定义组件流程

  1. 创建组件类NewComponent,此类是SkinnableComponent的子类

    class NewComponent extends SkinnableComponent{
    	
    }
    • 重写_initProperty函数,设置组件属性的默认值
    _initProperty(){
    	super._initProperty();
    
    	//在这里写你的组件新增的属性
    	this._newAttribute = 0;
    }
    • 如果属性需要在外部访问(通过jsx, refs访问),添加get set
    get newAttribute(){
    	return this._newAttribute;
    }
    set newAttribute(value){
    	if(this._newAttribute !=== value){
    		this._newAttribute = value;
    		//还可以做一些其它的操作
    	}
    }
    • 定义组件外观状态
    _getCurrentSkinStatus() {
    	if(value){
    		return '';
    	}
    	else{
    		return 'empty';
    	}
    }
  2. 创建皮肤类:NewSkin.js,此类是SkinBase的子类。重写render()函数,设置外观结构

    class NewSkin extends SkinBase{
    	render(){
    		return (
    			<div className={this.getClassByStatus(newComponentClass)}>
    				<img className='icon' ref='icon' src={this.target.icon}/>
    				<span className='spanCssClass'>{this.target.value}</span>
    			</div>
    		);
    	}
    }
  3. 重写组件类皮肤相关的函数

    1. 重写组件类的_initSkin()函数,设置监听
    	_initSkin(){
    	//给皮肤中的图片添加点击监听
    	this.findSkinPart('icon').addEventListener('click', this.btnClickHandler);
    }
    1. 重写组件类的_unstallSkin()函数,设置皮肤实例的销毁操作
    _unstallSkin(){
    	//移除皮肤中图片的点击监听
    	this.findSkinPart('icon').removeEventListener('click', this.btnClickHandler);
    }
    1. 重写组件类的_getDefaultSKinClass(),设置组件的默认皮肤
    _getDefaultSKinClass(){
    	//返回新建的组件皮肤类
    	return newSkinClass;
    }
  4. 创建样式文件,设置皮肤类中元素的的样式,此处以less文件为例

    .newComponentClass{
    	.icon{
    		width:50px;
    	}
    	.spanCssClass{
    		font-size:16px;
    		color:black;
    	}
    }
    
    .newComponentClass-empty{
    
    }

    至此,组件、皮肤类、样式文件全部创建完成

1.0.31

5 years ago

1.0.30

5 years ago

1.0.28

6 years ago

1.0.27

6 years ago

1.0.26

6 years ago

1.0.23

6 years ago

1.0.20

6 years ago

1.0.19

6 years ago

1.0.18

6 years ago

1.0.17

6 years ago

1.0.15

6 years ago

1.0.14

6 years ago

1.0.13

6 years ago

1.0.12

6 years ago

1.0.11

6 years ago

1.0.10

6 years ago

1.0.9

6 years ago

1.0.8

6 years ago

1.0.7

6 years ago

1.0.6

6 years ago

1.0.5

6 years ago

1.0.4

6 years ago

1.0.3

6 years ago

1.0.2

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago