daybrush / selecto

Selecto.js is a component that allows you to select elements in the drag area using the mouse or touch.

Home Page:https://daybrush.com/selecto

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

vue-selecto 框元素与鼠标位置不对应

hqiaozhang opened this issue · comments

@drag="onDrag" @rotate="onRotate" @renderGroup="onRenderGroup" @renderGroupEnd="onRenderGroupEnd" @dragEnd="onDragEnd" @renderStart="onRenderStart" @clickGroup="onClickGroup" /> <Selecto ref="selectoRef" :dragContainer="dragContainer" :selectableTargets="['.canvas .widget']" :toggleContinueSelect="['shift']" :hitRate="0" :selectByClick="true" :selectFromInside="false" :ratio="0" @dragStart="onDragStart" @select="onSelect" @selectEnd="onSelectEnd" /> <!-- 自定义源码 --> <custom-code-container v-if="isCustomPage" :isView="isView" :item="backgroundItem" /> <template v-else> <background-widget v-if="background" :key="background.id" :item="backgroundItem" :isView="isView" v-on="$listeners" /> <!-- 外部链接 --> <iframe v-if="links" :src="links"></iframe> <template v-else> <widget-container class="widget" :id="'widget'+item.id" :ref="'widget'+item.id" :class="['widget'+i]" v-for="(item, i) in widgets" v-show="item.visible" :key="item.id" :item="item" :isView="isView" v-on="$listeners" /> <!-- 线段 --> <drawCurveWidget v-if="linesWidgets" :item="linesWidgets" :allPaths="linePaths" :style="{pointerEvents: isDrawLine || isEditLine ? 'all' : 'none'}" /> </template>
<script> import { mixins } from './mixins' import eventBus from 'poster/utils/eventBus.js' import { deepFlat } from "@daybrush/utils"; import Selecto from "vue-selecto"; import Moveable from "vue-moveable"; import { GroupManager } from "@moveable/helper"; import CustomCodeContainer from '../containers/customCodeContainer' import WidgetContainer from '../containers/editContainer' import { mapState } from 'poster/poster.vuex' export default { mixins: [mixins], data() { const groupManager = new GroupManager([]); const targets = []; const moveableRef = null; const selectoRef = null; return { groupManager, targets, moveableRef, selectoRef, // dragContainer: document.querySelector('.edit_canvas'), dragContainer: null, activeWidget: null, selectedElements: [], isMoveableVisible: false, } }, computed: { ...mapState(['inputDragInfo', 'posterItems']), selectedElementRefs() { return this.targets } }, components: { CustomCodeContainer, Selecto, Moveable, WidgetContainer }, mounted() { const elements = this.$refs.selectoRef.getSelectableElements(); this.groupManager.set([], elements); this.moveableRef = this.$refs.moveableRef; this.selectoRef = this.$refs.selectoRef; this.$nextTick(() => { this.dragContainer = document.querySelector('.edit_canvas') }) eventBus.$on('destroyMoveable', this.deleteSelectedElements) }, methods: { handleCanvas(e) { console.log('run handleCanvas') if(this.activeWidget) { this.activeWidget.deactivated() this.activeWidget = null } }, getActiveWidgetRef(e, isUpdataStyle = true) { const { id } = e.target.__vue__.item const widget = this.$refs['widget'+id][0] if(isUpdataStyle && !widget.item.lock) { e.target.style.cssText += e.cssText; } // 如果该组件被锁定了不做任务操作 if(widget.item.lock) { return null } return widget }, toggleSelect(element) { // 切换元素的选中状态 const index = this.selectedElements.findIndex(selectedElement => selectedElement.$el.id === element.id); if (index === -1) { this.selectedElements.push(element); } else { this.selectedElements.splice(index, 1); } }, isElementSelected(element) { // 检查元素是否被选中 return this.selectedElements.some(selectedElement => selectedElement.$el.id === element.id); }, deleteSelectedElements() { // 删除选中元素 this.targets = this.targets.filter(element => !this.selectedElements.some(selectedElement => selectedElement.$el.id === element.id)); this.selectedElements = []; this.isMoveableVisible = false; }, updateSelectedElementsPosition(pos) { // 更新选中元素的位置 const x = parseInt(pos.x); const y = parseInt(pos.y); this.selectedElements.forEach(selectedElement => { const movedElement = this.targets.find(element => element.id === selectedElement.$el.id); if(movedElement) { movedElement.style.transform = 'none' } }); this.moveableRef.updateRect() this.moveableRef.request("draggable", { x, y}); }, onRenderStart(e) { // 关闭右键菜单 this.$parent.closeContextmenu() this.activated(e) }, onDrag(e) { const widget = this.getActiveWidgetRef(e) if(widget) { widget.onDrag(e.left, e.top, e) } // }, onResize(e) { const widget = this.getActiveWidgetRef(e) if(widget) { widget.onResize(e.width, e.height) } }, onRotate(e) { const widget = this.getActiveWidgetRef(e) if(widget) { widget.onRotate(Math.floor(e.rotate)) } }, setSelectedTargets(nextTargetes) { this.$refs.selectoRef.setSelectedTargets(deepFlat(nextTargetes)); this.targets = nextTargetes; }, activated(e) { const widget = this.getActiveWidgetRef(e, false) if(widget && this.activeWidget && this.activeWidget._uid !== widget._uid) { this.activeWidget.deactivated() } if(widget) { this.activeWidget = widget widget.activated(e) this.toggleSelect(widget) } }, onDragEnd(e) { const widget = this.getActiveWidgetRef(e, false) if(widget) { widget.onDragStop(e) } }, onRenderGroup(e) { e.events.forEach((ev, i) => { ev.target.style.cssText += ev.cssText; }); }, onRenderGroupEnd(e) { const { targets, transform } = e console.log(transform) // 提取 translate 的值 const translateRegex = /translate\((-?[\d.]+)px, (-?[\d.]+)px\)/; const [, translateX, translateY] = transform.match(translateRegex); // console.log(parseFloat(translateX)); // -234.7853489 // console.log(parseFloat(translateY)); // -193.0959523 // 提取 rotate 的值 const rotateRegex = /rotate\((-?[\d.]+)deg\)/; const [, rotate] = transform.match(rotateRegex); // console.log(parseFloat(rotate)); // 11.652700248605072 // 提取 scale 的值 const scaleRegex = /scale\(([\d.]+), ([\d.]+)\)/; const [, scaleX, scaleY] = transform.match(scaleRegex); // console.log(parseFloat(scaleX)); // 1 // console.log(parseFloat(scaleY)); // 1 targets.forEach(target => { const widget = this.$refs[target.id][0] if(widget) { const {offsetLeft, offsetTop, offsetWidth: w, offsetHeight: h} = target const x = offsetLeft + Math.round(translateX) const y = offsetTop + Math.round(translateY) const rotateZ = Math.round(rotate) widget.updateDragInfo({x, y, w, h, rotateZ}) } }); }, onClickGroup(e) { if (!e.moveableTarget) { this.setSelectedTargets([]); return; } if (e.isDouble) { const childs = this.groupManager.selectSubChilds( this.targets, e.moveableTarget ); this.setSelectedTargets(childs.targets()); return; } if (e.isTrusted) { this.$refs.selectoRef.clickTarget( e.inputEvent, e.moveableTarget ); } }, onDragStart(e) { const moveable = this.$refs.moveableRef; const target = e.inputEvent.target; const flatted = deepFlat(this.targets); if (target.tagName === "BUTTON" || moveable.isMoveableElement(target) || flatted.some(t => t === target || t.contains(target)) ) { e.stop(); } e.data.startTargets = this.targets; }, onSelect(e) { const { startAdded, startRemoved, isDragStartEnd } = e; if (isDragStartEnd) { return; } const nextChilds = this.groupManager.selectSameDepthChilds(e.data.startTargets, startAdded, startRemoved); this.setSelectedTargets(nextChilds.targets()); }, onSelectEnd(e) { const { isDragStartEnd, isClick, added, removed, inputEvent, } = e; const moveable = this.$refs.moveableRef; if (isDragStartEnd) { inputEvent.preventDefault(); moveable.waitToChangeTarget().then(() => { moveable.dragStart(inputEvent); }); } let nextChilds; if (isDragStartEnd || isClick) { nextChilds = this.groupManager.selectCompletedChilds(e.data.startTargets, added,removed); } else { nextChilds = this.groupManager.selectSameDepthChilds(e.data.startTargets, added, removed); } e.currentTarget.setSelectedTargets(nextChilds.flatten()); this.setSelectedTargets(nextChilds.targets()); }, setElementGuidelines(data) { for(let i = 0; i< data.length; i++) { const item = data[i] this.elementGuidelines.push({ element: '.widget'+i, className: "red", }) if(!_.isEmpty(item.childList)) { this.setElementGuidelines(item.childList) } } } }, watch: { inputDragInfo: { handler(pos) { this.$nextTick(() => { this.updateSelectedElementsPosition(pos) }) }, deep: true }, posterItems(data) { this.$nextTick(() => { const elements = this.$refs.selectoRef.getSelectableElements(); this.groupManager.set([], elements); }) this.elementGuidelines = [] this.setElementGuidelines(data) } } } </script> <style lang="scss" > .poster-editor { .main-panel { margin-top: 25px; } } /* pos guidelines */ .moveable-normal.red { background: red !important; } /* gap guidelines */ .moveable-gap.red { background: red !important; } /* When snapped to an element in elementGuidelines */ .moveable-bold.red { background: red !important; } /* A dashed line between target and element */ .moveable-dashed.red { border-top-color: red !important; border-left-color: red !important; } </style>

上以代码组件是动态渲染的,想通过vue-moveable实现组件框选功能,但是以上代码框选时,选框与鼠标位置不对应