Vue前端组件封装

前端UI组件封装,要考虑传递属性事件、插槽,必要的话传ref出来

举例封装一个Vuetify组件 v-data-table

传递参数

mounted钩子打印this.$attrs就是组件传递的的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- 子组件 -->
<template>
<div>
<p>props a: {{ a }}</p>
<p>$attrs: {{ $attrs }}</p>
</div>
</template>

<script>
export default {
props: {
a: {
type: String,
default: () => (''),
},
},
mounted() {
console.log(this.$attrs); // { "b": "2", "c": "3" }
},
}
</script>

在父组件传参a b c this.$attrs 打印 b c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- 父组件 -->
<template>
<div class="pa-4">
<h1>测试组件封装 传参 a="1"b="2"c="3"</h1>
<Son
a="1"
b="2"
c="3"
/>
</div>
</template>
<script>
import Son from './Son.vue';

export default {
components: {
Son,
},
}
</script>

默认把需要传递的参数,给子组件的UI框架组件添加上 v-bind="$attrs"

传递事件

子组件添加v-on="$listeners"

传递插槽

子组件循环$scopedSlots

ref传递

把UI组件上定义的的ref传给父组件(vue不支持ref传递,会有可能打破单项数据流,写出💩⛰️

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mounted() {
// console.log(this.$attrs, 'attrs 除了props以外的参数');
// console.log(this.$slots, 'slots 插槽');
// console.log(this.$refs.grid, '子组件 grid refs');
// console.log(this.$listeners, '接收到的事件');

// #region 把表格的ref暴露给container 建议少用ref以避免打破单向数据流
// TODO vue 不支持 ref传参
// const grid = this.$refs.grid;
// for (const key in grid) {
// this[key] = grid[key]; // ? 🙅
// }
// #endregion
},

mounted钩子ref注册全局方法

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
<template>
<v-app>
<ios-header :loginDialog="$refs.loginDialog"/>
<v-main>
<info-alert ref="infoAlert" />
<pepper-snackbar />
<pepper-comfirm ref="confirm" />
<login-dialog ref="loginDialog" />
<pepper-loading />
<router-view />
</v-main>
</v-app>
</template>

<script>
import PepperComfirm from '@pepper/pepperComponents/core/PepperConfirm.vue';

export default {
name: 'App',
components: {
PepperComfirm,
},
async mounted() {
this.$root.$confirm = this.$refs.confirm;
},
// ..

demo

DataTable.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
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
<template>
<v-data-table
v-bind="$attrs"
v-on="$listeners"
>
<template
v-for="(_, name) in $scopedSlots"
#[name]="data"
>
<slot
:name="name"
v-bind="data"
/>
</template>
</v-data-table>
</template>

<script>

export default {
name: 'DataTable',
props: {
},
data() {
return {
};
},
computed: {
},
methods: {
},
};
</script>
<style lang="scss" scoped>
::v-deep .v-data-table-header {
background-color: #3B3D4D !important;
tr {
border-radius: 5px;
}
// background: green !important;
}
.v-data-table {
background-color: transparent !important;
}

::v-deep .v-data-table__selected {
background: linear-gradient(45deg,
var(--v-primary-base) -200px,
rgba(255, 255, 255, 0)) !important;
}

::v-deep tr:hover:not(.v-data-table__expanded__content):not(.v-data-table__empty-wrapper) {
background: linear-gradient(45deg,
var(--v-primary-base) -200px,
rgba(255, 255, 255, 0)) !important;
}
</style>

作者

Wei Mo

发布于

2024-02-05

更新于

2024-04-10

许可协议

评论