فهرست منبع

Add Steps component

Update docs

Clear space

Update doc
qingwei.li 9 سال پیش
والد
کامیت
ec2e06037e

+ 6 - 0
components.json

@@ -154,5 +154,11 @@
   ],
   "rate": [
     "./packages/rate/index.js"
+  ],
+  "steps": [
+    "./packages/steps/index.js"
+  ],
+  "step": [
+    "./packages/step/index.js"
   ]
 }

+ 183 - 0
examples/docs/steps.md

@@ -0,0 +1,183 @@
+##  基础用法
+简单的步骤条。
+
+### 定宽步骤条
+
+<el-steps :space="100" :active="active" finish-status="success">
+  <el-step title="步骤 1"></el-step>
+  <el-step title="步骤 2"></el-step>
+  <el-step title="步骤 3"></el-step>
+</el-steps>
+
+<el-button @click.native="next">下一步</el-button>
+
+<script>
+  export default {
+    data() {
+      return {
+        active: 0
+      };
+    },
+
+    methods: {
+      next() {
+        if (this.active++ > 2) this.active = 0;
+      }
+    }
+  }
+</script>
+
+```html
+<el-steps :space="100" :active="active" finish-status="success">
+  <el-step title="步骤 1"></el-step>
+  <el-step title="步骤 2"></el-step>
+  <el-step title="步骤 3"></el-step>
+</el-steps>
+
+<el-button @click.native="next">下一步</el-button>
+
+<script>
+  export default {
+    data() {
+      return {
+        active: 0
+      };
+    },
+
+    methods: {
+      next() {
+        if (this.active++ > 2) this.active = 0;
+      }
+    }
+  }
+</script>
+```
+
+### 自适应步骤条
+
+<el-steps :active="1">
+  <el-step title="步骤 1"></el-step>
+  <el-step title="步骤 2"></el-step>
+  <el-step title="步骤 3"></el-step>
+</el-steps>
+
+```html
+<el-steps :active="1">
+  <el-step title="步骤 1"></el-step>
+  <el-step title="步骤 2"></el-step>
+  <el-step title="步骤 3"></el-step>
+</el-steps>
+```
+
+## 含状态步骤
+每一步骤显示出该步骤的状态。
+
+<el-steps :space="100" :active="1" finish-status="success">
+  <el-step title="已完成"></el-step>
+  <el-step title="进行中"></el-step>
+  <el-step title="步骤 3"></el-step>
+</el-steps>
+
+```html
+<el-steps :space="100" :active="1" finish-status="success">
+  <el-step title="已完成"></el-step>
+  <el-step title="进行中"></el-step>
+  <el-step title="步骤 3"></el-step>
+</el-steps>
+```
+
+## 有描述的步骤条
+每个步骤有其对应的步骤状态描述。
+
+<el-steps :space="200" :active="1">
+  <el-step title="步骤 1" description="这是一段很长很长很长的描述性文字"></el-step>
+  <el-step title="步骤 2" description="这是一段很长很长很长的描述性文字"></el-step>
+  <el-step title="步骤 3" description="这是一段很长很长很长的描述性文字"></el-step>
+</el-steps>
+
+```html
+<el-steps :space="200" :active="1">
+  <el-step title="步骤 1" description="这是一段很长很长很长的描述性文字"></el-step>
+  <el-step title="步骤 2" description="这是一段很长很长很长的描述性文字"></el-step>
+  <el-step title="步骤 3" description="这是一段很长很长很长的描述性文字"></el-step>
+</el-steps>
+```
+
+## 带图标的步骤条
+步骤条内可以启用各种自定义的图标。
+
+<el-steps :space="100" :active="1">
+  <el-step title="步骤 1" icon="edit"></el-step>
+  <el-step title="步骤 2" icon="upload"></el-step>
+  <el-step title="步骤 3" icon="picture"></el-step>
+</el-steps>
+
+```html
+<el-steps :space="100" :active="1">
+  <el-step title="步骤 1" icon="edit"></el-step>
+  <el-step title="步骤 2" icon="upload"></el-step>
+  <el-step title="步骤 3" icon="picture"></el-step>
+</el-steps>
+```
+
+## 竖式步骤条
+竖直方向的步骤条。
+
+<el-steps :space="100" direction="vertical" :active="1">
+  <el-step title="步骤 1"></el-step>
+  <el-step title="步骤 2"></el-step>
+  <el-step title="步骤 3"></el-step>
+</el-steps>
+
+```html
+<el-steps :space="100" direction="vertical" :active="1">
+  <el-step title="步骤 1"></el-step>
+  <el-step title="步骤 2"></el-step>
+  <el-step title="步骤 3"></el-step>
+</el-steps>
+```
+
+## 步骤错误提示
+每一步骤显示出该步骤的状态。
+
+<el-steps :space="100" :active="1" finish-status="success" process-status="error">
+  <el-step title="已完成"></el-step>
+  <el-step title="审核失败"></el-step>
+  <el-step title="步骤 3"></el-step>
+</el-steps>
+
+```html
+<el-steps :space="100" :active="1" finish-status="success" process-status="error">
+  <el-step title="已完成"></el-step>
+  <el-step title="审核失败"></el-step>
+  <el-step title="步骤 3"></el-step>
+</el-steps>
+```
+
+## API
+
+### Steps.props
+
+| 参数      | 说明    | 类型      | 可选值       | 默认值   |
+|---------- |-------- |---------- |-------------  |-------- |
+| space | 每个 step 的间距,不填写将自适应间距 | Number | | |
+| direction | 显示方向 | String | `vertical` `horizontal` | `horizontal` |
+| active | 设置当前激活步骤  | Number | | 0 |
+| process-status | 设置当前步骤的状态 | String | `wait` `process` `finish` `error` `success` | `process` |
+| finish-status | 设置结束步骤的状态 | String | `wait` `process` `finish` `error` `success` | `finish` |
+
+### Step.props
+| 参数      | 说明    | 类型      | 可选值       | 默认值   |
+|---------- |-------- |---------- |-------------  |-------- |
+| title | 标题 | String | | |
+| description | 描述性文字 | String | | |
+| icon | 图标 | Element Icon 提供的图标,如果要使用自定义图标可以通过 slot 方式写入 | String | |
+
+
+### Step.slot
+| name | 说明  |
+|----|----|
+| icon | 图标 |
+| title | 标题 |
+| description | 描述性文字 |
+

+ 1 - 1
examples/icon.json

@@ -1 +1 @@
-["search","share","setting","circle-cross","warning","information","circle-check","delete","d-arrow-left","d-arrow-right","picture","upload","menu","time","circle-close","arrow-down","arrow-up","arrow-right","arrow-left","close","document","d-caret","date","message","loading","ellipsis","plus","caret-left","caret-right","caret-bottom","edit","caret-top","check","minus","star-on","star-off"]
+["search","share","setting","circle-cross","warning","information","circle-check","delete","d-arrow-left","d-arrow-right","picture","upload","menu","time","circle-close","arrow-down","arrow-up","arrow-right","arrow-left","close","document","d-caret","date","message","loading","ellipsis","plus","caret-left","caret-right","caret-bottom","edit","caret-top","check","minus","star-off","star-on"]

+ 6 - 0
examples/nav.config.json

@@ -205,6 +205,12 @@
         "path": "/dropdown",
         "name": "下拉菜单 (dropdown)",
         "title": "Dropdown 下拉菜单"
+      },
+      {
+        "path": "/steps",
+        "name": "步骤条 (steps)",
+        "title": "Steps 步骤",
+        "description": "引导用户按照流程完成任务的分步导航条,可根据实际应用场景设定步骤,步骤不得少于 2 步。"
       }
     ]
   },

+ 7 - 0
packages/step/index.js

@@ -0,0 +1,7 @@
+const Step = require('../steps/src/step');
+
+Step.install = function(Vue) {
+  Vue.component(Step.name, Step);
+};
+
+module.exports = Step;

+ 31 - 0
packages/steps/cooking.conf.js

@@ -0,0 +1,31 @@
+var cooking = require('cooking');
+var path = require('path');
+
+cooking.set({
+  entry: {
+    index: path.join(__dirname, 'index.js')
+  },
+  dist: path.join(__dirname, 'lib'),
+  template: false,
+  format: 'umd',
+  moduleName: 'ElSteps',
+  extractCSS: 'style.css',
+
+  extends: ['vue', 'saladcss']
+});
+
+cooking.add('resolve.alias', {
+  'main': path.join(__dirname, '../../src'),
+  'packages': path.join(__dirname, '../../packages')
+});
+
+cooking.add('externals', {
+  vue: {
+    root: 'Vue',
+    commonjs: 'vue',
+    commonjs2: 'vue',
+    amd: 'vue'
+  }
+});
+
+module.exports = cooking.resolve();

+ 7 - 0
packages/steps/index.js

@@ -0,0 +1,7 @@
+const Steps = require('./src/steps');
+
+Steps.install = function(Vue) {
+  Vue.component(Steps.name, Steps);
+};
+
+module.exports = Steps;

+ 15 - 0
packages/steps/package.json

@@ -0,0 +1,15 @@
+{
+  "name": "el-steps",
+  "version": "0.0.0",
+  "description": "A steps component for Vue.js.",
+  "keywords": [
+    "element",
+    "vue",
+    "component"
+  ],
+  "main": "./lib/index.js",
+  "repository": "https://github.com/element-component/element/tree/master/packages/steps",
+  "author": "elemefe",
+  "license": "MIT",
+  "dependencies": {}
+}

+ 124 - 0
packages/steps/src/step.vue

@@ -0,0 +1,124 @@
+<template>
+  <div
+    class="el-step"
+    :style="style"
+    :class="['is-' + $parent.direction]">
+    <div
+      class="el-step__head"
+      :class="['is-' + currentStatus, { 'is-text': !icon }]">
+      <div
+        class="el-step__line"
+        :class="['is-' + $parent.direction,{ 'is-icon': icon }]">
+        <i class="el-step__line-inner" :style="lineStyle"></i>
+      </div>
+
+      <slot
+        v-if="currentStatus !== 'success' && currentStatus !== 'error'"
+        name="icon">
+        <i v-if="icon" :class="['el-step__icon', 'el-icon-' + icon]"></i>
+        <div v-else>{{ index + 1 }}</div>
+      </slot>
+      <i
+        v-else
+        class="el-step__icon"
+        :class="['el-icon-' + (currentStatus === 'success' ? 'check' : 'close')]">
+      </i>
+    </div>
+    <div
+      class="el-step__main"
+      :style="{ marginLeft: mainOffset }">
+      <div
+        class="el-step__title"
+        ref="title"
+        :class="['is-' + currentStatus]">
+        <slot name="title">{{ title }}</slot>
+      </div>
+      <div
+        class="el-step__description"
+        :class="['is-' + currentStatus]">
+        <slot name="description">{{ description }}</slot>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'el-step',
+
+  props: {
+    title: String,
+    icon: String,
+    description: String,
+    status: {
+      type: String,
+      default: 'wait'
+    }
+  },
+
+  data() {
+    return {
+      index: -1,
+      style: { width: 0, height: 0 },
+      lineStyle: { width: 0, height: 0 },
+      mainOffset: 0,
+      currentStatus: this.status
+    };
+  },
+
+  created() {
+    this.$parent.steps.push(this);
+  },
+
+  methods: {
+    updateStatus(val) {
+      const prevChild = this.$parent.$children[this.index - 1];
+
+      if (val > this.index) {
+        this.currentStatus = this.$parent.finishStatus;
+      } else if (val === this.index) {
+        this.currentStatus = this.$parent.processStatus;
+      } else {
+        this.currentStatus = 'wait';
+      }
+
+      if (prevChild) prevChild.calcProgress(this.currentStatus);
+    },
+
+    calcProgress(status) {
+      let step = 100;
+
+      this.lineStyle.transitionDelay = 150 * this.index + 'ms';
+      if (status === this.$parent.processStatus) {
+        step = 50;
+      } else if (status === 'wait') {
+        step = 0;
+        this.lineStyle.transitionDelay = (-150 * this.index) + 'ms';
+      }
+
+      this.$parent.direction === 'vertical'
+        ? this.lineStyle.height = step + '%'
+        : this.lineStyle.width = step + '%';
+    }
+  },
+
+  mounted() {
+    const parent = this.$parent;
+    const space = parent.space
+      ? parent.space + 'px'
+      : 100 / parent.steps.length + '%';
+
+    if (parent.direction === 'horizontal') {
+      this.style = { width: space };
+      this.mainOffset = -this.$refs.title.getBoundingClientRect().width / 2 + 16 + 'px';
+    } else {
+      this.style = { height: space };
+    }
+
+    const unwatch = this.$watch('index', val => {
+      this.$watch('$parent.active', this.updateStatus, { immediate: true });
+      unwatch();
+    });
+  }
+};
+</script>

+ 38 - 0
packages/steps/src/steps.vue

@@ -0,0 +1,38 @@
+<template>
+  <div class="el-steps" :class="['is-' + direction]"><slot></slot></div>
+</template>
+
+<script>
+export default {
+  name: 'el-steps',
+
+  props: {
+    space: Number,
+    active: Number,
+    direction: {
+      type: String,
+      default: 'horizontal'
+    },
+    finishStatus: {
+      type: String,
+      default: 'finish'
+    },
+    processStatus: {
+      type: String,
+      default: 'process'
+    }
+  },
+
+  data() {
+    return {
+      steps: []
+    };
+  },
+
+  mounted() {
+    this.steps.forEach((child, index) => {
+      child.index = index;
+    });
+  }
+};
+</script>

+ 6 - 0
packages/theme-default/src/common/var.css

@@ -367,4 +367,10 @@
     --card-border-color: var(--disabled-border-base);
     --card-border-radius: 4px;
     --card-padding: 20px;
+
+    /*Steps
+    --------------------------*/
+    --steps-border-color: var(--disabled-border-base);
+    --steps-border-radius: 4px;
+    --steps-padding: 20px;
 }

+ 2 - 0
packages/theme-default/src/index.css

@@ -35,3 +35,5 @@
 @import "./badge.css";
 @import "./card.css";
 @import "./rate.css";
+@import "./steps.css";
+@import "./step.css";

+ 204 - 0
packages/theme-default/src/step.css

@@ -0,0 +1,204 @@
+@charset "UTF-8";
+@import "./common/var.css";
+
+@component-namespace el {
+  @b step {
+    position: relative;
+    vertical-align: top;
+
+    @when horizontal {
+      display: inline-block;
+    }
+
+    @when vertical {
+      & .el-step__head,
+      & .el-step__main {
+        display: inline-block;
+      }
+
+      & .el-step__main {
+        padding-left: 10px;
+      }
+    }
+
+    @e line {
+      display: inline-block;
+      position: absolute;
+      border-color: inherit;
+      background-color: #c0ccda;
+      z-index: -1;
+
+      @when icon {
+        @when horizontal {
+          width: 55%;
+          margin-left: 35px;
+        }
+
+        @when vertical {
+          height: 55%;
+          margin-top: 35px;
+        }
+      }
+
+      @when horizontal {
+        top: 15px;
+        height: 2px;
+        width: 100%;
+        margin-right: -14px;
+      }
+
+      @when vertical {
+        width: 2px;
+        height: 100%;
+        box-sizing: border-box;
+        padding-top: 28px;
+      }
+    }
+
+    @e line-inner {
+      display: inherit;
+      border-width: 1px;
+      border-style: solid;
+      border-color: inherit;
+      transition: all 150ms;
+      width: 0;
+      height: 0;
+    }
+
+    @e icon {
+      line-height: 28px;
+    }
+
+    @e head {
+      circle: 28px transparent;
+      text-align: center;
+      line-height: 28px;
+      font-size: 28px;
+      vertical-align: top;
+      transition: all 150ms;
+
+      @when text {
+        font-size: 14px;
+        border-width: 2px;
+        border-style: solid;
+
+        @when process {
+          color: #fff;
+          background-color: #c0ccda;
+          border-color: #c0ccda;
+        }
+
+        @when wait {
+          color: #c0ccda;
+          background-color: #fff;
+          border-color: #c0ccda;
+        }
+
+        @when success {
+          color: #fff;
+          background-color: #13ce66;
+          border-color: #13ce66;
+        }
+
+        @when error {
+          color: #fff;
+          background-color: #ff4949;
+          border-color: #ff4949;
+        }
+
+        @when finish {
+          color: #fff;
+          background-color: #20a0ff;
+          border-color: #20a0ff;
+        }
+      }
+
+      @when process {
+        color: #c0ccda;
+        border-color: #c0ccda;
+      }
+
+      @when wait {
+        color: #c0ccda;
+        border-color: #c0ccda;
+      }
+
+      @when success {
+        color: #13ce66;
+        border-color: #13ce66;
+      }
+
+      @when error {
+        color: #ff4949;
+        border-color: #ff4949;
+      }
+
+      @when finish {
+        color: #20a0ff;
+        border-color: #20a0ff;
+      }
+    }
+
+    @e main {
+      white-space: normal;
+      padding-right: 10px;
+    }
+
+    @e title {
+      font-size: 14px;
+      margin-top: 5px;
+      display: inline-block;
+
+      @when process {
+        font-weight: 700;
+        color: #475669;
+      }
+
+      @when wait {
+        font-weight: normal;
+        color: #99a9bf;
+      }
+
+      @when success {
+        font-weight: 700;
+        color: #13ce66;
+      }
+
+      @when error {
+        font-weight: 700;
+        color: #ff4949;
+      }
+
+      @when finish {
+        font-weight: 700;
+        color: #20a0ff;
+      }
+    }
+
+    @e description {
+      font-size: 12px;
+      font-weight: normal;
+      line-height: 14px;
+
+      @when process {
+        color: #8492a6;
+      }
+
+      @when wait {
+        color: #c0ccda;
+      }
+
+      @when success {
+        color: #13ce66;
+      }
+
+      @when error {
+        color: #ff4949;
+      }
+
+      @when finish {
+        color: #20a0ff;
+      }
+    }
+  }
+}

+ 17 - 0
packages/theme-default/src/steps.css

@@ -0,0 +1,17 @@
+@charset "UTF-8";
+@import "./common/var.css";
+
+@component-namespace el {
+  @b steps {
+    overflow: hidden;
+    font-size: 0;
+
+    > :last-child .el-step__line {
+      display: none;
+    }
+
+    @when horizontal {
+      white-space: nowrap;
+    }
+  }
+}

+ 13 - 7
src/index.js

@@ -43,13 +43,15 @@ import Loading from '../packages/loading/index.js';
 import Icon from '../packages/icon/index.js';
 import Row from '../packages/row/index.js';
 import Col from '../packages/col/index.js';
-import Upload from '../packages/upload/index.js';
+// import Upload from '../packages/upload/index.js';
 import Progress from '../packages/progress/index.js';
 import Spinner from '../packages/spinner/index.js';
 import Message from '../packages/message/index.js';
+import Badge from '../packages/badge/index.js';
 import Card from '../packages/card/index.js';
 import Rate from '../packages/rate/index.js';
-import Badge from '../packages/badge/index.js';
+import Steps from '../packages/steps/index.js';
+import Step from '../packages/step/index.js';
 
 const install = function(Vue) {
   if (install.installed) return;
@@ -96,13 +98,15 @@ const install = function(Vue) {
   Vue.component(Icon.name, Icon);
   Vue.component(Row.name, Row);
   Vue.component(Col.name, Col);
-  Vue.component(Upload.name, Upload);
+  // Vue.component(Upload.name, Upload);
   Vue.component(Progress.name, Progress);
   Vue.component(Spinner.name, Spinner);
   Vue.component(Message.name, Message);
+  Vue.component(Badge.name, Badge);
   Vue.component(Card.name, Card);
   Vue.component(Rate.name, Rate);
-  Vue.component(Badge.name, Badge);
+  Vue.component(Steps.name, Steps);
+  Vue.component(Step.name, Step);
 
   Vue.use(Loading);
 
@@ -166,11 +170,13 @@ module.exports = {
   Icon,
   Row,
   Col,
-  Upload,
+  // Upload,
   Progress,
   Spinner,
+  Message,
+  Badge,
   Card,
   Rate,
-  Message,
-  Badge
+  Steps,
+  Step
 };