use-drawer.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import type {
  2. DrawerApiOptions,
  3. DrawerProps,
  4. ExtendedDrawerApi,
  5. } from './drawer';
  6. import { defineComponent, h, inject, nextTick, provide, reactive } from 'vue';
  7. import { useStore } from '@vben-core/shared/store';
  8. import VbenDrawer from './drawer.vue';
  9. import { DrawerApi } from './drawer-api';
  10. const USER_DRAWER_INJECT_KEY = Symbol('VBEN_DRAWER_INJECT');
  11. export function useVbenDrawer<
  12. TParentDrawerProps extends DrawerProps = DrawerProps,
  13. >(options: DrawerApiOptions = {}) {
  14. // Drawer一般会抽离出来,所以如果有传入 connectedComponent,则表示为外部调用,与内部组件进行连接
  15. // 外部的Drawer通过provide/inject传递api
  16. const { connectedComponent } = options;
  17. if (connectedComponent) {
  18. const extendedApi = reactive({});
  19. const Drawer = defineComponent(
  20. (props: TParentDrawerProps, { attrs, slots }) => {
  21. provide(USER_DRAWER_INJECT_KEY, {
  22. extendApi(api: ExtendedDrawerApi) {
  23. // 不能直接给 reactive 赋值,会丢失响应
  24. // 不能用 Object.assign,会丢失 api 的原型函数
  25. Object.setPrototypeOf(extendedApi, api);
  26. },
  27. options,
  28. });
  29. checkProps(extendedApi as ExtendedDrawerApi, {
  30. ...props,
  31. ...attrs,
  32. ...slots,
  33. });
  34. return () => h(connectedComponent, { ...props, ...attrs }, slots);
  35. },
  36. {
  37. inheritAttrs: false,
  38. name: 'VbenParentDrawer',
  39. },
  40. );
  41. return [Drawer, extendedApi as ExtendedDrawerApi] as const;
  42. }
  43. const injectData = inject<any>(USER_DRAWER_INJECT_KEY, {});
  44. const mergedOptions = {
  45. ...injectData.options,
  46. ...options,
  47. } as DrawerApiOptions;
  48. mergedOptions.onOpenChange = (isOpen: boolean) => {
  49. options.onOpenChange?.(isOpen);
  50. injectData.options?.onOpenChange?.(isOpen);
  51. };
  52. const api = new DrawerApi(mergedOptions);
  53. const extendedApi: ExtendedDrawerApi = api as never;
  54. extendedApi.useStore = (selector) => {
  55. return useStore(api.store, selector);
  56. };
  57. const Drawer = defineComponent(
  58. (props: DrawerProps, { attrs, slots }) => {
  59. return () =>
  60. h(VbenDrawer, { ...props, ...attrs, drawerApi: extendedApi }, slots);
  61. },
  62. {
  63. inheritAttrs: false,
  64. name: 'VbenDrawer',
  65. },
  66. );
  67. injectData.extendApi?.(extendedApi);
  68. return [Drawer, extendedApi] as const;
  69. }
  70. async function checkProps(api: ExtendedDrawerApi, attrs: Record<string, any>) {
  71. if (!attrs || Object.keys(attrs).length === 0) {
  72. return;
  73. }
  74. await nextTick();
  75. const state = api?.store?.state;
  76. if (!state) {
  77. return;
  78. }
  79. const stateKeys = new Set(Object.keys(state));
  80. for (const attr of Object.keys(attrs)) {
  81. if (stateKeys.has(attr) && !['class'].includes(attr)) {
  82. // connectedComponent存在时,不要传入Drawer的props,会造成复杂度提升,如果你需要修改Drawer的props,请使用 useVbenDrawer 或者api
  83. console.warn(
  84. `[Vben Drawer]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Drawer, please use useVbenDrawer or api.`,
  85. );
  86. }
  87. }
  88. }