BackgroundSelector.vue 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <template>
  2. <div class="background-selector">
  3. <template v-if="isCanvas">
  4. <el-radio-group v-model="bgType" class="bg-type-radio" size="small">
  5. <el-radio-button label="image">图片</el-radio-button>
  6. <el-radio-button label="color">纯色</el-radio-button>
  7. </el-radio-group>
  8. <div class="bg-section" v-if="bgType === 'image'">
  9. <div class="bg-label">选择背景图片</div>
  10. <MediaFileSelector v-model="mediaId" accept="image/*" :single="true" :onlyImage="true" />
  11. </div>
  12. <div class="bg-section" v-else>
  13. <div class="bg-label">选择纯色背景</div>
  14. <el-color-picker v-model="color" />
  15. </div>
  16. </template>
  17. <template v-else>
  18. <div class="bg-section">
  19. <div class="bg-label">选择颜色</div>
  20. <el-color-picker v-model="color" />
  21. </div>
  22. </template>
  23. </div>
  24. </template>
  25. <script setup lang="ts">
  26. import { ref, watch, computed } from 'vue';
  27. import MediaFileSelector from './MediaFileSelector.vue';
  28. const props = defineProps<{
  29. modelValue: string; // bg 字段,canvas 可能是图片url或颜色,其他组件为颜色
  30. isCanvas?: boolean; // 是否画布
  31. }>();
  32. const emit = defineEmits(['update:modelValue', 'change']);
  33. const bgType = ref<'image' | 'color'>('color');
  34. const mediaId = ref<string | null>(null);
  35. const color = ref<string>(props.modelValue || '#ffffff');
  36. // 初始化类型
  37. if (props.isCanvas) {
  38. if (props.modelValue && /^https?:\/\//.test(props.modelValue)) {
  39. bgType.value = 'image';
  40. mediaId.value = props.modelValue;
  41. } else {
  42. bgType.value = 'color';
  43. color.value = props.modelValue || '#ffffff';
  44. }
  45. }
  46. // 切换类型时同步
  47. watch(bgType, (val) => {
  48. if (val === 'image') {
  49. if (mediaId.value) {
  50. emit('update:modelValue', mediaId.value);
  51. emit('change', mediaId.value);
  52. }
  53. } else {
  54. emit('update:modelValue', color.value);
  55. emit('change', color.value);
  56. }
  57. });
  58. // 监听图片选择
  59. watch(mediaId, (val) => {
  60. if (bgType.value === 'image' && val) {
  61. emit('update:modelValue', val);
  62. emit('change', val);
  63. }
  64. });
  65. // 监听颜色选择
  66. watch(color, (val) => {
  67. if (bgType.value === 'color') {
  68. emit('update:modelValue', val);
  69. emit('change', val);
  70. }
  71. });
  72. // 外部变更时同步内部
  73. watch(
  74. () => props.modelValue,
  75. (val) => {
  76. if (props.isCanvas) {
  77. if (val && /^https?:\/\//.test(val)) {
  78. bgType.value = 'image';
  79. mediaId.value = val;
  80. } else {
  81. bgType.value = 'color';
  82. color.value = val || '#ffffff';
  83. }
  84. } else {
  85. color.value = val || '#ffffff';
  86. }
  87. }
  88. );
  89. </script>
  90. <style scoped>
  91. .background-selector {
  92. display: flex;
  93. flex-direction: column;
  94. gap: 6px;
  95. }
  96. .bg-section {
  97. margin-bottom: 6px;
  98. }
  99. .bg-label {
  100. font-size: 13px;
  101. color: #888;
  102. margin-bottom: 2px;
  103. }
  104. .bg-type-radio {
  105. margin-bottom: 8px;
  106. }
  107. </style>