add vc-steps demo

pull/165/head
wangxueliang 2018-03-09 18:52:31 +08:00
parent 42e60bb3d8
commit cb0740b60c
25 changed files with 795 additions and 10 deletions

View File

@ -108,3 +108,7 @@ const api = {
modalConfirm: confirm, modalConfirm: confirm,
} }
export { api } export { api }
import Steps from './steps'
const { Step } = Steps
export { Steps, Step }

View File

@ -39,6 +39,7 @@ export default {
}, },
model: { model: {
prop: 'current', prop: 'current',
event: 'change',
}, },
methods: { methods: {
renderPagination (locale) { renderPagination (locale) {

View File

@ -0,0 +1,18 @@
<template>
<div>
<a-steps :current="1">
<a-step title="Finished" description="This is a description." />
<a-step title="In Progress" description="This is a description." />
<a-step title="Waiting" description="This is a description." />
</a-steps>
</div>
</template>
<script>
import '../style'
import {} from 'antd'
export default {
data () {
return {}
},
}
</script>

View File

@ -0,0 +1,45 @@
<script>
import PropTypes from '../_util/vue-types'
import { initDefaultProps, getOptionProps, getComponentFromProp } from '../_util/props-util'
import VcSteps from '../vc-steps'
const getStepsProps = (defaultProps = {}) => {
const props = {
prefixCls: PropTypes.string,
iconPrefix: PropTypes.string,
current: PropTypes.number,
status: PropTypes.oneOf(['wait', 'process', 'finish', 'error']),
size: PropTypes.oneOf(['default', 'small']),
direction: PropTypes.oneOf(['horizontal', 'vertical']),
progressDot: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.func,
]),
}
return initDefaultProps(props, defaultProps)
}
export default {
name: 'Steps',
props: getStepsProps({
prefixCls: 'ant-steps',
iconPrefix: 'ant',
current: 0,
}),
Step: VcSteps.Step,
render () {
const props = getOptionProps(this)
const stepsProps = {
props,
on: this.$listeners,
}
return (
<VcSteps
{...stepsProps}
>
{getComponentFromProp(this, 'default')}
</VcSteps>
)
},
}
</script>

View File

@ -0,0 +1,21 @@
.@{steps-prefix-cls}-item-custom {
.@{steps-prefix-cls}-item-icon {
background: none;
border: 0;
width: auto;
height: auto;
> .@{steps-prefix-cls}-icon {
font-size: 24px;
line-height: @steps-icon-size;
top: 0;
left: 0.5px;
width: @steps-icon-size;
height: @steps-icon-size;
}
}
&.@{steps-prefix-cls}-item-process {
.@{steps-prefix-cls}-item-icon > .@{steps-prefix-cls}-icon {
color: @process-icon-color;
}
}
}

View File

@ -0,0 +1,2 @@
import '../../style/index.less'
import './index.less'

View File

@ -0,0 +1,187 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@steps-prefix-cls: ~"@{ant-prefix}-steps";
@process-icon-color: @processing-color;
@process-title-color: @heading-color;
@process-description-color: @text-color;
@process-tail-color: @border-color-split;
@process-icon-text-color: #fff;
@wait-icon-color: @disabled-color;
@wait-title-color: @text-color-secondary;
@wait-description-color: @wait-title-color;
@wait-tail-color: @process-tail-color;
@finish-icon-color: @process-icon-color;
@finish-title-color: @text-color;
@finish-description-color: @text-color-secondary;
@finish-tail-color: @primary-color;
@error-icon-color: @error-color;
@error-title-color: @error-color;
@error-description-color: @error-color;
@error-tail-color: @wait-tail-color;
@steps-background: @component-background;
@steps-icon-size: 32px;
@steps-small-icon-size: 24px;
@steps-dot-size: 8px;
@steps-current-dot-size: 10px;
@steps-desciption-max-width: 140px;
.@{steps-prefix-cls} {
.reset-component;
font-size: 0;
width: 100%;
display: flex;
}
.@{steps-prefix-cls}-item {
position: relative;
display: inline-block;
vertical-align: top;
flex: 1;
overflow: hidden;
&:last-child {
flex: none;
}
&:last-child &-tail,
&:last-child &-title:after {
display: none;
}
&-icon,
&-content {
display: inline-block;
vertical-align: top;
}
&-icon {
border: @border-width-base @border-style-base @wait-icon-color;
width: @steps-icon-size;
height: @steps-icon-size;
line-height: @steps-icon-size;
text-align: center;
border-radius: @steps-icon-size;
font-size: @font-size-lg;
margin-right: 8px;
transition: background-color .3s, border-color .3s;
font-family: @font-family-no-number;
> .@{steps-prefix-cls}-icon {
line-height: 1;
top: -1px;
color: @primary-color;
position: relative;
}
}
&-tail {
position: absolute;
left: 0;
width: 100%;
top: 12px;
padding: 0 10px;
&:after {
content: '';
display: inline-block;
background: @border-color-split;
height: 1px;
border-radius: 1px;
width: 100%;
transition: background .3s;
}
}
&-title {
font-size: @font-size-lg;
color: @text-color;
display: inline-block;
padding-right: 16px;
position: relative;
line-height: @steps-icon-size;
&:after {
content: '';
height: 1px;
width: 9999px;
background: @wait-tail-color;
display: block;
position: absolute;
top: @steps-icon-size / 2;
left: 100%;
}
}
&-description {
font-size: @font-size-base;
color: @text-color-secondary;
}
.step-item-status(wait);
.step-item-status(process);
&-process &-icon {
background: @process-icon-color;
> .@{steps-prefix-cls}-icon {
color: @process-icon-text-color;
}
}
&-process &-title {
font-weight: 500;
}
.step-item-status(finish);
.step-item-status(error);
&.@{steps-prefix-cls}-next-error .@{steps-prefix-cls}-item-title:after {
background: @error-icon-color;
}
}
.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical) {
.@{steps-prefix-cls}-item {
margin-right: 16px;
white-space: nowrap;
&:last-child {
margin-right: 0;
}
&:last-child .@{steps-prefix-cls}-item-title {
padding-right: 0;
}
&-tail {
display: none;
}
&-description {
max-width: @steps-desciption-max-width;
}
}
}
.step-item-status(@status) {
@icon-color: "@{status}-icon-color";
@title-color: "@{status}-title-color";
@description-color: "@{status}-description-color";
@tail-color: "@{status}-tail-color";
&-@{status} &-icon {
border-color: @@icon-color;
background-color: @steps-background;
> .@{steps-prefix-cls}-icon {
color: @@icon-color;
.@{steps-prefix-cls}-icon-dot {
background: @@icon-color;
}
}
}
&-@{status} > &-content > &-title {
color: @@title-color;
&:after {
background-color: @@tail-color;
}
}
&-@{status} > &-content > &-description {
color: @@description-color;
}
&-@{status} > &-tail:after {
background-color: @@tail-color;
}
}
@import 'custom-icon';
@import 'small';
@import 'vertical';
@import 'label-placement';
@import 'progress-dot';

View File

@ -0,0 +1,28 @@
.@{steps-prefix-cls}-label-vertical {
.@{steps-prefix-cls}-item {
overflow: visible;
&-tail {
padding: 0 24px;
margin-left: 48px;
}
&-content {
display: block;
text-align: center;
margin-top: 8px;
width: @steps-desciption-max-width;
}
&-icon {
display: inline-block;
margin-left: 36px;
}
&-title {
padding-right: 0;
&:after {
display: none;
}
}
&-description {
text-align: left;
}
}
}

View File

@ -0,0 +1,75 @@
.@{steps-prefix-cls}-dot {
.@{steps-prefix-cls}-item {
&-title {
line-height: @line-height-base;
}
&-tail {
width: 100%;
top: 2px;
margin: 0 0 0 @steps-desciption-max-width / 2;
padding: 0;
&:after {
height: 3px;
width: ~"calc(100% - 20px)";
margin-left: 12px;
}
}
&:first-child .@{steps-prefix-cls}-icon-dot {
left: 2px;
}
&-icon {
padding-right: 0;
width: @steps-dot-size;
height: @steps-dot-size;
line-height: @steps-dot-size;
border: 0;
margin-left: 67px;
background: transparent;
.@{steps-prefix-cls}-icon-dot {
float: left;
width: 100%;
height: 100%;
border-radius: 100px;
position: relative;
transition: all .3s;
/* expand hover area */
&:after {
content: "";
background: rgba(0, 0, 0, .001);
width: 60px;
height: 32px;
position: absolute;
top: -12px;
left: -26px;
}
}
}
&-process .@{steps-prefix-cls}-item-icon {
width: @steps-current-dot-size;
height: @steps-current-dot-size;
line-height: @steps-current-dot-size;
.@{steps-prefix-cls}-icon-dot {
top: -1px;
}
}
}
}
.@{steps-prefix-cls}-vertical.@{steps-prefix-cls}-dot {
.@{steps-prefix-cls}-item-icon {
margin-left: 0;
margin-top: 8px;
}
.@{steps-prefix-cls}-item-tail {
margin: 0;
left: -9px;
top: 2px;
padding: 22px 0 4px;
}
.@{steps-prefix-cls}-item:first-child .@{steps-prefix-cls}-icon-dot {
left: 0;
}
.@{steps-prefix-cls}-item-process .@{steps-prefix-cls}-icon-dot {
left: -2px;
}
}

View File

@ -0,0 +1,45 @@
.@{steps-prefix-cls}-small {
&.@{steps-prefix-cls}-horizontal:not(.@{steps-prefix-cls}-label-vertical) .@{steps-prefix-cls}-item {
margin-right: 12px;
&:last-child {
margin-right: 0;
}
}
.@{steps-prefix-cls}-item-icon {
width: @steps-small-icon-size;
height: @steps-small-icon-size;
line-height: @steps-small-icon-size;
text-align: center;
border-radius: @steps-small-icon-size;
font-size: @font-size-sm;
}
.@{steps-prefix-cls}-item-title {
font-size: @font-size-base;
line-height: @steps-small-icon-size;
padding-right: 12px;
&:after {
top: @steps-small-icon-size / 2;
}
}
.@{steps-prefix-cls}-item-description {
font-size: @font-size-base;
color: @text-color-secondary;
}
.@{steps-prefix-cls}-item-tail {
top: 8px;
padding: 0 8px;
}
.@{steps-prefix-cls}-item-custom .@{steps-prefix-cls}-item-icon {
width: inherit;
height: inherit;
line-height: inherit;
border-radius: 0;
border: 0;
background: none;
> .@{steps-prefix-cls}-icon {
font-size: @steps-small-icon-size;
line-height: @steps-small-icon-size;
transform: none;
}
}
}

View File

@ -0,0 +1,67 @@
.steps-vertical() {
display: block;
.@{steps-prefix-cls}-item {
display: block;
overflow: visible;
&-icon {
float: left;
margin-right: 16px;
}
&-content {
min-height: 48px;
overflow: hidden;
display: block;
}
&-title {
line-height: @steps-icon-size;
}
&-description {
padding-bottom: 12px;
}
}
> .@{steps-prefix-cls}-item > .@{steps-prefix-cls}-item-tail {
position: absolute;
left: 16px;
top: 0;
height: 100%;
width: 1px;
padding: @steps-icon-size + 6px 0 6px;
&:after {
height: 100%;
width: 1px;
}
}
> .@{steps-prefix-cls}-item:not(:last-child) > .@{steps-prefix-cls}-item-tail {
display: block;
}
> .@{steps-prefix-cls}-item > .@{steps-prefix-cls}-item-content > .@{steps-prefix-cls}-item-title {
&:after {
display: none;
}
}
&.@{steps-prefix-cls}-small {
.@{steps-prefix-cls}-item-tail {
position: absolute;
left: 12px;
top: 0;
padding: @steps-small-icon-size + 6px 0 6px;
}
.@{steps-prefix-cls}-item-title {
line-height: @steps-small-icon-size;
}
}
}
.@{steps-prefix-cls}-vertical {
.steps-vertical;
}
@media (max-width: @screen-xs) {
.@{steps-prefix-cls}-horizontal.@{steps-prefix-cls}-label-horizontal {
.steps-vertical;
}
}

View File

@ -49,6 +49,7 @@ export default {
}, },
model: { model: {
prop: 'current', prop: 'current',
event: 'change',
}, },
data () { data () {
const hasOnChange = this.onChange !== noop const hasOnChange = this.onChange !== noop

View File

@ -34,9 +34,10 @@ export default {
methods: { methods: {
renderIconNode () { renderIconNode () {
const { const {
prefixCls, progressDot, stepNumber, status, title, description, icon, prefixCls, progressDot, stepNumber, status, title, description,
iconPrefix, iconPrefix,
} = getOptionProps(this) } = getOptionProps(this)
const icon = this.icon || this.$slots.default
let iconNode let iconNode
const iconClassName = { const iconClassName = {
[`${prefixCls}-icon`]: true, [`${prefixCls}-icon`]: true,

View File

@ -3,8 +3,17 @@ import PropTypes from '../_util/vue-types'
import BaseMixin from '../_util/BaseMixin' import BaseMixin from '../_util/BaseMixin'
import debounce from 'lodash/debounce' import debounce from 'lodash/debounce'
import isFlexSupported from '../_util/isFlexSupported' import isFlexSupported from '../_util/isFlexSupported'
import { getOptionProps, filterEmpty, getEvents, getClass, getStyle, getValueByProp } from '../_util/props-util' import {
import { cloneElement } from '../_util/vnode' getOptionProps,
filterEmpty,
getEvents,
getClass,
getStyle,
getValueByProp,
getPropsData,
getComponentFromProp,
} from '../_util/props-util'
import Step from './Step'
export default { export default {
name: 'Steps', name: 'Steps',
@ -64,8 +73,8 @@ export default {
// +1 for fit edge bug of digit width, like 35.4px // +1 for fit edge bug of digit width, like 35.4px
const lastStepOffsetWidth = (domNode.lastChild.offsetWidth || 0) + 1 const lastStepOffsetWidth = (domNode.lastChild.offsetWidth || 0) + 1
// Reduce shake bug // Reduce shake bug
if (this.state.lastStepOffsetWidth === lastStepOffsetWidth || if (this.lastStepOffsetWidth === lastStepOffsetWidth ||
Math.abs(this.state.lastStepOffsetWidth - lastStepOffsetWidth) <= 3) { Math.abs(this.lastStepOffsetWidth - lastStepOffsetWidth) <= 3) {
return return
} }
this.setState({ lastStepOffsetWidth }) this.setState({ lastStepOffsetWidth })
@ -102,6 +111,7 @@ export default {
<div {...stepsProps}> <div {...stepsProps}>
{ {
filteredChildren.map((child, index) => { filteredChildren.map((child, index) => {
const childProps = getPropsData(child)
let className = getClass(child) let className = getClass(child)
// fix tail color // fix tail color
if (status === 'error' && index === current - 1) { if (status === 'error' && index === current - 1) {
@ -124,6 +134,7 @@ export default {
} }
const stepProps = { const stepProps = {
props: { props: {
...childProps,
stepNumber: `${index + 1}`, stepNumber: `${index + 1}`,
prefixCls, prefixCls,
iconPrefix, iconPrefix,
@ -134,7 +145,7 @@ export default {
class: className, class: className,
style: stepStyle, style: stepStyle,
} }
return cloneElement(child, stepProps) return <Step {...stepProps}>{getComponentFromProp(child, 'icon')}</Step>
}) })
} }
</div> </div>

View File

@ -1,4 +1,4 @@
@icon-url : "//at.alicdn.com/t/font_1434092639_4910953"; @icon-url : "http://at.alicdn.com/t/font_1434092639_4910953";
.ie-rotate(@rotation) { .ie-rotate(@rotation) {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation); filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation);
} }

View File

@ -10,10 +10,11 @@ export default {
} }
}, },
render () { render () {
const Icon = ({ type }) => <i className={`rcicon rcicon-${type}`} />
return ( return (
<Steps current={1}> <Steps current={1}>
<Step title='步骤1' icon={<Icon type='cloud' />} /> <Step title='步骤1' >
<i class={`rcicon rcicon-cloud`} slot='icon'/>
</Step>
<Step title='步骤2' icon='apple' /> <Step title='步骤2' icon='apple' />
<Step title='步骤3' icon='github' /> <Step title='步骤3' icon='github' />
</Steps> </Steps>

View File

@ -0,0 +1,41 @@
<script>
import Steps, { Step } from '../index'
import '../assets/index.less'
import '../assets/iconfont.less'
export default {
data () {
return {
steps: [{
title: '已完成',
description: '这里是多信息的描述啊描述啊描述啊描述啊哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶',
}, {
title: '进行中',
description: '这里是多信息的描述啊描述啊描述啊描述啊哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶',
}, {
title: '待运行',
description: '这里是多信息的描述啊描述啊描述啊描述啊哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶',
}, {
title: '待运行',
description: '这里是多信息的描述啊描述啊描述啊描述啊哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶哦耶',
}],
}
},
methods: {
addStep () {
this.steps.push({
title: '待运行',
description: '新的节点',
})
},
},
render () {
return (
<div>
<button onClick={this.addStep}>Add new step</button>
<Steps>{this.steps.map((step, i) => <Step key={i} title={step.title} description={step.description} />)}</Steps>
</div>
)
},
}
</script>

View File

@ -0,0 +1,24 @@
<script>
import Steps, { Step } from '../index'
import '../assets/index.less'
import '../assets/iconfont.less'
export default {
data () {
return {
description: '这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊',
}
},
render () {
const { description } = this
return (
<Steps current={2} status='error'>
<Step title='已完成' description={description} />
<Step title='进行中' description={description} />
<Step title='待运行' description={description} />
<Step title='待运行' description={description} />
</Steps>
)
},
}
</script>

View File

@ -0,0 +1,70 @@
<script>
import Steps, { Step } from '../index'
import '../assets/index.less'
import '../assets/iconfont.less'
function generateRandomSteps () {
const n = Math.floor(Math.random() * 3) + 3
const arr = []
for (let i = 0; i < n; i++) {
arr.push({
title: `步骤${(i + 1)}`,
})
}
return arr
}
const steps = generateRandomSteps()
export default {
data () {
return {
currentStep: Math.floor(Math.random() * steps.length),
}
},
methods: {
nextStep () {
let s = this.currentStep + 1
if (s === steps.length) {
s = 0
}
this.currentStep = s
},
},
render () {
const cs = this.currentStep
return (
<form class='my-step-form'>
<div>这个demo随机生成3~6个步骤初始随机进行到其中一个步骤</div>
<div>当前正在执行第{cs + 1}</div>
<div class='my-step-container'>
<Steps current={cs}>
{
steps.map((s, i) => {
return (
<Step
key={i}
title={s.title}
/>
)
})
}
</Steps>
</div>
<div><button type='button' onClick={this.nextStep}>下一步</button></div>
</form>
)
},
}
</script>
<style>
.my-step-form {
width: 100%;
}
.my-step-form > div {
margin-bottom: 20px;
}
.my-step-container {
width: 100%;
}
</style>

View File

@ -0,0 +1,25 @@
<script>
import Steps, { Step } from '../index'
import '../assets/index.less'
import '../assets/iconfont.less'
export default {
data () {
return {
description: '这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊',
}
},
render () {
const { description } = this
return (
<Steps progressDot size='small' current={1}>
<Step title='已完成' description={description} />
<Step title='进行中' description={description} />
<Step title='待运行' description={description} />
<Step title='待运行' description={description} />
<Step title='待运行' description={description} />
</Steps>
)
},
}
</script>

View File

@ -0,0 +1,38 @@
<script>
import Steps, { Step } from '../index'
import '../assets/index.less'
import '../assets/iconfont.less'
export default {
data () {
return {
description: '这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊',
}
},
render () {
const { description } = this
return (
<div>
<Steps current={1}>
<Step title='已完成' />
<Step title='进行中' />
<Step title='待运行' />
<Step title='待运行' />
</Steps>
<Steps current={1} style={{ marginTop: 40 }}>
<Step title='已完成' description={description} />
<Step title='进行中' description={description} />
<Step title='待运行' description={description} />
<Step title='待运行' description={description} />
</Steps>
<Steps current={1} style={{ marginTop: 40 }} status='error'>
<Step title='已完成' description={description} />
<Step title='进行中' description={description} />
<Step title='待运行' description={description} />
<Step title='待运行' description={description} />
</Steps>
</div>
)
},
}
</script>

View File

@ -0,0 +1,30 @@
<script>
import Steps, { Step } from '../index'
import '../assets/index.less'
import '../assets/iconfont.less'
export default {
data () {
return {}
},
render () {
return (
<div>
<Steps size='small' current={1}>
<Step title='已完成' />
<Step title='进行中' />
<Step title='待运行' />
<Step title='待运行' />
</Steps>
<Steps current={1}>
<Step title='步骤1' >
<i class={`rcicon rcicon-cloud`} slot='icon'/>
</Step>
<Step title='步骤2' icon='apple' />
<Step title='步骤3' icon='github' />
</Steps>
</div>
)
},
}
</script>

View File

@ -0,0 +1,25 @@
<script>
import Steps, { Step } from '../index'
import '../assets/index.less'
import '../assets/iconfont.less'
export default {
data () {
return {
description: '这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊',
}
},
render () {
const { description } = this
return (
<Steps direction='vertical'>
<Step title='已完成' description={description} />
<Step title='进行中' description={description} />
<Step title='待运行' description={description} />
<Step title='待运行' description={description} />
<Step title='待运行' description={description} />
</Steps>
)
},
}
</script>

View File

@ -0,0 +1,25 @@
<script>
import Steps, { Step } from '../index'
import '../assets/index.less'
import '../assets/iconfont.less'
export default {
data () {
return {
description: '这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊这里是多信息的描述啊',
}
},
render () {
const { description } = this
return (
<Steps direction='vertical' size='small'>
<Step title='已完成' description={description} />
<Step title='进行中' description={description} />
<Step title='待运行' description={description} />
<Step title='待运行' description={description} />
<Step title='待运行' description={description} />
</Steps>
)
},
}
</script>

View File

@ -3,7 +3,7 @@ const AsyncComp = () => {
const hashs = window.location.hash.split('/') const hashs = window.location.hash.split('/')
const d = hashs[hashs.length - 1] const d = hashs[hashs.length - 1]
return { return {
component: import(`../components/vc-steps/demo/${d}`), component: import(`../components/steps/demo/${d}`),
} }
} }
export default [ export default [