index.taro.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <template>
  2. <view>
  3. <nut-overlay
  4. v-if="overlay"
  5. :visible="visible"
  6. :close-on-click-overlay="closeOnClickOverlay"
  7. :class="overlayClass"
  8. :style="overlayStyle"
  9. :z-index="zIndex"
  10. :lock-scroll="lockScroll"
  11. :duration="duration"
  12. @click="onClickOverlay"
  13. />
  14. <Transition :name="transitionName" @after-enter="onOpened" @after-leave="onClosed">
  15. <view v-show="visible" :class="classes" :style="popStyle" @click="onClick">
  16. <slot v-if="showSlot"></slot>
  17. <view
  18. v-if="closeable"
  19. @click="onClickCloseIcon"
  20. class="nutui-popup__close-icon"
  21. :class="'nutui-popup__close-icon--' + closeIconPosition"
  22. >
  23. <nut-icon :name="closeIcon" size="12px" />
  24. </view>
  25. </view>
  26. </Transition>
  27. </view>
  28. </template>
  29. <script lang="ts">
  30. import {
  31. onMounted,
  32. onBeforeMount,
  33. onBeforeUnmount,
  34. onActivated,
  35. onDeactivated,
  36. watch,
  37. computed,
  38. reactive,
  39. PropType,
  40. CSSProperties,
  41. toRefs,
  42. getCurrentInstance
  43. } from 'vue';
  44. import { useLockScroll } from '../popup/use-lock-scroll';
  45. import { overlayProps } from '../overlay/index.taro.vue';
  46. import overlay from '../overlay/index.taro.vue';
  47. import icon from '../icon/index.taro.vue';
  48. import { createComponent } from '../../utils/create';
  49. const { componentName, create } = createComponent('popup');
  50. let _zIndex = 2000;
  51. export const popupProps = {
  52. ...overlayProps,
  53. position: {
  54. type: String,
  55. default: 'center'
  56. },
  57. transition: String,
  58. style: {
  59. type: Object as PropType<CSSProperties>
  60. },
  61. popClass: {
  62. type: String,
  63. default: ''
  64. },
  65. closeable: {
  66. type: Boolean,
  67. default: false
  68. },
  69. closeIconPosition: {
  70. type: String,
  71. default: 'top-right'
  72. },
  73. closeIcon: {
  74. type: String,
  75. default: 'close'
  76. },
  77. destroyOnClose: {
  78. type: Boolean,
  79. default: true
  80. },
  81. teleport: {
  82. type: [String, Element],
  83. default: 'body'
  84. },
  85. overlay: {
  86. type: Boolean,
  87. default: true
  88. },
  89. round: {
  90. type: Boolean,
  91. default: false
  92. }
  93. };
  94. export default create({
  95. children: [overlay],
  96. components: {
  97. [overlay.name]: overlay,
  98. [icon.name]: icon
  99. },
  100. props: {
  101. ...popupProps
  102. },
  103. emits: ['click', 'click-close-icon', 'open', 'close', 'opend', 'closed', 'update:visible', 'click-overlay'],
  104. setup(props, { emit }) {
  105. const { proxy } = getCurrentInstance() as any;
  106. const state = reactive({
  107. zIndex: props.zIndex ? (props.zIndex as number) : _zIndex,
  108. showSlot: true,
  109. transitionName: `popup-fade-${props.position}`,
  110. overLayCount: 1,
  111. keepAlive: false
  112. });
  113. const [lockScroll, unlockScroll] = useLockScroll(() => props.lockScroll);
  114. const classes = computed(() => {
  115. const prefixCls = componentName;
  116. return {
  117. [prefixCls]: true,
  118. ['round']: props.round,
  119. [`popup-${props.position}`]: true,
  120. [props.popClass]: true
  121. };
  122. });
  123. const popStyle = computed(() => {
  124. return {
  125. zIndex: state.zIndex,
  126. animationDuration: props.duration ? `${props.duration}s` : 'initial',
  127. ...props.style
  128. };
  129. });
  130. const open = () => {
  131. if (!props.visible) {
  132. if (props.zIndex !== undefined) {
  133. _zIndex = Number(props.zIndex);
  134. }
  135. emit('update:visible', true);
  136. lockScroll();
  137. state.zIndex = ++_zIndex;
  138. }
  139. if (props.destroyOnClose) {
  140. state.showSlot = true;
  141. }
  142. emit('open');
  143. };
  144. const close = () => {
  145. if (props.visible) {
  146. unlockScroll();
  147. emit('update:visible', false);
  148. if (props.destroyOnClose) {
  149. setTimeout(() => {
  150. state.showSlot = false;
  151. emit('close');
  152. }, +props.duration * 1000);
  153. }
  154. }
  155. };
  156. const onClick = (e: Event) => {
  157. emit('click', e);
  158. };
  159. const onClickCloseIcon = (e: Event) => {
  160. emit('click-close-icon', e);
  161. close();
  162. };
  163. const onClickOverlay = (e: Event) => {
  164. if (props.closeOnClickOverlay) {
  165. emit('click-overlay', e);
  166. close();
  167. }
  168. };
  169. const onOpened = (e: Event) => {
  170. emit('opend', e);
  171. };
  172. const onClosed = (e: Event) => {
  173. emit('closed', e);
  174. };
  175. onMounted(() => {
  176. props.transition
  177. ? (state.transitionName = props.transition)
  178. : (state.transitionName = `popup-slide-${props.position}`);
  179. props.visible && open();
  180. });
  181. onBeforeUnmount(() => {
  182. props.visible && close();
  183. });
  184. onBeforeMount(() => {
  185. if (props.visible) {
  186. unlockScroll();
  187. }
  188. });
  189. onActivated(() => {
  190. if (state.keepAlive) {
  191. emit('update:visible', true);
  192. state.keepAlive = false;
  193. }
  194. });
  195. onDeactivated(() => {
  196. if (props.visible) {
  197. close();
  198. state.keepAlive = true;
  199. }
  200. });
  201. watch(
  202. () => props.visible,
  203. (value) => {
  204. if (value) {
  205. open();
  206. } else {
  207. close();
  208. }
  209. }
  210. );
  211. watch(
  212. () => props.position,
  213. (value) => {
  214. value === 'center' ? (state.transitionName = 'popup-fade') : (state.transitionName = `popup-slide-${value}`);
  215. }
  216. );
  217. return {
  218. ...toRefs(state),
  219. popStyle,
  220. classes,
  221. onClick,
  222. onClickCloseIcon,
  223. onClickOverlay,
  224. onOpened,
  225. onClosed
  226. };
  227. }
  228. });
  229. </script>