浏览代码

feat: steps

ailululu 4 年之前
父节点
当前提交
955a9ad3ec
共有 5 个文件被更改,包括 304 次插入58 次删除
  1. 81 5
      src/packages/step/index.scss
  2. 32 5
      src/packages/step/index.vue
  3. 41 33
      src/packages/steps/demo.vue
  4. 90 0
      src/packages/steps/doc.md
  5. 60 15
      src/packages/steps/index.vue

+ 81 - 5
src/packages/step/index.scss

@@ -28,13 +28,21 @@
     font-size: 13px;
     // border-color: #909CA4;
     z-index: 1;
+    .nut-icon {
+      width: 100%;
+      height: 100%;
+    }
     &.is-text {
       border-radius: 50%;
       border-width: 1px;
       border-style: solid;
     }
-  }
-  &-inner {
+    &.is-icon {
+      border-radius: 50%;
+      border-width: 1px;
+      border-style: solid;
+      background-color: transparent;
+    }
   }
   &-main {
     display: inline-block;
@@ -66,9 +74,15 @@
     .nut-step-icon.is-text {
       background-color: #fff;
     }
+    .nut-step-icon.is-icon {
+      background-color: #fff;
+    }
     .nut-step-line {
       background: #3790ff;
     }
+    .nut-step-title {
+      color: #3790ff;
+    }
   }
   &.nut-step-process {
     .nut-step-head {
@@ -78,8 +92,11 @@
     .nut-step-icon.is-text {
       background-color: #3790ff;
     }
-    .nut-step-line {
-      background: #3790ff;
+    .nut-step-icon.is-icon {
+      background-color: #3790ff;
+    }
+    .nut-step-title {
+      color: #3790ff;
     }
   }
   &.nut-step-wait {
@@ -90,6 +107,12 @@
     .nut-step-icon.is-text {
       background-color: #fff;
     }
+    .nut-step-icon.is-icon {
+      background-color: #fff;
+    }
+    .nut-step-content {
+      color: #909ca4;
+    }
   }
   &.nut-step-error {
     .nut-step-head {
@@ -99,6 +122,9 @@
     .nut-step-icon.is-text {
       background-color: #fa2c19;
     }
+    .nut-step-icon.is-icon {
+      background-color: #fa2c19;
+    }
     .nut-step-line {
       background: #3790ff;
     }
@@ -118,7 +144,57 @@
   }
   .nut-step-main {
     display: inline-block;
-    padding-left: 10%;
+    padding-left: 6%;
     text-align: left;
   }
+  &.nut-steps-dot {
+    .nut-step-head {
+      margin-top: 7px;
+      margin-bottom: 0;
+    }
+    .nut-step-line {
+      top: 7px;
+      left: 50%;
+      right: -50%;
+    }
+    .nut-step-icon {
+      width: 8px;
+      height: 8px;
+      background: #3790ff;
+      border-radius: 50%;
+      box-sizing: content-box;
+    }
+    .nut-step-wait {
+      .nut-step-icon {
+        background-color: #959fb1;
+      }
+      .nut-step-content {
+        color: #909ca4;
+      }
+    }
+    .nut-step-finish {
+      .nut-step-icon {
+        background-color: #3790ff;
+      }
+    }
+    .nut-step-process {
+      .nut-step-icon {
+        position: relative;
+        background-color: #3790ff;
+        &:before {
+          content: '';
+          display: inline-block;
+          position: absolute;
+          left: 50%;
+          top: 50%;
+          margin-left: -7px;
+          margin-top: -7px;
+          width: 14px;
+          height: 14px;
+          background-color: rgba(55, 144, 255, 0.23);
+          border-radius: 50%;
+        }
+      }
+    }
+  }
 }

+ 32 - 5
src/packages/step/index.vue

@@ -2,12 +2,16 @@
   <view :class="classes">
     <view class="nut-step-head">
       <view class="nut-step-line"></view>
-      <view class="nut-step-icon" :class="[icon ? 'is-icon' : 'is-text']">
+      <view
+        class="nut-step-icon"
+        :class="[!state.dot ? (icon ? 'is-icon' : 'is-text') : '']"
+      >
         <template v-if="icon">
           <nut-icon class="nut-step-icon-inner" :class="icon" />
         </template>
+        <template v-else-if="state.dot"></template>
         <template v-else>
-          <view class="nut-step-inner">11</view>
+          <view class="nut-step-inner">{{ state.index }}</view>
         </template>
       </view>
     </view>
@@ -23,7 +27,7 @@
 </template>
 
 <script lang="ts">
-import { reactive, computed, nextTick, ref } from 'vue';
+import { reactive, computed, inject } from 'vue';
 import { createComponent } from '@/utils/create';
 const { create, componentName } = createComponent('step');
 
@@ -40,16 +44,39 @@ export default create({
     icon: {
       type: String,
       default: null
+    },
+    status: {
+      type: String,
+      default: null
+    },
+    data: {
+      type: String,
+      default: null
     }
   },
-  setup(props, { emit, slots }) {
+  setup(props, context) {
+    const steps: any = inject('stepsParent');
+    const defaults = context.slots?.default();
+    console.log('defaults', context.slots);
+    console.log('steps', steps.props.progressDot);
+    const state = reactive({
+      data: [],
+      index: context.slots.default()[0]?.children - 1,
+      dot: steps.props.progressDot
+    });
+    console.log('dot', state.dot);
+    // console.log('context', steps.state.steps[state.index])
     const classes = computed(() => {
       const prefixCls = componentName;
       return {
-        [prefixCls]: true
+        [prefixCls]: true,
+        [props.status
+          ? 'nut-step-' + props.status
+          : steps.state.steps[state.index].currentStatus]: true
       };
     });
     return {
+      state,
       classes
     };
   }

+ 41 - 33
src/packages/steps/demo.vue

@@ -2,55 +2,63 @@
   <div class="demo">
     <h2>基本用法</h2>
     <nut-steps current="1">
-      <nut-step class="" title="进行中">1</nut-step>
-      <nut-step class="nut-step-process" title="未开始">2</nut-step>
-      <nut-step class="" title="未开始">3</nut-step>
+      <nut-step title="进行中">1</nut-step>
+      <nut-step title="未开始">2</nut-step>
+      <nut-step title="未开始">3</nut-step>
     </nut-steps>
-    <h2>基本用法</h2>
+    <h2>标题和描述信息</h2>
+    <nut-steps current="2">
+      <nut-step
+        title="已完成"
+        content="步骤描述"
+        icon="nutui-iconfont nut-icon-wanshangshide"
+        >1</nut-step
+      >
+      <nut-step title="进行中" content="步骤描述">2</nut-step>
+      <nut-step title="未开始" content="步骤描述">3</nut-step>
+    </nut-steps>
+    <h2>自定义图标</h2>
     <nut-steps current="1">
-      <nut-step class="nut-step-finish" title="未开始">1</nut-step>
       <nut-step
-        class="nut-step-process"
-        title="进行中"
-        content="这是一段很长很长很长的描述性文字"
+        title="已完成"
+        icon="nutui-iconfont nut-icon-wanshangshide"
+        status="error"
+        >1</nut-step
+      >
+      <nut-step title="进行中" icon="nutui-iconfont nut-icon-notice"
         >2</nut-step
       >
-      <nut-step class="nut-step-wait" title="未开始">3</nut-step>
+      <nut-step
+        class="nut-step-wait"
+        title="未开始"
+        icon="nutui-iconfont nut-icon-notice"
+        >3</nut-step
+      >
     </nut-steps>
-    <h2>自定义图标和颜色</h2>
-    <div class="" style="height: 300px">
-      <nut-steps>
+    <h2>竖向步骤条</h2>
+    <div style="height: 300px">
+      <nut-steps direction="vertical" current="2">
         <nut-step
-          class="nut-step-finish"
           title="已完成"
           icon="nutui-iconfont nut-icon-wanshangshide"
-        ></nut-step>
+          content="您的订单已经打包完成,商品已发出"
+          >1</nut-step
+        >
+        <nut-step title="进行中" content="您的订单正在配送途中">2</nut-step>
         <nut-step
-          class="nut-step-process"
-          title="进行中"
-          icon="nutui-iconfont nut-icon-notice"
-          >2</nut-step
+          title="未开始"
+          content="收货地址为:北京市经济技术开发区科创十一街18号院京东大厦"
+          >3</nut-step
         >
-        <nut-step class="nut-step-wait" title="未开始" content="">3</nut-step>
       </nut-steps>
     </div>
-    <h2>竖向步骤条</h2>
-    <div class="" style="height: 300px">
-      <nut-steps direction="vertical">
-        <nut-step
-          class="nut-step-error"
-          title="已完成"
-          content="您的订单已经打包完成,商品已发出"
+    <div style="height: 300px">
+      <nut-steps direction="vertical" progressDot current="2">
+        <nut-step title="已完成" content="您的订单已经打包完成,商品已发出"
           >1</nut-step
         >
+        <nut-step title="进行中" content="您的订单正在配送途中">2</nut-step>
         <nut-step
-          class="nut-step-process"
-          title="进行中"
-          content="您的订单正在配送途中"
-          >2</nut-step
-        >
-        <nut-step
-          class="nut-step-wait"
           title="未开始"
           content="收货地址为:北京市经济技术开发区科创十一街18号院京东大厦"
           >3</nut-step

+ 90 - 0
src/packages/steps/doc.md

@@ -0,0 +1,90 @@
+# Steps 步骤条 组件
+
+### 介绍
+
+拆分展示某项流程的步骤,引导用户按流程完成任务或向用户展示当前状态。
+
+### 安装
+
+```javascript
+import { createApp } from 'vue';
+import { Steps } from '@nutui/nutui';
+
+const app = createApp();
+app.use(Steps);
+```
+
+## 代码演示
+
+### 基本用法
+
+```html
+<nut-steps current="1">
+  <nut-step title="进行中">1</nut-step>
+  <nut-step title="未开始">2</nut-step>
+  <nut-step title="未开始">3</nut-step>
+</nut-steps>
+```
+
+### 标题和描述信息
+
+```html
+<nut-steps current="2">
+  <nut-step title="已完成" content="步骤描述" icon="nutui-iconfont nut-icon-wanshangshide">1</nut-step>
+  <nut-step title="进行中" content="步骤描述">2</nut-step>
+  <nut-step title="未开始" content="步骤描述">3</nut-step>
+</nut-steps>
+```
+
+### 自定义图标
+
+```html
+<nut-steps current="1">
+  <nut-step title="已完成" icon="nutui-iconfont nut-icon-wanshangshide" status="error">1</nut-step>
+  <nut-step title="进行中" icon="nutui-iconfont nut-icon-notice">2</nut-step> 
+  <nut-step class="nut-step-wait" title="未开始" icon="nutui-iconfont nut-icon-notice">3</nut-step>
+</nut-steps>
+```
+
+### 竖向步骤条
+
+```html
+<nut-steps direction="vertical" current="2">
+  <nut-step title="已完成" icon="nutui-iconfont nut-icon-wanshangshide" content="您的订单已经打包完成,商品已发出" >1</nut-step>
+  <nut-step title="进行中" content="您的订单正在配送途中" >2</nut-step>
+  <nut-step title="未开始" content="收货地址为:北京市经济技术开发区科创十一街18号院京东大厦">3</nut-step>
+</nut-steps>
+```
+
+### 点状步骤和垂直方向
+```html
+<nut-steps direction="vertical" progressDot current="2">
+  <nut-step title="已完成" content="您的订单已经打包完成,商品已发出" >1</nut-step>
+  <nut-step title="进行中" content="您的订单正在配送途中">2</nut-step>
+  <nut-step title="未开始" content="收货地址为:北京市经济技术开发区科创十一街18号院京东大厦">3</nut-step>
+</nut-steps>
+```
+
+
+## API
+
+### Props
+
+#### nut-steps
+
+| 参数                   | 说明                                                        | 类型           | 默认值      |
+| ---------------------- | ----------------------------------------------------------- | -------------- | ----------- |
+| direction	             | 	显示方向,`horizontal`,`vertical`  | String        | horizontal  | 
+| current	               | 	当前所在的步骤           | Number、String        | 0       |
+| progressDot            |  点状步骤条     | Boolean | false         |
+
+
+
+#### nut-step
+
+| 参数           | 说明                   | 类型     | 默认值      |
+| ---------------- | ---------------------- | ------------ | ----------- |
+| title            | 流程步骤的标题         | String | 步骤 |
+| content          | 流程步骤的描述性文字       | String | 步骤描述 |
+| icon          | 图标       | String | - |
+| status           | 流程状态       | String | String、Number | "process"(可选值 "wait"、"process"、"finish"、"error" |

+ 60 - 15
src/packages/steps/index.vue

@@ -5,7 +5,14 @@
 </template>
 
 <script lang="ts">
-import { toRefs, computed, onMounted, reactive } from 'vue';
+import {
+  provide,
+  computed,
+  onMounted,
+  reactive,
+  watch,
+  onBeforeMount
+} from 'vue';
 import step from '@/packages/step/index.vue';
 import { createComponent } from '@/utils/create';
 const { create, componentName } = createComponent('steps');
@@ -19,42 +26,73 @@ export default create({
     },
     current: {
       type: String,
-      default: ''
+      default: 'false'
     },
     status: {
       validator(value) {
         return ['wait', 'process', 'finish', 'error'].includes(value);
       },
       default: 'process'
+    },
+    progressDot: {
+      type: Boolean,
+      default: false
     }
   },
   setup(props, { emit, slots }) {
     const state = reactive({
-      steps: {}
+      steps: {},
+      children: []
     });
     const classes = computed(() => {
       const prefixCls = componentName;
       return {
         [prefixCls]: true,
-        ['nut-steps-' + props.direction]: true
+        ['nut-steps-' + props.direction]: true,
+        [props.progressDot ? 'nut-steps-dot' : '']: true
       };
     });
+    onBeforeMount(() => {
+      console.log('onBeforeMount');
+      init();
+    });
     onMounted(() => {
-      if (slots.default) {
-        state.steps = slots.default();
-        console.log('slots1', state.steps.length);
-        console.log('slots2', state.steps[0].children);
-        states();
-      }
+      console.log('onMounted');
+      // init();
     });
-    function states() {
+    // watch(
+    //   () => props.current,
+    //   val => {
+    //     console.log()
+    //     states();
+    //   }
+    // );
+    // watch(
+    //   () =>  props.source,
+    //   val => {
+    //     init();
+    //   }
+    // )
+    const init = () => {
+      state.steps = (slots as any)?.default();
+      stepStates();
+    };
+    const stepStates = () => {
+      if (props.progressDot) {
+        console.log('state.steps', state.steps);
+        state.steps.dot = true;
+      }
       const total = state.steps.length;
       state.steps.forEach((child, index) => {
         child.stepNumber = index + 1;
+
+        state.children = index;
+        // console.log('data', state.children)
+
         if (props.direction === 'horizontal') {
           child.total = total;
         }
-        console.log('11', child);
+        // console.log('父', child);
         if (!child.currentStatus) {
           if (index == props.current - 1) {
             if (props.status != 'error') {
@@ -69,13 +107,20 @@ export default create({
           }
         }
         if (index + 1 === total) {
-          child.currentStatus += 'nut-step-last';
+          child.currentStatus += ' nut-step-last';
         }
       });
-    }
+    };
+    // provide('parent', {
+    //   slots
+    // });
+    provide('stepsParent', {
+      props,
+      state
+    });
     return {
       classes,
-      states
+      stepStates
     };
   }
 });