Coder Social home page Coder Social logo

react-ui's Introduction

This Project Is Deprecated

Try another component library Shineout

此项目已经暂停维护,已发布一个新的轻量,性能更优化的组件库 Shineout,欢迎移步使用。

A collection of components for React, base on bootstrap 4.0. Docs

Usage

  • npm install
npm install rctui
var ReactUI = require('rctui')
var Form = ReactUI.Form
// or
import { Form } from 'rctui'
...
// import one Component without other components
var Input = require('rctui/Input')
var CheckboxGroup = require('rctui/CheckboxGroup')
var FormControl = require('rctui/FormControl')
// or
import Input from 'rctui/Input'

If you don't want compile the file or encounter any compile problems, you can use the built file

// html
<script src="https://unpkg.com/rctui/dist/index.js"></script>
// webpack config
externals: {'react': 'React', 'react-dom': 'ReactDOM', 'rctui': 'rctui'},
// jsx
import { Form } from 'rctui'
...

cli

There is a internal cli command, help you easy start you app.

need nodejs >= 4,npm >= 3

Waning options all/webpack will overwrite your webpack.config.js file

npm install rctui
node node_modules/rctui/cli/init.js [options]
options:
    - all        install dependencies and devDependencies package, simple demo code, devServer, webpack config
    - update     install / update package
    - demo       a simple demo
    - server     node devServer.js
    - webpack    webpack.config.js !warning: will overwrite your webpack.config.js file

Start Kit

如果配置仍然有问题的话,可以尝试使用这个 Start Kit.

react-ui's People

Contributors

lobos avatar npmcdn-to-unpkg-bot avatar p2227 avatar tanyafuzhou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-ui's Issues

在table中使用pagination组件,pagination中传入的参数total不能正常获取

大神们,我参考demo例子使用Table组件,添加Pagination组件,如下:

<Table 
      ...
      data={data}
      pagination={<Pagination size={10} total={30}/>} >
    </Table>

Pagination组件中显示的页数一直为1。断点调试源码,Pagination组件的total值会被Table组件内部定义的total给覆盖,导致在Pagination组件中获取的total值为Table的单页数据长度,而不是Pagination中传入的total总数据长度。

我是npm install 安装"rctui": "^0.6.8"的。

为什么我报错了?

You may need an appropriate loader to handle this file type.
| "use strict";
|
| export const Checkbox = require('./Checkbox');
| export const CheckboxGroup = require('./CheckboxGroup');
| export const Datetime = require('./Datetime');

loader是
{test: /.(jsx|js)$/, loader: 'babel-loader', exclude: /node_modules/, query: {
cacheDirectory: true,
presets: ['es2015', 'react','stage-0']
}

Modal在firefox的兼容性问题

在Firefox中,Modal中button即使设置为“submit”仍不能触发提交表单的行为,主要是event.initEvent缺少2个参数,如event.initEvent("submit",true,true).

另外“This feature has been removed from the Web standards. Though some browsers may still support it, it is in the process of being dropped. Do not use it in old or new projects. Pages or Web apps using it may break at any time.” 希望替换成比较合适的方法

关于Form验证部分的疑问

Form验证,通常是存在一个主动校验和被动校验的过程,主动校验就是点击submit提交,如果某些表单验证失败,那么不会触发提交,但是会触发所有表单的错误消息显示,被动校验就是经过onChange,onBlur或者onFetch这些事情来校验的,我想问问你在主动校验这一块是如何设计的呢?还有,第一次访问表单,错误消息通常是不会被显示的,但是校验还是会走一遍,这个不显示你是怎么控制的呢?还有一些场景下希望submit按钮是随着整个表单的验证状态而变化,置灰或者不置灰,或者还显示一个加载状态之类的

Did you ever thought about scoper css?

I saw your demo, all components style is in a global scope.Avoid effected by other style which in global scope,Did you ever thought about scoper css?

0.7 开发规划,日志

#0.7 开发规划

react ui 0.7版的规划放在这里吧。有什么想法也可以在这里讨论。

先说下目标吧,0.7主要是解决theme的问题。
之前因为项目赶着用,加了一套theme在项目里的,因为没什么时间,是很粗暴的把purecss复制了一份,改了一些数值。加载的时候,通过动态拼接require资源地址来实现。

// theme.js
let THEME = 'pure';

function requireCss(pack) {
  require(`./${theme}/${pack}.less`);
};

function setTheme(theme) {
  THEME = theme;
}

// component.js
requireCss('button');

这个临时方案虽然可以实现,但是非常low,所以决定开个版本解决theme的问题。

0.7 计划使用bootstrap作为基础样式库
这个项目一开始的时候,是用的bootstrap作为样式库。那个时候还没有按需打包,整个js才50KB,而一个bootstrap就100多KB了,觉得太划不来,所以用了purecss。现在来看,一是purecss太过小众,而且已经年久失修,跟不上时代了;二是做theme的话,需要大量的配置,purecss改起来成本太高。还是傍着bootstrap这条大腿吧。鉴于bootstrap 4.0已经抛弃less使用sass,所以会尝试使用sass。

0.7的整个theme的结构目前构想是这样的。

|- styles/
  |- themes/
    |- _bootstrap.scss
    |- _other_theme.scss
    |- ...
  |- _buttons.scss
  |- _checkbox.scss
  |- ...
|- Button.js
|- Checkbox.js
|- ...

只留一份组件的scss文件,不同theme抽取出变量放到themes下面。bootstrap.scss作为基础库,提供默认值。其他的theme通过import这个基础库,用自定义的变量覆盖掉默认值。
bootstrap.scss 和 mixins 定期同步 boostrap 4.0 的文件到项目里,文件保持和bootstrap一致,方便以后直接使用bootstrap的theme。
bootstrap.scss

$gray-dark:                 #373a3c !default;
$gray:                      #55595c !default;
$gray-light:                #818a91 !default;
$gray-lighter:              #eceeef !default;
$gray-lightest:             #f7f7f9 !default;

$brand-primary:             #0275d8 !default;
$brand-success:             #5cb85c !default;
$brand-info:                #5bc0de !default;
$brand-warning:             #f0ad4e !default;
$brand-danger:              #d9534f !default;

other_theme.scss

@import 'bootstrap.scss';

// color ==================================================
$brand-primary:      #337ab7;
$brand-success:      #5cb85c;
$brand-info:         #5bc0de;

buttons.scss 默认引入bootstrap.scss文件

@import "themes/bootstrap";

:local(.button) {
  line-height: @base-line-height;
  padding: @btn-padding;
  color: @btn-color;
  border: 1px solid @btn-border;
  background-color: @btn-bg;
  border-radius: @btn-radius;
  ...

Button.js 引入button.scss

import styles from './styles/buttons.scss';
...
// 利用 css-loader 实现 css-module 的功能
className = classnames(styles.button, ...);
...

到这里为止,除了local css(css-module)这个以外,用户在使用上和之前的版本没有多大区别。如果使用者需要使用其它的theme,可以安装rctui-theme-loader,在webpack里加一个preLoader配置。

module: {
  preLoaders: [
    { test: /\.scss$/, loader: 'rctui-theme-loader?theme=other_theme' }
  ]
}

其实这个loader做的事情很简单,在webpack处理scss文件之前,把 @import 'themes/bootstrap' 替换成指定的theme文件。

module.exports = function (content) {
  var query = loaderUtils.parseQuery(this.query);
  if (query.theme) {
    content = content.replace('themes/bootstrap', `themes/${query.theme}`);
  }
  return content;
}

在考虑后面theme-loader可以引入外部的配置文件,覆盖内置的配置。不过先把目前的工作完成再说。

Select的clickAway有异常

Uncaught TypeError: Cannot read property 'firstChild' of undefined @ ReactUI.js:7027 
findComponentRoot @ ReactUI.js:7027
findReactNodeByID @ ReactUI.js:6991
getNodeFromInstance @ ReactUI.js:6497
findDOMNode @ ReactUI.js:14237
Component.getClickAwayEvent.fn @ ReactUI.js:3825

这个我也不确定是不是我使用不当或者配置不当而引起的,我google了一下,大部分情况都说是由于同时有两个不同版本的react实例而引起的,所以我尝试使用同一版本的react。我本地的react一开始是0.14.3,我看你server上的那个是0.14.0,但是我换成0.14.0依旧报错。

但是这个react不是已经在webpack中被当做external了吗?

我本地访问docs的site里面的select可以正常使用,在自己的project里面就会报上面的异常,实在不知道因为什么了,大神有时间帮看看吧,谢谢


nimbus-image-1450347736950

关于Form组件重置的问题

请教下,现Form组件不支持表单重置,有什么方法可以在原有Form组件的基础上实现表单的reset啊?

在 npm install rctui 时报错,问下什么问题?

npm ERR! Please include the following file with any support request:
npm ERR! /Volumes/ZBMOBI/React/scada/npm-debug.log
ZbmobideMacBook-Pro:scada zbmobi$ sudo npm install rctui
npm WARN package.json [email protected] No repository field.
npm WARN peerDependencies The peer dependency react-router@^0.13.3 included from rctui will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
npm ERR! Darwin 14.4.0
npm ERR! argv "node" "/usr/local/bin/npm" "install" "rctui"
npm ERR! node v0.10.35
npm ERR! npm v2.11.3
npm ERR! code EPEERINVALID

npm ERR! peerinvalid The package react-router does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer [email protected] wants react-router@^0.13.3

npm ERR! Please include the following file with any support request:
npm ERR! /Volumes/ZBMOBI/React/scada/npm-debug.log

React-UI 0.6 Form设计

React-UI 0.6 Form设计

0.6版最大的变化,把整个Form架构重新写了一遍,差不多覆盖了整个UI库的2/3。

0.6之前的Form,是这样一个结构。

使用的时候是这样的

<Form layout="aligned" onSubmit={...} data={...}>
  <FormControl name="text" label="text" type="text" min={2} max={6} />
  <FormControl name="email" label="email" type="email">
    <span className="rct-input-group">
      <span className="addon"><Icon icon="email" /></span>
      <Input type="email" />
    </span>
  </FormControl>
  ...
</Form>

这样设计是想把所有的表单组件注册到FormControl,由FormControl实现validate,生成tip文字,和Form交互的工作。不过由于写这个UI库的时候,接触React时间还不长,有些**还是停留在Angularjs和Vue的双向绑定上,另外也没有想到好的办法解决获取Form表单数据的问题。所以给所有的表单组件加上了getValue和setValue两个方法进行传值。

这个设计实现了我开始想实现的大部分功能,但是很快发现不太够用了。很多表单都会有一两个比较复杂的交互,单纯通过FormControl的props很难描述,通过使用children这样的方式,也非常吃力,因为一个FormControl只能描述一个FormData字段,如果一行有多个表单组件,就不好用了。另外,由于Form内使用了cloneElement,在最外层也无法拿到原始的ref。
最致命的是,在使用mixin的时候,使用getValue和setValue不会有多大的问题。但是,后来大部分组件都采用了higherorder component,来附加一些通用的功能,比如取服务端数据用的Fetch。这样FormControl就无法直接通过setValue和getValue来操作数据了。虽然可以通过改变higherorder来支持,但是这样显然是不对的。

所以,在0.6的时候,决心对Form进行一次重构。新的架构是这样的。

最大的变化是增加了两个FormItem,一个是higherorder的组件,用来包装input类的表单组件,实现了原来FormControl的validate的功能。另外一个是对这个higherorder组件的封装,暴露出来供使用者调用。

原先的FormControl职责变得简单一些,不再处理数据,只用来生成label文字,汇总FormItem子组件(一个FormControl下可以有多个FormItem)的状态,生成相应的提示/错误信息。

最困难的是Form的部分。数据向下传递比较简单,要在onSubmit的时候获取到所有表单项的状态:是否通过校验,这个比较麻烦。在一个FormItem没有触发onChange的情况下,Form如何知道这个FormItem存在,并让它去做validate校验?如果通过了校验,怎么拿到初始值?

想了好几种解决方案,都不太理想。最终决定,增加了一个itemBind机制。

    this.itemBind = (item) => {
      this.items[item.id] =item;

      let data = this.state.data;
      data[item.name] = item.value;
      this.setState({ data });

      // bind triger item
      if (item.valiBind) {
        item.valiBind.forEach((vb) => {
          this.validationPools[vb] = (this.validationPools[vb] || []).concat(item.validate);
        });
      }
    };

    this.itemUnbind = (id, name) => {
      let data = this.state.data;
      delete this.items[id];
      delete data[name];
      delete this.validationPools[name];
      this.setState({ data });
    };

    this.itemChange = (id, value, err) => {
      let data = this.state.data;
      const name = this.items[id].name;

      if (data[name] !== value) {
        data[name] = value;
        this.setState({ data });
      }

      let valiBind = this.validationPools[name];
      if (valiBind) {
        valiBind.forEach((validate) => {
          if (validate) {
            validate();
          }
        });
      }

      this.items[id].$validation = err;
    };
  }

每个FormItem初始化的时候直接bind到Form的items,数据改变的时候,通过itemChange方法,直接把数据和状态提交到Form的formData。Form在submit的时候,检查items里面每个item是否通过validate,如果没有执行过validate,通知item执行。如果所有items状态都ok,再触发onSubmit。

这一切对于使用者来说是黑盒的。对外的Api基本上是没有变的。

一个完整的Form调用现在是这样。

<Form data={...} onSubmit={...}>
  <FormControl label="label">
    原生input:
    <FormItem name="filed1" value="初始值" min={2} max={12} validator={...}>
      <input />
    </FormItem>
    自定义组件,需要支持value传入值,onChange传出值
    <FormItem>
      <CustomComponent {...} />
    </FormItem>
    Input组件
    <Input name="filed2" type="url" />
  </FormControl>
</Form>

如果FormControl只有一个组件,可以写成这样,这样就和之前的版本没有区别了。

<Form data={...} onSubmit={...} layout="...">
  <FormControl label="label" name="filed" type="text" required min={2} max={12} validator={...} />
</Form>

demo见这里

动态表单

这个是一直想实现的功能,0.6里也顺带完成了,通过一个json格式,动态生成一个表单。

<Form button="确定" fetch={'json/form.json'} controls={[
  { name: 'text', type: 'text', min: 3, max: 12, label: 'text', grid: 1/3 },
  { name: 'datetime', required: true, type: 'datetime', label: 'datetime', tip: '自定义tip文字' },
  { label: 'two items', items: [
    { name: 'startTime', type: 'date' },
    '-',
    { name: 'endTime', type: 'date' }
  ] },
  {
    name: 'select', type: 'select', label: 'select', grid: 1/2, fetch: {url:"json/countries.json", cache:3600},
    mult: true, filterAble: true, valueTpl: "{en}",
    optionTpl: '<img src="//lobos.github.io/react-ui/images/flags/{code}.png" /> {country}-{en}'
  }
]} />

实现这一步比较简单了,因为原本Form所有的children都是FormControl,只要把controls遍历一下,return <FormControl {...control} />就好了

在线的示例

Licence empty

The licence file is empty. Is that means that the project is not open source anymore ?

Tree组件不能正常渲染

我直接拷贝教程的树结构,放在../sources/menu.json中,使用如下代码,但是树目录不能正常渲染出来,查看节点,只看到<ul class="rct-tree"></ul>,内部节点都没绘制出来,请问下是什么问题啊?

import React from 'react';
import { Tree, Icon, Refetch} from 'rctui';

var MenuComponent = React.createClass({
    getInitialState: function() {
      return {
        readOnly: false,
        selectAble: true,
        greedy: false,
        sep: ',',
        value: 'role_delete',
        showValue: 'role_delete',
        showAccountsIcon: false,
        treeData: null
      };
    },
    componentWillMount () {
      Refetch.get('../sources/menu.json', null, {cache: 3600})
        .then(res => {
          this.setState({ treeData: res });
        });
    },
    handleChange (value) {
      if (Array.isArray(value)) {
        value = JSON.stringify(value);
      }
      this.setState({ showValue: value });
    },
    render:function() {
      return <Tree data={this.state.treeData}
        readOnly={this.state.readOnly}
        selectAble={this.state.selectAble}
        greedy={this.state.greedy}
        icons={
          this.state.showAccountsIcon ?
            [
              <Icon icon="accounts-add" />,
              <Icon icon="accounts" />,
              <Icon icon="account" />
            ]:
            undefined
        }
        onChange={this.handleChange}
        textTpl="{text}({id})"
        valueTpl="{id}"
        value={this.state.value}
        open={true}
        sep={this.state.sep}
      />;
    }
});

module.exports = MenuComponent;

ES6 support required

Hi, webpack compile error occur
screen shot 2015-09-23 at 11 32 24
what i have done

import { Pagination, Table } from 'rctui'

and webpack loader config

{test: /\.jsx?$/,
loaders: ['react-hot', 'babel?stage=0'],
exclude: /node_modules/,
include: __dirname}

引用的时候语法错误?static displayName= "xxxx"

ERROR in ./~/rctui/src/js/components/checkbox.jsx
Module build failed: SyntaxError: ~/work/test/react-test/node_modules/rctui/src/js/components/checkbox.jsx: Unexpected token (8:21)
6 |
7 | class Checkbox extends React.Component {

8 | static displayName = "Checkbox"
| ^
9 |
10 | static propTypes = {
11 | checked: React.PropTypes.bool,
at Parser.pp.raise (/Users/sukui/work/test/react-test/node_modules/babel-core/node_modules/babylon/lib/parser/location.js:24:13)
at Parser.pp.unexpected (/Users/sukui/work/test/react-test/node_modules/babel-core/node_modules/babylon/lib/parser/util.js:82:8)

貌似不支持static 关键字 ?

关于react-ui的一些问题以及规划

写这篇文章呢,要先给一些同学道个歉,因为最近换了工作,事情比较多,有些同学给我发的gmail(也有因为GFW的原因,时断时续)和提的issue,过了很久才回复。也有位同学让我建个QQ群之类的讨论问题,但是因为工作关系,基本不能用QQ,所以在这里发个帖子,回答一些问题,并且说下后面的规划吧。

有了ant-design这样NB的库,是否还有必要继续react-ui

第一个问题,算是自问自答。
react-ui写了一大半的时候,发现蚂蚁金服开源了ant-design这个项目,当时觉得挺迷茫的,因为只有一个人,基本上把工作之余的时间都搭进去了,才做到这个程度。和蚂蚁金服相比,一堆牛人,有很NB的设计,官网很酷炫,文档也很健全。
那个时候反复的思考,这个项目还有没有继续下去的必要。仔细对比了一下,发现还是可以做下去的。
react-ui是一个完全从易用性的角度去思考的一个库,原则是调用的时候,越简单越好,写的代码越少越好,即使某些地方不符合react**的。
比如select,react-ui的调用方式

<Select placeholder="Group by continent"
  groupBy="continent"
  filterAble={true}
  optionTpl='<img src="images/flags/{code}.png" /> {country}-{en}'
  valueTpl="{country}-{en}"
  data={dataSource("json/countries.json", null, {cache: true})} />

ant-design的调用方式

<Select defaultValue="lucy"
    style={{width:200}}
    showSearch={false}
    onChange={handleChange}>
    <OptGroup label="Manager">
      <Option value="jack">jack</Option>
      <Option value="lucy">lucy</Option>
    </OptGroup>
    <OptGroup label="Engineer">
      <Option value="yiminghe">yiminghe</Option>
    </OptGroup>
  </Select>

同样的还有CheckboxGroup,Tree等等。
有人说ant的方式是更符合react的**的,同时更加的灵活。我同意。
但是我的想法是,一个好用的组件,使用者只需要传一组数据进去,并不要知道组件内部的结构是什么,就可以完成这个组件的调用。并且同一组数据,只改一下调用,就可以实现类似Select到Radio的转换。

<RadioGroup textTpl={'{country}-{en}'} data={dataSource("json/countries.json", null, {cache: true})} />

为了更加方便的调用,创建了FormControl这个组件,把所有的表单组件注册到FromControl,在这个FormControl上实现自动的validate,自动的tip。这样从而避免在表单组件外面再加一个Validator,这个是我不愿意接受的。

同样的,还有Modal,Message这样的组件,使用的时候完全不像React的组件,更接近传统的JS库,只提供了静态方法,在任意的地方调用。

另外,大家都说,有redux,有flux,所有的数据都应该通过props传入,这样才符合规范,才是现代化的。但是对我来说,就是喜欢简单粗暴的传入一个链接地址获取数据。我只是想给select几个选项值,要去写action,写store,写reducer,connect……OMG!
当然,如果你喜欢props,你仍然可以直接传入data。

为什么要用purecss

最初的版本里,css部分是用的bootstrap,慢慢的发现不能接受了,因为bootstrap差不多有100多kb的体积,而那个时候整个js库的文件也才60多kb。当时想了很多方案,最后选了yahoo的purecss,因为非常的小,只有20kb不到,并且官网的文档里也明确说明可以和bootstrap搭配使用。
不过purecss确实是比较简陋,所以在项目里加了一个theme的模块,可以对css进行扩展。是有打算做一些热门ui的皮肤,但是一直搁置中。
另外在某个版本里,使用了css module的方式来防止css污染,不过这样不能方便的扩展,所以又换回了'rct-'这个前缀。现在还是会比较纠结是否使用css module的问题,打算等后面重构css部分的时候再做决定。

为什么没有拆分成独立的子项目

这个问题也困扰了我一段时间,因为有些同学用react-ui,只是看重了某一个组件。而且,从理论上来说,一个单独的组件比整个UI库更好维护啊。
于是就建了一个rctui的group,把整个项目分拆。后来发现随着组件的拆分维护工作进入了一个地狱,比如utils这个库改了一行代码,用到它的Button要升级,用到Button的其他库也要升级,都要push到github,publish到npm。然后发现其他所有用到utils的库都在等着升级……
所以又回到一个库的状态,但是还是有点纠结。直到后来听了一个facebook大神的讲课,说facebook只有一个仓库,全部的代码都在上面。
好吧,不纠结了。
最后就是发布到npm之前费点事,把代码从src挪到根目录下面,只需要某个组件的话可以单独引用。

尽可能的轻

这个是react-ui保持一个完整的库的另一个原因,如果拆分成很多库,再通过一个项目合起来的时候,不可避免的会增加很多冗余的代码。
从一开始,就一直在避免整个项目变得太庞大。因此放弃了underscore、lodash这样的神器,所有的utils都是自己写,或者从别的库里一点一点的剥出来。也因为这个原因,迟迟没有升级到es6(babel转换后大约会增加1/4左右的体积),后来终于没有忍住,一下升到es7(再后来,这变成了一个悲伤的故事)。
其他的部分,比如Grid,使用了一个动态的方法生成css,用几kb实现了一个任意多列等分、支持responsive的栅格系统,从而减少了几十kb css的加载。不过因为生成了很多style标签,暂时没有想清楚是否有问题。
此外,ajax库的选择,最初的时候是用了superagent,算是比较轻量的了,差不多20多kb,但是还是觉得比较重,那个时候js部分只有60多kb。选了n个ajax库,最后选了一个几乎没多少人知道的qwest,因为它是Promise A+P规范,因为它只有7kb。

不能解决所有问题

我给一个同事讲(吹嘘)我的table的时候(因为我觉得react-ui的table写的还蛮NB的),他就问如果要多层表头,你怎么办?如果要合并单元格,你怎么办?我就哑口无言咧。
后来就慢慢想通了,react-ui的实现方式,在灵活性上是有一些缺失的,确实有很多问题解决不了的。事实上,也没必要去解决所有的问题,只要去解决大多数场景的问题。如果可以用20%的时间解决80%的问题,那就很完美了。

下一个版本的规划

有个同学给发邮件给我说,0.5.0到0.5.2,改了很多代码,其实90%是因为babel从5升到6,发现一些es7的语法不支持了,所以干脆把所有es7的代码全改了。这个事情说明,步子迈大了,确实会扯到蛋的……

0.6 应该会是真正的改很多代码,目前的规划以重构为主:

  • 在线build的部分,facebook已经官方推荐babel了,也没精力维护,就去掉了。
  • 任意等分的Grid,这个0.5.2已经实现了。
  • 对dataSource和qwest还是不太满意,在qwest的基础上封装了一个refetch,Promise A+规范,不需要polyfill,支持jsonp,cache。
  • dataSource不再从data传入(接口会保留两三个版本吧),使用一个新的属性fetch,支持promise和options两种方式,内部使用higherorder component方式封装。
  • validate从FormControl拆分到各个表单组件,目前的这种方式对于一行多个组件实现起来有问题。应该也是higherorder component的方式。
  • 因为封装了两层higherorder component的原因,FormControl的getValue应该会取消,并且直接调用组件内部的方法并不太好。取消了会带来一些问题,获取Form值是否通过组件的name来实现?还得想另一个方法来实现Form提交前自动的validate。

0.7 会以css为主,使用autoprefixer代替目前的mixins,考虑加一两套皮肤。

另外,单元测试。目前utils下面基本所有的代码都通过了单元测试。component的测试比较麻烦,一直也没精力完成,但是后面也要做的。

很多同学的问题都是webpack打包的,其实很多大神,Dan啊,tj啊都写了start kit的,可以参考他们的,后面有空也会写个简单的。

最后,大家对react-ui这个库有什么看法、建议和问题,或者希望增加哪些组件,都可以在这里提出来,我会尽力解决的。发issue和邮件也可以。

webpack 打包,报错,不知道什么原因?

You may need an appropriate loader to handle this file type.
| "use strict";
|
| export const Checkbox = require('./Checkbox');
| export const CheckboxGroup = require('./CheckboxGroup');
| export const Datetime = require('./Datetime');
@ ./src/public/js/index/index.js 7:14-30

webpack配置:
{
test: /.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
cacheDirectory: true,
presets: [
'es2015',
'react'
],
plugins: ['transform-runtime']
}
},

Uncaught ReferenceError: React is not defined

你好,我采用你源码的方式:
import { Component, PropTypes } from 'react';
class Input extends Component {
}

运行会报错:Uncaught ReferenceError: React is not defined

必须修改成:
import React , { Component, PropTypes } from 'react';

请问是什么原因呢?

是缺少什么Loader吗?

不带分页的Table,全选无效的疑问

不带分页的时候lastSize = data.length % size
这样start和end都等于0,全选无效了。
版本0.6.4

  Table.prototype.onSelect = function onSelect(i, e) {
    var checked = typeof e === 'boolean' ? e : e.target.checked,
        data = this.state.data,
        index = this.state.index, 
        size = this.props.pagination ? this.props.pagination.props.size : data.length,
        start = 0,
        end = 0,
        lastSize = data.length % size,
        lastIndex = Math.ceil(data.length / size);
    if (i === 'all') {
      start = (index - 1) * size;
      end = index === lastIndex ? (index - 1) * size + lastSize : index * size;
    } else {
      start = (index - 1) * size + i;
      end = start + 1;
    }

    for (; start < end; start++) {
      data[start].$checked = checked;
    }
    this.setState({ data: data });
  };

2KB实现任意等分,支持responsive的栅格系统(Grid)

2KB实现任意等分支持responsive的栅格系统(GRID)

基本上所有的UI库里都会有个栅格系统,比如bootstrap的12等分,purecss的24等分,阿里妈妈的64等分等等。数字越大,处理的粒度自会更细一些,适用的场景也会更多。但是即使24等分这样约数很多的系统,依然不可避免的有一些盲区,比如5等分,7等分。

为了适应更多的场景,purecss在24等分的基础上额外的提供了5等分的方案。然而,这带来了另外一个问题。

作为一个现代的栅格系统,不支持responsive是说不过去的,一般都会提供手机、平板、桌面、宽屏4种屏幕宽度的适配,每种宽度都要定义24等分的class,这样下来purecss的grid压缩后差不多10KB左右大小,而整个purecss的其它代码加一起也不到20KB。并且这仅仅是grid的部分,如果加上purecss没有实现的offset,体积又要增加一倍。对于非常轻量化的UI库来说,这实在是一个庞大的包袱。

动态生成style

那么有没有办法让整个库更小一些呢?实际上大部分的UI库栅格系统都是打包的时候通过less的mixins或者直接是js生成的,那么可不可以把这个生成的过程放到浏览器来做呢?于是有了第一个版本:

// 提取公约数,实现 rct-u-1-3 这样的别名调用
function getGcd(m, n) {
    let u = m, v = n
    while (v !== 0) {
    [u, v] = [v, u % v]
    }
  return u
}

// 生成24等分栅格
function gridUnit(pre, responsive) {
  responsive = responsive ? responsive + '-' : ''
  let text = [], width
  for (let i = 1; i <= 24; i++) {
    let gcd = getGcd(i, 24)
    width = (i * 100 / 24).toFixed(6)
    text.push(`.${pre}-${responsive}${i}-24`)
    if (gcd > 1) {
      text.push(`,.${pre}-${responsive}` + (i / gcd) + '-' + (24 / gcd))
    }
    text.push(`{width:${width}%;}`)
  }
  for (let i = 1; i <= 5; i++) {
    width = (i * 20).toFixed(6)
    text.push(`.${pre}-${responsive}${i}-5{width:${width}%;}`)
  }
  return text.join('')
}

export function create (pre = 'rct-g') {
  let style = document.createElement('style')
  let text = []
  style.type = 'text/css'

  text.push(`
.${pre} {
  display: inline-block;
  zoom: 1;
  letter-spacing: normal;
  word-spacing: normal;
  vertical-align: top;
  text-rendering: auto;
}`)

  text.push(`.${pre}-1{width:100%}`)
  text.push(gridUnit(pre))

  ; [['35.5', 'sm'], ['48', 'md'], ['64', 'lg'], ['80', 'xl']].forEach(([x, m]) => {
    text.push(`@media screen and (min-width: ${x}em) {`)
    text.push(gridUnit(pre, m))
    text.push('}')
  })

  style.innerHTML = text.join('')
  document.head.appendChild(style)
}

功能很简单,就是在页面加载的时候,生成一个和purecss的Grid一样的style内容,插到head里去。页面里用到的时候,就像普通的grid一样使用就好了。

<div class="rct-g">
    <div class="rct-u-1-3"><p>Thirds</p></div>
    <div class="rct-u-1-3"><p>Thirds</p></div>
    <div class="rct-u-1-3"><p>Thirds</p></div>
</div>

而文件的大小,从10多KB一下变成1KB不到。

任意等分的栅格

体积的问题解决了,还有另一个问题,如果需要5等分,7等分,甚至13等分的系统怎么办呢?再生成5等分,7等分的css?如果要1024等分呢……
既然动态了,就动态的彻底一些吧。
如果要做任意等分,那么在页面加载的时候生成一个完整的style内容肯定是不可能了,那么只有按需生成,需要什么grid的时候就生成一个。另外,让使用者记住类似'rct-u-md-1-3'这样的class也不是什么好选择。于是就变成了这样:

const GRIDS = {};
const RESPONSIVE = {
  'sm': '568',
  'md': '768',
  'lg': '992',
  'xl': '1200'
};

module.exports = function getGrid(width, responsive) {
  let gridClass = generate(width, responsive);

  return `${gridPre} ${gridPre}-1 ${gridClass}`;
}

function generate(width, responsive) {
  if (!width || width <= 0) {
    return '';
  }

  width = (width * 100).toFixed(4);
  width = width.substr(0, width.length - 1);

  responsive = responsive || defaultResponsive;
  let key = responsive + '-' + width.replace('.', '-');

  if (!GRIDS[key]) {
    generateGrid(width, key, responsive);
  }
  return `${gridPre}-${key}`;
}

function generateGrid(width, key, responsive) {
  GRIDS[key] = true;
  let minWidth = RESPONSIVE[responsive];
  let text = `@media screen and (min-width: ${minWidth}px) { .${gridPre}-${key}{width: ${width}%} }`;

  let style = document.createElement('style');
  style.type = 'text/css';
  style.innerHTML = text
  document.head.appendChild(style);
}

当我们需要一个grid的时候,调用getGrid这个方法,width是一个分数,比如1/2, 2/5, 4/8,计算数值乘以100得到一个截断小数点后4位得到一个宽度,这个宽度既作为class的宽度值,再加上前缀变为className,生成style插入head。为了防止重复插入,使用了一个全局变量GRIDS来记录生成的class。getGrid会返回这个className,妈妈再也不怕我写错className啦。

不过这个方式也会有个副作用,就是每生成一个grid,就会插入一个style标签。尝试过只用一个标签来维护,就是每生成一个grid,把之前的style值取出来,加上当前生成的style内容,再塞回去。测试下来,性能很不理想,性能比直接插入style相差100倍左右。另外,尝试过延迟批量生成style的方式,发现只延迟50ms都不可接受。事实上,插入style的速度非常快,生成从1到100等分栅格,共5050个grid的style标签,chrome下测试大约100ms。实际应用中,一个页面不同布局的grid不会太多,可以忽略不计。

然后,可以再完善一下,加入offset。

export function getGrid(options) {
  if (!options) {
    return '';
  }

  let { width, offset, responsive } = options;
  let gridClass = generate(width, 'grid', responsive);
  let offsetClass = generate(offset, 'offset', responsive);

  return `${gridPre} ${gridPre}-1 ${gridClass} ${offsetClass}`;
}

function generate(width, type, responsive) {
  if (!width || width <= 0) {
    return '';
  }

  if (width > 1) { width = 1; }
  width = (width * 100).toFixed(4);
  width = width.substr(0, width.length - 1);

  responsive = responsive || defaultResponsive;
  let key = responsive + '-' + width.replace('.', '-');
  if (type === 'grid') {
    if (!GRIDS[key]) {
      generateGrid(width, key, responsive);
    }
    return `${gridPre}-${key}`;
  } else {
    if (!OFFSETS[key]) {
      generateOffset(width, key, responsive);
    }
    return `${offsetPre}-${key}`;
  }
}

function generateGrid(width, key, responsive) {
  GRIDS[key] = true;
  let minWidth = RESPONSIVE[responsive];
  let text = `@media screen and (min-width: ${minWidth}em) { .${gridPre}-${key}{width: ${width}%} }`;

  createStyle(text);
}

function generateOffset(width, key, responsive) {
  OFFSETS[key] = true;
  let minWidth = RESPONSIVE[responsive];
  let text = `@media screen and (min-width: ${minWidth}em) { .${offsetPre}-${key}{margin-left: ${width}%} }`;

  createStyle(text);
}

function createStyle(text) {
  let style = document.createElement('style');
  style.type = 'text/css';
  style.innerHTML = text
  document.head.appendChild(style);
}

完整代码见这里

写一个React Grid

方法有了,就实际使用下把,写个React的组件,其实很简单。

import { Component, PropTypes } from 'react';
import { getGrid } from './utils/grids';

class Grid extends Component {
  render () {
    let { width, offset, responsive, style, children } = this.props;
    let className = getGrid({ width, offset, responsive });
    return (
      <div style={style} className={className}>
        {children}
      </div>
    );
  }
}

Grid.propTypes = {
  children: PropTypes.any,
  offset: PropTypes.number,
  responsive: PropTypes.string,
  style: PropTypes.object,
  width: PropTypes.number
};

module.exports = Grid;

使用的时候,这样

<Grid width={ 1/2 }>
  <Grid width={ 1/3 }>1/3</Grid>
  <Grid width={ 2/3 }>2/3</Grid>
</Grid>

结果

<div class="rct-grid rct-grid-1 rct-grid-md-50-000 ">
<div class="rct-grid rct-grid-1 rct-grid-md-33-333 ">1/3</div>
<div class="rct-grid rct-grid-1 rct-grid-md-66-666 ">2/3</div>
</div>

在线的demo

Modal.open(options) ,参数header,content中不能ref索引

Uncaught Error: Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. This usually means that you're trying to add a ref to a component that doesn't have an owner (that is, was not created inside of another component's render method). Try rendering this component inside of a new top-level component which will hold the ref.

编译问题请教

你好,感觉这个UI不错 打算应用,但是,编译ES6的时候遇到问题,编译使用的是glup+babel6,用babel编译的ES6和jsx,但是,在编译的时候报错,如图
代码中错误指向let { label, layout, items, children, ...otherProps} = props;都是类似这样的赋值报错,作者知道这个该怎么解决么?查了很久,都没找到解决办法。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.