index.vue 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <template>
  2. <view class="icon-list" :class="mode" :style="{ '--columns': getColumnCount() }">
  3. <view v-for="(item, index) in displayIcons" :key="index" class="icon-item" @click="_handleClick(item.urlMap?.internal_url)">
  4. <view class="icon-wrapper">
  5. <image :src="item.image || `http://iph.href.lu/48x48?text=${index}`" :style="{ borderRadius: `${radius}px` }" mode="aspectFill" />
  6. </view>
  7. <view class="icon-text">{{ item.text }}</view>
  8. </view>
  9. </view>
  10. </template>
  11. <script setup>
  12. import { computed } from 'vue';
  13. const props = defineProps({
  14. icons: {
  15. type: Array,
  16. default: () => [1, 2, 3, 4],
  17. },
  18. mode: {
  19. type: String,
  20. default: 'row4',
  21. validator: (value) => ['row4', 'row8', 'row5', 'row10'].includes(value),
  22. },
  23. radius: {
  24. type: Number,
  25. default: 0,
  26. },
  27. });
  28. const getColumnCount = () => {
  29. switch (props.mode) {
  30. case 'row4':
  31. case 'row8':
  32. return 4;
  33. case 'row5':
  34. case 'row10':
  35. return 5;
  36. default:
  37. return 4;
  38. }
  39. };
  40. const getMaxItems = () => {
  41. switch (props.mode) {
  42. case 'row4':
  43. return 4;
  44. case 'row8':
  45. return 8;
  46. case 'row5':
  47. return 5;
  48. case 'row10':
  49. return 10;
  50. default:
  51. return 4;
  52. }
  53. };
  54. const _handleClick = (url) => {
  55. if (url) {
  56. uni.navigateTo({
  57. url,
  58. fail: (err) => {
  59. uni.switchTab({
  60. url,
  61. });
  62. },
  63. });
  64. }
  65. };
  66. const displayIcons = computed(() => {
  67. return props.icons.slice(0, getMaxItems());
  68. });
  69. </script>
  70. <style lang="less" scoped>
  71. .navigator {
  72. width: 100%;
  73. height: 100%;
  74. display: flex;
  75. flex-direction: column;
  76. align-items: center;
  77. justify-content: center;
  78. }
  79. .icon-list {
  80. display: grid;
  81. grid-template-columns: repeat(var(--columns), 1fr);
  82. gap: 16rpx;
  83. width: 100%;
  84. padding: 16px;
  85. box-sizing: border-box;
  86. background-color: #fff;
  87. border-radius: 8px;
  88. .icon-item {
  89. display: flex;
  90. flex-direction: column;
  91. gap: 4px;
  92. align-items: center;
  93. .icon-wrapper {
  94. width: 44px;
  95. height: 44px;
  96. overflow: hidden;
  97. image {
  98. width: 100%;
  99. height: 100%;
  100. object-fit: cover;
  101. }
  102. }
  103. .icon-text {
  104. width: 100%;
  105. overflow: hidden;
  106. color: #333;
  107. font-size: 12px;
  108. white-space: nowrap;
  109. text-align: center;
  110. text-overflow: ellipsis;
  111. }
  112. }
  113. }
  114. .row4 {
  115. grid-template-rows: 1fr;
  116. }
  117. .row8 {
  118. grid-template-rows: repeat(2, 1fr);
  119. }
  120. .row5 {
  121. grid-template-rows: 1fr;
  122. }
  123. .row10 {
  124. grid-template-rows: repeat(2, 1fr);
  125. }
  126. </style>