index.vue 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. <template>
  2. <div class="actions">
  3. <span
  4. v-for="(action, i) in items"
  5. :class="{ active: equal(current as any, action), disabled: action.disabled }"
  6. :key="action.key || i"
  7. @click="emit('update:current', current === action ? null : action)"
  8. >
  9. <ui-icon :type="action.icon" class="icon" :tip="action.text" />
  10. </span>
  11. </div>
  12. </template>
  13. <script lang="ts" setup>
  14. import { useActive } from "@/hook";
  15. import { ref, toRaw, watchEffect, onBeforeUnmount, nextTick, watch } from "vue";
  16. export type ActionsItem<T = any> = {
  17. icon: string;
  18. key?: T;
  19. text: string;
  20. disabled?: boolean;
  21. action?: () => (() => void) | void;
  22. };
  23. export type ActionsProps = {
  24. items: ActionsItem[];
  25. current?: ActionsItem | null;
  26. single?: boolean;
  27. };
  28. const props = defineProps<ActionsProps>();
  29. const emit = defineEmits<{ (e: "update:current", data: ActionsItem | null): void }>();
  30. const equal = (a: ActionsItem | null, b: ActionsItem | null) => toRaw(a) === toRaw(b);
  31. watch(
  32. () => props.current,
  33. (current) => {
  34. if (!current) return;
  35. if (props.single) {
  36. emit("update:current", null);
  37. }
  38. },
  39. { immediate: true }
  40. );
  41. watch(
  42. () => props.current,
  43. (current, p, onCleanup) => {
  44. if (!current) return;
  45. const fn = current.action && current.action();
  46. fn && onCleanup(fn);
  47. },
  48. { immediate: true }
  49. );
  50. </script>
  51. <style lang="scss" scoped>
  52. .actions {
  53. display: flex;
  54. gap: 3px;
  55. background: rgba(27, 27, 28, 0.8);
  56. box-shadow: inset 0px 0px 0px 2px rgba(255, 255, 255, 0.1);
  57. border-radius: 4px 4px 4px 4px;
  58. padding: 4px 10px;
  59. span {
  60. flex: 1;
  61. height: 32px;
  62. width: 32px;
  63. border-radius: 4px 4px 4px 4px;
  64. opacity: 1;
  65. display: flex;
  66. align-items: center;
  67. justify-content: center;
  68. color: rgba(255, 255, 255, 0.6);
  69. font-size: 14px;
  70. cursor: pointer;
  71. transition: all 0.3s ease;
  72. .icon {
  73. font-size: 22px;
  74. }
  75. &:hover,
  76. &.active {
  77. background: rgba(0, 200, 175, 0.16);
  78. color: #00c8af;
  79. }
  80. }
  81. }
  82. </style>