CanvasBoard.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <template>
  2. <div class="canvas-board-wrapper" :style="wrapperStyle">
  3. <div class="canvas-board" :style="canvasStyle">
  4. <slot />
  5. </div>
  6. </div>
  7. </template>
  8. <script setup lang="ts">
  9. import { computed } from 'vue';
  10. interface Props {
  11. width?: number | string;
  12. height?: number | string;
  13. bg?: string;
  14. scale?: number;
  15. }
  16. const props = defineProps<Props>();
  17. const canvasStyle = computed(() => {
  18. // console.log('props.bg', props.bg);
  19. let bgValue = props.bg;
  20. let imgUrl: string | undefined;
  21. // 尝试解析 bg 为数组并取 url
  22. if (typeof bgValue === 'string' && bgValue.trim().startsWith('[')) {
  23. try {
  24. const arr = JSON.parse(bgValue);
  25. if (Array.isArray(arr) && arr.length > 0 && arr[0].url) {
  26. imgUrl = arr[0].url;
  27. }
  28. } catch (e) {
  29. // 解析失败,忽略
  30. }
  31. }
  32. const isHex = typeof bgValue === 'string' && /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(bgValue);
  33. const isImg = typeof bgValue === 'string' && /^https?:\/\/.+\.(png|jpe?g|webp|gif|bmp|svg)(\?.*)?$/i.test(bgValue);
  34. if (isHex) {
  35. // console.log('Is Hex BG');
  36. return {
  37. width: '100%',
  38. height: '100%',
  39. background: props.bg,
  40. display: 'flex',
  41. alignItems: 'center',
  42. justifyContent: 'center',
  43. fontSize: '20px',
  44. color: '#aaa',
  45. borderRadius: '12px',
  46. boxShadow: '0 2px 8px rgba(0,0,0,0.08)'
  47. };
  48. } else if (isImg) {
  49. // console.log('Is Img BG');
  50. return {
  51. width: '100%',
  52. height: '100%',
  53. backgroundImage: `url(${bgValue})`,
  54. backgroundSize: 'cover',
  55. backgroundPosition: 'center',
  56. backgroundRepeat: 'no-repeat',
  57. display: 'flex',
  58. alignItems: 'center',
  59. justifyContent: 'center',
  60. fontSize: '20px',
  61. color: '#aaa',
  62. borderRadius: '12px',
  63. boxShadow: '0 2px 8px rgba(0,0,0,0.08)'
  64. };
  65. } else if (imgUrl) {
  66. // console.log('Is Img BG (from array)');
  67. return {
  68. width: '100%',
  69. height: '100%',
  70. backgroundImage: `url(${imgUrl})`,
  71. backgroundSize: 'cover',
  72. backgroundPosition: 'center',
  73. backgroundRepeat: 'no-repeat',
  74. display: 'flex',
  75. alignItems: 'center',
  76. justifyContent: 'center',
  77. fontSize: '20px',
  78. color: '#aaa',
  79. borderRadius: '12px',
  80. boxShadow: '0 2px 8px rgba(0,0,0,0.08)'
  81. };
  82. } else {
  83. // console.log('Is Default BG');
  84. return {
  85. width: '100%',
  86. height: '100%',
  87. background: '#fff',
  88. display: 'flex',
  89. alignItems: 'center',
  90. justifyContent: 'center',
  91. fontSize: '20px',
  92. color: '#aaa',
  93. borderRadius: '12px',
  94. boxShadow: '0 2px 8px rgba(0,0,0,0.08)'
  95. };
  96. }
  97. });
  98. const wrapperStyle = computed(() => {
  99. const width = typeof props.width === 'number' ? props.width : parseFloat(props.width || '600');
  100. const height = typeof props.height === 'number' ? props.height : parseFloat(props.height || '400');
  101. const scale = props.scale && props.scale !== 1 ? props.scale : 1;
  102. return {
  103. width: width * scale + 'px',
  104. height: height * scale + 'px',
  105. display: 'flex',
  106. alignItems: 'center',
  107. justifyContent: 'center',
  108. position: 'relative',
  109. overflow: 'hidden'
  110. };
  111. });
  112. </script>
  113. <style scoped>
  114. .canvas-board-wrapper {
  115. width: 100%;
  116. height: 100%;
  117. display: flex;
  118. align-items: center;
  119. justify-content: center;
  120. position: relative;
  121. overflow: hidden;
  122. }
  123. .canvas-board {
  124. transition: all 0.2s;
  125. }
  126. </style>