TabBar.svelte 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. <script>
  2. import { createEventDispatcher } from 'svelte';
  3. import Icon from '../icon/Icon.svelte';
  4. export let labels = []; //选项卡内容组 label group of TabBar
  5. export let active = 0; //当前选中的选项卡索引 index of active label
  6. export let line = false; //底部是否显示线条 whether to show line at the bottom
  7. export let lineW = 4; //线条占当前Tab宽度的比例 line width ratio of current Tab
  8. export let love = false; //是否开启关爱版 whether to open love version
  9. export let injClass = ''; //TabBar最外层注入CSS TabBar outermost layer injection CSS
  10. export let tabInjClass = ''; //tab注入CSS tab injection CSS
  11. export let activeTabInjClass = ''; //选中tab注入CSS selected tab injection CSS
  12. export let activeInjClass = ''; //线条注入CSS line injection CSS
  13. const dispatch = createEventDispatcher(); //事件派发器 event dispatcher
  14. const clickFun = i => {
  15. active = i;
  16. //派发TabBar点击事件,active表示点击的Tab索引值,即labels索引值
  17. //Dispatch TabBar click event, active indicates the index value of the clicked Tab, that is, the index value of labels
  18. dispatch('change', active);
  19. };
  20. let tabW = 0;
  21. $: activeW = tabW / labels.length / lineW;
  22. $: activeLeft = active * (tabW / labels.length) + tabW / labels.length / 2 - activeW / 2;
  23. </script>
  24. <div bind:clientWidth={tabW} class={`bg-white dark:bg-gray1 relative ${injClass}`} style="padding-bottom: env(safe-area-inset-bottom);">
  25. {#if line}
  26. <div
  27. class={`mx-auto rounded-full h-[2px] absolute transition-all bottom-px bg-primary dark:bg-dark ${activeInjClass}`}
  28. style="width:{lineW < 1 ? tabW / labels.length : activeW < 2 ? 2 : activeW}px;left:{lineW < 1
  29. ? active * (tabW / labels.length)
  30. : activeLeft}px;"
  31. />
  32. {/if}
  33. <div class={`flex justify-between`}>
  34. {#each labels as label, i}
  35. <!-- svelte-ignore a11y-click-events-have-key-events -->
  36. <div
  37. on:click={() => clickFun(i)}
  38. class={`flex-1 flex flex-col justify-center text-center py-1 active:opacity-80 cursor-pointer ${
  39. i === active ? 'text-primary dark:text-dark' : 'text-gray6'
  40. } ${love ? 'text-lg' : 'text-sm'} ${tabInjClass} ${i === active && activeTabInjClass}`}
  41. >
  42. {#if label.icon}
  43. <div class={`${!label.text && 'py-2'}`}>
  44. <i class:hidden={i !== active}>
  45. <Icon
  46. {...label.icon}
  47. name={label.activeIcon ? label.activeIcon.name : label.icon.name}
  48. size={i === active
  49. ? (label.activeIcon && label.activeIcon.size * (love ? 1.2 : 1)) || label.icon.size * (love ? 1.2 : 1)
  50. : label.icon.size * (love ? 1.2 : 1)}
  51. top={0}
  52. />
  53. </i>
  54. <i class:hidden={i === active}>
  55. <Icon
  56. {...label.icon}
  57. name={label.icon.name}
  58. size={i === active
  59. ? (label.activeIcon && label.activeIcon.size * (love ? 1.2 : 1)) || label.icon.size * (love ? 1.2 : 1)
  60. : label.icon.size * (love ? 1.2 : 1)}
  61. top={0}
  62. />
  63. </i>
  64. </div>
  65. {/if}
  66. {#if label.text}
  67. <div class={`${label.icon ? 'mt-[2px]' : 'py-1 text-lg'} ${i === active && !label.icon ? ' font-bold' : ''}`}>
  68. {label.text}
  69. </div>
  70. {/if}
  71. </div>
  72. {/each}
  73. </div>
  74. </div>