slide-icons.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. <template>
  2. <ElCollapse class="icon-layout" v-model="activeGroups">
  3. <ElCollapseItem
  4. v-for="group in searchGroups"
  5. :name="group.name"
  6. v-if="searchGroups.length"
  7. >
  8. <template #title>
  9. <h2>{{ group.name }}</h2>
  10. </template>
  11. <div class="type-children" v-for="typeChildren in group.children">
  12. <h3 v-if="typeChildren.name">{{ typeChildren.name }}</h3>
  13. <div class="icon-items">
  14. <div
  15. v-for="item in typeChildren.children"
  16. @click="drawIcon(`./icons/${item.icon}.svg`, item.name, item)"
  17. >
  18. <Icon :name="item.icon" size="32px" />
  19. <span>{{ item.name }}</span>
  20. </div>
  21. </div>
  22. </div>
  23. </ElCollapseItem>
  24. <el-empty description="暂无数据" v-else />
  25. </ElCollapse>
  26. </template>
  27. <script lang="ts" setup>
  28. import { computed, ref } from "vue";
  29. import { ElCollapse, ElCollapseItem, ElEmpty } from "element-plus";
  30. import { getSvgContent, parseSvgContent } from "@/utils/resource";
  31. import { Draw } from "../../../components/container/use-draw.ts";
  32. import { iconGroups as groups } from "../../../constant";
  33. const props = defineProps<{ draw: Draw }>();
  34. const emit = defineEmits<{ (e: "exit"): void }>();
  35. const drawIcon = async (url: string, name: string, item: any) => {
  36. const svgContent = parseSvgContent(await getSvgContent(url));
  37. console.log(item);
  38. const maxSize = 100;
  39. const addHeight = (maxSize / svgContent.width) * svgContent.height;
  40. const size = {
  41. width: maxSize,
  42. height: addHeight,
  43. };
  44. if (size.height > maxSize) {
  45. size.height = maxSize;
  46. size.width = (maxSize / svgContent.height) * svgContent.width;
  47. }
  48. props.draw.enterDrawShape(
  49. "icon",
  50. {
  51. url,
  52. ...size,
  53. name,
  54. fill: "#000000",
  55. ...(item.parse || {}),
  56. },
  57. true
  58. );
  59. emit("exit");
  60. };
  61. const activeGroups = ref(groups.map((item) => item.name));
  62. const keyword = ref("");
  63. const searchGroups = computed(() => {
  64. return groups
  65. .map((typeChildren) => {
  66. const filterTypeChildren = typeChildren.children
  67. .map((type) => {
  68. const children = type.children.filter((item) =>
  69. item.name.includes(keyword.value)
  70. );
  71. return {
  72. ...type,
  73. children,
  74. };
  75. })
  76. .filter((type) => type.children.length > 0);
  77. return {
  78. ...typeChildren,
  79. children: filterTypeChildren,
  80. };
  81. })
  82. .filter((typeChildren) => typeChildren.children.length > 0);
  83. });
  84. </script>
  85. <style lang="scss" scoped>
  86. .icon-layout {
  87. width: 320px;
  88. height: 100%;
  89. background-color: var(--el-menu-bg-color);
  90. border-right: solid 1px var(--el-menu-border-color);
  91. overflow-y: auto;
  92. padding: 0 20px;
  93. font-size: 14px;
  94. color: #333;
  95. h2,
  96. h3 {
  97. font-size: inherit;
  98. color: inherit;
  99. }
  100. // .type-children:not(:first-child) {
  101. // margin-top: 20px;
  102. // }
  103. h3 {
  104. margin-bottom: 20px;
  105. }
  106. }
  107. .icon-items {
  108. display: flex;
  109. flex-wrap: wrap;
  110. > div {
  111. width: 25%;
  112. text-align: center;
  113. display: flex;
  114. flex-direction: column;
  115. align-items: center;
  116. justify-content: space-between;
  117. margin-bottom: 20px;
  118. span {
  119. margin-top: 10px;
  120. }
  121. }
  122. }
  123. </style>