| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- <template>
- <view :catch-move="lockScroll">
- <nut-overlay
- v-if="overlay"
- :visible="visible"
- :close-on-click-overlay="closeOnClickOverlay"
- :class="overlayClass"
- :style="overlayStyle"
- :z-index="zIndex"
- :lock-scroll="lockScroll"
- :duration="duration"
- @click="onClickOverlay"
- />
- <Transition :name="transitionName" @after-enter="onOpened" @after-leave="onClosed">
- <view v-show="visible" :class="classes" :style="popStyle" @click="onClick">
- <div class="nutui-popup__content-wrapper" v-show="showSlot"><slot></slot></div>
- <view
- v-if="closed"
- @click="onClickCloseIcon"
- class="nutui-popup__close-icon"
- :class="'nutui-popup__close-icon--' + closeIconPosition"
- >
- <nut-icon :name="closeIcon" size="12px" />
- </view>
- </view>
- </Transition>
- </view>
- </template>
- <script lang="ts">
- import {
- onMounted,
- onBeforeMount,
- onBeforeUnmount,
- onActivated,
- onDeactivated,
- watch,
- computed,
- reactive,
- PropType,
- CSSProperties,
- toRefs,
- getCurrentInstance
- } from 'vue';
- import { useLockScroll } from '../popup/use-lock-scroll';
- import { overlayProps } from '../overlay/index.taro.vue';
- import overlay from '../overlay/index.taro.vue';
- import icon from '../icon/index.taro.vue';
- import { createComponent } from '@/packages/utils/create';
- const { componentName, create } = createComponent('popup');
- let _zIndex = 2000;
- export const popupProps = {
- ...overlayProps,
- position: {
- type: String,
- default: 'center'
- },
- transition: String,
- style: {
- type: Object as PropType<CSSProperties>
- },
- popClass: {
- type: String,
- default: ''
- },
- closeable: {
- type: Boolean,
- default: false
- },
- closeIconPosition: {
- type: String,
- default: 'top-right'
- },
- closeIcon: {
- type: String,
- default: 'close'
- },
- destroyOnClose: {
- type: Boolean,
- default: true
- },
- teleport: {
- type: [String, Element],
- default: 'body'
- },
- overlay: {
- type: Boolean,
- default: true
- },
- round: {
- type: Boolean,
- default: false
- },
- safeAreaInsetBottom: {
- type: Boolean,
- default: false
- }
- };
- export default create({
- children: [overlay],
- components: {
- [overlay.name]: overlay,
- [icon.name]: icon
- },
- props: {
- ...popupProps
- },
- emits: ['click', 'click-close-icon', 'open', 'close', 'opend', 'closed', 'update:visible', 'click-overlay'],
- setup(props, { emit }) {
- const state = reactive({
- zIndex: props.zIndex ? (props.zIndex as number) : _zIndex,
- showSlot: true,
- transitionName: `popup-fade-${props.position}`,
- overLayCount: 1,
- keepAlive: false,
- closed: props.closeable
- });
- const [lockScroll, unlockScroll] = useLockScroll(() => props.lockScroll);
- const classes = computed(() => {
- const prefixCls = componentName;
- return {
- [prefixCls]: true,
- ['round']: props.round,
- [`popup-${props.position}`]: true,
- [`popup-${props.position}--safebottom`]: props.position === 'bottom' && props.safeAreaInsetBottom,
- [props.popClass]: true
- };
- });
- const popStyle = computed(() => {
- return {
- zIndex: state.zIndex,
- animationDuration: props.duration ? `${props.duration}s` : 'initial',
- ...props.style
- };
- });
- const open = () => {
- if (props.zIndex != 2000) {
- _zIndex = Number(props.zIndex);
- }
- emit('update:visible', true);
- lockScroll();
- state.zIndex = ++_zIndex;
- if (props.destroyOnClose) {
- state.showSlot = true;
- }
- emit('open');
- };
- const close = () => {
- if (props.visible) {
- unlockScroll();
- emit('update:visible', false);
- if (props.destroyOnClose) {
- setTimeout(() => {
- state.showSlot = false;
- emit('close');
- }, +props.duration * 1000);
- }
- }
- };
- const onClick = (e: Event) => {
- emit('click', e);
- };
- const onClickCloseIcon = (e: Event) => {
- emit('click-close-icon', e);
- close();
- };
- const onClickOverlay = (e: Event) => {
- if (props.closeOnClickOverlay) {
- emit('click-overlay', e);
- close();
- }
- };
- const onOpened = (e: Event) => {
- emit('opend', e);
- };
- const onClosed = (e: Event) => {
- emit('closed', e);
- };
- onMounted(() => {
- props.transition
- ? (state.transitionName = props.transition)
- : (state.transitionName = `popup-slide-${props.position}`);
- props.visible && open();
- });
- onBeforeUnmount(() => {
- props.visible && close();
- });
- onBeforeMount(() => {
- if (props.visible) {
- unlockScroll();
- }
- });
- onActivated(() => {
- if (state.keepAlive) {
- emit('update:visible', true);
- state.keepAlive = false;
- }
- });
- onDeactivated(() => {
- if (props.visible) {
- close();
- state.keepAlive = true;
- }
- });
- watch(
- () => props.visible,
- (value) => {
- if (value) {
- open();
- } else {
- close();
- }
- }
- );
- watch(
- () => props.position,
- (value) => {
- value === 'center' ? (state.transitionName = 'popup-fade') : (state.transitionName = `popup-slide-${value}`);
- }
- );
- watch(
- () => props.closeable,
- (value) => {
- state.closed = value;
- }
- );
- return {
- ...toRefs(state),
- popStyle,
- classes,
- onClick,
- onClickCloseIcon,
- onClickOverlay,
- onOpened,
- onClosed
- };
- }
- });
- </script>
|