有些情况第三方的UI组件库不能满足我们自己的需求,需要定制一些功能上去,有没有一种可能,vue也可以写像写面向对象语言一样,继承一个组件,然后定制一些功能呢
以下案例基于vue3实现
例如我现在有一个组件NButton
,现在想给这个组件加上一个权限判断,当登录用户没有此按钮的权限时,将对此按钮不可见或禁用等
extends
文档地址:https://cn.vuejs.org/api/options-composition.html#extends
详细信息:
使一个组件可以继承另一个组件的组件选项。
我们通过extends: NButton
继承一个组件库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
<script lang="ts"> import { defineComponent } from 'vue' import { NButton } from "naive-ui"
export default defineComponent({ extends: NButton, setup: NButton.setup, props: { permission: [String] }, mounted() { if (this.permission !== "resource:add") { this.$el.style.display = "none"; } } }); </script>
|
在home文件中导入此组件
1 2 3 4 5 6 7 8 9 10
| <template> <div> <YButton type="success" permission="resource:add">按钮</YButton> </div> </template>
<script setup lang="ts"> import YButton from "@/components/YButton.vue" </script>
|
可以看到我们按钮自定义的按钮显示出来了
这时我们把permission
删掉试试,按钮就被隐藏了,这时也达到了开头提到的需求
1
| <YButton type="success">按钮</YButton>
|
但是此方法在只能继承某个组件,不能对组件加入一些其他dom元素,万一我还需要加个其他标签怎么办呢
且此方法因为获取父组件的setup,所以在ts中,语法检查会报错,望大佬解释以下
透传 Attributes
文档地址:https://cn.vuejs.org/guide/components/attrs.html
“透传 attribute”指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 class、style 和 id。
深层组件继承
文档地址:https://cn.vuejs.org/guide/components/attrs.html#nested-component-inheritance
透传的 attribute 不会包含 上声明过的 props 或是针对 emits 声明事件的 v-on 侦听函数,换句话说,声明过的 props 和侦听函数被 “消费”了。
以上面的作为例子,简单说就是,当一个NButton
作为根组件时,绑定在YButton
上的 attribute 会直接传给里面的NButton
上
下面我们用这种方式进行编码
1 2 3 4 5 6 7 8 9 10 11
| <template> <n-button><slot></slot></n-button> </template>
<script> import { defineComponent } from 'vue';
export default defineComponent({
}); </script>
|
可以看到我们的按钮正常显示了,然后我们再加入我们的权限验证
1 2 3 4 5 6 7 8 9 10
| export default defineComponent({ props: { permission: String }, mounted() { if (this.$props.permission !== "resource:add") { this.$el.style.display = "none" } } });
|
但是这时仍还有一个问题就是,目前我们只能挂载默认插槽,具名插槽没有显示出来,我们可以用循环$slots
来插入进去,
1 2 3
| <n-button> <slot v-for="(s, name) in $slots" :name="name"></slot> </n-button>
|
添加其他html标签
文档地址:禁用 Attributes 继承
因为 template 中的根标签或默认继承 Attributes,所以我们可以使用inheritAttrs
选项来禁用继承
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
<template> <div v-if="$props.permission === 'resource:add'"> <n-button v-bind="$attrs"> <slot v-for="(s, name) in $slots" :name="name"></slot> </n-button> 我是新增的元素 </div> </template>
<script lang="ts"> import { defineComponent } from 'vue';
export default defineComponent({ inheritAttrs: false, props: { permission: String }, mounted() { } }); </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
<YButton type="success" permission="resource:add"> <template #icon> <n-icon> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"> <path d="M256 48C141.31 48 48 141.32 48 256c0 114.86 93.14 208 208 208c114.69 0 208-93.31 208-208c0-114.87-93.13-208-208-208zm0 313a94 94 0 0 1 0-188h4.21l-14.11-14.1a14 14 0 0 1 19.8-19.8l40 40a14 14 0 0 1 0 19.8l-40 40a14 14 0 0 1-19.8-19.8l18-18c-2.38-.1-5.1-.1-8.1-.1a66 66 0 1 0 66 66a14 14 0 0 1 28 0a94.11 94.11 0 0 1-94 94z" fill="currentColor"/> </svg> </n-icon> </template> 刷新 </YButton>
|