Semantic-UI的React实现(四):基本元素组件的共通处理(父类)实现

上一篇(Semantic-UI的React实现(三):基本元素组件)已经提到过,基本元素组件的实现因为没有复杂的交互,仅仅是CSS类的编辑和组装,因此实现原理相对比较简单。

但简单的东西要想做的简洁,往往不简单。

抽象与封装

想要简洁高效地封装数十个基本组件,将组件的相同处理部分抽象出来是非常必要的。在ES6中js新增了class关键字(当然这只是一个语法糖,其背后的处理原理仍然是prototype那一套东西。),有了这个关键字js在抽象与封装的思想上比之前更进了一步。

当用“继承”的思想去考虑问题后,组件的共通处理很明显可以通过继承一个共同父类来完成(通常我更愿意用接口而非继承,无奈js学艺不精,不清楚接口继承如何实现)。继承以后,所有基本组件的以下处理,均可以由父类的处理完成:

  1. 编辑和组装CSS类
  2. 渲染组件本身
  3. 封装事件系统的方法回调

实现细节

编辑和组装CSS类

在系列文章二的时候有提到过,基本组件的CSS编辑和组装,在PropsHelper中实现,所有细节对外隐藏,组件仅需声明相关属性即可。如Header使用到的属性:


  1. // 属性定义 
  2. const PROP_TYPES = PropsHelper.getDefaultPropTypes().concat([ 
  3.   'size', 'sub', 'dividing', 'floated', 'aligned', 'inverted', 'inline', 'color' 
  4. ]);  

这些可用属性的声明,再加上Button组件实例的props,即可编辑和组装出所需的CSS类名集合。在Header的render方法中,仅需调用:


  1. render() { 
  2.  
  3.   // 渲染元素 
  4.   let style = this.createElementStyle(this.props, PROP_TYPES) + ' header'; 
  5.   return super.render(style); 
  6. }  

具体的生成style的细节,在Header的父类UiElement中:


  1. /** 
  2.  * 生成元素的style 
  3.  */ 
  4. createElementStyle(props, propsDef) { 
  5.  
  6.   ... 
  7.   return PropsHelper.createStyle(props, propsDef) + ' ' + style; 
  8. }  

渲染组件

渲染组件也是共通处理实现的,作为子类的基本组件,仅需调用super.render即可:


  1. render(style, children, props) { 
  2.  
  3.   return React.createElement( 
  4.     this.props.as,                // 组件的html标签(默认div) 
  5.     { 
  6.       id: this.props.id,          // 组件ID 
  7.       className: style,           // 组件class 
  8.       ...this.getEventCallback(), // 事件回调声明 
  9.       ...props                    // 组件其他props(用于生成class的props不需要了) 
  10.     }, 
  11.     children ? children : this.props.children 
  12.   ); 
  13. }  

最开始的时候,其实并没有这个实现,各个组件的渲染过程还是留在组件各自的render中的。但随着组件的增多,发现这部分代码可重用性非常大。如果有特殊的组件不适用这个过程,直接在该组件中覆写该方法即可。这对整体代码的可维护性也有很大程度的提高。

事件系统的回调

这个功能目前还在实现中。我的目标是,任何组件仅需声明而无需在该组件内部实现回调,由公共方法来实现回调处理。如一个Button想要用onClick方法,直接声明:


  1. <Button onClick={this.handleClick}>Btn</Button> 

但在Button组件内部无需实现onClick的回调处理。(实际上也无法实现,因为Button的render处理是在其父类UiElement中实现的)


  1. const EVENT_CALLBACK = [ 
  2.   'onKeyDown', 'onKeyPress', 'onKeyUp', 
  3.   'onFocus', 'onBlur', 
  4.   'onChange', 'onInput', 'onSubmit', 
  5.   'onClick', 'onContextMenu', 'onDoubleClick', 'onDrag', 'onDragEnd', 'onDragEnter', 
  6.   'onDragExit', 'onDragLeave', 'onDragOver', 'onDragStart', 'onDrop', 'onMouseDown', 
  7.   'onMouseEnter', 'onMouseLeave', 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp', 
  8.   'onSelect', 
  9.   'onTouchCancel', 'onTouchEnd', 'onTouchMove', 'onTouchStart', 
  10.   'onScroll', 'onWheel', 
  11.   'onLoad', 'onError', 
  12.   'onTransitionEnd', 
  13.   'onAnimationStart', 'onAnimationEnd', 'onAnimationIteration', 
  14. ];  

对于事件系统的回调,在constructor中是这样定义的:


  1. constructor(props) { 
  2.   super(props); 
  3.  
  4.   let eventProps = {}; 
  5.   for (let key in props) { 
  6.     if (key.indexOf('on') == 0 && EVENT_CALLBACK.indexOf(key) >= 0) { 
  7.       eventProps[key] = this.handleCallback.bind(this, key); 
  8.     } 
  9.   } 
  10.  
  11.   this.eventCallbacks = eventProps; 
  12. }  

这个组件传入的props中如果包含'onXXX'并且这个'onXXX'在EVENT_CALLBACK中有定义,则认为该组件声明了一个事件系统的回调,那么UiElement将绑定这个回调的具体处理。处理过程如此实现:


  1. handleCallback(callback, e) { 
  2.  
  3.   if (this.props.callback) { 
  4.     this.props.callback(e); 
  5.   } 
  6. }  

回顾

在UiElement中,实现了三类公共功能供基本组件类调用:

  1. 编辑和组装CSS类
  2. 渲染组件本身
  3. 封装事件系统的方法回调

实现以后,基本组件类的相同处理均被抽离出来,仅剩下一些声明性质的代码。例如Header组件的实现被简化为:


  1. import React from 'react'; 
  2.  
  3. import PropsHelper from './PropsHelper'; 
  4. import UiElement from './UiElement'; 
  5.  
  6. // 属性定义 
  7. const PROP_TYPES = PropsHelper.getDefaultPropTypes().concat([ 
  8.   'size', 'sub', 'dividing', 'floated', 'aligned', 'inverted', 'inline', 'color' 
  9. ]); 
  10.  
  11. /** 
  12.  * 标题组件 
  13.  */ 
  14. class Header extends UiElement { 
  15.  
  16.   // 类型定义 
  17.   static propTypes = { 
  18.     ...PropsHelper.createPropTypes(PROP_TYPES) 
  19.   }; 
  20.  
  21.   // 默认值定义 
  22.   static defaultProps = { 
  23.     ...PropsHelper.getDefaultPropsValue(PROP_TYPES) 
  24.   }; 
  25.  
  26.   /** 
  27.    * 取得渲染内容 
  28.    */ 
  29.   render() { 
  30.  
  31.     // 渲染元素 
  32.     let style = this.createElementStyle(this.props, PROP_TYPES) + ' header'; 
  33.     return super.render(style); 
  34.   } 
  35.  
  36. export default Header;  

这样的好处是显而易见的:

  1. 简化实现代码提高可阅读性
  2. 封装共通处理提高可维护性
  3. 通过方法覆写保持可扩展性

通过这几篇,基础组件的封装处理应该说完了,接下来的几篇打算说说复杂组件的实现。在完成所有组件的封装后,还打算扩展一些复杂组件的功能(代码丑,只能多实现些功能了。总之要和官方做成不一样的/(ㄒoㄒ)/~~)。

作者:sheva

来源:51CTO

时间: 2024-09-14 10:31:55

Semantic-UI的React实现(四):基本元素组件的共通处理(父类)实现的相关文章

Semantic-UI的React实现(三):基本元素组件

Semantic-UI官方的React组件化已经快要接近完成了,最近开放了官网:http://react.semantic-ui.com/.从官网看,基本组件已经基本完备,还有几个Addon也在进行中. 基本元素组件 Semantic-UI中的基本元素均为纯CSS类定义的组件,没有js的操作,因此实现起来比较简单.有了前面基础类UiElement和辅助类PropsHelper的实现,要实现一个基本元素组件非常轻松. 以Button组件举例.Button组件可以单独存在,也可以作为组组件使用.另外

最流行前端框架对比 Bootstrap/Foundation by ZURB/Semantic UI/Pure by Yahoo!/UIkit by YOOtheme

当今时代众多CSS的前端框架纷涌而至,但真正的优秀的却屈指可数. 在这篇文章中我们将对我认为最好的五个框架进行比较,每个框架都有自己优缺点和特定的应用领域,这允许你根据特定项目的需求选择合适的框架.比如, 如果你的项目比较简单,你就不需要复杂的框架,此外,许多选项是模块化的,这允许你仅使用你需要的组件,或者混合使用不同框架的组件. 我们要讨论的框架都是基于其在github上的人气展示的,首先说最流行的,当然是:Bootstrap. (注意:下面的一些信息在未来的几周和几月后就过时了,如:GitH

安装 Semantic UI框架安装使用方法

Semantic UI 是一套开源的 CSS 与 JavaScript 框架,提供了一些设计好的界面组件,你可以在项目里直接使用这些组件.它还提供了一套很方便的定制主题的方法,你可以用自己的想法去改变界面组件的样式.在这个教程里我们学习一下安装 Semantic UI . 准备工具 你需要使用命令行去安装,Windows 用 Powershell ,Mac 使用终端.然后确定你已经安装好了 npm 与 gulp . 安装 Semantic UI 先为项目创建一个目录,然后进入到这个目录的下面,比

深入理解React中es6创建组件this的方法_javascript技巧

首发于:https://mingjiezhang.github.io/. 在JavaScript中,this对象是运行时基于函数的执行环境(也就是上下文)绑定的. 从react中的demo说起 Facebook最近一次更新react时,将es6中的class加入了组件的创建方式当中.Facebook也推荐组件创建使用通过定义一个继承自 React.Component 的class来定义一个组件类.官方的demo: class LikeButton extends React.Component

semantic ui框架,菜单切换问题。不管用 不知道因为什么

问题描述 semantic ui框架,菜单切换问题.不管用 不知道因为什么 问题:现在引了semantic.min.css,jquery-1.12.3.js,semantic.min.js这三个文件,菜单切换不管用.是还要引其他文件么. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dt

Android UI设计系列之自定义DrawView组件实现数字签名效果(5)_Android

最近项目中有个新的需求,用户在完交易需要进行输入支付密码付款的时候,要让用户签下自己的签名,提起到数字签名这个东西,感觉有点高大上,后来想想数字签名的原理也不是太复杂,主要实现原理就是利用了View的绘图原理,把用户在屏幕上的手指移动轨迹显示在屏幕上,接着把在屏幕上显示的轨迹View转换成一张图片,最后把图片保存到本地或者上传到服务器... 还是老规矩,首先看一下工程目录吧: public class DrawView extends View { /** * 签名画笔 */ private P

React实现轮播组件的开发例子

第一步,需求 首先,写一个组件必须先考虑改组件的需求有哪些,支持的配置需要哪些. 如上已经说了改组件的需求: 轮播的图片 配置轮播图片切换的速度 可配置是否自动轮播 可配置自动轮播的时候鼠标放上去是否暂停 可配置自动轮播的速度 可配置是否需要前后箭头 可配置是否需要 dot (我不知道怎么表述好,反正意思你懂) 这一步先到此为止--- 第二步,构建项目 这里我们是使用 React 框架,当然也是用它的好搭档 webpack 来构建自动化流程咯-? 不懂 webpack 的配置可以看我的博客关于

从零学React Native之08Image组件

开发过程中, 几乎每个项目都会用到图片. RN就是通过Image组件显示图片.既可以加载网络图片,也可以加载本地资源图片. Image组件必须在样式中声明图片的款和高.如果没有声明,则图片将不会被呈现在界面上. 网络图片加载 加载网络图片非常简单, 直接上代码: 修改index.ios.js或者inde.android.js import React, { Component } from 'react'; import { AppRegistry, StyleSheet, View, Imag

从零学React Native之12 组件的生命周期

一个React Native组件从它被加载,到最终被卸载会经历一个完整的生命周期.所谓生命周期,就是一个对象从开始生成到最后消亡所经历的状态,理解生命周期,是合理开发的关键. ES6语法和之前的ES5语法有所变化,本篇文章是根据ES6语法写的. 在ES5语法中,有getDefaultPropTypes这个函数,这个函数在组件被创建时,调用一次,它的返回值成为了this.props的初始值. 而ES6语法中,属性的类型和默认值声明不像ES5语法那样在组件定义内部声明,而是在组件定义的外部声明,所以