ActionSheet.svelte 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. <script>
  2. import { createEventDispatcher, getContext } from 'svelte';
  3. import Popup from '../popup/Popup.svelte';
  4. import zh_CN from '../../lang/zh_CN';
  5. // 定义事件派发器
  6. // Define event dispatcher
  7. const dispatch = createEventDispatcher();
  8. // 当前语言
  9. // current language
  10. const currentLang = getContext('STDF_lang') || zh_CN;
  11. const actionSheetLang = currentLang.actionSheet;
  12. // 是否显示
  13. // Whether to show
  14. export let visible = false;
  15. // 标题
  16. // Title
  17. export let title = '';
  18. //标题对齐方式
  19. //Title alignment
  20. export let titleAlign = 'center';
  21. // 菜单项,style有 normal、theme、danger、disabled
  22. // Menu items, style has normal, theme, danger, disabled
  23. export let actions = [];
  24. // 弹出层参数
  25. // Popup parameters
  26. export let popup = {};
  27. // 是否显示取消选项。
  28. // Whether to show the cancel option.
  29. export let showCancel = false;
  30. // 取消选项文本
  31. // Cancel option text
  32. export let cancelText = actionSheetLang.cancelText;
  33. // 点击选项是否关闭
  34. // Click option to close
  35. export let actionClosable = true;
  36. // 对齐方式
  37. // Alignment
  38. export let align = 'center';
  39. // 标题对齐方式
  40. // Title alignment
  41. const titleAlignClass = { left: 'text-left', center: 'text-center', right: 'text-right' };
  42. // 选项样式
  43. // Option style
  44. const stateClass = {
  45. normal: ' ',
  46. theme: ' text-primary dark:text-dark ',
  47. danger: ' text-error ',
  48. disabled: ' text-black/20 dark:text-white/20 ',
  49. };
  50. // 图片圆角
  51. // Image radius
  52. const imgRadiusClass = { none: 'rounded-none', base: 'rounded', full: 'rounded-full', lg: 'rounded-lg' };
  53. // 图片对齐方式
  54. // Image alignment
  55. const alignClass = { left: 'justify-start pl-4', center: 'justify-center', right: 'justify-end pr-4' };
  56. // 计算弹出层高度
  57. // Calculate the height of the popup
  58. const getTransitionDistanceunc = (title, showCancel, actions) => {
  59. const titleHeight = title ? 40 : 0;
  60. const cancelHeight = showCancel ? 56 : 0;
  61. // 循环 actions,如果有 desc 高度为 61, 没有 desc 高度为 56,分割线每条1px,计算总高度
  62. // Loop actions, if there is desc, the height is 61, if there is no desc, the height is 56, and the divider is 1px each, and the total height is calculated
  63. const actionsHeight = actions.reduce((total, item) => {
  64. return total + (item.desc ? 60 : 56);
  65. }, 0);
  66. return titleHeight + cancelHeight + actionsHeight + actions.length - 1;
  67. };
  68. // 取消按钮点击事件
  69. // Click event of cancel button
  70. const cancelFunc = () => {
  71. visible = false;
  72. dispatch('cancel'); //派发取消事件
  73. };
  74. // 选项点击事件,如果选项不可点击,不触发事件,如果可点击,触发事件,如果 actionClosable 为 true,关闭弹出层
  75. // Click event of action, if the action is not clickable, the event will not be triggered, if it is clickable, the event will be triggered, and if actionClosable is true, the popup will be closed
  76. const clickActionFunc = (index, item) => {
  77. if (item.style !== 'disabled') {
  78. dispatch('clickAction', { index, item }); //派发选项点击事件,返回选项索引和选项对象
  79. if (actionClosable) {
  80. visible = false;
  81. }
  82. }
  83. };
  84. // 监听 visible 变化,如果为 true,派发 open 事件,如果为 false,派发 close 事件
  85. // Listen to the change of visible, if it is true, dispatch the open event, if it is false, dispatch the close event
  86. $: {
  87. if (visible) {
  88. dispatch('open');
  89. } else {
  90. dispatch('close');
  91. }
  92. }
  93. </script>
  94. <Popup bind:visible size={0} maskClosable transitionDistance={getTransitionDistanceunc(title, showCancel, actions)} {...popup}>
  95. {#if title}
  96. <div
  97. class={`truncate text-xs text-black/50 dark:text-white/50 border-b border-black/5 dark:border-white/5 h-10 flex flex-col justify-center ${
  98. titleAlignClass[titleAlign] || titleAlignClass['left']
  99. }`}
  100. >
  101. {title}
  102. </div>
  103. {/if}
  104. <div>
  105. {#each actions as item, index}
  106. <!-- svelte-ignore a11y-click-events-have-key-events -->
  107. <!-- svelte-ignore a11y-no-static-element-interactions -->
  108. <div
  109. class={`${item.style !== 'disabled' ? 'active:scale-90 ' : ''}transition-all flex items-center gap-2 ${
  110. alignClass[align] || alignClass['center']
  111. }`}
  112. on:click={() => clickActionFunc(index, item)}
  113. >
  114. <!-- 图片 -->
  115. {#if item.showImg}
  116. <div class={`w-6 h-6 overflow-hidden ${imgRadiusClass[item.imgRadius] || 'rounded-full'}`}>
  117. <img class="w-full h-full object-cover" src={item.imgSrc} alt="" />
  118. </div>
  119. {/if}
  120. <div>
  121. <div
  122. class={`truncate text-center font-bold${stateClass[item.style] || stateClass.normal}flex flex-col justify-center${
  123. item.desc ? ' h-10' : ' h-14'
  124. }`}
  125. >
  126. {item.content}
  127. </div>
  128. {#if item.desc}
  129. <div class="truncate text-center text-xs pb-1 text-black/50 dark:text-white/40">{item.desc}</div>
  130. {/if}
  131. </div>
  132. </div>
  133. {#if index !== actions.length - 1}
  134. <div class="h-px w-full bg-black/5 dark:bg-white/5" />
  135. {/if}
  136. {/each}
  137. </div>
  138. {#if showCancel}
  139. <div class="bg-black/5 dark:bg-white/5 h-2" />
  140. <!-- svelte-ignore a11y-click-events-have-key-events -->
  141. <!-- svelte-ignore a11y-no-static-element-interactions -->
  142. <div class="active:scale-90 transition-all text-center h-12 flex flex-col justify-center" on:click={cancelFunc}>{cancelText}</div>
  143. {/if}
  144. </Popup>