mirror of
https://github.com/palxiao/poster-design.git
synced 2025-07-03 03:56:41 +08:00
382 lines
9.1 KiB
Vue
382 lines
9.1 KiB
Vue
<template>
|
|
<div id="zoom-control">
|
|
<ul v-show="show" class="zoom-selecter">
|
|
<li v-for="(item, index) in zoomList" :key="index" :class="['zoom-item', { 'zoom-item-active': activezoomIndex === index }]" @click.stop="selectItem(index)">
|
|
<!-- <i v-if="item.icon" :class="['iconfont', item.icon]"></i> -->
|
|
<span>{{ item.text }}</span>
|
|
<i v-if="activezoomIndex === index" class="iconfont icon-selected"></i>
|
|
</li>
|
|
</ul>
|
|
<div v-if="!hideControl" class="zoom-control-wrap">
|
|
<div :class="['zoom-icon radius-left', { disable: activezoomIndex === 0 }]" @click.stop="activezoomIndex > 0 ? sub() : ''">
|
|
<i class="iconfont icon-sub"></i>
|
|
</div>
|
|
<div :class="['zoom-text', { 'zoom-text-active': show }]" @click.stop="show = !show">{{ zoom.text }}</div>
|
|
<div :class="['zoom-icon radius-right', { disable: otherIndex === otherList.length - 1 }]" @click.stop="otherIndex < otherList.length - 1 ? add() : ''">
|
|
<i class="iconfont icon-add"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { useStore } from 'vuex'
|
|
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
import addMouseWheel from '@/common/methods/addMouseWheel'
|
|
import { OtherList, TZoomData, ZoomList } from './data';
|
|
import { useSetupMapGetters } from '@/common/hooks/mapGetters';
|
|
import { useRoute } from 'vue-router';
|
|
|
|
const route = useRoute()
|
|
const store = useStore()
|
|
|
|
// 组件大小控制器
|
|
let holder: number | undefined
|
|
|
|
const hideControl = ref(false)
|
|
const activezoomIndex = ref(0)
|
|
const zoomList = ref<TZoomData[]>(ZoomList)
|
|
const show = ref(false)
|
|
const zoom = ref<TZoomData>({
|
|
value: 0,
|
|
text: '',
|
|
})
|
|
const otherList = ref<TZoomData[]>(OtherList)
|
|
const otherIndex = ref(-1)
|
|
const bestZoom = ref(0)
|
|
const curAction = ref('')
|
|
|
|
const { dPage, dScreen, zoomScreenChange, dZoom } = useSetupMapGetters(['dPage', 'dScreen', 'zoomScreenChange', 'dZoom'])
|
|
|
|
watch(
|
|
activezoomIndex,
|
|
(data) => {
|
|
if (data < 0 || data > zoomList.value.length - 1) {
|
|
return
|
|
}
|
|
zoom.value = JSON.parse(JSON.stringify(zoomList.value[data]))
|
|
}
|
|
)
|
|
|
|
watch(
|
|
otherIndex,
|
|
(data) => {
|
|
if (data < 0 || data > otherList.value.length - 1) {
|
|
return
|
|
}
|
|
zoom.value = JSON.parse(JSON.stringify(otherList.value[data]))
|
|
}
|
|
)
|
|
|
|
watch(
|
|
zoom,
|
|
(data) => {
|
|
let realValue = data.value
|
|
if (realValue === -1) {
|
|
realValue = calcZoom()
|
|
}
|
|
store.dispatch('updateZoom', realValue)
|
|
// updateZoom(realValue)
|
|
autoFixTop()
|
|
}
|
|
)
|
|
|
|
watch(
|
|
dScreen,
|
|
() => {
|
|
screenChange()
|
|
},
|
|
{ deep: true, }
|
|
)
|
|
|
|
watch(
|
|
zoomScreenChange,
|
|
() => {
|
|
activezoomIndex.value = zoomList.value.length - 1
|
|
screenChange()
|
|
}
|
|
)
|
|
|
|
watch(
|
|
dPage,
|
|
() => {
|
|
screenChange()
|
|
},
|
|
{ deep: true }
|
|
)
|
|
|
|
onMounted(async () => {
|
|
await nextTick()
|
|
window.addEventListener('click', close)
|
|
if (route.path === '/draw') {
|
|
activezoomIndex.value = 3
|
|
hideControl.value = true
|
|
} else {
|
|
activezoomIndex.value = zoomList.value.length - 1
|
|
}
|
|
// 添加滚轮监听
|
|
addMouseWheel('page-design', (isDown: boolean) => {
|
|
mousewheelZoom(isDown)
|
|
})
|
|
// 添加窗口大小监听
|
|
window.addEventListener('resize', (event) => {
|
|
changeScreen()
|
|
})
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
window.removeEventListener('click', close)
|
|
})
|
|
|
|
// ...mapActions(['updateZoom', 'updateScreen']),
|
|
function changeScreen() {
|
|
clearTimeout(holder)
|
|
holder = setTimeout(() => {
|
|
const screen = document.getElementById('page-design')
|
|
if (!screen) return
|
|
store.dispatch('updateScreen', {
|
|
width: screen.offsetWidth,
|
|
height: screen.offsetHeight,
|
|
})
|
|
// updateScreen({
|
|
// width: screen.offsetWidth,
|
|
// height: screen.offsetHeight,
|
|
// })
|
|
}, 300)
|
|
}
|
|
|
|
function screenChange() {
|
|
// 弹性尺寸即时修改
|
|
if (activezoomIndex.value === zoomList.value.length - 1) {
|
|
store.dispatch('updateZoom', calcZoom())
|
|
// this.updateZoom(this.calcZoom())
|
|
autoFixTop()
|
|
}
|
|
}
|
|
|
|
function selectItem(index: number) {
|
|
activezoomIndex.value = index
|
|
otherIndex.value = -1
|
|
show.value = false
|
|
}
|
|
|
|
function close(_: MouseEvent) {
|
|
show.value = false
|
|
}
|
|
|
|
function add() {
|
|
curAction.value = 'add'
|
|
show.value = false
|
|
if (
|
|
activezoomIndex.value === zoomList.value.length - 2 ||
|
|
activezoomIndex.value === zoomList.value.length - 1
|
|
) {
|
|
activezoomIndex.value = zoomList.value.length
|
|
// this.otherIndex += 1
|
|
if (bestZoom.value) {
|
|
nearZoom(true)
|
|
} else {
|
|
otherIndex.value += 1
|
|
}
|
|
return
|
|
}
|
|
if (activezoomIndex.value != zoomList.value.length) {
|
|
activezoomIndex.value++
|
|
return
|
|
}
|
|
if (otherIndex.value < otherList.value.length - 1) {
|
|
otherIndex.value++
|
|
}
|
|
}
|
|
|
|
function sub() {
|
|
curAction.value = ''
|
|
show.value = false
|
|
if (otherIndex.value === 0) {
|
|
otherIndex.value = -1
|
|
activezoomIndex.value = zoomList.value.length - 2
|
|
return
|
|
}
|
|
if (otherIndex.value != -1) {
|
|
otherIndex.value--
|
|
return
|
|
}
|
|
if (activezoomIndex.value === zoomList.value.length - 1) {
|
|
if (bestZoom) {
|
|
nearZoom()
|
|
} else {
|
|
activezoomIndex.value = zoomList.value.length - 2
|
|
}
|
|
return
|
|
}
|
|
if (activezoomIndex.value != 0) {
|
|
activezoomIndex.value--
|
|
}
|
|
}
|
|
|
|
function mousewheelZoom(down: boolean) {
|
|
const value = Number(dZoom.value.toFixed(0))
|
|
if (down && value <= 1) return
|
|
store.dispatch('updateZoom', down ? value - 1 : value + 1)
|
|
// updateZoom(down ? value - 1 : value + 1)
|
|
zoom.value.text = (value + '%') as any
|
|
autoFixTop()
|
|
}
|
|
|
|
function nearZoom(add?: boolean) {
|
|
for (let i = 0; i < zoomList.value.length; i++) {
|
|
activezoomIndex.value = i
|
|
if (zoomList.value[i].value > bestZoom.value) {
|
|
if (add) break
|
|
} else if (zoomList.value[i].value < bestZoom.value) {
|
|
if (!add) break
|
|
}
|
|
}
|
|
bestZoom.value = 0
|
|
}
|
|
|
|
function calcZoom() {
|
|
let widthZoom = ((dScreen.value.width - 142) * 100) / dPage.value.width
|
|
let heightZoom = ((dScreen.value.height - 122) * 100) / dPage.value.height
|
|
|
|
bestZoom.value = Math.min(widthZoom, heightZoom)
|
|
return bestZoom.value
|
|
}
|
|
|
|
async function autoFixTop() {
|
|
await nextTick()
|
|
const presetPadding = 60
|
|
const el = document.getElementById('out-page')
|
|
if (!el) return
|
|
const clientHeight = window.innerHeight - 54
|
|
// const parentHeight = (el.offsetParent as HTMLElement).offsetHeight - 54
|
|
let padding = (clientHeight - el.offsetHeight) / 2
|
|
if (typeof curAction.value === 'undefined') {
|
|
padding += presetPadding / 2
|
|
}
|
|
curAction.value === 'add' && (padding -= presetPadding)
|
|
store.commit('updatePaddingTop', padding > 0 ? padding : 0)
|
|
}
|
|
|
|
defineExpose({
|
|
screenChange
|
|
})
|
|
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
@color-select: #1b1634;
|
|
@color1: #ffffff; // 选项板背景
|
|
@color2: #ffffff; // Appears 3 times
|
|
@color3: #666666; // 文字主颜色
|
|
@color4: #c2c2c2; // 禁用
|
|
@color5: rgba(0, 0, 0, 0.12); // 高亮选项背景
|
|
@z-border-color: #e6e6e6;
|
|
|
|
#zoom-control {
|
|
bottom: 20px;
|
|
position: absolute;
|
|
right: 302px;
|
|
z-index: 1000;
|
|
.zoom-control-wrap {
|
|
display: flex;
|
|
flex-direction: row;
|
|
font-size: 14px;
|
|
height: 40px;
|
|
.radius-left {
|
|
border-bottom-left-radius: 50%;
|
|
border-top-left-radius: 50%;
|
|
border-block-end: 1px solid @z-border-color;
|
|
border-block-start: 1px solid @z-border-color;
|
|
}
|
|
.radius-right {
|
|
border-bottom-right-radius: 50%;
|
|
border-top-right-radius: 50%;
|
|
border-block-end: 1px solid @z-border-color;
|
|
border-block-start: 1px solid @z-border-color;
|
|
}
|
|
.zoom-icon {
|
|
align-items: center;
|
|
background-color: @color2;
|
|
color: @color3;
|
|
cursor: pointer;
|
|
display: flex;
|
|
justify-content: center;
|
|
width: 40px;
|
|
&:hover {
|
|
background-color: @color1;
|
|
color: @color-select;
|
|
}
|
|
}
|
|
.disable {
|
|
color: @color4;
|
|
&:hover {
|
|
background-color: @color2;
|
|
color: @color4;
|
|
cursor: not-allowed;
|
|
}
|
|
}
|
|
.zoom-text {
|
|
user-select: none;
|
|
align-items: center;
|
|
background-color: @color2;
|
|
color: @color3;
|
|
cursor: pointer;
|
|
display: flex;
|
|
justify-content: center;
|
|
width: 60px;
|
|
border-block-end: 1px solid @z-border-color;
|
|
border-block-start: 1px solid @z-border-color;
|
|
&:hover {
|
|
background-color: @color1;
|
|
color: @color-select;
|
|
}
|
|
}
|
|
}
|
|
.zoom-selecter {
|
|
background-color: @color1;
|
|
color: @color3;
|
|
position: absolute;
|
|
top: -8px;
|
|
transform: translateY(-100%);
|
|
width: 100%;
|
|
z-index: 1000;
|
|
&:after {
|
|
bottom: -8px;
|
|
content: '';
|
|
left: 50%;
|
|
position: absolute;
|
|
transform: translateX(-50%);
|
|
}
|
|
.zoom-item {
|
|
align-items: center;
|
|
cursor: pointer;
|
|
display: flex;
|
|
font-size: 14px;
|
|
height: 34px;
|
|
padding: 10px;
|
|
width: 100%;
|
|
i {
|
|
margin-right: 10px;
|
|
&:last-child {
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
span {
|
|
flex: 1;
|
|
}
|
|
&:hover {
|
|
background-color: @color5;
|
|
color: @color-select;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// #zoom-control-active {
|
|
// background-color: @color1;
|
|
// background-color: @color5;
|
|
// color: @color-select;
|
|
// color: @color-select;
|
|
// }
|
|
</style>
|