创建Button组件
<template>
<button>
<slot/>
</button>
</template>
父组件属性传递
<template>
<div>
<Button @click="handleClick">你好</Button>
</div>
</template>
- 默认父组件传递的所有属性都绑定到子组件的根元素
- 使用
inheritAttrs: false
可以取消默认绑定 - 使用
$attrs
或者context.attrs
获取所有属性 - 使用
v-bind="$attrs"
批量绑定属性 - 使用
const {size, ...rest} = context.attrs
将属性分解
给Button添加theme基础样式
<div>
<Button>你好</Button>
<Button theme="button">你好</Button>
<Button theme="link">你好</Button>
<Button theme="text">你好</Button>
</div>
<template>
<button class="pika-button" :class="{[`theme-${theme}`]: theme}">
<slot/>
</button>
</template>
<script lang="ts">
export default {
props: {
theme: {
type: String,
default: 'button'
}
}
}
</script>
添加基础样式
<style lang="scss" scoped>
$h: 32px;
$border-color: #d9d9d9;
$color: #333;
$blue: #40a9ff;
$radius: 4px;
.pika-button {
box-sizing: border-box;
height: $h;
padding: 0 12px;
cursor: pointer;
display: inline-flex;
justify-content: center;
align-items: center;
white-space: nowrap;
background: white;
color: $color;
border: 1px solid $border-color;
border-radius: $radius;
box-shadow: 0 1px 0px fade-out(black, 0.95);
& + & {
margin-left: 8px;
}
&:hover,
&:focus {
color: $blue;
border-color: $blue;
}
&:focus {
outline: none;
}
&::-moz-focus-inner {
border: 0;
}
}
</style>
- inline-flex和flex的区别:inline-flex把容器变成内联元素, flex把容器变成块级元素
- white-space: nowrap;不换行
- ::-moz-focus-inner兼容火狐浏览器
UI组件库的CSS注意事项
- 不能使用scoped
- 因为data-v-xxx中的xxx每次运行都可能不同
- 必须输出稳定不变的class选择器,方便使用者覆盖
- 必须加前缀
- .button不行,容易被使用者覆盖,.pika-button可以
- .theme-link不行,容易被使用者覆盖 .pika-theme-link可以
CSS最小影响原则
UI库的CSS不能影响到用户的CSS
在lib目录中新建pika.scss
用户要使用UI库,就要先引入这个css, 所有class以pika-开头或者class中包含pika-的就使用这个css[class^="pika-"],
[class*=" pika-"] {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 16px;
font-family: -apple-system, "Noto Sans", "Helvetica Neue", Helvetica,
"Nimbus Sans L", Arial, "Liberation Sans", "PingFang SC", "Hiragino Sans GB",
"Noto Sans CJK SC", "Source Han Sans SC", "Source Han Sans CN",
"Microsoft YaHei", "Wenquanyi Micro Hei", "WenQuanYi Zen Hei", "ST Heiti",
SimHei, "WenQuanYi Zen Hei Sharp", sans-serif;
}
注意顺序,必须在最开始import ```typescript import ‘./lib/pika.scss’ import ‘./index.scss’ import { router } from ‘./router’; import { createApp } from ‘vue’ import App from ‘./App.vue’
createApp(App) .use(router) .mount(‘#app’)
<a name="epQhE"></a>
### 支持theme属性
```css
&.pika-theme-link {
border-color: transparent;
box-shadow: none;
color: $blue;
&:hover, &:focus {
color: lighten($blue, 10%)
}
}
&.pika-theme-text {
border-color: transparent;
box-shadow: none;
color: inherit;
&:hover, &:focus {
background: darken(white, 5%);
}
}
支持size属性
使用计算属性
setup(props){
const {theme, size} = props
const classes = computed(()=>{
return {
[`pika-theme-${theme}`]: theme,
[`pika-size-${size}`]: size,
}
})
return {
classes
}
}
&.pika-size-big {
font-size: 24px;
height: 48px;
padding: 0 16px;
}
&.pika-size-small {
font-size: 12px;
height: 20px;
padding: 0 4px;
}
支持level属性
<div>
<Button theme="link" size="big" level="main">大大大</Button>
<Button theme="link">普普通</Button>
<Button theme="link" size="small" level="danger">小小小</Button>
</div>
支持disabled
props需指定为Boolean值
props: {
disabled: {
type: Boolean,
default: false
}
}
当传了props时则认为是true
<Button disabled>禁用</Button>
<template>
<button class="pika-button" :class="classes" :disabled="disabled">
<slot />
</button>
</template>
&.pika-theme-button {
&[disabled] {
cursor: not-allowed;
color: $grey;
&:hover {
border-color: $grey;
}
}
}
&.pika-theme-link,
&.pika-theme-text {
&[disabled] {
cursor: not-allowed;
color: $grey;
}
}
支持loading
<Button loading>加载中</Button>
<button class="pika-button" :class="classes" :disabled="disabled">
<span v-if="loading" class="pika-loadingIndicator"></span>
<slot />
</button>
@keyframes pika-spin {
0% {
transform: rotate(0deg)
}
100% {
transform: rotate(360deg)
}
}
.pika-loadingIndicator {
width: 14px;
height: 14px;
display: inline-block;
margin-right: 4px;
border-radius: 8px;
border-color: $blue $blue $blue transparent;
border-style: solid;
border-width: 2px;
animation: pika-spin 1s infinite linear;
}