We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
有这样一个场景,页面渲染的信息是配置出来的,也就是我们渲染的内容是动态的。这种场景我们往往需要开发动态组件去支持。而动态组件可能会使用多种组件去实现。下面将介绍在 vue3 中,如何进行组件props 透传。
以下结合 element-plus 组件为例。
下面是动态组件里包含的几种 element-plus 组件:
而每一种 element-plus 组件都可能包含不同的 属性、事件、插槽、实例方法。比如 el-input 组件,如何让动态组件支持 el-input 所有的功能呢。一种方法是将 el-input 所有支持的属性、事件、插槽、实例方法在动态中都去实现一遍。但是如果动态组件也需要支持 el-date-picker 组件、 el-select 组件呢。那么工作量将会翻几番,并且当这几种组件有更新,你的动态组件也要进行调整。
如果要满足上面的所有需求,那么要支持: 1、属性透传:props属性、事件、style样式、class 名称 2、slots 插槽透传 3、v-model 指令的支持 4、实例方法的支持
注意:而为了同时满足上面的需求,目前发现只有使用 jsx方式才能支持,所以下面的示例也基本是基于 jsx 去实现了。
jsx
首先定义一个 props 去接收 element-plus 组件的动态属性
props: { // element-plus props elCompProps: { type: Object, default: null, }, }
属性绑定。使用对象结构的方式
// DynamicComp import { ElInput } from "element-plus"; export default defineComponent({ props: { // element-plus props elCompProps: { type: Object, default: null, }, }, setup(props, { attrs, slots, emit, expose }) { return () => ( <div> <ElInput /* 支持属性绑定、事件传递 */ {...props.elCompProps} > </ElInput> </div> ); }, });
而如果仅仅是支持该功能,也可以通过 template模板方式,可以通过 v-bind指令实现。这里不多介绍。
template
v-bind
在使用动态组件时,我们就可以轻易的将 props属性、事件、style样式、class 名称 进行透传了:
<script setup lang="tsx"> import DynamicComp from "./dynamic-comp"; const handlerValueChange = (val: string) => { alert(val); }; </script> <template> <div style="margin-top: 100px"> <DynamicComp :el-comp-props="{ /* attrbute props 可以支持 style、class */ style: 'width:300px;font-size:20px;', class: 'custom-class-name', placeholder: '随便录入', /* event props 记得加上前缀 'on' */ onChange: handlerValueChange, }" > </DynamicComp> </div> </template>
slots 插槽透传,目前只有 jsx方式可以支持(或许其他方式我不知道),而通过jsx方式实现起来也非常简单。
// DynamicComp import { ElInput } from "element-plus"; export default defineComponent({ setup(props, { attrs, slots, emit, expose }) { return () => ( <div> <ElInput > {/* 支持插槽 */} {slots} </ElInput> </div> ); }, });
使用动态组件的地方就和你直接使用 el-input 方式一样:
<script setup lang="tsx"> import DynamicComp from "./dynamic-comp"; </script> <template> <div style="margin-top: 100px"> <DynamicComp> <!-- el-input 组件支持的2种插槽 --> <template #suffix><div style="color: red">111</div></template> <template #prefix>222</template> </DynamicComp> </div> </template>
对于动态组件,支持v-model 会提高使用组件的友好度。v-mode 在jsx 中的使用,你也参考官方文档
// DynamicComp import { ElInput } from "element-plus"; export default defineComponent({ props: { // 可以通过 v-model 使用该组件 modelValue: [String, Number], }, setup(props, { attrs, slots, emit, expose }) { return () => ( <div> <ElInput /* 支持 v-model */ modelValue={props.modelValue} onUpdate:modelValue={(value) => { emit("update:modelValue", value); }} > </ElInput> </div> ); }, });
使用动态组件
<script setup lang="tsx"> import DynamicComp from "./dynamic-comp"; // v-model 值 const modelValue = ref("1123"); </script> <template> <div style="margin-top: 100px"> <DynamicComp v-model="modelValue"> </DynamicComp> </div> </template>
像 el-input 组件存在一些实例方法或者属性,我们同样可以在jsx中通过expose暴露出去。
expose
暴露el-input 组件的实例,我是通过定义一个变量去操作的:
// element-plus 组件的ref const elCompRef = ref<ComponentPublicInstance | null>(null);
动态组件实现:
// DynamicComp import { ElInput } from "element-plus"; import type { ComponentPublicInstance } from "vue"; export default defineComponent({ setup(props, { attrs, slots, emit, expose }) { // element-plus 组件的ref const elCompRef = ref<ComponentPublicInstance | null>(null); const currentInstanceMethod = () => { alert(1); }; expose({ // el-plus 相关组件的实例 elCompRef, // 动态组件本身提供的实例 test: currentInstanceMethod, }); return () => ( <div> <ElInput ref={elCompRef} > </ElInput> </div> ); }, });
<script setup lang="tsx"> import DynamicComp from "./dynamic-comp"; const dynamicCompRef = ref<InstanceType<typeof DynamicComp> | null>(null); const handlerValueChange = (val: string) => { alert(modelValue.value); }; const clearTest = () => { // @ts-ignore dynamicCompRef.value?.elCompRef.clear(); }; </script> <template> <div style="margin-top: 100px"> <DynamicComp ref="dynamicCompRef" > </DynamicComp> <button @click="clear">清除</button> </div> </template>
动态组件支持了上述的功能,你将大大减少维护成本。
--完--
The text was updated successfully, but these errors were encountered:
<template> <a-table ref="component" v-bind="props"> <template v-for="(slot, k) in $slots" :key="k" v-slot:[k]="slotProps"> <component :is="slot" v-bind="slotProps"></component> </template> </a-table> </template> <script lang="ts" setup> import { Table } from 'ant-design-vue' // 引入 antd 组件 import { tableProps } from 'ant-design-vue/es/table/Table' // 引入组件定义的 props import { onMounted, ref } from 'vue'; const props = defineProps(tableProps()) // 定义 props const component = ref() </script>
slots 是可以通过 <component :is="slot"> 传递的
slots
<component :is="slot">
Sorry, something went wrong.
@SublimeCT 谢谢你的方案
No branches or pull requests
前言
有这样一个场景,页面渲染的信息是配置出来的,也就是我们渲染的内容是动态的。这种场景我们往往需要开发动态组件去支持。而动态组件可能会使用多种组件去实现。下面将介绍在 vue3 中,如何进行组件props 透传。
动态组件
下面是动态组件里包含的几种 element-plus 组件:
而每一种 element-plus 组件都可能包含不同的 属性、事件、插槽、实例方法。比如 el-input 组件,如何让动态组件支持 el-input 所有的功能呢。一种方法是将 el-input 所有支持的属性、事件、插槽、实例方法在动态中都去实现一遍。但是如果动态组件也需要支持 el-date-picker 组件、 el-select 组件呢。那么工作量将会翻几番,并且当这几种组件有更新,你的动态组件也要进行调整。
如果要满足上面的所有需求,那么要支持:
1、属性透传:props属性、事件、style样式、class 名称
2、slots 插槽透传
3、v-model 指令的支持
4、实例方法的支持
注意:而为了同时满足上面的需求,目前发现只有使用
jsx
方式才能支持,所以下面的示例也基本是基于jsx
去实现了。属性透传
首先定义一个 props 去接收 element-plus 组件的动态属性
属性绑定。使用对象结构的方式
而如果仅仅是支持该功能,也可以通过
template
模板方式,可以通过v-bind
指令实现。这里不多介绍。在使用动态组件时,我们就可以轻易的将 props属性、事件、style样式、class 名称 进行透传了:
slots 插槽透传
slots 插槽透传,目前只有
jsx
方式可以支持(或许其他方式我不知道),而通过jsx
方式实现起来也非常简单。使用动态组件的地方就和你直接使用 el-input 方式一样:
v-model 指令的支持
对于动态组件,支持v-model 会提高使用组件的友好度。v-mode 在jsx 中的使用,你也参考官方文档
使用动态组件
实例方法的支持
像 el-input 组件存在一些实例方法或者属性,我们同样可以在jsx中通过
expose
暴露出去。暴露el-input 组件的实例,我是通过定义一个变量去操作的:
动态组件实现:
使用动态组件
总结
动态组件支持了上述的功能,你将大大减少维护成本。
--完--
The text was updated successfully, but these errors were encountered: