提交 dae05a55 编写于 作者: A afc163

merge

......@@ -11,7 +11,7 @@ var Affix = antd.Affix;
React.render(
<Affix>
<button className="ant-btn ant-btn-primary">offset=0</button>
<button className="ant-btn ant-btn-primary">固定在顶部</button>
</Affix>
, document.getElementById('components-affix-demo-basic'));
````
......@@ -10,8 +10,8 @@
var Affix = antd.Affix;
React.render(
<Affix offset="200">
<button className="ant-btn ant-btn-primary">offset=200</button>
<Affix offset="75">
<button className="ant-btn ant-btn-primary">固定在距离顶部 75px 的位置</button>
</Affix>
, document.getElementById('components-affix-demo-offset'));
````
......@@ -2,6 +2,35 @@ import React from 'react';
import joinClasses from 'react/lib/joinClasses';
import rcUtil from 'rc-util';
function getScroll(w, top) {
var ret = w['page' + (top ? 'Y' : 'X') + 'Offset'];
var method = 'scroll' + (top ? 'Top' : 'Left');
if (typeof ret !== 'number') {
var d = w.document;
//ie6,7,8 standard mode
ret = d.documentElement[method];
if (typeof ret !== 'number') {
//quirks mode
ret = d.body[method];
}
}
return ret;
}
function getOffset(element) {
var rect = element.getBoundingClientRect();
var body = document.body;
var clientTop = element.clientTop || body.clientTop || 0;
var clientLeft = element.clientLeft || body.clientLeft || 0;
var scrollTop = getScroll(window, true);
var scrollLeft = getScroll(window);
return {
top: rect.top + scrollTop - clientTop,
left: rect.left + scrollLeft - clientLeft
};
}
var Affix = React.createClass({
getDefaultProps() {
......@@ -12,46 +41,58 @@ var Affix = React.createClass({
getInitialState() {
return {
affix: false
affix: false,
affixStyle: null
};
},
handleScroll() {
var affix = this.state.affix;
var offset = this.props.offset;
var scrollTop = (document.documentElement && document.documentElement.scrollTop) ||
document.body.scrollTop;
var scrollTop = getScroll(window, true);
var elemOffset = getOffset(this.getDOMNode());
if (!affix && scrollTop >= offset) {
if (!affix && (elemOffset.top - this.props.offset) < scrollTop) {
this.setState({
affix: true
affix: true,
affixStyle: {
top: this.props.offset,
left: elemOffset.left,
width: this.getDOMNode().offsetWidth
}
});
}
if (affix && scrollTop < offset) {
if (affix && (elemOffset.top - this.props.offset) > scrollTop) {
this.setState({
affix: false
affix: false,
affixStyle: null
});
}
},
componentDidMount() {
this.scrollEvent = rcUtil.Dom.addEventListener(window, 'scroll', this.handleScroll);
this.resizeEvent = rcUtil.Dom.addEventListener(window, 'resize', this.handleScroll);
},
componentWillUnmount() {
if (this.scrollEvent) {
this.scrollEvent.remove();
}
if (this.resizeEvent) {
this.resizeEvent.remove();
}
},
render() {
var affix = this.state.affix ? 'affix' : '';
var affix = this.state.affix ? 'ant-affix' : '';
var className = this.props.className;
return (
<div {...this.props} className={joinClasses(className, affix)}>
{this.props.children}
<div {...this.props}>
<div className={joinClasses(className, affix)} style={this.state.affixStyle}>
{this.props.children}
</div>
</div>
);
}
......@@ -59,4 +100,3 @@ var Affix = React.createClass({
});
module.exports = Affix;
# Affix
- category: Components
- chinese: 固
- chinese: 固
---
将页面元素钉在可视范围。
## 何时使用
当内容区域比较长,需要滚动页面时,这部分内容对应的操作或者导航需要在滚动范围内始终展现。常用于侧边菜单和按钮组合。
页面可视范围过小时,慎用此功能以免遮挡页面内容。
## API
属性如下
| 成员 | 说明 | 类型 | 默认值 |
|-------------|----------------|--------------------|--------------|
| offset | 达到指定偏移量后触发 | Number | 0 |
| offset | 达到指定偏移量后触发 | Number | 0 |
......@@ -24,5 +24,4 @@ React.render(<div>
closable
onClose={onClose} />
</div>, document.getElementById('components-alert-demo-closable'));
````
````
\ No newline at end of file
......@@ -9,8 +9,8 @@
## 何时使用
-系统需要向用户显示警告的信息时。
- 始终展现,不会自动消失,用户可以点击关闭。
-某个页面需要向用户显示警告的信息时。
- 非浮层的静态展现形式,始终展现,不会自动消失,用户可以点击关闭。
## API
......
......@@ -5,10 +5,13 @@
---
旋转木马,轮播组件
旋转木马,一组轮播的区域
## 何时使用
- 当有一组平级的内容。
- 当内容空间不足时,可以用走马灯的形式进行收纳,进行轮播展现。
- 常用于一组图片或卡片轮播。
## API
......
......@@ -11,6 +11,6 @@
var Datepicker = antd.Datepicker;
React.render(
<Datepicker value="" />
<Datepicker />
, document.getElementById('components-datepicker-demo-basic'));
````
......@@ -7,7 +7,6 @@
---
````jsx
// or require('antd/lib/datepicker');
var Datepicker = antd.Datepicker;
React.render(
......
......@@ -10,7 +10,7 @@ import DateTimeFormat from 'gregorian-calendar-format';
// 和顶部文案保持一致
import Locale from 'gregorian-calendar-format/lib/locale/zh-cn';
Locale.shortMonths = ['1月', '2月', '3月', '4月', '5月', '6月',
'7月', '8月', '9月', '10月', '11月', '12月'];
'7月', '8月', '9月', '10月', '11月', '12月'];
// 以下两行代码
// 给没有初始值的日期选择框提供本地化信息
......@@ -42,7 +42,8 @@ export default React.createClass({
format: 'yyyy-MM-dd',
placeholder: '请选择日期',
transitionName: 'slide-up',
onSelect: function () {}
onSelect() {
}
};
},
handleChange(v) {
......@@ -69,9 +70,13 @@ export default React.createClass({
disabled={this.props.disabled}
trigger={<span className="ant-calendar-picker-icon" />}
calendar={calendar}
adjustOrientOnCalendarOverflow={true}
adjustOrientOnCalendarOverflow={{
x: true,
y: false
}}
formatter={new DateTimeFormat(this.props.format)}
value={this.state.value}
defaultValue={this.props.defaultValue}
prefixCls="ant-calendar-picker"
onChange={this.handleChange}>
<input
......
......@@ -21,6 +21,7 @@
| 参数 | 说明 | 类型 | 默认值 |
|--------------|----------------|----------|--------------|
| value | 日期 | string | 无 |
| defaultValue | 默认日期 | string | 无 |
| format | 展示的日期格式 | string | "yyyy-MM-dd" |
| disabledDate | 不可选择的日期 | function | 无 |
| onSelect | 选择日期的回调 | function | 无 |
......
......@@ -4,6 +4,8 @@
默认子节点进场动画。为避免与本站页面的进场冲突,所以 `EnterAnimation` 里延时 1 秒,递增 `interval` 为 0.3。
刷新页面看效果。
---
````jsx
......
......@@ -4,6 +4,8 @@
通过加上 `enter-data` 属性来指定需要动画进场的元素,并且可以定义每个元素的动画效果,用到的参数有 `type` `queueId` `delay`
刷新页面看效果。
---
````jsx
......
......@@ -52,8 +52,12 @@
|参数 |类型 |默认值 |详细 |
|-----------------|-------|-------------|----------------------------------------------------|
|type |string |`right` |执行动画的内置参数 |
|style |string |null |同上, style 的样式动画, `type` 有值,此项无效|
|eStyle |string |null |同上, style 的样式动画, `type` 有值,此项无效|
|direction |string |`enter`|动画进场或出场样式,以 `enter` `leave` 两值|
|duration |number |0.5 |每个动画的时间|
|ease |string|`cubic-bezier(0.165, 0.84, 0.44, 1);`|样式缓动;|
|delay |number |0 |整个区块的延时,以秒为单位|
|upend |boolean|false |是否倒放,从最后一个dom开始往上播放|
|interval |number |0.1 |递增延时值,以秒为单位|
### enter-data
......@@ -68,9 +72,9 @@
|-----------------|-----------------|----------------|----------------------------------------------------|
|type |string |`right` |内置动画样式:<br/> `alpha` `left` `right` `top` `bottom` `scale` `scaleBig` `scaleX` `scaleY`|
|style |string |null |动画样式,如 `transform: translateX(100px)``type` 有值此项无效|
|direction |string |`enter` |动画进出场方向:`enter` `leave`|
|duration |number |0.5 |动画的时间,以秒为单位|
|ease |string |`cubic-bezier(0.165, 0.84, 0.44, 1)`|样式缓动,只支持 css 样式缓动|
|direction |string |`enter` |动画进出场方向:`enter` `leave`,覆盖标签里的值|
|duration |number |0.5 |动画的时间,以秒为单位,覆盖标签里的值|
|ease |string |`cubic-bezier(0.165, 0.84, 0.44, 1)`|样式缓动,只支持 css 样式缓动,覆盖标签里的值|
|delay |number |0 |动画的延时,依照结构递增以上的 `interval`|
|queueId |number |0 |动画的线程|
......
......@@ -48,13 +48,13 @@ React.render(
<label className="col-6">Checkbox 多选框:</label>
<div className="col-18">
<label className="ant-checkbox-vertical">
<Checkbox /> 选项一
<Checkbox />选项一
</label>
<label className="ant-checkbox-vertical">
<Checkbox /> 选项二
<Checkbox />选项二
</label>
<label className="ant-checkbox-vertical">
<Checkbox disabled={true} /> 选项三(不可选)
<Checkbox disabled={true} />选项三(不可选)
</label>
</div>
</div>
......
# 导航菜单
- order: 0
基本使用。
---
````jsx
var Menu = antd.Menu;
var MenuItem = Menu.Item;
var SubMenu = Menu.SubMenu;
function handleClick(key) {
console.log('selected ' + key);
}
var align={
points:['lt','lb']
};
React.render(<Menu onClick={handleClick} horizontal>
<SubMenu align={align} title={<span><i className="anticon anticon-apple"></i><span>导航一</span></span>}>
<MenuItem key="1">选项1</MenuItem>
<MenuItem key="2">选项2</MenuItem>
<MenuItem key="3">选项3</MenuItem>
<MenuItem key="4">选项4</MenuItem>
</SubMenu>
<SubMenu align={align} title={<span><i className="anticon anticon-apple"></i><span>导航二</span></span>}>
<MenuItem key="5">选项5</MenuItem>
<MenuItem key="6">选项6</MenuItem>
<SubMenu title={<span><i className="anticon anticon-apple"></i><span>三级导航</span></span>}>
<MenuItem key="7">选项7</MenuItem>
<MenuItem key="8">选项8</MenuItem>
</SubMenu>
</SubMenu>
<SubMenu align={align} title={<span><i className="anticon anticon-apple"></i><span>导航三</span></span>}>
<MenuItem key="9">选项9</MenuItem>
<MenuItem key="10">选项10</MenuItem>
<MenuItem key="11">选项11</MenuItem>
<MenuItem key="12">选项12</MenuItem>
</SubMenu>
</Menu>
, document.getElementById('components-menu-demo-nav'));
````
# 侧边菜单
- order: 1
基本使用。
---
````jsx
var Menu = antd.Menu;
var MenuItem = Menu.Item;
var SubMenu = Menu.SubMenu;
function handleClick(key) {
console.log('selected ' + key);
}
React.render(<Menu onClick={handleClick} style={{width:200}} vertical>
<SubMenu title={<span><i className="anticon anticon-apple"></i><span>导航一</span></span>}>
<MenuItem key="1">选项1</MenuItem>
<MenuItem key="2">选项2</MenuItem>
<MenuItem key="3">选项3</MenuItem>
<MenuItem key="4">选项4</MenuItem>
</SubMenu>
<SubMenu title={<span><i className="anticon anticon-apple"></i><span>导航二</span></span>}>
<MenuItem key="5">选项5</MenuItem>
<MenuItem key="6">选项6</MenuItem>
<SubMenu title={<span><i className="anticon anticon-apple"></i><span>三级导航</span></span>}>
<MenuItem key="7">选项7</MenuItem>
<MenuItem key="8">选项8</MenuItem>
</SubMenu>
</SubMenu>
<SubMenu title={<span><i className="anticon anticon-apple"></i><span>导航三</span></span>}>
<MenuItem key="9">选项9</MenuItem>
<MenuItem key="10">选项10</MenuItem>
<MenuItem key="11">选项11</MenuItem>
<MenuItem key="12">选项12</MenuItem>
</SubMenu>
</Menu>
, document.getElementById('components-menu-demo-side'));
````
import Menu from 'rc-menu';
import React from 'react';
const AntMenu = React.createClass({
getDefaultProps(){
return {
prefixCls: 'ant-menu'
};
},
render(){
return <Menu {...this.props}/>;
}
});
AntMenu.Divider = Menu.Divider;
AntMenu.Item = Menu.Item;
AntMenu.SubMenu = Menu.SubMenu;
export default AntMenu;
......@@ -5,3 +5,47 @@
---
为页面和功能提供导航的菜单列表。
## 何时使用
导航菜单是一个网站的灵魂,用户依赖导航在各个页面中进行跳转。一般分为顶部导航和侧边导航,顶部导航提供全局性的类目和功能,侧边导航提供多级结构来收纳和排列网站架构。
```html
<Menu>
<MenuItem>菜单项</MenuItem>
<SubMenu title="子菜单">
<MenuItem>子菜单项</MenuItem>
</SubMenu>
</Menu>
```
## API
### Menu props
| 参数 | 说明 | 类型 | 默认值 |
|----------|----------------|----------|--------------|
| horizontal | 是否横向菜单 | boolean | false |
| vertical | 是否侧向菜单 | boolean | false |
| multiple | 支持多选 | | false |
| selectedKeys | 选中的菜单项 key 数组 | | |
| onSelect | 被选中时调用,参数为选中的 menuitem key 值 | function | 无 |
| onDeselect | 取消选中时调用,参数为选中的 menuitem key 值,仅在multiple生效 | function | 无 |
| onClick | 点击 menuitem 调用此函数,参数为点击的 menuitem key 值 | function | 无 |
| style | 根节点样式 | object | | |
### Menu.Item props
| 参数 | 说明 | 类型 | 默认值 |
|----------|----------------|----------|--------------|
| disabled | 是否禁用 | Boolean | false |
| key | item 的唯一标志 | String | | |
### Menu.SubMenu props
| 参数 | 说明 | 类型 | 默认值 |
|----------|----------------|----------|--------------|
| title | 子菜单项值 | String or React.Element | |
| align | 子菜单的对齐配置 | object | {points:['lt','rt']} 弹出子菜单的 left top 和子菜单项的 right top 对齐 |
| children | (MenuItem or SubMenu)[] | 子菜单的菜单项 | | |
# 基本
- order: 0
最简单的用法,五秒后自动关闭。
---
````jsx
var notification = require('antd/lib/notification');
var openNotification = function() {
notification.open({
message: "这是标题",
description: "这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案"
});
};
React.render(
<div>
<button className='ant-btn ant-btn-primary' onClick={openNotification}>打开通知提醒框</button>
</div>,
document.getElementById('components-notification-demo-basic'));
````
# 不自动消失
- order: 6
将 duration 配置为 null 即可。
---
````jsx
var notification = require('antd/lib/notification');
var openNotification = function() {
notification.open({
message: "这是标题",
description: "这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案这是提示框的文案",
duration: null
});
};
React.render(
<button className="ant-btn ant-btn-primary" onClick={openNotification}>显示通知,不自动消失</button>
, document.getElementById('components-notification-demo-duration'));
````
# 回调函数
- order: 3
点击关闭按钮时触发回调函数。
---
````jsx
var notification = require('antd/lib/notification');
var close = function() {
console.log("我被默认的关闭按钮关闭了!");
};
var openNotification = function() {
var args = {
message: "这是标题",
description: "这是提示框的文案这是提示框示框的文案这是提示是提示框的文案这是提示框的文案",
onClose: close
};
notification.open(args);
};
React.render(
<div>
<button className='ant-btn ant-btn-primary' onClick={openNotification}>打开通知提醒框</button>
</div>,
document.getElementById('components-notification-demo-onclose'));
````
# 自定义关闭按钮同时触发回调函数
- order: 5
关闭自定义的关闭按钮时触发回调函数,同时还可以在默认关闭按钮上添加另一个回调函数。
---
````jsx
var notification = require('antd/lib/notification');
var key = 'someKeyString';
var close = function() {
// 自定义按钮关闭时的业务处理
console.log("我被自定义的关闭按钮关闭了!");
// 隐藏提醒框
notification.close(key);
};
var onClose = function() {
// 默认按钮关闭时的业务处理
console.log("我被默认的关闭按钮关闭了!");
};
var btn = <button onClick={close} className="ant-btn ant-btn-primary ant-btn-sm">自定义关闭按钮并触发回调函数</button>;
var openNotification = function() {
notification.open({
message: "这是标题",
description: "这是提示框的文案这是提示框示框的文案这是提示是提示框的文案这是提示框的文案",
btn: btn,
key: key,
onClose: onClose
});
};
React.render(
<button className="ant-btn ant-btn-primary" onClick={openNotification}>打开通知提醒框</button>
, document.getElementById('components-notification-demo-with-btn-onclose'));
````
# 自定义关闭按钮
- order: 4
自定义关闭按钮的样式和文字。
---
````jsx
var notification = require('antd/lib/notification');
var key = 'someKeyStringString';
var close = function() {
notification.close(key);
};
var btn = <button onClick={close} className="ant-btn ant-btn-primary ant-btn-sm">自定义关闭按钮</button>;
var openNotification = function() {
notification.open({
message: "这是标题",
description: "这是提示框的文案这是提示框示框的文案这是提示是提示框的文案这是提示框的文案",
btn: btn,
key: key
});
};
React.render(
<div>
<button className="ant-btn ant-btn-primary" onClick={openNotification}>打开通知提醒框</button>
</div>,
document.getElementById('components-notification-demo-with-btn'));
````
# 带有Icon的通知提醒框
- order: 2
通知提醒框左侧有图标。
---
````jsx
var notification = require('antd/lib/notification');
var openNotificationWithIcon = function(type) {
return function(){
notification[type]({
message: "这是标题",
description: "这是提示框的文案这是提示框示框的文案这是提示是提示框的文案这是提示框的文案"
});
};
};
React.render(<div>
<button className="ant-btn" onClick={openNotificationWithIcon('success')}>成功</button>
<button className="ant-btn" onClick={openNotificationWithIcon('info')}>消息</button>
<button className="ant-btn" onClick={openNotificationWithIcon('warn')}>警告</button>
<button className="ant-btn" onClick={openNotificationWithIcon('error')}>错误</button>
</div>
, document.getElementById('components-notification-demo-with-icon'));
````
<style>
.code-box-demo .ant-btn {
margin-right: 1em;
}
</style>
import Notification from 'rc-notification';
import assign from 'object-assign';
import React from 'react';
let top = 24;
let notificationInstance;
function getNotificationInstance() {
notificationInstance = notificationInstance || Notification.newInstance({
prefixCls: 'ant-notification',
style: {
top: top,
right: 0
}
});
return notificationInstance;
}
function notice(args) {
let duration;
if (args.duration === undefined) {
duration = 500;
} else {
duration = args.duration;
}
if (args.icon) {
let prefixCls = ' ant-notification-notice-content-icon-';
let iconClass = 'anticon anticon-';
switch (args.icon) {
case 'success':
iconClass += 'check-circle-o';
break;
case 'info':
iconClass += 'info-circle-o';
break;
case 'error':
iconClass += 'exclamation-circle-o';
break;
case 'warn':
iconClass += 'question-circle-o';
break;
default:
iconClass += 'info-circle';
}
getNotificationInstance().notice({
content: <div>
<i className={iconClass + prefixCls + 'icon-' + args.icon + prefixCls + 'icon'}></i>
<p className={prefixCls + 'message'}>{args.message}</p>
<p className={prefixCls + 'description'}>{args.description}</p>
</div>,
duration: duration,
closable: true,
onClose: args.onClose,
style: {}
});
} else {
let prefixCls = 'ant-notification-notice-content-';
if (!args.btn) {
getNotificationInstance().notice({
content: <div>
<p className={prefixCls + 'message'}>{args.message}</p>
<p className={prefixCls + 'description'}>{args.description}</p>
</div>,
duration: duration,
closable: true,
onClose: args.onClose,
style: {}
});
} else {
getNotificationInstance().notice({
content: <div>
<p className={prefixCls + 'message'}>{args.message}</p>
<p className={prefixCls + 'description'}>{args.description}</p>
<span className={prefixCls + 'btn'}>
{args.btn}
</span>
</div>,
duration: duration,
closable: true,
onClose: args.onClose,
key: args.key,
style: {}
});
}
}
}
var api = {
open(args){
notice(args);
},
close(key){
if (notificationInstance) {
notificationInstance.removeNotice(key);
}
},
config(options) {
top = isNaN(options.top) ? 24 : options.top;
}
};
['success', 'info', 'warn', 'error'].forEach((type) => {
api[type] = (args) => {
var newArgs = assign({}, args, {
icon: type
});
return api.open(newArgs);
};
});
export default api;
# Notification
- category: Components
- chinese: 系统通知
- chinese: 通知提醒
---
全局展示通知提醒信息。
## 何时使用
在系统右上角显示通知提醒信息。经常用于以下情况:
- 较为复杂的通知内容。
- 带有交互的通知,给出用户下一步的行动点。
- 系统主动推送。
## API
- `notification.success(config)`
- `notification.error(config)`
- `notification.info(config)`
- `notification.warn(config)`
- `notification.open(config)`
- `notification.close(key: String)`
config 参数如下:
| 参数 | 说明 | 类型 | 默认值 |
|----------- |--------------------------------------------- | ----------- |--------|
| message | 通知提醒标题,必选 | React.Element or String | 无 |
| description | 通知提醒内容,必选 | React.Element or String | 无 |
| btn | 自定义关闭按钮 | React.Element | 无 |
| key | 当前通知唯一标志 | String | 无 |
| onClose | 点击默认关闭按钮时触发的回调函数 | Function | 无 |
| duration | 默认五秒后自动关闭,配置为 null 则不自动关闭 | Number | 5 |
还提供了一个全局配置方法,需要在调用前提前配置,一次有效。
- `notification.config(options)`
```js
message.config({
top: 100
});
```
| 参数 | 说明 | 类型 | 默认值 |
|------------|--------------------|----------------------------|--------------|
| top | 消息距离顶部的位置 | Number | 24px |
......@@ -13,22 +13,29 @@ export default React.createClass({
transitionName: '',
placement: 'top',
trigger: 'click',
onConfirm: function() {},
onCancel: function() {}
onConfirm: function () {
},
onCancel: function () {
}
};
},
confirm: function() {
confirm: function () {
this.props.onConfirm.call(this);
this.setState({
visible: false
});
},
cancel: function() {
cancel: function () {
this.props.onCancel.call(this);
this.setState({
visible: false
});
},
onVisibleChange(v){
this.setState({
visible: v
});
},
render() {
const overlay = <div>
<div className={prefixCls + '-content'}>
......@@ -36,6 +43,7 @@ export default React.createClass({
<i className="anticon anticon-exclamation-circle"></i>
{this.props.title}
</p>
<div className={prefixCls + '-buttons'}>
<button onClick={this.cancel} className="ant-btn ant-btn-sm">取 消</button>
<button onClick={this.confirm} className="ant-btn ant-btn-primary ant-btn-sm">确 定</button>
......@@ -52,12 +60,13 @@ export default React.createClass({
return (
<Tooltip placement={this.props.placement}
prefixCls={prefixCls}
renderPopupToBody={false}
transitionName={transitionName}
visible={this.state.visible}
trigger={this.props.trigger}
overlay={overlay}>
prefixCls={prefixCls}
renderPopupToBody={false}
onVisibleChange={this.onVisibleChange}
transitionName={transitionName}
visible={this.state.visible}
trigger={this.props.trigger}
overlay={overlay}>
{this.props.children}
</Tooltip>
);
......
# 联动
- order: 6
省市联动是典型的例子。
---
````jsx
var Select = antd.Select;
var Option = Select.Option;
var provinceData = ['浙江', '江苏'];
var cityData = {
'浙江': ['杭州', '宁波', '温州'],
'江苏': ['南京', '苏州', '镇江']
};
var App = React.createClass({
getInitialState() {
return {
cities: cityData[provinceData[0]]
};
},
handleProvinceChange(value) {
this.setState({
cities: cityData[value]
});
},
render() {
var provinceOptions = provinceData.map(function(province) {
return <Option value={province}>{province}</Option>;
});
var cityOptions = this.state.cities.map(function(city) {
return <Option value={city}>{city}</Option>;
});
return <div>
<Select defaultValue={provinceData[0]} style={{width:150}} onChange={this.handleProvinceChange}>
{provinceOptions}
</Select>
&nbsp;
<Select value={this.state.cities[0]} style={{width:150}} onChange={this.handleCityChange}>
{cityOptions}
</Select>
</div>;
}
});
React.render(<App />, document.getElementById('components-select-demo-coordinate'));
````
......@@ -24,7 +24,8 @@
| 参数 | 说明 | 类型 | 默认值 |
|----------|----------------|----------|--------------|
| value | 指定默认选中的条目 | string/Array<String> | 无 |
| value | 指定选中的条目 | string/Array<String> | 无 |
| defaultValue | 指定默认选中的条目 | string/Array<String> | 无 |
| multiple | 支持多选 | | false |
| filterOption | 是否根据输入项进行筛选 | | true |
| tags | 可以把随意输入的条目作为tag,输入项不需要与下拉选项匹配 | |false |
......
......@@ -10,6 +10,7 @@
````jsx
var Table = antd.Table;
var columns = [{
title: '姓名',
dataIndex: 'name',
......@@ -29,11 +30,7 @@ var columns = [{
dataIndex: 'address'
}];
function resolve(result) {
return result.data;
}
var dataSource = {
var dataSource = new Table.DataSource({
url: "/components/table/demo/data.json",
resolve: function(result) {
return result.data;
......@@ -55,14 +52,34 @@ var dataSource = {
sortField: sorter.field,
sortOrder: sorter.order
};
for (let key in filters) {
for (var key in filters) {
params[key] = filters[key];
}
console.log('请求参数:', params);
return params;
}
};
});
var Test=React.createClass({
getInitialState() {
return {
dataSource: dataSource
};
},
refresh() {
this.setState({
dataSource: this.state.dataSource.clone()
});
},
render() {
return <div>
<Table columns={columns} dataSource={this.state.dataSource} />
<button className="ant-btn ant-btn-primary" onClick={this.refresh}>
外部重新加载数据
</button>
</div>;
}
});
React.render(<Table columns={columns} dataSource={dataSource} />
, document.getElementById('components-table-demo-ajax'));
React.render(<Test />, document.getElementById('components-table-demo-ajax'));
````
# 不显示分页
- order: 8
- order: 9
传入 pagination 为 false 即可。
......
......@@ -15,7 +15,30 @@ function defaultResolve(data) {
return data || [];
}
export default React.createClass({
class DataSource {
init(config) {
this.config = config;
this.url = config.url || '';
this.resolve = config.resolve || defaultResolve;
this.getParams = config.getParams || noop;
this.getPagination = config.getPagination || noop;
this.headers = config.headers || {};
}
constructor(config) {
if (config) {
this.init(config);
}
}
clone() {
var d = new DataSource();
d.init(this.config);
return d;
}
}
var AntTable = React.createClass({
getInitialState() {
return {
// 减少状态
......@@ -42,6 +65,10 @@ export default React.createClass({
};
},
propTypes: {
dataSource: React.PropTypes.instanceOf(DataSource)
},
componentWillReceiveProps(nextProps) {
if (('pagination' in nextProps) && nextProps.pagination !== false) {
this.setState({
......@@ -75,11 +102,7 @@ export default React.createClass({
},
getRemoteDataSource() {
return objectAssign({
resolve: defaultResolve,
getParams: noop,
getPagination: noop
}, this.props.dataSource);
return this.props.dataSource;
},
toggleSortOrder(order, column) {
......@@ -336,7 +359,7 @@ export default React.createClass({
}
// remote 模式使用 this.dataSource
let dataSource = this.getRemoteDataSource();
jQuery.ajax({
return jQuery.ajax({
url: dataSource.url,
data: dataSource.getParams.apply(this, this.prepareParamsArguments(state)) || {},
headers: dataSource.headers,
......@@ -450,3 +473,7 @@ export default React.createClass({
</div>;
}
});
AntTable.DataSource = DataSource;
export default AntTable;
......@@ -38,17 +38,18 @@ var dataSource = [{
**远程数据模式**是更常见的业务场景,是一次只从服务端读取一页的数据放在前端,执行筛选、排序、切换页码等操作时均向后台发送请求,后台返回当页的数据和相关分页信息。
通过指定表格的数据源 `dataSource` 为一个对象如下。
通过指定表格的数据源 `dataSource` 为一个 DataSource 的实例如下。
```jsx
var dataSource = {
var dataSource = new Table.DataSource({
url: '/api/users',
resolve: function(result) {
return result.data;
},
getPagination: function(result) {}
getParams: function(pagination, filters, sorter) {}
};
});
<Table dataSource={dataSource} />
```
......
......@@ -2,7 +2,7 @@
- order: 0
默认选中第项。
默认选中第项。
---
......@@ -15,10 +15,10 @@ function callback(key) {
}
React.render(
<Tabs defaultActiveKey="2" onChange={callback}>
<TabPane tab="tab 1" key="1">选项卡一</TabPane>
<TabPane tab="tab 2" key="2">选项卡二</TabPane>
<TabPane tab="tab 3" key="3">选项卡三</TabPane>
<Tabs defaultActiveKey="1" onChange={callback}>
<TabPane tab="选项卡一" key="1">选项卡一内容</TabPane>
<TabPane tab="选项卡二" key="2">选项卡二内容</TabPane>
<TabPane tab="选项卡三" key="3">选项卡三内容</TabPane>
</Tabs>
, document.getElementById('components-tabs-demo-basic'));
````
......@@ -14,9 +14,9 @@ function callback(key) {}
React.render(
<Tabs defaultActiveKey="1" onChange={callback}>
<TabPane tab="tab 1" key="1">选项卡一</TabPane>
<TabPane tab="tab 2" disabled={true} key="2">选项卡二</TabPane>
<TabPane tab="tab 3" key="3">选项卡三</TabPane>
<TabPane tab="选项卡一" key="1">选项卡一</TabPane>
<TabPane tab="选项卡二" disabled={true} key="2">选项卡二</TabPane>
<TabPane tab="选项卡三" key="3">选项卡三</TabPane>
</Tabs>
, document.getElementById('components-tabs-demo-disabled'));
````
......@@ -10,19 +10,17 @@
var Tabs = antd.Tabs;
var TabPane = Tabs.TabPane;
function callback(key) {}
var tabContent = [
<span><i className="anticon anticon-apple"></i>tab 1</span>,
<span><i className="anticon anticon-android"></i>tab 2</span>,
<span><i className="anticon anticon-lock"></i>tab 3</span>,
<span><i className="anticon anticon-apple"></i>选项卡一</span>,
<span><i className="anticon anticon-android"></i>选项卡二</span>,
<span><i className="anticon anticon-lock"></i>选项卡三</span>,
];
React.render(
<Tabs defaultActiveKey="2" onChange={callback}>
<Tabs defaultActiveKey="2">
<TabPane tab={tabContent[0]} key="1">选项卡一</TabPane>
<TabPane tab={tabContent[1]} key="2">选项卡</TabPane>
<TabPane tab={tabContent[2]} key="3">选项卡</TabPane>
<TabPane tab={tabContent[1]} key="2">选项卡</TabPane>
<TabPane tab={tabContent[2]} key="3">选项卡</TabPane>
</Tabs>
, document.getElementById('components-tabs-demo-icon'));
````
......@@ -12,9 +12,9 @@ var TabPane = Tabs.TabPane;
React.render(
<Tabs defaultActiveKey="2" size="mini">
<TabPane tab="tab 1" key="1">选项卡一</TabPane>
<TabPane tab="tab 2" key="2">选项卡二</TabPane>
<TabPane tab="tab 3" key="3">选项卡三</TabPane>
<TabPane tab="选项卡一" key="1">选项卡一内容</TabPane>
<TabPane tab="选项卡二" key="2">选项卡二内容</TabPane>
<TabPane tab="选项卡三" key="3">选项卡三内容</TabPane>
</Tabs>
, document.getElementById('components-tabs-demo-size'));
````
......
......@@ -14,15 +14,15 @@ function callback(key) {}
React.render(
<Tabs defaultActiveKey="1" onChange={callback}>
<TabPane tab="tab 1" key="1">选项卡一</TabPane>
<TabPane tab="tab 2" key="2">选项卡二</TabPane>
<TabPane tab="tab 3" key="3">选项卡三</TabPane>
<TabPane tab="tab 4" key="4">选项卡四</TabPane>
<TabPane tab="tab 5" key="5">选项卡五</TabPane>
<TabPane tab="tab 6" key="6">选项卡六</TabPane>
<TabPane tab="tab 7" key="7">选项卡七</TabPane>
<TabPane tab="tab 8" key="8">选项卡八</TabPane>
<TabPane tab="tab 9" key="9">选项卡九</TabPane>
<TabPane tab="选项一" key="1">选项卡一</TabPane>
<TabPane tab="选项二" key="2">选项卡二</TabPane>
<TabPane tab="选项三" key="3">选项卡三</TabPane>
<TabPane tab="选项四" key="4">选项卡四</TabPane>
<TabPane tab="选项五" key="5">选项卡五</TabPane>
<TabPane tab="选项六" key="6">选项卡六</TabPane>
<TabPane tab="选项七" key="7">选项卡七</TabPane>
<TabPane tab="选项八" key="8">选项卡八</TabPane>
<TabPane tab="选项九" key="9">选项卡九</TabPane>
</Tabs>
, document.getElementById('components-tabs-demo-slide'));
````
import React from 'react';
import Tree from 'rc-tree';
var TreeNode = Tree.TreeNode;
var antDTree = React.createClass({
var AntTree = React.createClass({
render() {
return <Tree {...this.props} >
{this.props.children}
</Tree>;
}
});
antDTree.TreeNode = TreeNode;
module.exports = antDTree;
AntTree.TreeNode = Tree.TreeNode;
export default AntTree;
# Tree
- category: Components
- chinese: 树形控件
- chinese: 树
---
树形控件。
## 何时使用
文件夹、组织架构、生物分类、国家地区等等,世间万物的大多数结构都是树形结构。使用`树控件`可以完整展现其中的层级关系,并具有展开收起选择等交互功能。
......@@ -5,10 +5,16 @@
---
上传控件,包括选择上传和拖拽上传两种形式。
文件选择上传和拖拽上传控件。
## 何时使用
上传是将信息从个人计算机(本地计算机)传递到中央计算机(远程计算机)系统上,让网络上的人都能看到.将制作好的网页、文字、图片、视频通过网页或者上传工具软件发布到互联网上的服务器系统上去,以便让其他人浏览、欣赏。这一过程称为上传。
- 当需要上传一个或一些文件时。
- 当需要展现上传的进度时。
- 当需要使用拖拽交互时。
## API
| 参数 | 说明 | 类型 | 默认值 |
......
......@@ -2,9 +2,9 @@
- order: 0
基本的表单校验子。
基本的表单校验子。
每个表单域要声明 `name` 属性作为校验的标识,可通过其 `isValidating` `errors` 属性判断是否处于校验中、是否校验不通过状态,具体可参见 **用户名** 校验。
每个表单域要声明 `name` 属性作为校验的标识,可通过其 `isValidating``errors` 属性判断是否处于校验中、是否校验不通过状态,具体可参见 **用户名** 校验。
表单提交的时候,通过 Validation 的 validate 方法判断是否所有表单域校验通过(isValid 会作为回调函数的参数传入)。
......@@ -50,11 +50,13 @@ var Form = React.createClass({
passwd: undefined,
rePasswd: undefined,
textarea: undefined
}
},
isEmailOver: false, // email 是否输入完毕
emailValidateMethod: 'onBlur' // 用于改变 email 的验证方法
};
},
validateStyle(item, hasFeedback=true) {
renderValidateStyle(item, hasFeedback=true) {
var formData = this.state.formData;
var status = this.state.status;
......@@ -68,6 +70,20 @@ var Form = React.createClass({
return classes;
},
handleEmailInputBlur() {
this.setState({
isEmailOver: true
});
},
handleEmailInputFocus() {
if (this.state.isEmailOver) {
this.setState({
emailValidateMethod: 'onChange'
});
}
},
handleReset(e) {
this.refs.validation.reset();
this.setState(this.getInitialState());
......@@ -76,6 +92,9 @@ var Form = React.createClass({
handleSubmit(e) {
e.preventDefault();
this.setState({
isEmailOver: true
});
var validation = this.refs.validation;
validation.validate((valid) => {
if (!valid) {
......@@ -93,24 +112,21 @@ var Form = React.createClass({
callback();
} else {
setTimeout(function () {
if (value === 'yiminghe') {
if (value === 'Jasonwood') {
callback([new Error('抱歉,该用户名已被占用。')]);
} else {
callback();
}
}, 1000);
}, 800);
}
},
checkPass(rule, value, callback) {
if (this.state.formData.passwd) {
this.refs.validation.forceValidate(['rePasswd']);
}
callback();
},
checkPass2(rule, value, callback) {
if (value !== this.state.formData.passwd) {
if (value && value !== this.state.formData.passwd) {
callback('两次输入密码不一致!');
} else {
callback();
......@@ -123,13 +139,13 @@ var Form = React.createClass({
return (
<form onSubmit={this.handleSubmit} className="ant-form-horizontal">
<Validation ref='validation' onValidate={this.handleValidate}>
<Validation ref="validation" onValidate={this.handleValidate}>
<div className="ant-form-item">
<label className="col-6" for="name" required>用户名:</label>
<label className="col-7" for="name" required>用户名:</label>
<div className="col-12">
<div className= {this.validateStyle("name")}>
<div className={this.renderValidateStyle('name')}>
<Validator rules={[{required: true, min: 5, message: '用户名至少为 5 个字符'}, {validator: this.userExists}]}>
<input name='name' className="ant-input" value={formData.name} />
<input name="name" className="ant-input" value={formData.name} placeholder="实时校验,输入 JasonWood 看看" />
</Validator>
{status.name.isValidating ? <div className="ant-form-explain">正在校验中...</div> : null}
{status.name.errors ? <div className="ant-form-explain">{status.name.errors.join(',')}</div> : null}
......@@ -138,11 +154,11 @@ var Form = React.createClass({
</div>
<div className="ant-form-item">
<label className="col-6" for="email" required>邮箱:</label>
<label className="col-7" for="email" required>邮箱:</label>
<div className="col-12">
<div className= {this.validateStyle("email")}>
<Validator rules={{type: 'email', message: '请填写正确的邮箱地址'}} trigger="onBlur">
<input name='email' className="ant-input" value={formData.email} onChange={this.setField.bind(this, 'email')}/>
<div className={this.renderValidateStyle('email', this.state.isEmailOver)}>
<Validator rules={[{required: true, type:'email', message: '请输入正确的邮箱地址'}]} trigger={this.state.emailValidateMethod}>
<input name="email" className="ant-input" value={formData.email} placeholder="onBlur 与 onChange 相结合" onBlur={this.handleEmailInputBlur} onFocus={this.handleEmailInputFocus} />
</Validator>
{status.email.errors ? <div className="ant-form-explain">{status.email.errors.join(',')}</div> : null}
</div>
......@@ -150,11 +166,11 @@ var Form = React.createClass({
</div>
<div className="ant-form-item">
<label className="col-6" required>国籍:</label>
<label className="col-7" required>国籍:</label>
<div className="col-12">
<div className= {this.validateStyle("select", false)}>
<div className={this.renderValidateStyle('select', false)}>
<Validator rules={[{required: true, message: '请选择您的国籍'}]}>
<Select style={{width:200}} name="select" value={formData.select}>
<Select style={{width:100 + "%"}} name="select" value={formData.select}>
<Option value="china">中国</Option>
<Option value="use">美国</Option>
<Option value="japan">日本</Option>
......@@ -168,9 +184,9 @@ var Form = React.createClass({
</div>
<div className="ant-form-item ant-form-item-compact">
<label className="col-6" required>性别:</label>
<label className="col-7" required>性别:</label>
<div className="col-12">
<div className= {this.validateStyle("radio", false)}>
<div className={this.renderValidateStyle('radio', false)}>
<Validator rules={[{required: true, message: '请选择您的性别'}]}>
<RadioGroup name="radio" value={formData.radio}>
<Radio value="male"></Radio>
......@@ -183,11 +199,11 @@ var Form = React.createClass({
</div>
<div className="ant-form-item">
<label className="col-6" required>密码:</label>
<label className="col-7" required>密码:</label>
<div className="col-12">
<div className= {this.validateStyle("passwd", false)}>
<Validator trigger="onBlur" rules={[{required: true, whitespace: true, message: '请填写密码'}, {validator: this.checkPass}]}>
<input name='passwd' className="ant-input" type="password" value={formData.passwd}/>
<div className={this.renderValidateStyle('passwd')}>
<Validator rules={[{required: true, whitespace: true, message: '请填写密码'}, {validator: this.checkPass}]}>
<input name="passwd" className="ant-input" type="password" value={formData.passwd}/>
</Validator>
{status.passwd.errors ? <div className="ant-form-explain">{status.passwd.errors.join(',')}</div> : null}
</div>
......@@ -195,28 +211,28 @@ var Form = React.createClass({
</div>
<div className="ant-form-item">
<label className="col-6" required>确认密码:</label>
<label className="col-7" required>确认密码:</label>
<div className="col-12">
<div className= {this.validateStyle("rePasswd", false)}>
<Validator trigger="onBlur" rules={[{
<div className={this.renderValidateStyle('rePasswd')}>
<Validator rules={[{
required: true,
whitespace: true,
message: '请再次输入密码'
}, {validator: this.checkPass2}]}>
<input name='rePasswd' className="ant-input" type="password" value={formData.rePasswd}/>
<input name="rePasswd" className="ant-input" type="password" value={formData.rePasswd} placeholder="两次输入密码保持一致"/>
</Validator>
{status.rePasswd.errors ? <div className="ant-form-explain"> {status.rePasswd.errors.join(', ')}</div> : null}
</div>
</div>
</div>
<div className="ant-form-item">
<label className="col-6" required>备注:</label>
<label className="col-7" required>备注:</label>
<div className="col-12">
<div className= {this.validateStyle("textarea", false)}>
<div className={this.renderValidateStyle('textarea', false)}>
<Validator rules={[{required: true, message: '真的不打算写点什么吗?'}]}>
<textarea className="ant-input" name="textarea" placeholder="写点什么吧"></textarea>
<textarea className="ant-input" name="textarea" value={formData.textarea} placeholder="写点什么吧">
</textarea>
</Validator>
{status.textarea.errors ? <div className="ant-form-explain">{status.textarea.errors.join(',')}</div> : null}
</div>
......@@ -224,10 +240,10 @@ var Form = React.createClass({
</div>
<div className="ant-form-item">
<div className="col-offset-6 col-12">
<div className="col-offset-7 col-12">
<button type="submit" className="ant-btn ant-btn-primary">确 定</button>
&nbsp;&nbsp;&nbsp;
<a href='#' className="ant-btn" onClick={this.handleReset}>重 置</a>
<a href="#" className="ant-btn" onClick={this.handleReset}>重 置</a>
</div>
</div>
</Validation>
......
......@@ -4,6 +4,8 @@
密码校验实例。
这里使用了 validation 的 `forceValidate(fields, callback)` 方法,在对第一次输入的密码进行校验时会触发二次密码的校验。
---
````jsx
......@@ -145,14 +147,14 @@ var Form = React.createClass({
return (
<form onSubmit={this.handleSubmit} className="ant-form-horizontal">
<Validation ref='validation' onValidate={this.handleValidate}>
<Validation ref="validation" onValidate={this.handleValidate}>
<div className="ant-form-item">
<label className="col-6" required>密码:</label>
<div className="col-10">
<div className= {this.renderValidateStyle("pass", false)}>
<div className={this.renderValidateStyle('pass', false)}>
<Validator rules={[{required: true, whitespace: true, message: '请填写密码'}, {validator: this.checkPass}]} trigger="onChange">
<input name='pass' className="ant-input" type="password" value={formData.pass}/>
<input name="pass" className="ant-input" type="password" value={formData.pass}/>
</Validator>
{status.pass.errors ? <div className="ant-form-explain">{status.pass.errors.join(',')}</div> : null}
</div>
......@@ -165,13 +167,13 @@ var Form = React.createClass({
<div className="ant-form-item">
<label className="col-6" required>确认密码:</label>
<div className="col-10">
<div className= {this.renderValidateStyle("rePass", false)}>
<div className={this.renderValidateStyle('rePass', false)}>
<Validator rules={[{
required: true,
whitespace: true,
message: '请再次输入密码'
}, {validator: this.checkPass2}]}>
<input name='rePass' className="ant-input" type="password" value={formData.rePass}/>
<input name="rePass" className="ant-input" type="password" value={formData.rePass}/>
</Validator>
{status.rePass.errors ? <div className="ant-form-explain"> {status.rePass.errors.join(', ')}</div> : null}
</div>
......@@ -185,7 +187,7 @@ var Form = React.createClass({
<div className="col-offset-6 col-12">
<button type="submit" className="ant-btn ant-btn-primary">确 定</button>
&nbsp;&nbsp;&nbsp;
<a href='#' className="ant-btn" onClick={this.handleReset}>重 置</a>
<a href="#" className="ant-btn" onClick={this.handleReset}>重 置</a>
</div>
</div>
</Validation>
......
......@@ -10,7 +10,7 @@
## 何时使用
同表单结合使用,对表单域进行校验。
同表单结合使用,对表单域进行校验,提供前台校验和后台实时反馈校验,并对表单错误提供有效信息提示
## API
......@@ -53,7 +53,7 @@
- `type` : 声明校验的值类型(如 string email),这样就会使用默认提供的规则进行校验,更多详见 [type](https://github.com/yiminghe/async-validator#user-content-type)
- `required`: 是否必填;
- `pattern`: 声明校验正则表达式;
- `min` / `max`: 最小值、最大值声明;
- `min` / `max`: 最小值、最大值声明(对于 string 和 array 来说,针对的是其长度 length。)
- `len`: 字符长度;
- `enum`: 枚举值,对应 type 值为 `enum`,例如 `role: {type: "enum", enum: ['A', 'B', 'C']}`
- `whitespace`: 是否允许空格, `true` 为允许;
......
......@@ -7,7 +7,6 @@ var antd = {
Carousel: require('./components/carousel'),
Tabs: require('./components/tabs'),
Modal: require('./components/modal'),
Menu: require('rc-menu'),
Dropdown: require('./components/dropdown'),
Progress: require('./components/progress'),
Popover: require('./components/popover'),
......@@ -28,10 +27,12 @@ var antd = {
EnterAnimation: require('./components/enter-animation'),
Radio: require('./components/radio'),
RadioGroup: require('./components/radio/group'),
Notification: require('./components/notification'),
Alert: require('./components/alert'),
Validation: require('./components/validation'),
Tree: require('./components/Tree'),
Upload: require('./components/upload')
Upload: require('./components/upload'),
Menu: require('./components/Menu')
};
module.exports = antd;
......
......@@ -8,7 +8,7 @@
<ul class="{%- if category === post.meta.category %}aside-list-show{%- endif %}">
{%- for item in items %}
<li class="{%- if item.title === post.title %}current{%- endif %}">
<a href="{{permalink_url(item)}}">
<a href="{{permalink_url(item)}}" class="{%- if item.meta.disabled %}nav-link-disabled{%- endif %}">
{{item.title}}
<span class="chinese">{{item.meta.chinese}}</span>
</a>
......
<div class="code-box" id="code-box-{{post.meta.id}}">
<div class="code-box" id="{{post.meta.id|removeCodeBoxIdPrefix}}">
<div class="code-box-demo">
<div id="{{post.meta.id}}"></div>
{{ post.html }}
</div>
<div class="code-box-meta markdown">
<div class="code-box-title">
<a href="#code-box-{{post.meta.id}}">{{ post.title }}</a>
<a href="#{{post.meta.id|removeCodeBoxIdPrefix}}">{{ post.title }}</a>
</div>
{{ post.meta.description }}
<span class="collapse anticon anticon-circle-o-right"></span>
<span class="collapse anticon anticon-circle-o-right" unselectable="none" style="-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;"></span>
</div>
</div>
......@@ -105,6 +105,9 @@ module.exports = function(nico) {
},
rootDirectoryIs: function(directory, rootDirectory) {
return directory.split('/')[0] === rootDirectory;
},
removeCodeBoxIdPrefix: function(id) {
return id.split('-').slice(2).join('-');
}
};
......
# 色系和交互
- category: 色彩
- order: 0
---
# 色彩
- category: 色彩
- order: 0
- disabled: true
---
## 有意义的颜色
色彩在界面设计中的使用应同时具备品牌识别性以及界面设计功能性。众所周知色彩是相当感性的东西,设计中对色彩的运用首要应考虑到品牌层面的表达,另外很重要的一点是色彩的运用应达到信息传递,动作指引,交互反馈,或是强化和凸现某一个元素的目的。任何颜色的选取和使用应该是有意义的。
## 色板
Ant Design 的色板由 16 种基本色彩以及通过黑白叠加的方式扩展的色板组成。
### 主色
<script src="https://t.alipayobjects.com/images/T12b4hXcdhXXXXXXXX.js"></script>
<span class="donut" data-peity='{ "fill": ["#ED1C1C", "#E75B10", "#FF6600", "#FDBF06", "#F1E60E", "#96DA19", "#31C009", "#06D9CF", "#0EC4DF", "#2DB7F5", "#1062CE", "#3344D8", "#582DAA", "#BC1ACD", "#FB1479", "#C21D63"], "innerRadius": 70, "radius": 110 }'>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</span>
<script>$('.donut').peity('donut');</script>
### 扩展色板
Ant Design 提供了16 种主色。每一种颜色都按照添加白色或者黑色 5% 的规则,可以延展出 40 种颜色,由于 100% 的白色覆盖,90-100% 之间的黑色覆盖在视觉上看不出太多的差别,因此每种颜色省略前后4种颜色保留 36 色的衍生色,基本已经可以满足日常系统设计的需求。
<div id="extend-palettes"></div>
### 灰色
灰色是中性化的颜色,通常传递出来的感觉是沉稳,在配色心理学中描述“专业化、系统化”的词条中灰色的使用占了较高的比例。同时灰色也是一种比较百搭的颜色,和很多颜色都可以很好的进行搭配使用。实际设计的过程中,常常用于字体颜色、边界色、阴影色以及界面中大面积背景的底色搭配。
<div id="grey-palette"></div>
## 交互
设计元素本身由于交互行为会引发一系列细微的视觉变化,而元素本身的颜色变化有时也能很好的实现这一目的。在进行这类设计的同时,建议采取在颜色上添加黑色或者白色并按照 nX5% 的规律递增的方式来实现。以下图为例,当鼠标移动到某个特定元素,就视为浮起,对应颜色就相应增加白色叠加,相反点击的行为可以理解为按下去,在颜色上就相应的增加黑色的叠加。
<img src="https://t.alipayobjects.com/images/T1fZJhXahgXXXXXXXX.png" width="100%">
<img src="https://t.alipayobjects.com/images/T1ZHxhXdNmXXXXXXXX.png" width="100%">
<style>
.color-palette {
margin: 32px 0;
overflow: hidden;
width: 800px;
}
.color-palette div {
float: left;
width: 33px;
height: 33px;
border-radius: 4px;
margin-right: 3px;
margin-bottom: 3px;
}
.color-palette .main-color {
width: 70px;
height: 70px;
line-height: 70px;
text-align: center;
color: #fff;
font-size: 12px;
}
</style>
<script src="https://t.alipayobjects.com/images/T1DrxhXe0mXXXXXXXX.js"></script>
`````jsx
let Palette = React.createClass({
render() {
let color = this.props.color;
let values = new Values(color).all(5);
let extendTintColors = values.map((value, i) => {
if (i >= (values.length-1)/2) {
return null;
}
return <div style={{backgroundColor: '#' + value.hex}}></div>;
}).reverse();
let extendShadeColors = values.map((value, i) => {
if (i <= (values.length-1)/2 || i >= values.length-3) {
return null;
}
return <div style={{backgroundColor: '#' + value.hex}}></div>;
});
return <div className="color-palette">
<div className="main-color" style={{backgroundColor: color}}>{color}</div>
{extendTintColors}
{extendShadeColors}
</div>;
}
});
let ExtendPalettes = React.createClass({
render() {
var colors = ["#ED1C1C", "#E75B10", "#FF6600", "#FDBF06", "#F1E60E", "#96DA19", "#31C009", "#06D9CF", "#0EC4DF", "#2DB7F5", "#1062CE", "#3344D8", "#582DAA", "#BC1ACD", "#FB1479", "#C21D63"];
return <div>
{colors.map((color) => {
return <Palette color={color} />;
})}
</div>;
}
});
let GreyPalette = React.createClass({
render() {
var colors = ["#ED1C1C", "#E75B10", "#FF6600", "#FDBF06", "#F1E60E", "#96DA19", "#31C009", "#06D9CF", "#0EC4DF", "#2DB7F5", "#1062CE", "#3344D8", "#582DAA", "#BC1ACD", "#FB1479", "#C21D63"];
return <Palette color="#808080" />;
}
});
React.render(<GreyPalette />, document.getElementById('grey-palette'));
React.render(<ExtendPalettes />, document.getElementById('extend-palettes'));
`````
......@@ -5,3 +5,199 @@
---
跨平台的字体设定,力求在各个操作系统下都有最佳展示效果。
## 字体家族
- 中文字体族:
<img src="https://t.alipayobjects.com/images/T1NrdhXghnXXXXXXXX.png" width="100%">
- 英文文字体族:
<img src="https://t.alipayobjects.com/images/T1bcXhXfNeXXXXXXXX.png" width="100%">
字体家族 css 代码如下:
```css
font-family: "Helvetica Neue",Helvetica,"Hiragino Sans GB","STHeitiSC-Light","Microsoft YaHei","微软雅黑",Arial,sans-serif;
```
代码字体:
```css
font-family: "PT Mono",Menlo,Consolas,"Courier New",monospace;
```
## 字体使用规范
<div class="row">
<div class="col col-12">
<div class="font-type head-1">
<div class="font-title">主标题</div>
<h1 class="font-text">
<span>我是标题</span>
<span>加粗</span>
<span>#666</span>
<span>16px</span>
</h1>
</div>
<div class="font-type head-2">
<div class="font-title">次级标题</div>
<h2 class="font-text">
<span>我是标题</span>
<span>加粗</span>
<span>#666</span>
<span>14px</span>
</h2>
</div>
<div class="font-type head-3">
<div class="font-title">小标题</div>
<h3 class="font-text">
<span>我是标题</span>
<span>加粗</span>
<span>#666</span>
<span>12px</span>
</h3>
</div>
<div class="font-type text">
<div class="font-title">正文</div>
<p class="font-text">
<span>我是正文</span>
<span>#666</span>
<span>12px</span>
</p>
</div>
<div class="font-type help-text">
<div class="font-title">辅助文字</div>
<p class="font-text">
<span>我是辅助文字</span>
<span>#999</span>
<span>12px</span>
</p>
</div>
<div class="font-type disabled-text">
<div class="font-title">失效文字</div>
<p class="font-text">
<span>我是失效文字</span>
<span>#ccc</span>
<span>12px</span>
</p>
</div>
<div class="font-type link-text">
<div class="font-title">链接文字</div>
<p class="font-text">
<a href="#">
<span>我是链接文字</span>
<span>#2db7f5</span>
<span>12px</span>
</a>
</p>
</div>
</div>
<div class="col col-12">
<div class="font-type head-1">
<div class="font-title">Main Head</div>
<h1 class="font-text">
<span>I am example text</span>
<span>bold</span>
<span>#666</span>
<span>16px</span>
</h1>
</div>
<div class="font-type head-2">
<div class="font-title">Sub Head</div>
<h2 class="font-text">
<span>I am example text</span>
<span>bold</span>
<span>#666</span>
<span>14px</span>
</h2>
</div>
<div class="font-type head-3">
<div class="font-title">Small Head</div>
<h3 class="font-text">
<span>I am example text</span>
<span>bold</span>
<span>#666</span>
<span>12px</span>
</h3>
</div>
<div class="font-type text">
<div class="font-title">Text</div>
<p class="font-text">
<span>I am example text</span>
<span>#666</span>
<span>12px</span>
</p>
</div>
<div class="font-type help-text">
<div class="font-title">Help Text</div>
<p class="font-text">
<span>I am example text</span>
<span>#999</span>
<span>12px</span>
</p>
</div>
<div class="font-type disabled-text">
<div class="font-title">Disabled Text</div>
<p class="font-text">
<span>I am example text</span>
<span>#ccc</span>
<span>12px</span>
</p>
</div>
<div class="font-type link-text">
<div class="font-title">Link Text</div>
<p class="font-text">
<a href="#">
<span>I am example text</span>
<span>#2db7f5</span>
<span>12px</span>
</a>
</p>
</div>
</div>
</div>
<style>
.font-type {
margin: 20px 0;
overflow: hidden;
font-size: 12px;
}
.font-type h1,
.font-type h2,
.font-type h3,
.font-type p {
margin: 0;
color: #666;
}
.font-type > * {
display: inline-block;
}
.font-title {
font-size: 14px;
width: 100px;
text-align: right;
margin-right: 30px;
}
.font-text {
width: 300px;
}
.font-text span {
margin-right: 8px;
}
.head-1 h1 {
font-size: 16px;
}
.head-2 h2 {
font-size: 14px;
}
.head-3 h3 {
font-size: 12px;
}
.disabled-text .font-text {
color: #ccc;
}
</style>
......@@ -4,3 +4,114 @@
- order: 1
---
良好的排版规范能大大提升用户的视觉体验。
## 行高和段落
考虑到阅读的舒适度和节奏感,句子和段落间需要合适的间距。行距決定了段落中各行文字的垂直距离,通过字体本身行高来控制,我们行高默认为字号的1.5倍。段落间距決定了段落上下的间距,一般采用直接空一行来解决。
<div class="row">
<div class="col col-12 paragraph-12px">
<h3>12px 段落</h3>
<p>汉学家称这个空白字为「盘古之白」,因为它劈开了全角字和半角字之间的混沌。</p>
<p>另有有研究显示,打字的时候不喜欢在中文和英文之间加空格的人,感情路都走得很辛苦,有七成的比例会在34 岁的时候跟自己不爱的人结婚,而其余三成的人最后只能把遗产留给自己的猫。毕竟爱情跟书写都需要适时地留白。</p>
</div>
<div class="col col-12 paragraph-14px">
<h3>14px 段落</h3>
<p>汉学家称这个空白字为「盘古之白」,因为它劈开了全角字和半角字之间的混沌。</p>
<p>另有有研究显示,打字的时候不喜欢在中文和英文之间加空格的人,感情路都走得很辛苦,有七成的比例会在34 岁的时候跟自己不爱的人结婚,而其余三成的人最后只能把遗产留给自己的猫。毕竟爱情跟书写都需要适时地留白。</p>
</div>
</div>
<style>
.paragraph-14px, .paragraph-12px {
padding: 15px;
line-height: 1.5;
}
.paragraph-14px p,
.paragraph-12px p {
margin: 1em 0;
}
.paragraph-14px {
font-size: 14px;
}
.paragraph-12px {
font-size: 12px;
}
</style>
## 标点和空格
<img align="right" src="https://t.alipayobjects.com/images/T1KrXhXlxnXXXXXXXX.png" width="200">
1. 使用全角中文标点。
2. 遇到完整的英文整句、特殊名词,其内容使用半角标点。
3. 数字使用半角字符。
4. 不重复使用标点符号。
### 空格规范
1. 中文和英文间需要空格。
2. 数字与单位之间需要增加空格。
例外:度、百分比与数字之间不需要增加空格。
3. 中文链接之间增加空格。
## 文字背景
当文字和背景明暗对比小于一定比值时,人眼识别文字信息将会变得吃力,尤其在明亮的室外或晃动的情况下。
方法:若彩色背景,可先将色彩去色转为黑白,分别吸取并查看背景和文字的 `HSV` 色值。
两者的 V 值的差额便是明暗对比差。这个明暗对比差建议不小于 40。
<img src="https://t.alipayobjects.com/images/T1UYphXe8lXXXXXXXX.png" width="100%">
## 对齐
### 中文/英文居左对齐
中文和英文均采用左对齐的方式,是因为文字的阅读顺序一般是从左到右的。
<img src="https://t.alipayobjects.com/images/T1nHhhXl4mXXXXXXXX.png" width="100%">
### 数字/小数点对齐
<img align="right" src="https://t.alipayobjects.com/images/T1YbthXhRkXXXXXXXX.png" width="400">
<p style="height:220px;width:380px;">数字通常采用右对齐或小数点对齐,这样便于对个十百千位上的数字进行对比。</p>
### 冒号对齐
<img align="right" src="https://t.alipayobjects.com/images/T1hcJhXnlXXXXXXXXX.png" width="400">
<p style="height:220px;width:380px;">以冒号对齐的方式在form表单中尤其常见。主要是为了区分标题和内容区块,除了美观简洁外,让用户能迅速看清标题减少出错概率。</p>
## 文案长度
语言通常是越简单越明确,而提示性文字更需要简明扼要,让用户一目了然,减少操作失误。提示性句子长度是业务而定,建议一般不超过 16–18 个字。
<img align="right" style="margin:30px 100px" src="https://t.alipayobjects.com/images/T17cthXgpbXXXXXXXX.png" width="300">
保持简明准确的方法:
- 每个句子只包含一个观点;
- 使用明确的词;
- 尽可能使用主动语态少用被动语态;
## 层级引导
我们通常使用对比的手法来区分出信息的层次感,信息主次分明能准确地将信息清晰地传达给用户,让用户第一眼获取所需资讯,提升阅读体验。
<img src="https://t.alipayobjects.com/images/T1GYBhXghjXXXXXXXX.png" width="600">
### Squint test
我们可以采用 [模糊测试](https://chrome.google.com/webstore/detail/the-squint-test/gppnipfbappicilfniaimcnagbpfflpg) 的方法,即眯起眼睛从整体来检视结构上的合理与否。
<img src="https://t.alipayobjects.com/images/T1bY4hXkpfXXXXXXXX.png" width="600">
......@@ -225,7 +225,7 @@ a.logo {
display: block;
}
.nav ul li a.disabled {
a.nav-link-disabled {
cursor: not-allowed;
color: #ddd !important;
pointer-events: none;
......@@ -558,6 +558,12 @@ footer ul li > a {
padding-left: 8px;
}
.markdown > ol li {
list-style: decimal;
margin-left: 20px;
padding-left: 8px;
}
.markdown code {
margin: 0 3px;
}
......
.ant-affix {
position: fixed;
}
......@@ -4,7 +4,6 @@
line-height: 34px;
text-align: center;
user-select: none;
-webkit-user-select: none;
border-bottom: 1px solid #e9e9e9;
a:hover {
......@@ -209,6 +208,7 @@
&-footer-btn {
text-align: center;
display: block;
line-height: 42px;
}
&-footer > div {
......
......@@ -11,6 +11,10 @@
position: relative;
display: inline-block;
&-input {
outline: none;
}
&-icon {
position: absolute;
-webkit-user-select: none;
......
......@@ -6,14 +6,12 @@
label {
position: relative;
&[required]:before {
position: absolute;
display: inline-block;
left: ~"-5px \9"; // ie8-9
margin-right: 4px;
content: "*";
color: @label-required-color;
font-family: SimSun;
font-size: @font-size-base;
.translate3d(-10px; 0; 0);
color: @label-required-color;
}
> .@{iconfont-css-prefix} {
......@@ -127,9 +125,7 @@ form {
.@{css-prefix}input,
.@{css-prefix}input-group .@{css-prefix}input,
.@{css-prefix}input-group .@{css-prefix}input-group-addon {
height: @input-height-lg;
font-size: @font-size-base;
padding: 6px 7px;
.input-lg();
}
// Input combined with select
......@@ -266,9 +262,8 @@ form {
bottom: 0;
right: 0;
font-family: "anticon" !important;
width: 32px;
height: 32px;
line-height: 32px;
.square(@input-height-lg);
line-height: @input-height-lg;
text-align: center;
font-size: 14px;
}
......
......@@ -23,9 +23,12 @@
@import "divider";
@import "slider";
@import "radio";
@import "notification";
@import "tag";
@import "alert";
@import "tree";
@import "carousel/slick";
@import "carousel/slick-theme";
@import "upload";
@import "menu";
@import "affix";
@import "../mixins/index";
@menuPrefixCls: ~"@{css-prefix}menu";
.@{menuPrefixCls} {
outline: none;
margin-bottom: 0;
padding-left: 0; // Override default ul/ol
list-style: none;
z-index: 99999;
border: 1px solid #d9d9d9;
box-shadow: 0 0 4px #d9d9d9;
border-radius: 3px;
color: #666;
&-item-group-list {
margin: 0;
padding: 0;
}
&-item-group-title {
color: #999;
line-height: 1.5;
padding: 8px 10px;
border-bottom: 1px solid #dedede;
}
&-item-active, &-submenu-active {
background-color: #eaf8fe;
}
&-item-selected {
background-color: #eaf8fe;
}
& > li&-submenu {
padding: 0;
}
&-submenu-lt-lb > .@{menuPrefixCls} {
top: 100%;
left: 0;
margin-top: 4px;
}
&-submenu-lt-rt > .@{menuPrefixCls} {
top: 0;
left: 100%;
margin-left: 4px;
}
&-item,&-submenu-title {
margin: 0;
position: relative;
display: block;
padding: 7px 7px 7px 16px;
white-space: nowrap;
// Disabled state sets text to gray and nukes hover/tab effects
&.@{menuPrefixCls}-item-disabled, &.@{menuPrefixCls}-submenu-disabled {
color: #777 !important;
}
}
& > &-item-divider {
height: 1px;
margin: 1px 0;
overflow: hidden;
padding: 0;
line-height: 0;
background-color: #e5e5e5;
}
&-submenu {
position: relative;
> .@{menuPrefixCls} {
display: none;
position: absolute;
min-width: 160px;
background-color: #fff;
}
&-open {
> .@{menuPrefixCls} {
display: block;
}
}
}
.@{menuPrefixCls}-submenu-title, .@{menuPrefixCls}-item {
.anticon {
width: 14px;
height: 14px;
margin-right: 8px;
top: -1px;
}
}
&-horizontal {
background-color: #F3F5F7;
border: none;
border-bottom: 1px solid transparent;
border-bottom: 1px solid #d9d9d9;
box-shadow: none;
& > .@{menuPrefixCls}-item , & > .@{menuPrefixCls}-submenu > .@{menuPrefixCls}-submenu-title {
padding: 15px 20px;
}
& > .@{menuPrefixCls}-submenu, & > .@{menuPrefixCls}-item {
float: left;
border-bottom: 2px solid transparent;
&-active {
border-bottom: 2px solid #2db7f5;
background-color: #F3F5F7;
color: #2baee9;
}
}
&:after {
content: "\20";
display: block;
height: 0;
clear: both;
}
}
&-vertical {
padding: 12px 0;
& > .@{menuPrefixCls}-item , & > .@{menuPrefixCls}-submenu > .@{menuPrefixCls}-submenu-title {
padding: 12px 8px 12px 24px;
}
}
}
@import "../mixins/index";
@notificationPrefixCls: ~"@{css-prefix}notification";
@noticeWidth: 335px;
@noticePadding: 16px;
@noticeMarginBottom: 10px;
.@{notificationPrefixCls} {
position: fixed;
z-index: 1000;
width: @noticeWidth;
margin-right: 24px;
&-notice {
padding: @noticePadding;
border-radius: @border-radius-base;
box-shadow: 0 0 4px @legend-border-color;
background: @body-background;
line-height: 1.5;
position: relative;
margin-bottom: @noticeMarginBottom;
overflow: hidden;
&-content {
&-message {
font-size: 14px;
color: @text-color;
margin-bottom: 4px;
}
&-description {
font-size: @font-size-base;
color: @legend-color;
}
}
&-content-icon {
position: relative;
&-message {
font-size: 14px;
color: @text-color;
margin-left: 51px;
margin-bottom: 4px;
}
&-description {
margin-left: 51px;
font-size: @font-size-base;
color: @legend-color;
}
&-icon {
position: absolute;
left: 16px;
top: 50%;
margin-top: -26px;
font-size: 35px;
&-success{
color: @success-color;
}
&-info{
color: @primary-color;
}
&-warn{
color: @warning-color;
}
&-error{
color: @error-color;
}
}
}
&-close-x:after {
content: "\e61e";
font-family: "anticon";
cursor: pointer;
.iconfont-size-under-12px(10px);
}
&-close {
position: absolute;
right: 16px;
top: 10px;
color: #999;
outline: none;
}
&-content-btn {
float: right;
margin-top: 16px;
}
}
&-fade-enter {
left: @noticeWidth;
opacity: 0;
transition: all .3s ease-in-out;
}
&-fade-enter&-fade-enter-active {
opacity: 1;
left: 0;
}
&-fade-leave {
opacity: 1;
margin-bottom: @noticeMarginBottom;
padding-top: @noticePadding;
padding-bottom: @noticePadding;
max-height: 150px;
transition: all .3s ease-in-out;
}
&-fade-leave&-fade-leave-active {
opacity: 0;
max-height: 0;
margin-bottom: 0;
padding-top: 0;
padding-bottom: 0;
}
}
......@@ -133,7 +133,7 @@
display: none;
}
&-placement-top {
&-placement-points-bc-tc {
padding: @slider-tooltip-arrow-width 0 @slider-tooltip-distance 0;
}
......@@ -158,7 +158,7 @@
border-style: solid;
}
&-placement-top &-arrow {
&-placement-points-bc-tc &-arrow {
bottom: @slider-tooltip-distance - @slider-tooltip-arrow-width;
left: 50%;
margin-left: -@slider-tooltip-arrow-width;
......
......@@ -34,15 +34,18 @@
width: 100%;
position: relative;
white-space: nowrap;
padding-right: 32px;
border-bottom: 1px solid #f3f3f3;
border-bottom: 1px solid #e9e9e9;
margin-bottom: 15px;
.clearfix;
}
&-nav-container-scrolling {
padding-left: 32px;
padding-right: 32px;
}
&-tab-prev, &-tab-next {
user-select: none;
-webkit-user-select: none;
z-index: 2;
margin-right: -2px;
margin-top: 1px;
......@@ -79,6 +82,12 @@
}
}
&-tab-btn-disabled {
cursor: default;
color: #ccc;
pointer-events: none;
}
&-tab-next {
right: 2px;
......@@ -89,7 +98,6 @@
&-tab-prev {
left: 0;
background: #fff;
transform: rotate(180deg);
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
&-icon:before {
......
......@@ -41,6 +41,11 @@ ol {
list-style: none;
}
// Remove the clear button of a text input control in IE10+
input::-ms-clear, input::-ms-reveal {
display: none;
}
// Links
// -- TODO --
a {
......@@ -93,6 +98,3 @@ a {
.invisible {
visibility: hidden;
}
.affix {
position: fixed;
}
// size mixins for input
.input-lg() {
padding: @input-padding-lg;
padding: @input-padding-vertical-lg @input-padding-horizontal;
height: @input-height-lg;
font-size: @input-font-size-lg;
}
.input-sm() {
padding: @input-padding-vertical-sm @input-padding-horizontal;
height: @input-height-sm;
font-size: @input-font-size-sm;
}
// input status
......@@ -42,7 +40,7 @@
width: 100%;
height: @input-height-base;
cursor: text;
font-size: @input-font-size;
font-size: @font-size-base;
line-height: @line-height-base;
color: @input-color;
background-color: @input-bg;
......
......@@ -10,8 +10,8 @@
// ------ Base & Require ------
@body-background : #fff;
@font-family : "Helvetica Neue",Helvetica,"Hiragino Sans GB","Microsoft YaHei","微软雅黑",SimSun,sans-serif;
@code-family : "PT Mono", Menlo, "Courier New", monospace;
@font-family : "Helvetica Neue",Helvetica,"Hiragino Sans GB","STHeitiSC-Light","Microsoft YaHei","微软雅黑",Arial,sans-serif;
@code-family : "PT Mono",Menlo,Consolas,"Courier New",monospace;
@text-color : #666;
@font-size-base : 12px;
@line-height-base : 1.5;
......@@ -121,17 +121,13 @@
@input-padding-horizontal : 7px;
@input-padding-vertical-base : 4px;
@input-padding-vertical-sm : 1px;
@input-padding-lg : 4px 7px 5px;
@input-padding-vertical-lg : 6px;
@input-placeholder-color : #ccc;
@input-color : #666;
@input-border-color : #d9d9d9;
@input-bg : #fff;
@input-font-size-lg : 14px;
@input-font-size : @font-size-base;
@input-font-size-sm : @font-size-base;
@input-hover-border-color : @primary-color;
@input-focus-border-color : @primary-color;
@input-disabled-bg : #f3f5f7;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册