feat: convert moveable to composition API

This commit is contained in:
IchliebedichZhu 2024-03-20 19:09:19 +00:00
parent 54b9338e52
commit 048351e698

View File

@ -8,113 +8,163 @@
<template>
<div id="empty" class="moveable__remove-item zk-moveable-style"></div>
</template>
<script lang="ts">
import { defineComponent, nextTick } from 'vue'
<script lang="ts" setup>
import { Events, defineComponent, nextTick, onMounted, watch } from 'vue'
import Moveable, { EVENTS } from 'moveable' // PROPERTIES, METHODS,
import Moveable, { EVENTS, OnRotate, WithEventStop } from 'moveable' // PROPERTIES, METHODS,
import MoveableHelper from 'moveable-helper'
import { mapGetters, mapActions } from 'vuex'
import { mapGetters, mapActions, useStore } from 'vuex'
// import { setTransformAttribute } from '@/common/methods/handleTransform'
import useSelecto from './Selecto'
import { useSetupMapGetters } from '@/common/hooks/mapGetters'
import { storeToRefs } from 'pinia'
import { useCanvasStore } from '@/pinia'
export default defineComponent({
setup() {},
computed: mapGetters(['dSelectWidgets', 'dActiveElement', 'activeMouseEvent', 'showMoveable', 'showRotatable', 'dWidgets', 'updateRect', 'updateSelect', 'guidelines']),
watch: {
async dActiveElement(val) {
const {
dSelectWidgets, dActiveElement, activeMouseEvent,
showMoveable, showRotatable, dWidgets,
updateRect, updateSelect,
} = useSetupMapGetters(['dSelectWidgets', 'dActiveElement', 'activeMouseEvent', 'showMoveable', 'showRotatable', 'dWidgets', 'updateRect', 'updateSelect'])
const store = useStore()
const { guidelines } = storeToRefs(useCanvasStore())
// computed: mapGetters(['dSelectWidgets', 'dActiveElement', 'activeMouseEvent', 'showMoveable', 'showRotatable', 'dWidgets', 'updateRect', 'updateSelect', 'guidelines'])
let _target: string = ""
let moveable: Moveable | null = null
let holdPosition: { left: number, top: number } | null = null
let startHL: number = 0
let startLS: number = 0
let resetRatio: number = 0
let resizeTempData: { width: number, height: number } | null = null
watch(
() => dActiveElement.value,
async (val) => {
if (!val.record) {
return
}
if (!moveable) return
//
if (val.uuid != -1) {
await nextTick()
const target = `[id="${val.uuid}"]`
this._target = `[id="${val.uuid}"]`
this.moveable.rotatable = true //
_target = `[id="${val.uuid}"]`
moveable.rotatable = true //
//
// this.moveable.renderDirections = val.type === 'w-text' ? ['e', 'se'] : 'w-image' ? ['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se'] : ['nw', 'ne', 'sw', 'se']
switch (val.type) {
case 'w-text':
this.moveable.renderDirections = ['e', 'se']
moveable.renderDirections = ['e', 'se']
break
case 'w-image':
this.moveable.renderDirections = ['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se']
moveable.renderDirections = ['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se']
break
case 'w-svg':
this.moveable.renderDirections = ['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se']
moveable.renderDirections = ['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se']
break
default:
this.moveable.renderDirections = ['nw', 'ne', 'sw', 'se']
moveable.renderDirections = ['nw', 'ne', 'sw', 'se']
break
}
// // Set Move Auto
this.moveable.setState({ target: this._target }, () => {
moveable.setState({ target: _target }, () => {
// mouseevent
if (this.activeMouseEvent) {
this.moveable.dragStart(this.activeMouseEvent)
if (activeMouseEvent.value) {
moveable?.dragStart(activeMouseEvent.value)
// TODO 使mouseevent
this.$store.commit('setMouseEvent', null)
store.commit('setMouseEvent', null)
}
})
// // End
this.$store.commit('setShowMoveable', true)
store.commit('setShowMoveable', true)
// 线
if (!this.moveable.elementGuidelines.includes(target)) {
this.moveable.elementGuidelines.push(target)
if (!moveable.elementGuidelines?.includes(target)) {
moveable.elementGuidelines?.push(target)
}
} else {
this.moveable.target = `[id="empty"]`
if (this.moveable.target !== `[id="empty"]`) {
moveable.target = `[id="empty"]`
if (moveable.target !== `[id="empty"]`) {
setTimeout(() => {
this.moveable.target = `[id="empty"]`
if (!moveable) return
moveable.target = `[id="empty"]`
}, 210)
}
// feature: 线
this.moveable.elementGuidelines.length = 0
if (moveable.elementGuidelines) {
moveable.elementGuidelines.length = 0
}
},
showMoveable(val) {
}
}
)
watch(
() => showMoveable.value,
val => {
if (!moveable) return
if (val) {
this.moveable.target = this._target
moveable.target = _target
} else {
this.moveable.target = `[id="empty"]`
moveable.target = `[id="empty"]`
}
},
showRotatable(val) {
}
)
watch(
() => showRotatable.value,
val => {
// TODO:
this.moveable.renderDirections = val ? ['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se'] : []
this.moveable.resizable = val
this.moveable.scalable = val
document.getElementsByClassName('moveable-rotation')[0].style.display = val ? 'block' : 'none'
},
updateRect(val) {
this.moveable.updateRect()
},
updateSelect() {
const items = this.$store.getters.dSelectWidgets
if (!moveable) return
moveable.renderDirections = val ? ['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se'] : []
moveable.resizable = val
moveable.scalable = val
const el = document.getElementsByClassName('moveable-rotation')[0] as HTMLElement
el.style.display = val ? 'block' : 'none'
}
)
watch(
() => updateRect.value,
() => {
moveable?.updateRect()
}
)
watch(
() => updateSelect.value,
() => {
const items = store.getters.dSelectWidgets
setTimeout(async () => {
this.moveable.updateRect()
await this.$nextTick()
if (!moveable) return
moveable.updateRect()
await nextTick()
for (let i = 0; i < items.length; i++) {
console.log(items[i].uuid)
document.getElementById(items[i].uuid)?.classList.add('widget-selected')
}
this.moveable.renderDirections = []
this.moveable.rotatable = false
moveable.renderDirections = []
moveable.rotatable = false
const targetCollector = [].slice.call(document.querySelectorAll('.widget-selected'))
console.log(targetCollector)
this.moveable.target = targetCollector
moveable.target = targetCollector
for (let i = 0; i < items.length; i++) {
document.getElementById(items[i].uuid)?.classList.remove('widget-selected')
}
}, 400)
},
//
dSelectWidgets: {
handler(items) {
const alt = this.$store.getters.dAltDown
}
)
/** 选择的元素 */
watch(
() => dSelectWidgets.value,
(items) => {
if (!moveable) return
const alt = store.getters.dAltDown
// if (items.length > 1) {
// console.log('')
// }
@ -122,28 +172,32 @@ export default defineComponent({
for (let i = 0; i < items.length; i++) {
document.getElementById(items[i].uuid)?.classList.add('widget-selected')
}
this.moveable.renderDirections = []
this.moveable.rotatable = false
moveable.renderDirections = []
moveable.rotatable = false
const targetCollector = [].slice.call(document.querySelectorAll('.widget-selected'))
// this.moveable.target = `[id="empty"]`
this.moveable.target = targetCollector
moveable.target = targetCollector
for (let i = 0; i < items.length; i++) {
document.getElementById(items[i].uuid)?.classList.remove('widget-selected')
}
}
},
deep: true,
},
// 线
guidelines(lines) {
console.log(lines)
{ deep: true }
)
this.moveable.verticalGuidelines = lines.verticalGuidelines
this.moveable.horizontalGuidelines = lines.horizontalGuidelines
},
},
mounted() {
let holdGroupPosition: any = null
/** 标尺线 */
watch(
() => guidelines.value,
(lines) => {
if (!moveable) return
console.log(lines)
moveable.verticalGuidelines = lines.verticalGuidelines
moveable.horizontalGuidelines = lines.horizontalGuidelines
}
)
onMounted(() => {
let holdGroupPosition: Record<string, any> | null = null
const moveableOptions: any = {
target: document.querySelector(`[id="empty"]`),
// container: document.querySelector('#page-design'),
@ -184,8 +238,8 @@ export default defineComponent({
// -- END --
triggerAblesSimultaneously: true,
}
const moveable = new Moveable(document.body, moveableOptions)
this.moveable = moveable
const moveableInstance = new Moveable(document.body, moveableOptions)
moveable = moveableInstance
const helper: any = new MoveableHelper()
@ -194,7 +248,7 @@ export default defineComponent({
// console.log(event)
// 'resizeStart', 'resize', 'resizeEnd', rotate, onScale, onScaleStart
if (['resizeStart', 'rotate', 'resize'].includes(event)) {
moveable.on(event, (...args) => {
moveable?.on(event as any, (...args) => {
// this.$emit(event, ...args)
helper[helperEvent] && helper[helperEvent](...args)
})
@ -206,49 +260,62 @@ export default defineComponent({
moveable
.on('dragStart', ({ inputEvent, target, stop }) => {
if (inputEvent.target.nodeName === 'PRE') {
this.dActiveElement.editable && stop()
dActiveElement.value.editable && stop()
}
this.dActiveElement.lock && stop()
dActiveElement.value.lock && stop()
})
.on('drag', ({ target, transform, left, top, inputEvent }) => {
// target!.style.transform = transform]
target!.style.left = `${left}px`
target!.style.top = `${top}px`
this.holdPosition = { left, top }
holdPosition = { left, top }
})
.on('dragEnd', ({ target, isDrag, inputEvent }) => {
// console.log('onDragEnd', inputEvent)
// TODO mouseevent
this.$store.commit('setMouseEvent', null)
store.commit('setMouseEvent', null)
inputEvent.stopPropagation()
inputEvent.preventDefault()
// console.log(this.holdPosition, inputEvent.pageX, inputEvent.pageY)
if (this.holdPosition) {
this.updateWidgetData({
uuid: this.dActiveElement.uuid,
if (holdPosition) {
store.dispatch('updateWidgetData', {
uuid: dActiveElement.value.uuid,
key: 'left',
value: Number(this.holdPosition?.left),
value: Number(holdPosition?.left),
})
this.updateWidgetData({
uuid: this.dActiveElement.uuid,
// this.updateWidgetData({
// uuid: this.dActiveElement.uuid,
// key: 'left',
// value: Number(this.holdPosition?.left),
// })
store.dispatch('updateWidgetData', {
uuid: dActiveElement.value.uuid,
key: 'top',
value: Number(this.holdPosition?.top),
value: Number(holdPosition?.top),
})
this.holdPosition = null // important
// this.updateWidgetData({
// uuid: this.dActiveElement.uuid,
// key: 'top',
// value: Number(this.holdPosition?.top),
// })
holdPosition = null // important
setTimeout(() => {
this.pushHistory()
store.dispatch('pushHistory')
// this.pushHistory()
}, 100)
}
})
// .on('keyUp', (e) => {
// moveable.updateRect()
// })
.on('rotate', ({ target, beforeDist, dist, transform }: any) => {
// { target, beforeDist, dist, transform }
.on('rotate', ({ target, beforeDist, dist, transform }) => {
// console.log('onRotate', Number(this.dActiveElement.rotate) + Number(beforeDist + dist))
// target.style.transform = transform
console.log(target.style.transform)
})
.on('rotateEnd', (e: any) => {
.on('rotateEnd', (e) => {
const tf = e.target.style.transform
const iof = tf.indexOf('rotate')
let rotate = ''
@ -258,29 +325,34 @@ export default defineComponent({
rotate = half.slice(0, half.indexOf(')'))
}
rotate &&
this.updateWidgetData({
uuid: this.dActiveElement.uuid,
store.dispatch("updateWidgetData", {
uuid: dActiveElement.value.uuid,
key: 'rotate',
value: rotate,
})
// this.updateWidgetData({
// uuid: this.dActiveElement.uuid,
// key: 'rotate',
// value: rotate,
// })
})
.on('resizeStart', (args) => {
console.log(args.target.style.transform)
this.moveable.snappable = false
if (this.dActiveElement.type === 'w-text') {
if (!moveable) return
moveable.snappable = false
if (dActiveElement.value.type === 'w-text') {
if (String(args.direction) === '1,0') {
moveable.keepRatio = false
moveable.scalable = false
}
if (String(args.direction) === '1,1') {
moveable.keepRatio = false
resizeStartWidth = args.target.offsetWidth
this.startHL = Number(args.target!.style.lineHeight.replace('px', ''))
this.startLS = Number(args.target!.style.letterSpacing.replace('px', ''))
this.resetRatio = 1
resizeStartWidth = (args.target as HTMLElement).offsetWidth
startHL = Number(args.target!.style.lineHeight.replace('px', ''))
startLS = Number(args.target!.style.letterSpacing.replace('px', ''))
resetRatio = 1
}
} else if (this.dActiveElement.type === 'w-image' || this.dActiveElement.type === 'w-qrcode' || this.dActiveElement.type === 'w-svg') {
} else if (dActiveElement.value.type === 'w-image' || dActiveElement.value.type === 'w-qrcode' || dActiveElement.value.type === 'w-svg') {
const dirs = ['1,0', '0,-1', '-1,0', '0,1']
dirs.includes(String(args.direction)) && (moveable.keepRatio = false)
}
@ -288,34 +360,35 @@ export default defineComponent({
.on('resize', (args: any) => {
const { target, width, height, dist, delta, clientX, clientY, direction } = args
console.log(2, args)
if (this.dActiveElement.type === 'w-text') {
if (dActiveElement.value.type === 'w-text') {
if (String(direction) === '1,1') {
this.resetRatio = width / resizeStartWidth
target!.style.fontSize = this.dActiveElement.fontSize * this.resetRatio + 'px'
target!.style.letterSpacing = this.startLS * this.resetRatio + 'px'
target!.style.lineHeight = this.startHL * this.resetRatio + 'px'
resetRatio = width / resizeStartWidth
target!.style.fontSize = dActiveElement.value.fontSize * resetRatio + 'px'
target!.style.letterSpacing = startLS * resetRatio + 'px'
target!.style.lineHeight = startHL * resetRatio + 'px'
}
target.style.width = width
target.style.height = height
this.resizeTempData = { width, height }
resizeTempData = { width, height }
// moveable.updateRect()
target.style.backgroundImage = 'none'
// moveable.keepRatio !== this.resetRatio > 1 && (moveable.keepRatio = this.resetRatio > 1)
} else if (this.dActiveElement.type == 'w-image' || this.dActiveElement.type === 'w-qrcode' || this.dActiveElement.type === 'w-svg') {
this.resizeTempData = { width, height }
} else if (this.dActiveElement.type == 'w-group') {
} else if (dActiveElement.value.type == 'w-image' || dActiveElement.value.type === 'w-qrcode' || dActiveElement.value.type === 'w-svg') {
resizeTempData = { width, height }
} else if (dActiveElement.value.type == 'w-group') {
// let record = this.dActiveElement.record
// this.dActiveElement.tempScale = width / record.width
this.$store.commit('resize', { width: width, height: height })
store.commit('resize', { width: width, height: height })
// this.resizeTempData = { width, height }
// let record = this.dActiveElement.record
// setTransformAttribute(target, 'scale', width / record.width)
} else {
this.$store.commit('resize', { width: width, height: height })
store.commit('resize', { width: width, height: height })
}
this.dActiveElement.rotate && (target!.style.transform = target!.style.transform.replace('(0deg', `(${this.dActiveElement.rotate}`))
dActiveElement.value.rotate && (target!.style.transform = target!.style.transform.replace('(0deg', `(${dActiveElement.value.rotate}`))
})
.on('resizeEnd', (e: any) => {
if (!moveable) return
moveable.resizable = true
// moveable.scalable = true
moveable.snappable = true
@ -325,7 +398,7 @@ export default defineComponent({
// //
// return
// }
console.log('重置translate', this.dActiveElement)
console.log('重置translate', dActiveElement.value)
//
// if (this.dActiveElement.cache && this.dActiveElement.cache.recordLeft) {
// const left = e.lastEvent.drag.translate[0] + Number(this.dActiveElement.cache.recordLeft)
@ -338,19 +411,32 @@ export default defineComponent({
// }
const left = e.lastEvent.drag.translate[0]
const top = e.lastEvent.drag.translate[1]
this.updateWidgetMultiple({
uuid: this.dActiveElement.uuid,
store.dispatch("updateWidgetMultiple", {
uuid: dActiveElement.value.uuid,
data: [
{
key: 'left',
value: Number(this.dActiveElement.left) + left,
value: Number(dActiveElement.value.left) + left,
},
{
key: 'top',
value: Number(this.dActiveElement.top) + top,
value: Number(dActiveElement.value.top) + top,
},
],
})
// this.updateWidgetMultiple({
// uuid: this.dActiveElement.uuid,
// data: [
// {
// key: 'left',
// value: Number(this.dActiveElement.left) + left,
// },
// {
// key: 'top',
// value: Number(this.dActiveElement.top) + top,
// },
// ],
// })
// translate
const tf = e.target.style.transform
const iof = tf.indexOf('translate')
@ -361,47 +447,52 @@ export default defineComponent({
// this.moveable.updateRect()
// }, 10)
}
if (this.resizeTempData) {
this.$store.commit('resize', this.resizeTempData)
this.resizeTempData = null
if (resizeTempData) {
store.commit('resize', resizeTempData)
resizeTempData = null
setTimeout(async () => {
await this.$nextTick()
this.moveable.updateRect()
await nextTick()
if (moveable) {
moveable.updateRect()
}
}, 10)
}
try {
if (this.dActiveElement.type === 'w-text') {
if (dActiveElement.value.type === 'w-text') {
const d = e.direction || e.lastEvent.direction
String(d) === '1,1' && (this.dActiveElement.fontSize = this.dActiveElement.fontSize * this.resetRatio)
String(d) === '1,1' && (dActiveElement.value.fontSize = dActiveElement.value.fontSize * resetRatio)
}
} catch (err) {}
moveable.keepRatio = true
})
.on('scaleStart', (e) => {
if (this.dActiveElement.type === 'w-text') {
this.startHL = Number(e.target!.style.lineHeight.replace('px', ''))
this.startLS = Number(e.target!.style.letterSpacing.replace('px', ''))
this.resetRatio = 1
if (dActiveElement.value.type === 'w-text') {
startHL = Number(e.target!.style.lineHeight.replace('px', ''))
startLS = Number(e.target!.style.letterSpacing.replace('px', ''))
resetRatio = 1
} else {
if (!moveable) return
moveable.scalable = false
}
})
.on('scale', (e) => {
if (!moveable) return
moveable.resizable = false
const { target, scale, transform } = e
this.resetRatio = scale[0]
resetRatio = scale[0]
target!.style.transform = transform
this.dActiveElement.rotate && (target!.style.transform = target!.style.transform.replace('0deg', this.dActiveElement.rotate))
dActiveElement.value.rotate && (target!.style.transform = target!.style.transform.replace('0deg', dActiveElement.value.rotate))
})
.on('scaleEnd', (e) => {
.on('scaleEnd', (e: Record<string, any>) => {
if (!moveable) return
moveable.resizable = true
// moveable.scalable = true
moveable.keepRatio = true
console.log(e.target.style.transform)
try {
if (this.dActiveElement.type === 'w-text') {
if (dActiveElement.value.type === 'w-text') {
const d = e.direction || e.lastEvent.direction
String(d) === '1,1' && (this.dActiveElement.fontSize = this.dActiveElement.fontSize * this.resetRatio)
String(d) === '1,1' && (dActiveElement.value.fontSize = dActiveElement.value.fontSize * resetRatio)
}
} catch (err) {}
})
@ -412,7 +503,7 @@ export default defineComponent({
const events = e.events
for (let i = 0; i < events.length; i++) {
const ev = events[i]
const currentWidget = this.dWidgets.find((item: any) => item.uuid === ev.target.getAttribute('data-uuid'))
const currentWidget = dWidgets.value.find((item: any) => item.uuid === ev.target.getAttribute('data-uuid'))
const left = Number(currentWidget.left) + ev.beforeTranslate[0]
// debug -- start --
if (i === 1) {
@ -429,12 +520,12 @@ export default defineComponent({
for (const key in holdGroupPosition) {
if (Object.prototype.hasOwnProperty.call(holdGroupPosition, key)) {
const item = holdGroupPosition[key]
this.updateWidgetData({
store.dispatch('updateWidgetData', {
uuid: key,
key: 'left',
value: item.left,
})
this.updateWidgetData({
store.dispatch("updateWidgetData", {
uuid: key,
key: 'top',
value: item.top,
@ -445,7 +536,7 @@ export default defineComponent({
// background: linear-gradient(to right, #ccc 0%, #ccc 50%, transparent 50%);
// background-size: 12px 1px;
})
.on('resizeGroupStart', ({ events }: any) => {
.on('resizeGroupStart', ({ events }) => {
console.log(events)
// events.forEach((ev, i) => {
// const frame = this.frames[i];
@ -462,7 +553,7 @@ export default defineComponent({
// ev.dragStart && ev.dragStart.set(frame.translate);
// });
})
.on('resizeGroup', (e: any) => {
.on('resizeGroup', (e) => {
// events.forEach(({ target, width, height, drag }, i) => {
// const frame = this.frames[i];
// target.style.width = `${width}px`;
@ -473,26 +564,28 @@ export default defineComponent({
// = `translate(${drag.beforeTranslate[0]}px, ${drag.beforeTranslate[1]}px)`;
// });
})
.on('resizeGroupEnd', ({ targets, isDrag }: any) => {
.on('resizeGroupEnd', ({ targets, isDrag }) => {
console.log('onResizeGroupEnd', targets, isDrag)
})
// -- Start --
useSelecto(this.moveable)
useSelecto(moveable)
// -- END --
},
async created() {
})
async function created() {
await nextTick()
const Ele = document.getElementById('page-design')
// TODO
Ele?.addEventListener('scroll', () => {
this.moveable.updateRect()
})
},
methods: {
...mapActions(['updateWidgetData', 'updateWidgetMultiple', 'pushHistory']),
},
moveable && (moveable.updateRect())
})
}
created()
// ...mapActions(['updateWidgetData', 'updateWidgetMultiple', 'pushHistory']),
</script>
<style lang="less">