Appearance
Button组件
一.定义组件所需Props 
components/button/src/button.ts
import { ExtractPropTypes, PropType } from 'vue'
export type Size = 'tiny' | 'small' | 'medium' | 'large'
export type Type =
  | 'primary'
  | 'success'
  | 'warning'
  | 'danger'
  | 'info'
  | 'default'
  | ''
export const buttonProps = {
  size: String as PropType<Size>, // 按钮大小
  type: {
    type: String as PropType<Type>, // 按钮格式
    validator: (val: string) => {
      return [
        'default',
        'primary',
        'success',
        'warning',
        'danger',
        'info',
        ''
      ].includes(val)
    },
    default: ''
  },
  iconPlacement: {
    // 图标位置
    type: String as PropType<'left' | 'right'>,
    default: 'left'
  },
  nativeType: {
    // 按钮类型
    type: String as PropType<'button' | 'submit' | 'reset'>,
    default: 'button'
  },
  // 状态 加载、禁用、圆角
  loading: Boolean,
  disabled: Boolean,
  round: Boolean
}
export const buttonEmits = {
  click: (e: MouseEvent) => e instanceof MouseEvent
}
export type ButtonProps = ExtractPropTypes<typeof buttonProps>
export type buttonEmits = typeof buttonEmits
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
二.button.vue 结构实现 
<template>
  <button
    :class="[
      bem.b(),
      bem.m(type),
      bem.m(size),
      bem.is('loading', loading),
      bem.is('disabled', disabled),
      bem.is('round', round)
    ]"
    :disabled="disabled || loading"
    :type="nativeType"
  >
    <slot></slot>
  </button>
</template>
<script lang="ts" setup>
import { createNamespace } from '@zi-shui/utils/create'
import { buttonEmits, buttonProps } from './button'
defineOptions({
  name: 'ZButton'
})
// 获取属性,及事件
const props = defineProps(buttonProps)
const emit = defineEmits(buttonEmits)
const bem = createNamespace('button')
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
三.Button入口编写
import { withInstall } from '@zi-shui/utils/withInstall'
import _Button from './src/button.vue'
const Button = withInstall(_Button)
export default Button // 导出Icon组件
export type { buttonProps } from './src/button'
declare module 'vue' {
  export interface GlobalComponents {
    ZButton: typeof Button
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
四.Button组件试用
<ZButton
    :disabled="true"
    :loading="true"
    :round="true"
    type="primary"
    size="tiny"
 >爱你😘</ZButton>
1
2
3
4
5
6
7
2
3
4
5
6
7
五.组件功能实现
1).样式编写
先准备点公共样式,放到theme-chalk/src/common/var.scss
$color-primary: #409eff;
$color-white: #ffffff;
$color-black: #000000;
$color-success: #67c23a;
$color-warning: #e6a23c;
$color-danger: #f56c6c;
$color-info: #909399;
1
2
3
4
5
6
7
2
3
4
5
6
7
@use 'mixins/mixins' as *;
@use 'common/var' as *;
@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
@include b(button) {
  // BEM规范
  align-items: center;
  display: inline-flex;
  cursor: pointer;
  outline: none;
  border: #fafafa;
  border-radius: 5px;
  user-select: none;
  min-height: 40px;
  line-height: 1;
  vertical-align: middle;
  padding: 0 20px;
  @include m(tiny) {
    padding: 0 15px;
  }
  @include m(medium) {
    padding: 0 20px;
  }
  @include m(small) {
    padding: 0 18px;
  }
  @include m(large) {
    padding: 0 25px;
  }
  @include when(disabled) {
    // 针对不同类型处理
    &,
    &:hover,
    &:focus {
      cursor: not-allowed;
    }
  }
  @include when(loading) {
    // 针对不同类型处理
    svg.loading {
      animation: rotate 1s linear infinite;
    }
  }
  @include when(round) {
    border-radius: 20px;
  }
  @include m(primary) {
    //渲染不同类型的button
    @include button-variant($color-white, $color-primary, $color-primary);
  }
  @include m(success) {
    @include button-variant($color-white, $color-success, $color-success);
  }
  @include m(warning) {
    @include button-variant($color-white, $color-warning, $color-warning);
  }
  @include m(danger) {
    @include button-variant($color-white, $color-danger, $color-danger);
  }
  @include m(info) {
    @include button-variant($color-white, $color-info, $color-info);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
提供scss的辅助方法,方便后续使用
@mixin button-variant($color, $background-color, $border-color) {
    color: $color;
    background: $background-color;
    border-color: $border-color;
}
1
2
3
4
5
2
3
4
5
2).插槽显示处理
编写个loading组件用于显示loading 、loadingIcon.vue
<template>
  <ZIcon>
    <svg
      xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      viewBox="0 0 1024 1024"
      class="loading"
    >
      <path
        d="M512 1024c-69.1 0-136.2-13.5-199.3-40.2C251.7 958 197 921 150 874c-47-47-84-101.7-109.8-162.7C13.5 648.2 0 581.1 0 512c0-19.9 16.1-36 36-36s36 16.1 36 36c0 59.4 11.6 117 34.6 171.3c22.2 52.4 53.9 99.5 94.3 139.9c40.4 40.4 87.5 72.2 139.9 94.3C395 940.4 452.6 952 512 952c59.4 0 117-11.6 171.3-34.6c52.4-22.2 99.5-53.9 139.9-94.3c40.4-40.4 72.2-87.5 94.3-139.9C940.4 629 952 571.4 952 512c0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9a437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.2C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7c26.7 63.1 40.2 130.2 40.2 199.3s-13.5 136.2-40.2 199.3C958 772.3 921 827 874 874c-47 47-101.8 83.9-162.7 109.7c-63.1 26.8-130.2 40.3-199.3 40.3z"
        fill="currentColor"
      ></path>
    </svg>
  </ZIcon>
</template>
<script lang="ts" setup>
import ZIcon from '@zi-shui/components/icon'
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3).实现功能
<template>
  <button
    :class="[
      bem.b(),
      bem.m(type),
      bem.m(size),
      bem.is('loading', loading),
      bem.is('disabled', disabled),
      bem.is('round', round)
    ]"
    :disabled="disabled || loading"
    :type="nativeType"
    @click="handleClick"
  >
    <template v-if="iconPlacement == 'left'">
      <LoadingComponent v-if="loading"></LoadingComponent>
      <template v-else-if="slots.icon">
        <Component :is="slots.icon"></Component>
      </template>
    </template>
    <slot></slot>
    <template v-if="iconPlacement == 'right'">
      <LoadingComponent v-if="loading"></LoadingComponent>
      <template v-else-if="slots.icon">
        <Component :is="slots.icon"></Component>
      </template>
    </template>
  </button>
</template>
<script lang="ts" setup>
import { createNamespace } from '@zi-shui/utils/create'
import LoadingComponent from './loadingIcon.vue'
import { useSlots } from 'vue'
import { buttonEmits, buttonProps } from './button'
defineOptions({
  name: 'ZButton'
})
// 获取属性,及事件
defineProps(buttonProps)
const emit = defineEmits(buttonEmits)
const bem = createNamespace('button')
const slots = useSlots()
const handleClick = (e: MouseEvent) => {
  emit('click', e)
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
六.文档编写
# 按钮 Button
按钮用来触发一些操作。
## 基础用法
<script setup lang="ts">
import { BatteryDead,BatteryFullSharp,Heart } from '@vicons/ionicons5'
const handleClick = () =>{
  alert('🙂')
}
</script>
<ZButton>Default</ZButton>
<ZButton type="primary">Primary</ZButton>
<ZButton type="success">Success</ZButton>
<ZButton type="warning">Warning</ZButton>
<ZButton type="danger">Danger</ZButton>
<ZButton type="info">Info</ZButton>
```vue
<template>
  <ZButton>Default</ZButton>
  <ZButton type="primary">Primary</ZButton>
  <ZButton type="success">Success</ZButton>
  <ZButton type="warning">Warning</ZButton>
  <ZButton type="danger">Danger</ZButton>
  <ZButton type="info">Info</ZButton>
</template>
```
## 禁用
<ZButton type="primary" disabled>Primary</ZButton>
```html
<ZButton type="primary" disabled>Primary</ZButton>
```
## 图标
<ZButton :round="true" size="large" @click="handleClick">
<template #icon>
<ZIcon size="20">
<Heart />
</ZIcon>
</template>
我爱你
</ZButton>
<ZButton :round="true" :loading="true">
<template #icon>
<ZIcon size="20">
<Heart />
</ZIcon>
</template>
我爱你
</ZButton>
<ZButton :round="true" icon-placement="right">
<template #icon>
<ZIcon size="20">
<Heart />
</ZIcon>
</template>
我爱你
</ZButton>
```html
<ZButton :round="true" size="large" @click="handleClick">
  <template #icon>
    <ZIcon size="20">
      <Heart />
    </ZIcon>
  </template>
  我爱你
</ZButton>
<ZButton :round="true" :loading="true">
  <template #icon>
    <ZIcon size="20">
      <Heart />
    </ZIcon>
  </template>
  我爱你
</ZButton>
<ZButton :round="true" icon-placement="right">
  <template #icon>
    <ZIcon size="20">
      <Heart />
    </ZIcon>
  </template>
  我爱你
</ZButton>
```
## 事件
<ZButton @click="handleClick">
点我啊
</ZButton>
```html
<ZButton @click="handleClick"> 点我啊 </ZButton>
```
## API
### Button Props
| 名称           | 类型                                                   | 默认值  | 说明                 |
| -------------- | ------------------------------------------------------ | ------- | -------------------- |
| size           | tiny \| small \| medium \| large                       | medium  | 按钮大小             |
| type           | primary \| success \|warning \|danger \|info\| default | default | 按钮颜色             |
| icon-placement | left \| right                                          | left    | icon 位置            |
| nativeType     | button \| reset \| submit                              | button  | 按钮类型             |
| disabled       | boolean                                                | false   | 按钮是否禁用         |
| loading        | boolean                                                | false   | 按钮是否显示加载状态 |
| round          | boolean                                                | false   | 按钮是否显示圆角     |
### Button Slots
| 名称    | 默认值    | 说明       |
| ------- | --------- | ---------- |
| default | undefined | 按钮的内容 |
| icon    | undefined | 按钮的图标 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128