SlideStylePanel.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <template>
  2. <div class="slide-style-panel">
  3. <div class="title">背景填充</div>
  4. <div class="row">
  5. <Select
  6. style="flex: 10;"
  7. :value="background.type"
  8. @change="value => updateBackgroundType(value)"
  9. >
  10. <SelectOption value="solid">纯色填充</SelectOption>
  11. <SelectOption value="image">图片填充</SelectOption>
  12. </Select>
  13. <div style="flex: 1;"></div>
  14. <Popover trigger="click" v-if="background.type === 'solid'">
  15. <template #content>
  16. <ColorPicker
  17. :modelValue="background.value"
  18. @update:modelValue="value => updateBackground({ value })"
  19. />
  20. </template>
  21. <ColorButton :color="background.value" style="flex: 10;" />
  22. </Popover>
  23. <Select
  24. style="flex: 10;"
  25. :value="background.size || 'cover'"
  26. @change="value => updateBackground({ size: value })"
  27. v-else
  28. >
  29. <SelectOption value="initial">原始大小</SelectOption>
  30. <SelectOption value="contain">缩放</SelectOption>
  31. <SelectOption value="repeat">拼贴</SelectOption>
  32. <SelectOption value="cover">缩放铺满</SelectOption>
  33. </Select>
  34. </div>
  35. <div class="background-image-wrapper" v-if="background.type === 'image'">
  36. <FileInput @change="files => uploadBackgroundImage(files)">
  37. <div class="background-image">
  38. <div
  39. class="content"
  40. :style="backgroundStyle"
  41. >
  42. <IconFont type="icon-plus" />
  43. </div>
  44. </div>
  45. </FileInput>
  46. </div>
  47. <div class="row"><Button style="flex: 1;" @click="applyAllSlide()">应用到全部</Button></div>
  48. </div>
  49. </template>
  50. <script lang="ts">
  51. import { computed, defineComponent, Ref } from 'vue'
  52. import { useStore } from 'vuex'
  53. import { MutationTypes, State } from '@/store'
  54. import { Slide, SlideBackground } from '@/types/slides'
  55. import useHistorySnapshot from '@/hooks/useHistorySnapshot'
  56. import ColorButton from './common/ColorButton.vue'
  57. import { getImageDataURL } from '@/utils/image'
  58. import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
  59. export default defineComponent({
  60. name: 'slide-style-panel',
  61. components: {
  62. ColorButton,
  63. },
  64. setup() {
  65. const store = useStore<State>()
  66. const slides = computed(() => store.state.slides)
  67. const currentSlide: Ref<Slide> = computed(() => store.getters.currentSlide)
  68. const background = computed(() => {
  69. if(!currentSlide.value.background) {
  70. return {
  71. type: 'solid',
  72. value: '#fff',
  73. } as SlideBackground
  74. }
  75. return currentSlide.value.background
  76. })
  77. const { backgroundStyle } = useSlideBackgroundStyle(background)
  78. const { addHistorySnapshot } = useHistorySnapshot()
  79. const updateBackgroundType = (type: 'solid' | 'image') => {
  80. if(type === 'solid') {
  81. const background: SlideBackground = {
  82. type: 'solid',
  83. value: '#fff',
  84. }
  85. store.commit(MutationTypes.UPDATE_SLIDE, { background })
  86. }
  87. else {
  88. const background: SlideBackground = {
  89. type: 'image',
  90. value: '',
  91. size: 'cover',
  92. }
  93. store.commit(MutationTypes.UPDATE_SLIDE, { background })
  94. }
  95. addHistorySnapshot()
  96. }
  97. const updateBackground = (props: Partial<SlideBackground>) => {
  98. store.commit(MutationTypes.UPDATE_SLIDE, { background: { ...background.value, ...props } })
  99. addHistorySnapshot()
  100. }
  101. const uploadBackgroundImage = (files: File[]) => {
  102. const imageFile = files[0]
  103. if(!imageFile) return
  104. getImageDataURL(imageFile).then(dataURL => updateBackground({ value: dataURL }))
  105. }
  106. const applyAllSlide = () => {
  107. const newSlides = slides.value.map(slide => {
  108. return {
  109. ...slide,
  110. background: currentSlide.value.background,
  111. }
  112. })
  113. store.commit(MutationTypes.SET_SLIDES, newSlides)
  114. addHistorySnapshot()
  115. }
  116. return {
  117. background,
  118. backgroundStyle,
  119. updateBackgroundType,
  120. updateBackground,
  121. uploadBackgroundImage,
  122. applyAllSlide,
  123. }
  124. },
  125. })
  126. </script>
  127. <style lang="scss" scoped>
  128. .row {
  129. width: 100%;
  130. display: flex;
  131. align-items: center;
  132. margin-bottom: 10px;
  133. }
  134. .title {
  135. margin-bottom: 10px;
  136. }
  137. .background-image-wrapper {
  138. margin-bottom: 10px;
  139. }
  140. .background-image {
  141. height: 0;
  142. padding-bottom: 56.25%;
  143. border: 1px dashed $borderColor;
  144. border-radius: $borderRadius;
  145. position: relative;
  146. transition: all .2s;
  147. &:hover {
  148. border-color: $themeColor;
  149. color: $themeColor;
  150. }
  151. .content {
  152. position: absolute;
  153. top: 0;
  154. bottom: 0;
  155. left: 0;
  156. right: 0;
  157. display: flex;
  158. justify-content: center;
  159. align-items: center;
  160. background-position: center;
  161. cursor: pointer;
  162. }
  163. }
  164. </style>