| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- <template>
- <view :class="classes" @click="handleClick">
- <div
- v-if="destroy"
- :class="[
- 'nut-dialog-wrapper',
- customClass,
- { 'nut-dialog-image-wrapper': type === 'image' }
- ]"
- :id="id"
- >
- <transition :name="animation ? 'nutFade' : ''">
- <div
- :class="'nut-dialog-mask'"
- :style="{ background: maskBgStyle }"
- @click="modalClick"
- v-show="curVisible"
- ></div>
- </transition>
- <transition :name="animation ? 'nutEase' : ''">
- <div class="nut-dialog-box" v-show="curVisible" @click="modalClick">
- <div class="nut-dialog" @click.stop>
- <a
- href="javascript:;"
- v-if="closeBtn"
- @click="closeBtnClick"
- class="nut-dialog-close"
- ></a>
- <template v-if="type === 'image'">
- <a
- href="javascript:;"
- @click="imageLinkClick"
- class="nut-dialog-link"
- >
- <img :src="imgSrc" class="nut-dialog-image" alt />
- </a>
- </template>
- <template v-else>
- <div class="nut-dialog-body">
- <span
- class="nut-dialog-title"
- v-html="title"
- v-if="title"
- ></span>
- <div
- class="nut-dialog-content"
- v-if="isShowContent"
- :style="{ textAlign }"
- >
- <slot></slot>
- </div>
- <div
- class="nut-dialog-content"
- v-html="content"
- v-else-if="content"
- :style="{ textAlign }"
- ></div>
- </div>
- <div class="nut-dialog-footer" v-if="!noFooter">
- <button
- class="nut-dialog-btn nut-dialog-cancel"
- v-if="!noCancelBtn"
- @click="cancelBtnClick(cancelAutoClose)"
- >{{ cancelBtnTxt }}</button
- >
- <button
- class="nut-dialog-btn nut-dialog-ok"
- v-if="!noOkBtn"
- :class="{ disabled: okBtnDisabled }"
- :disabled="okBtnDisabled"
- @click="okBtnClick"
- >{{ okBtnTxt }}</button
- >
- </div>
- </template>
- </div>
- </div>
- </transition>
- </div>
- </view>
- </template>
- <script lang="ts">
- import { ref, onMounted, watch, watchEffect, computed } from 'vue';
- import { createComponent } from '@/utils/create';
- const { componentName, create } = createComponent('dialog');
- const lockMaskScroll = (bodyCls => {
- let scrollTop = 0;
- return {
- afterOpen: function() {
- scrollTop =
- (document.scrollingElement && document.scrollingElement.scrollTop) ||
- document.body.scrollTop;
- document.body.classList.add(bodyCls);
- document.body.style.top = -scrollTop + 'px';
- },
- beforeClose: function() {
- if (document.body.classList.contains(bodyCls)) {
- document.body.classList.remove(bodyCls);
- if (document.scrollingElement) {
- document.scrollingElement.scrollTop = scrollTop;
- }
- }
- }
- };
- })('dialog-open');
- export default create({
- props: {
- id: {
- type: String,
- default: ''
- },
- title: {
- type: String,
- default: ''
- },
- content: {
- type: String,
- default: ''
- },
- type: {
- type: String,
- default: ''
- },
- link: {
- type: String,
- default: ''
- },
- imgSrc: {
- type: String,
- default: ''
- },
- animation: {
- type: Boolean,
- default: true
- },
- lockBgScroll: {
- type: Boolean,
- default: false
- },
- visible: {
- type: Boolean,
- default: false
- },
- closeBtn: {
- type: Boolean,
- default: false
- },
- closeOnClickModal: {
- type: Boolean,
- default: true
- },
- noFooter: {
- type: Boolean,
- default: false
- },
- noOkBtn: {
- type: Boolean,
- default: false
- },
- noCancelBtn: {
- type: Boolean,
- default: false
- },
- cancelBtnTxt: {
- type: String,
- default: '取消'
- },
- okBtnTxt: {
- type: String,
- default: '确定'
- },
- okBtnDisabled: {
- type: Boolean,
- default: false
- },
- cancelAutoClose: {
- type: Boolean,
- default: true
- },
- textAlign: {
- type: String,
- default: 'center'
- },
- onOkBtn: {
- type: Function,
- default: null
- },
- onCloseBtn: {
- type: Function,
- default: null
- },
- onCancelBtn: {
- type: Function,
- default: null
- },
- closeCallback: {
- type: Function,
- default: null
- },
- onClickImageLink: {
- type: Function,
- default: null
- },
- maskBgStyle: {
- type: String,
- default: ''
- },
- canDestroy: {
- type: Boolean,
- default: true
- },
- customClass: {
- type: String,
- default: ''
- },
- closeOnPopstate: {
- type: Boolean,
- default: false
- }
- },
- // emits: ['click'],
- setup(props, { emit, slots }) {
- const curVisible = ref(false);
- let destroy = ref(true);
- onMounted(() => {
- curVisible.value = props.visible;
- });
- const isShowContent = computed(() => {
- return slots.default;
- });
- const todestroy = () => {
- if (!props.canDestroy) {
- destroy = ref(false);
- }
- };
- const close = (target?: string) => {
- emit('close', target);
- emit('close-callback', target);
- todestroy();
- if (
- typeof props.closeCallback === 'function' &&
- props.closeCallback(target) === false
- ) {
- return;
- }
- curVisible.value = false;
- };
- const modalClick = () => {
- if (!props.closeOnClickModal) {
- return;
- }
- close('modal');
- };
- const okBtnClick = () => {
- emit('ok-btn-click');
- if (typeof props.onOkBtn === 'function') {
- props.onOkBtn.call(props);
- }
- };
- const cancelBtnClick = (autoClose: boolean) => {
- emit('cancel-btn-click');
- if (!autoClose) {
- return;
- }
- if (typeof props.onCancelBtn === 'function') {
- if (props.onCancelBtn.call(props) === false) {
- return;
- }
- }
- close('cancelBtn');
- };
- const closeBtnClick = () => {
- if (typeof props.onCloseBtn === 'function') {
- if (props.onCloseBtn.call(props) === false) {
- return;
- }
- }
- close('closeBtn');
- };
- //图片类型弹窗中的链接点击事件,默认跳转
- const imageLinkClick = () => {
- if (
- props.onClickImageLink &&
- props.onClickImageLink.call(props) === false
- ) {
- return;
- }
- if (props.link) {
- location.href = props.link;
- }
- };
- const handleClick = (event: Event) => {
- emit('click', event);
- };
- onMounted(() => {
- if (props.closeOnPopstate) {
- window.addEventListener('popstate', function() {
- close();
- });
- }
- });
- watchEffect(() => {
- if (props.lockBgScroll) {
- //锁定or解锁页面滚动
- lockMaskScroll[curVisible.value ? 'afterOpen' : 'beforeClose']();
- }
- });
- watch(
- () => props.visible,
- val => {
- curVisible.value = val;
- }
- );
- const classes = computed(() => {
- return {
- [componentName]: true
- };
- });
- return {
- handleClick,
- curVisible,
- destroy,
- modalClick,
- close,
- todestroy,
- okBtnClick,
- cancelBtnClick,
- closeBtnClick,
- imageLinkClick,
- isShowContent,
- classes
- };
- }
- });
- </script>
- <style lang="scss">
- @import 'index.scss';
- </style>
|