| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- <template>
- <div class="slide-style-panel">
- <div class="title">背景填充</div>
- <div class="row">
- <Select
- style="flex: 10;"
- :value="background.type"
- @change="value => updateBackgroundType(value)"
- >
- <SelectOption value="solid">纯色填充</SelectOption>
- <SelectOption value="image">图片填充</SelectOption>
- </Select>
- <div style="flex: 1;"></div>
- <Popover trigger="click" v-if="background.type === 'solid'">
- <template #content>
- <ColorPicker
- :modelValue="background.value"
- @update:modelValue="value => updateBackground({ value })"
- />
- </template>
- <ColorButton :color="background.value" style="flex: 10;" />
- </Popover>
- <Select
- style="flex: 10;"
- :value="background.size || 'cover'"
- @change="value => updateBackground({ size: value })"
- v-else
- >
- <SelectOption value="initial">原始大小</SelectOption>
- <SelectOption value="contain">缩放</SelectOption>
- <SelectOption value="repeat">拼贴</SelectOption>
- <SelectOption value="cover">缩放铺满</SelectOption>
- </Select>
- </div>
- <div class="background-image-wrapper" v-if="background.type === 'image'">
- <FileInput @change="files => uploadBackgroundImage(files)">
- <div class="background-image">
- <div
- class="content"
- :style="backgroundStyle"
- >
- <IconFont type="icon-plus" />
- </div>
- </div>
- </FileInput>
- </div>
- <div class="row"><Button style="flex: 1;" @click="applyAllSlide()">应用到全部</Button></div>
- </div>
- </template>
- <script lang="ts">
- import { computed, defineComponent, Ref } from 'vue'
- import { useStore } from 'vuex'
- import { MutationTypes, State } from '@/store'
- import { Slide, SlideBackground } from '@/types/slides'
- import useHistorySnapshot from '@/hooks/useHistorySnapshot'
- import ColorButton from './common/ColorButton.vue'
- import { getImageDataURL } from '@/utils/image'
- import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
- export default defineComponent({
- name: 'slide-style-panel',
- components: {
- ColorButton,
- },
- setup() {
- const store = useStore<State>()
- const slides = computed(() => store.state.slides)
- const currentSlide: Ref<Slide> = computed(() => store.getters.currentSlide)
- const background = computed(() => {
- if(!currentSlide.value.background) {
- return {
- type: 'solid',
- value: '#fff',
- } as SlideBackground
- }
- return currentSlide.value.background
- })
- const { backgroundStyle } = useSlideBackgroundStyle(background)
- const { addHistorySnapshot } = useHistorySnapshot()
- const updateBackgroundType = (type: 'solid' | 'image') => {
- if(type === 'solid') {
- const background: SlideBackground = {
- type: 'solid',
- value: '#fff',
- }
- store.commit(MutationTypes.UPDATE_SLIDE, { background })
- }
- else {
- const background: SlideBackground = {
- type: 'image',
- value: '',
- size: 'cover',
- }
- store.commit(MutationTypes.UPDATE_SLIDE, { background })
- }
- addHistorySnapshot()
- }
- const updateBackground = (props: Partial<SlideBackground>) => {
- store.commit(MutationTypes.UPDATE_SLIDE, { background: { ...background.value, ...props } })
- addHistorySnapshot()
- }
- const uploadBackgroundImage = (files: File[]) => {
- const imageFile = files[0]
- if(!imageFile) return
- getImageDataURL(imageFile).then(dataURL => updateBackground({ value: dataURL }))
- }
- const applyAllSlide = () => {
- const newSlides = slides.value.map(slide => {
- return {
- ...slide,
- background: currentSlide.value.background,
- }
- })
- store.commit(MutationTypes.SET_SLIDES, newSlides)
- addHistorySnapshot()
- }
- return {
- background,
- backgroundStyle,
- updateBackgroundType,
- updateBackground,
- uploadBackgroundImage,
- applyAllSlide,
- }
- },
- })
- </script>
- <style lang="scss" scoped>
- .row {
- width: 100%;
- display: flex;
- align-items: center;
- margin-bottom: 10px;
- }
- .title {
- margin-bottom: 10px;
- }
- .background-image-wrapper {
- margin-bottom: 10px;
- }
- .background-image {
- height: 0;
- padding-bottom: 56.25%;
- border: 1px dashed $borderColor;
- border-radius: $borderRadius;
- position: relative;
- transition: all .2s;
- &:hover {
- border-color: $themeColor;
- color: $themeColor;
- }
- .content {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- background-position: center;
- cursor: pointer;
- }
- }
- </style>
|