feat(projects): 增加useModal hooks,并添加lodash-es依赖

This commit is contained in:
Yanbowen 2021-12-24 12:08:19 +08:00
parent c9c5ca9989
commit d9ccce69df
12 changed files with 195 additions and 10 deletions

View File

@ -58,6 +58,7 @@
"@iconify/vue": "^3.1.1",
"@types/bmapgl": "^0.0.5",
"@types/chroma-js": "^2.1.3",
"@types/lodash-es": "^4.17.5",
"@types/qs": "^6.9.7",
"@typescript-eslint/eslint-plugin": "^5.8.0",
"@typescript-eslint/parser": "^5.8.0",
@ -77,6 +78,7 @@
"eslint-plugin-vue": "^8.2.0",
"husky": "^7.0.4",
"lint-staged": "^12.1.3",
"lodash-es": "^4.17.21",
"patch-package": "^6.4.7",
"postinstall-postinstall": "^2.1.0",
"prettier": "^2.5.1",

View File

@ -10,6 +10,7 @@ specifiers:
'@iconify/vue': ^3.1.1
'@types/bmapgl': ^0.0.5
'@types/chroma-js': ^2.1.3
'@types/lodash-es': ^4.17.5
'@types/qs': ^6.9.7
'@typescript-eslint/eslint-plugin': ^5.8.0
'@typescript-eslint/parser': ^5.8.0
@ -35,6 +36,7 @@ specifiers:
form-data: ^4.0.0
husky: ^7.0.4
lint-staged: ^12.1.3
lodash-es: ^4.17.21
naive-ui: ^2.23.1
patch-package: ^6.4.7
pinia: ^2.0.8
@ -88,6 +90,7 @@ devDependencies:
'@iconify/vue': registry.npmmirror.com/@iconify/vue/3.1.1_vue@3.2.26
'@types/bmapgl': registry.npmmirror.com/@types/bmapgl/0.0.5
'@types/chroma-js': registry.npmmirror.com/@types/chroma-js/2.1.3
'@types/lodash-es': registry.npmmirror.com/@types/lodash-es/4.17.5
'@types/qs': registry.npmmirror.com/@types/qs/6.9.7
'@typescript-eslint/eslint-plugin': registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.8.0_836011a006f4f5d67178564baf2b6d34
'@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser/5.8.0_eslint@8.5.0+typescript@4.5.4
@ -107,6 +110,7 @@ devDependencies:
eslint-plugin-vue: registry.npmmirror.com/eslint-plugin-vue/8.2.0_eslint@8.5.0
husky: registry.npmmirror.com/husky/7.0.4
lint-staged: registry.npmmirror.com/lint-staged/12.1.3
lodash-es: registry.nlark.com/lodash-es/4.17.21
patch-package: registry.npmmirror.com/patch-package/6.4.7
postinstall-postinstall: registry.npmmirror.com/postinstall-postinstall/2.1.0
prettier: registry.npmmirror.com/prettier/2.5.1
@ -2073,7 +2077,6 @@ packages:
resolution: {integrity: sha1-Q+YmxG5lkbd1C+srUBFzkMYJ4+4=, registry: https://registry.npm.taobao.org/, tarball: https://registry.nlark.com/lodash-es/download/lodash-es-4.17.21.tgz}
name: lodash-es
version: 4.17.21
dev: false
registry.nlark.com/lodash.get/4.4.2:
resolution: {integrity: sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/lodash.get/download/lodash.get-4.4.2.tgz}
@ -3877,7 +3880,7 @@ packages:
dev: true
registry.npmmirror.com/@commitlint/load/15.0.0:
resolution: {integrity: sha512-Ak1YPeOhvxmY3ioe0o6m1yLGvUAYb4BdfGgShU8jiTCmU3Mnmms0Xh/kfQz8AybhezCC3AmVTyBLaBZxOHR8kg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@commitlint/load/download/@commitlint/load-15.0.0.tgz?cache=0&sync_timestamp=1637131952207&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40commitlint%2Fload%2Fdownload%2F%40commitlint%2Fload-15.0.0.tgz}
resolution: {integrity: sha512-Ak1YPeOhvxmY3ioe0o6m1yLGvUAYb4BdfGgShU8jiTCmU3Mnmms0Xh/kfQz8AybhezCC3AmVTyBLaBZxOHR8kg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@commitlint/load/download/@commitlint/load-15.0.0.tgz}
name: '@commitlint/load'
version: 15.0.0
engines: {node: '>=v12'}
@ -4122,13 +4125,11 @@ packages:
version: 4.17.5
dependencies:
'@types/lodash': registry.npmmirror.com/@types/lodash/4.14.178
dev: false
registry.npmmirror.com/@types/lodash/4.14.178:
resolution: {integrity: sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/lodash/download/@types/lodash-4.14.178.tgz}
name: '@types/lodash'
version: 4.14.178
dev: false
registry.npmmirror.com/@types/minimist/1.2.2:
resolution: {integrity: sha1-7nceK6Sz3Fs3KTXVSf2WF780W4w=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/minimist/download/@types/minimist-1.2.2.tgz}

View File

@ -1,7 +1,11 @@
<template>
<div v-if="reloadFlag" class="relative">
<slot></slot>
<div v-show="showPlaceholder" class="absolute-lt w-full h-full" :class="placeholderClass">
<div
v-show="showPlaceholder"
class="absolute-lt w-full h-full border-[var(--border-color)] border-1px dark:bg-dark"
:class="placeholderClass"
>
<div v-show="loading" class="absolute-center">
<n-spin :show="true" :size="loadingSize" />
</div>

View File

@ -0,0 +1,58 @@
<template>
<NModal
v-model:show="show"
v-bind="getModalProps"
:loading="loading"
@positive-click="positiveClick"
@negative-click="negativeClick"
>
{{ isFunction(props.content) ? props.content() : props.content }}
</NModal>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { NModal } from 'naive-ui';
import type { ModalProps } from 'naive-ui';
import { omit, isFunction } from 'lodash-es';
export interface HookModalProps extends Partial<ModalProps> {
closeModal?: () => void;
}
const props = withDefaults(defineProps<HookModalProps>(), {
closeModal: () => {}
});
/** 重组NModal的props */
const getModalProps = computed(() => omit(props, ['onPositiveClick', 'onNegativeClick']));
const loading = ref(false);
const show = computed({
get() {
return props.show ?? false;
},
set(val: boolean) {
if (Object.is(val, false)) {
props.closeModal?.();
}
}
});
async function positiveClick() {
loading.value = true;
try {
await props?.onPositiveClick?.();
show.value = false;
} catch (error) {
loading.value = false;
} finally {
loading.value = false;
}
}
async function negativeClick() {
await props?.onNegativeClick?.();
show.value = false;
}
</script>

View File

@ -5,5 +5,6 @@ import BannerSvg from './BannerSvg/index.vue';
import HoverContainer from './HoverContainer/index.vue';
import LoadingEmptyWrapper from './LoadingEmptyWrapper/index.vue';
import IconSelect from './IconSelect/index.vue';
import Modal from './Modal/index.vue';
export { NaiveProvider, SystemLogo, LoginBg, BannerSvg, HoverContainer, LoadingEmptyWrapper, IconSelect };
export { NaiveProvider, SystemLogo, LoginBg, BannerSvg, HoverContainer, LoadingEmptyWrapper, IconSelect, Modal };

View File

@ -2,5 +2,6 @@ import useContext from './useContext';
import useBoolean from './useBoolean';
import useLoading from './useLoading';
import useLoadingEmpty from './useLoadingEmpty';
import useModal from './useModal';
export { useContext, useBoolean, useLoading, useLoadingEmpty };
export { useContext, useBoolean, useLoading, useLoadingEmpty, useModal };

View File

@ -0,0 +1,45 @@
import { createVNode, render, getCurrentInstance, nextTick } from 'vue';
import type { AppContext, ComponentInternalInstance } from 'vue';
import { Modal } from '@/components';
import type { HookModalProps } from '@/components/common/Modal/index.vue';
export default function useModal() {
let modalInstance: ComponentInternalInstance;
const appContext = getCurrentInstance()?.appContext as AppContext;
function getModalInstance() {
if (modalInstance) {
return modalInstance;
}
const container = document.createElement('template');
const VNode = createVNode(Modal);
VNode.appContext = appContext;
render(VNode, container);
modalInstance = VNode.component!;
modalInstance.props.closeModal = hideModal;
return modalInstance;
}
async function showModal(props: HookModalProps) {
const modalInstance = getModalInstance();
Object.assign<any, HookModalProps>(modalInstance?.props, {
...props,
show: true
});
await nextTick();
}
function hideModal() {
Object.assign<any, HookModalProps>(modalInstance?.props, { show: false });
}
return {
showModal,
hideModal
};
}
export type ModalInstance = ReturnType<typeof useModal>;

View File

@ -32,6 +32,7 @@ export type RouteKey =
| 'component'
| 'component_button'
| 'component_card'
| 'component_modal'
| 'component_table'
| 'multi-menu'
| 'multi-menu_first'

View File

@ -219,6 +219,14 @@ const routeConstMap = new Map<RouteKey, RouteConst>([
title: '卡片'
}
],
[
'component_modal',
{
name: 'component_modal',
path: '/component/modal',
title: '弹窗'
}
],
[
'component_table',
{

View File

@ -1,6 +1,6 @@
import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '@/layouts';
import { ComponentButton, ComponentCard, ComponentTable } from '@/views';
import { ComponentButton, ComponentCard, ComponentModal, ComponentTable } from '@/views';
import { routeName, routePath, routeTitle } from '../constant';
const component: RouteRecordRaw = {
@ -34,6 +34,16 @@ const component: RouteRecordRaw = {
keepAlive: true
}
},
{
name: routeName('component_modal'),
path: routePath('component_modal'),
component: ComponentModal,
meta: {
title: routeTitle('component_modal'),
requiresAuth: true,
keepAlive: true
}
},
{
name: routeName('component_table'),
path: routePath('component_table'),

View File

@ -1,5 +1,6 @@
import ComponentButton from './button/index.vue';
import ComponentCard from './card/index.vue';
import ComponentModal from './modal/index.vue';
import ComponentTable from './table/index.vue';
export { ComponentButton, ComponentCard, ComponentTable };
export { ComponentButton, ComponentCard, ComponentModal, ComponentTable };

View File

@ -0,0 +1,53 @@
<template>
<n-card title="弹窗" class="h-full shadow-sm rounded-16px">
<n-grid cols="s:1 m:2" responsive="screen" :x-gap="16" :y-gap="16">
<n-grid-item>
<n-card title="普通弹窗" class="min-h-180px">
<n-button @click="visible = true">来吧</n-button>
<n-modal v-model:show="visible">
<n-card style="width: 600px" title="模态框" :bordered="false" size="huge">
<template #header-extra></template>
内容
<template #footer>尾部</template>
</n-card>
</n-modal>
</n-card>
</n-grid-item>
<n-grid-item>
<n-card title="Hook弹窗" class="min-h-180px">
<n-button @click="handleShow">来吧</n-button>
</n-card>
</n-grid-item>
</n-grid>
</n-card>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { NCard, NGrid, NGridItem, NModal, NButton } from 'naive-ui';
import { useModal } from '@/hooks';
const visible = ref(false);
const { showModal } = useModal();
function handleShow() {
showModal({
title: '确认',
content: () => '111',
maskClosable: true,
preset: 'dialog',
positiveText: '确认',
bordered: false,
onPositiveClick: () => {
return new Promise(resolve => {
setTimeout(() => {
resolve(111);
}, 3000);
});
},
onNegativeClick: () => {},
negativeText: '算了'
});
}
</script>
<style lang="scss" scoped></style>