123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- <template>
- <div class="actions">
- <span
- v-for="(action, i) in items"
- :class="{ active: equal(selected, action), disabled: action.disabled }"
- :key="action.key || i"
- @click="clickHandler(action)"
- >
- <ui-icon :type="action.icon" class="icon" :tip="action.text" />
- </span>
- </div>
- </template>
- <script lang="ts" setup>
- import { useActive } from "@/hook";
- import { ref, toRaw, watchEffect, onBeforeUnmount, nextTick, watch } from "vue";
- export type ActionsItem<T = any> = {
- icon: string;
- key?: T;
- text: string;
- disabled?: boolean;
- action?: () => (() => void) | void;
- };
- export type ActionsProps = {
- items: ActionsItem[];
- current?: ActionsItem | null;
- single?: boolean;
- };
- const props = defineProps<ActionsProps>();
- const emit = defineEmits<{ (e: "update:current", data: ActionsItem | null): void }>();
- const equal = (a: ActionsItem | null, b: ActionsItem | null) => toRaw(a) === toRaw(b);
- const selected = ref<ActionsItem | null>(null);
- const clickHandler = (select: ActionsItem) => {
- selected.value = equal(selected.value, select) ? null : select;
- emit("update:current", selected.value);
- if (props.single) {
- nextTick(() => selected.value && clickHandler(selected.value));
- }
- };
- watch(
- () => props.current,
- () => {
- if (!props.current && selected.value) {
- clickHandler(selected.value);
- }
- }
- );
- watch(
- selected,
- (_n, _o, onCleanup) => {
- if (selected.value?.action) {
- const cleanup = selected.value.action();
- cleanup && onCleanup(cleanup);
- }
- },
- { flush: "sync" }
- );
- onBeforeUnmount(() => {
- selected.value = null;
- });
- </script>
- <style lang="scss" scoped>
- .actions {
- display: flex;
- gap: 3px;
- background: rgba(27, 27, 28, 0.8);
- box-shadow: inset 0px 0px 0px 2px rgba(255, 255, 255, 0.1);
- border-radius: 4px 4px 4px 4px;
- padding: 4px 10px;
- span {
- flex: 1;
- height: 32px;
- width: 32px;
- border-radius: 4px 4px 4px 4px;
- opacity: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- color: rgba(255, 255, 255, 0.6);
- font-size: 14px;
- cursor: pointer;
- transition: all 0.3s ease;
- .icon {
- font-size: 22px;
- }
- &:hover,
- &.active {
- background: rgba(0, 200, 175, 0.16);
- color: #00c8af;
- }
- }
- }
- </style>
|