Rewrite Modals/ImageViewer with composition API

This commit is contained in:
AkiraFukushima 2022-04-28 21:15:26 +09:00
parent 2acc8468ca
commit 892719141b
No known key found for this signature in database
GPG Key ID: B6E51BAC4DE1A957
5 changed files with 131 additions and 148 deletions

View File

@ -11,7 +11,7 @@
<span class="button-area"
><el-button type="text" v-show="showLeft" @click="decrementIndex()"> <font-awesome-icon icon="angle-left" /> </el-button
></span>
<Media :src="imageURL" :type="imageType"></Media>
<Media :src="imageURL" :imageType="imageType"></Media>
<span class="button-area"
><el-button type="text" v-show="showRight" @click="incrementIndex()"> <font-awesome-icon icon="angle-right" /> </el-button
></span>
@ -21,51 +21,49 @@
</transition>
</template>
<script>
import Media from './Media'
import { mapState } from 'vuex'
<script lang="ts">
import { defineComponent, computed } from 'vue'
import { useStore } from '@/store'
import { ACTION_TYPES } from '@/store/TimelineSpace/Modals/ImageViewer'
import Media from './ImageViewer/Media.vue'
export default {
export default defineComponent({
name: 'image-viewer',
components: {
Media
},
name: 'image-viewer',
computed: {
...mapState({
modalOpen: state => state.TimelineSpace.Modals.ImageViewer.modalOpen
}),
imageURL() {
return this.$store.getters['TimelineSpace/Modals/ImageViewer/imageURL']
},
imageType() {
return this.$store.getters['TimelineSpace/Modals/ImageViewer/imageType']
},
showLeft() {
return this.$store.getters['TimelineSpace/Modals/ImageViewer/showLeft']
},
showRight() {
return this.$store.getters['TimelineSpace/Modals/ImageViewer/showRight']
setup() {
const space = 'TimelineSpace/Modals/ImageViewer'
const store = useStore()
const modalOpen = computed(() => store.state.TimelineSpace.Modals.ImageViewer.modalOpen)
const imageURL = computed(() => store.getters[`${space}/imageURL`])
const imageType = computed(() => store.getters[`${space}/imageType`])
const showLeft = computed(() => store.getters[`${space}/showLeft`])
const showRight = computed(() => store.getters[`${space}/showRight`])
const close = () => {
store.dispatch(`${space}/${ACTION_TYPES.CLOSE_MODAL}`)
}
},
methods: {
close() {
this.$store.dispatch('TimelineSpace/Modals/ImageViewer/closeModal')
},
decrementIndex() {
if (this.showLeft) this.$store.dispatch('TimelineSpace/Modals/ImageViewer/decrementIndex')
},
incrementIndex() {
if (this.showRight) this.$store.dispatch('TimelineSpace/Modals/ImageViewer/incrementIndex')
},
closeHandle(event) {
switch (event.srcKey) {
case 'close':
this.close()
break
}
const decrementIndex = () => {
if (showLeft.value) store.dispatch(`${space}/${ACTION_TYPES.DECREMENT_INDEX}`)
}
const incrementIndex = () => {
if (showRight.value) store.dispatch(`${space}/${ACTION_TYPES.INCREMENT_INDEX}`)
}
return {
modalOpen,
imageURL,
imageType,
showLeft,
showRight,
close,
decrementIndex,
incrementIndex
}
}
}
})
</script>
<style lang="scss" scoped>

View File

@ -0,0 +1,80 @@
<template>
<div id="current-media" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.8)">
<video :src="imageSrc" v-if="isMovie()" autoplay loop controls v-on:loadstart="loaded()"></video>
<video :src="imageSrc" v-else-if="isGIF()" autoplay loop v-on:loadstart="loaded()"></video>
<video :src="imageSrc" v-else-if="isAudio()" autoplay loop controls v-on:loadstart="loaded()"></video>
<img :src="imageSrc" v-else v-on:load="loaded()" />
</div>
</template>
<script lang="ts">
import { defineComponent, ref, toRefs, watch, computed } from 'vue'
import { useStore } from '@/store'
import { ACTION_TYPES } from '@/store/TimelineSpace/Modals/ImageViewer'
import exifImageUrl from '@/components/utils/exifImageUrl'
export default defineComponent({
name: 'Media',
props: {
src: {
type: String,
default: ''
},
imageType: {
type: String,
default: ''
}
},
setup(props) {
const srcRef = toRefs(props).src
const imageTypeRef = toRefs(props).imageType
const imageSrc = ref('')
imageSrc.value = srcRef.value
const store = useStore()
const loading = computed(() => store.state.TimelineSpace.Modals.ImageViewer.loading)
const isMovie = () => ['video'].includes(imageTypeRef.value)
const isGIF = () => ['gifv'].includes(imageTypeRef.value)
const isAudio = () => ['audio'].includes(imageTypeRef.value)
watch(srcRef, async (newSrc, _oldSrc) => {
imageSrc.value = newSrc
if (newSrc && !isMovie() && !isGIF() && !isAudio()) {
try {
const transformed = await exifImageUrl(newSrc)
imageSrc.value = transformed
} catch (err) {
console.error(err)
}
}
})
const loaded = () => store.dispatch(`TimelineSpace/Modals/ImageViewer/${ACTION_TYPES.LOADED}`)
return {
imageSrc,
loading,
isMovie,
isGIF,
isAudio,
loaded
}
}
})
</script>
<style lang="scss" scoped>
#current-media {
max-width: 80%;
min-width: 10%;
height: 80%;
display: inline-flex;
img,
video {
max-height: 100%;
max-width: 100%;
align-self: center;
}
}
</style>

View File

@ -1,103 +0,0 @@
<template>
<div
id="current-media"
v-loading="loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
>
<video
:src="src"
v-if="isMovieFile()"
autoplay
loop
controls
v-on:loadstart="loaded()"
></video>
<video
:src="src"
v-else-if="isGIF()"
autoplay
loop
v-on:loadstart="loaded()"
></video>
<video
:src="src"
v-else-if="isAudio()"
autoplay
loop
controls
v-on:loadstart="loaded()"
></video>
<img :src="imageSrc" v-else v-on:load="loaded()" />
</div>
</template>
<script>
import { mapState } from 'vuex'
import exifImageUrl from '@/components/utils/exifImageUrl'
export default {
props: {
src: {
type: String,
default: '',
},
type: {
type: String,
default: '',
},
},
data() {
return {
imageSrc: this.src,
}
},
watch: {
src: async function (newSrc, _oldSrc) {
this.imageSrc = newSrc
if (newSrc && !this.isMovieFile() && !this.isGIF()) {
try {
const transformed = await exifImageUrl(newSrc)
this.imageSrc = transformed
} catch (err) {
console.error(err)
}
}
},
},
computed: {
...mapState({
loading: (state) => state.TimelineSpace.Modals.ImageViewer.loading,
}),
},
methods: {
isMovieFile() {
return ['video'].includes(this.type)
},
isGIF() {
return ['gifv'].includes(this.type)
},
isAudio() {
return ['audio'].includes(this.type)
},
async loaded() {
this.$store.dispatch('TimelineSpace/Modals/ImageViewer/loaded')
},
},
}
</script>
<style lang="scss" scoped>
#current-media {
max-width: 80%;
min-width: 10%;
height: 80%;
display: inline-flex;
img,
video {
max-height: 100%;
max-width: 100%;
align-self: center;
}
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<div class="shortcut">
<el-dialog :title="$t('modals.shortcut.title')" v-model="shortcutModal" width="500px" class="shortcut-modal">
<el-dialog :title="$t('modals.shortcut.title')" v-model="shortcutModal" width="500px" custom-class="shortcut-modal">
<table class="shortcuts">
<tbody>
<tr>

View File

@ -46,28 +46,36 @@ const mutations: MutationTree<ImageViewerState> = {
}
}
export const ACTION_TYPES = {
OPEN_MODAL: 'openModal',
CLOSE_MODAL: 'closeModal',
INCREMENT_INDEX: 'incrementIndex',
DECREMENT_INDEX: 'decrementIndex',
LOADED: 'loaded'
}
const actions: ActionTree<ImageViewerState, RootState> = {
openModal: ({ commit }, { currentIndex, mediaList }) => {
[ACTION_TYPES.OPEN_MODAL]: ({ commit }, { currentIndex, mediaList }) => {
commit(MUTATION_TYPES.CHANGE_MODAL, true)
commit(MUTATION_TYPES.CHANGE_CURRENT_INDEX, currentIndex as number)
commit(MUTATION_TYPES.CHANGE_MEDIA_LIST, mediaList as Array<Entity.Attachment>)
commit(MUTATION_TYPES.CHANGE_LOADING, true)
},
closeModal: ({ commit }) => {
[ACTION_TYPES.CLOSE_MODAL]: ({ commit }) => {
commit(MUTATION_TYPES.CHANGE_MODAL, false)
commit(MUTATION_TYPES.CHANGE_CURRENT_INDEX, -1)
commit(MUTATION_TYPES.CHANGE_MEDIA_LIST, [])
commit(MUTATION_TYPES.CHANGE_LOADING, false)
},
incrementIndex: ({ commit }) => {
[ACTION_TYPES.INCREMENT_INDEX]: ({ commit }) => {
commit(MUTATION_TYPES.INCREMENT_INDEX)
commit(MUTATION_TYPES.CHANGE_LOADING, true)
},
decrementIndex: ({ commit }) => {
[ACTION_TYPES.DECREMENT_INDEX]: ({ commit }) => {
commit(MUTATION_TYPES.DECREMENT_INDEX)
commit(MUTATION_TYPES.CHANGE_LOADING, true)
},
loaded: ({ commit }) => {
[ACTION_TYPES.LOADED]: ({ commit }) => {
commit(MUTATION_TYPES.CHANGE_LOADING, false)
}
}