
[toc]
需求分析
- 借鉴 AntD/ Bulma/Eleme/iView/Vuetify 等
- 需求
- 可以有不同的等级
- 可以是链接,可以是文字
- 可以 click/focus/鼠标悬浮
- 可以设置size
- 可以设置状态为禁用
- 可以设置状态为加载中
API 设计
1
2
3
4
5
6
7
8
|
<Button @click=?
@focus=?
@mouseover=?
theme="button/link/text"
level="big/normal/small"
disabled
loading>
</Button>
|
Button.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<template>
<button>
<slot></slot>
</button>
</template>
<script lang="ts">
export default {
name: 'Button'
};
</script>
<style lang="scss" scoped>
</style>
|
ButtonDemo.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<script setup lang="ts">
import Button from '@/lib/Button.vue';
</script>
<template>
<h1>Button 示例</h1>
<h2>示例一</h2>
<div>
<Button>按钮</Button>
</div>
</template>
<script lang="ts">
export default {
name: 'ButtonDemo'
};
</script>
|
- 使用
<slot></slot>来让UI库用户自定义button内部的结构
Button.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<script setup lang="ts">
import Button from '@/lib/Button.vue';
const onClick = () => {
console.log('hi');
};
</script>
<template>
<h1>Button 示例</h1>
<h2>示例一</h2>
<div>
<Button @click="onClick">
按钮
</Button>
</div>
</template>
<script lang="ts">
export default {
name: 'ButtonDemo'
};
</script>
|
- vue自动将绑定的事件传到子组件中根节点上
- 不用再处理事件代理逻辑
这样会带来一个问题:点击外层元素,而未点击到button元素上也会触发事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// Button.vue
<template>
<div>
<button>
<slot></slot>
</button>
</div>
</template>
<script lang="ts">
export default {
name: 'Button'
};
</script>
<style lang="scss" scoped>
div {
border: 1px solid red;
}
</style>
|
让div不继承属性
- 使用
inheritAttrs: false来禁用 Attribute 继承,。偶人为true
- 此时事件没有绑在子组件任何一个元素上
Button.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<template>
<div>
<button>
<slot></slot>
</button>
</div>
</template>
<script lang="ts">
export default {
name: 'Button',
inheritAttrs: false
};
</script>
<style lang="scss" scoped>
div {
border: 1px solid red;
}
</style>
|
Vue 3 属性绑定细节
- 在父组件/元素上写
$attrs,实现所有属性的祖传孙元素
$attrs会以对象的形式展示所有祖元素/组件上的属性
- 使用
v-bind="$attrs",此处不可缩写
Button.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<template>
<div>
<button v-bind="$attrs">
<slot></slot>
</button>
</div>
</template>
<script lang="ts">
export default {
name: 'Button',
inheritAttrs: false
};
</script>
<style lang="scss" scoped>
div {
border: 1px solid red;
}
</style>
|
- 小结:让组件内部某一个节点拥有外部(使用该组件时)传入的(写在标签上的)所有属性,而其他节点不同时拥有的情况
- 在
setup中使用context.attrs将属性结构出来
- 在
script setup语法糖中,使用useAttrs()获取$attrs来处理
- 解构赋值取出属性
const {size, ...rest} = attrs;
- 在外层div上绑定
<div :size="size">...</div>
- 在button上绑定其他剩余属性
<button v-bind="rest"><slot></slot></button>
Button.vue
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
|
<script setup lang="ts">
import {useAttrs} from 'vue';
const attrs = useAttrs();
const {size, ...rest} = attrs;
</script>
<template>
<div :size="size">
<button v-bind="rest">
<slot></slot>
</button>
</div>
</template>
<script lang="ts">
export default {
name: 'Button',
inheritAttrs: false
};
</script>
<style lang="scss" scoped>
div {
border: 1px solid red;
}
</style>
|
小结
Vue3属性绑定
- 默认所有属性都绑定到根元素
- 使用
inheritAttrs: false可以取消默认绑定
- 使用
$attrs或者context.attrs获取使用该组件时绑定的所有属性
- 单文件组件