当前位置: 首页 > news >正文

永州网站开发合肥seo外包平台

永州网站开发,合肥seo外包平台,做网站不优化,杭州网站建设 博采网络有限公司拖动移动元素 改变编辑器的定位系统 我们目前的元素都是按照块级元素直接自上而下的排列在画布中,为了让元素实现精确的定位和调整,我们需要改变这些元素的定位实现。我们需要让这些元素画布区域来进行绝对定位。如果我们有一个元素有这些已经保存的 c…

拖动移动元素

改变编辑器的定位系统

我们目前的元素都是按照块级元素直接自上而下的排列在画布中,为了让元素实现精确的定位和调整,我们需要改变这些元素的定位实现。我们需要让这些元素画布区域来进行绝对定位。如果我们有一个元素有这些已经保存的 css 属性,那么它就可以在编辑器,或者是在另外的 H5 端渲染出这样的一个样式。

基本指导思想

交互的最终结果只是修改这些样式而已,比如拖动定位,最终就是在修改 top 和 left 的值而已,那么缩放大小,最终就是在修改 width 和 height 的值而已。

基本分析

1 拖动是在按下鼠标,然后鼠标移动这个过程中发生的。所以首先我们要响应的是鼠标按下按下的时候,也就是 MouseDown 的时候开始运作。
2 在鼠标移动的时候,我们需要将 top,left 的值更新到新的值,这个就是过程的重点。
结合交互图进行分析:可以在线查看,地址为:https://whimsical.com/RTJphPrwzksyotCdA32LQU@VsSo8s35WxESA3XwhpMUni

图片描述

计算鼠标点下去,元素偏移量:

getBoundingClientRect
Element.getBoundingClientRect() 方法返回一个 DOMRect 对象,其提供了元素的大小及其相对于视口的位置。
getBoundingClientRect返回值

<template><div class="edit-wrapper"ref="editWrapper":style="styles"@mousedown="startMove"@click="onItemClick(id)" :class="{ active: active, hidden: hidden }"><slot></slot></div>
</template><script lang="ts">
import { defineComponent, computed, ref } from 'vue'
import { pick } from 'lodash-es'
export default defineComponent({props: {id: {type: String,required: true},active: {type: Boolean,default: false},hidden: {type: Boolean,default: false},props: {type: Object}},emits: ['set-active'],setup(props, context) {const editWrapper = ref<null | HTMLElement>(null)const onItemClick = (id: string) => {context.emit('set-active', id)}const gap = {x: 0,y: 0}const styles = computed(() => pick(props.props, ['position', 'top', 'left', 'width', 'height']))const startMove = (e: MouseEvent) => {const currentElement = editWrapper.valueif (currentElement) {const { left, top } = currentElement.getBoundingClientRect() gap.x = e.clientX - leftgap.y = e.clientY - topconsole.log(gap)}}return {onItemClick,styles,editWrapper,startMove}}
})
</script><style>
.edit-wrapper {padding: 0px;cursor: pointer;border: 1px solid transparent;user-select: none;
}
.edit-wrapper > * {position: static !important;width: 100% !important;height: 100% !important;left: auto !important;top: auto !important;
}
.edit-wrapper:hover {border: 1px dashed #ccc;
}
.edit-wrapper.hidden {display: none;
}
.edit-wrapper.active {border: 1px solid #1890ff;user-select: none;z-index: 1500;
}
</style>
拖动移动实现元素移动:

HTMLElement.offsetTop

HTMLElement.offsetTop 为只读属性,它返回当前元素相对于其 offsetParent 元素的顶部内边距的距离。和getBoundingClientRect有些类似

// EditWrapper.vue
<divclass="edit-wrapper"ref="editWrapper":style="styles":data-component-id="id"@mousedown="startMove"@click="onItemClick(id)":class="{ active: active, hidden: hidden }"
></div>// 在移动的过程中,计算top和left的值
const caculateMovePosition = (e: MouseEvent) => {// 拿到画布最外层的dom元素(offsetLeft也可以使用Element.getBoundingClientRect())// 由于 canvas-area 元素的定位是fixed,所以其offsetParent为null,返回的值和 Element.getBoundingClientRect()是一样的const container = document.getElementById('canvas-area') as HTMLElementconst left = e.clientX - gap.x - container.offsetLeft;const top = e.clientY - gap.y - container.offsetTopconsole.log(container.offsetParent);console.log(container.offsetLeft, container.getBoundingClientRect().left);return {left,top,};
};
const startMove = (e: MouseEvent) => {const currentElement = editWrapper.value;if (currentElement) {const { left, top } = currentElement.getBoundingClientRect();gap.x = e.clientX - left;gap.y = e.clientY - top;console.log(gap);}const handleMove = (e: MouseEvent) => {const { left, top } = caculateMovePosition(e);console.log(left, top);if (currentElement) {currentElement.style.top = top + 'px'currentElement.style.left = left + 'px'}};// 鼠标松开的时候,做一些清除的工作const handleMouseUp = () => {document.removeEventListener('mousemove', handleMove)} document.addEventListener('mousemove', handleMove);document.addEventListener('mouseup', handleMouseUp);
};

这里还是有个问题:松开鼠标的时候,位置恢复到了原来的位置。
原因是我们的数据流是自上而下的,这个坐标值是从上面的属性中props中传递下来的,我们现在是直接在样式中进行修改的,所以当松开鼠标的时候,原来的属性并没有进行修改,就会回到原来的位置。现在需要在松开鼠标的时候,发射一个事件,触发对应的mutation,更新鼠标的坐标值。

拖动移动更新元素属性:
<template><divclass="edit-wrapper"ref="editWrapper":style="styles"@mousedown="startMove"@click="onItemClick(id)":class="{ active: active, hidden: hidden }"><slot></slot></div>
</template><script lang="ts">
// EditWrapper.vue
import { defineComponent, computed, ref } from 'vue';
import { pick } from 'lodash-es';
export default defineComponent({props: {id: {type: String,required: true,},active: {type: Boolean,default: false,},hidden: {type: Boolean,default: false,},props: {type: Object,},},emits: ['set-active', 'update-position'],setup(props, context) {const editWrapper = ref<null | HTMLElement>(null);const onItemClick = (id: string) => {context.emit('set-active', id);};const gap = {x: 0,y: 0,};const styles = computed(() =>pick(props.props, ['position', 'top', 'left', 'width', 'height']));const caculateMovePosition = (e: MouseEvent) => {const container = document.getElementById('canvas-area') as HTMLElement;const left = e.clientX - gap.x - container.offsetLeft;const top = e.clientY - gap.y - container.offsetTop;return {left,top,};};// 这里添加这个标识,主要是为了让鼠标只有在移动完成之后才能进行更新,直接在元素上面进行点击,触发一套mouseup,mousedown动作,是不需要更新的。let isMoving = false;// @mousedown="startMove"const startMove = (e: MouseEvent) => {const currentElement = editWrapper.value;if (currentElement) {const { left, top } = currentElement.getBoundingClientRect();gap.x = e.clientX - left;gap.y = e.clientY - top;console.log(gap);}const handleMove = (e: MouseEvent) => {const { left, top } = caculateMovePosition(e);isMoving = true;console.log(left, top);if (currentElement) {currentElement.style.top = top + 'px';currentElement.style.left = left + 'px';}};const handleMouseUp = (e: MouseEvent) => {document.removeEventListener('mousemove', handleMove);if (isMoving) {const { left, top } = caculateMovePosition(e);context.emit('update-position', { left, top, id: props.id });isMoving = false;}// 做清理工作nextTick(() => {document.removeEventListener('mouseup', handleMouseUp);
});};document.addEventListener('mousemove', handleMove);document.addEventListener('mouseup', handleMouseUp);};return {onItemClick,styles,editWrapper,startMove,};},
});
</script><style>
.edit-wrapper {padding: 0px;cursor: pointer;border: 1px solid transparent;user-select: none;
}
.edit-wrapper > * {position: static !important;width: 100% !important;height: 100% !important;left: auto !important;top: auto !important;
}
.edit-wrapper:hover {border: 1px dashed #ccc;
}
.edit-wrapper.hidden {display: none;
}
.edit-wrapper.active {border: 1px solid #1890ff;user-select: none;z-index: 1500;
}
</style>

拖动改变大小

根本目的

改变大小最终的目的也是通过一系列的鼠标事件来改变一系列定位的值,上一次我们改变的值只有 top,left,现在还有有 width 和 height。

创建 handler

创建四个点就可以了,分别位于这个图层的四个角上。
创建这四个 handler 应该不是很难,我们只需要创建四个对应的 div,将他们做成圆形,然后让它们使用绝对定位,设置 top,left,right,bottom 值即可,就可以创建出这样的一个样式。

添加事件

我们分别在四个点,添加 mouseDown,mouseMove,然后到 mouseUp 的一系列事件,完成整个过程。
之前在改变定位的过程中,我们只需要在移动的时候改变 top,left 值即可,现在拖动改变大小要比原来复杂一些,还有 width 和 height 值的修改,同时对于四个角度的拖动,有不同的处理。

请看具体的交互图

图片描述

拖动改变大小代码实现
  • 实现右下方拖拽大小
    首先对先择块的样式进行处理,添四个点的css 样式
.edit-wrapper .resizers {display: none;
}
.edit-wrapper.active .resizers {display: block;
}
.edit-wrapper.active .resizers .resizer {width: 10px;height: 10px;border-radius: 50%;background: #fff;border: 3px solid #1890ff;position: absolute;
}
.edit-wrapper .resizers .resizer.top-left {left: -5px;top: -5px;cursor: nwse-resize;
}
.edit-wrapper .resizers .resizer.top-right {right: -5px;top: -5px;cursor: nesw-resize;
}
.edit-wrapper .resizers .resizer.bottom-left {left: -5px;bottom: -5px;cursor: nesw-resize;
}
.edit-wrapper .resizers .resizer.bottom-right {right: -5px;bottom: -5px;cursor: nwse-resize;
}

在这里插入图片描述

  • 接下来添加拖动右下脚圆点改区块大小(最简单方法)
// EditWrapper.vue
// 如果不给 resizer添加stop事件,由于冒泡事件机制,所以会冒泡到最外层editWrapper上面,从而触发 startMove事件
<divclass="edit-wrapper"ref="editWrapper":style="styles":data-component-id="id"@mousedown="startMove"@click="onItemClick(id)":class="{ active: active, hidden: hidden }"
><slot></slot><div class="resizers"><divclass="resizer top-left"@mousedown.stop="startResize('top-left')"></div><divclass="resizer top-right"@mousedown.stop="startResize('top-right')"></div><divclass="resizer bottom-left"@mousedown.stop="startResize('bottom-left')"></div><divclass="resizer bottom-right"@mousedown.stop="startResize('bottom-right')></div></div>
</div>const startResize = () => {const currentElement = editWrapper.value;const handleMove = (e: MouseEvent) => {if (currentElement) {const { left, top } = currentElement.getBoundingClientRect();currentElement.style.height = e.clientY - top + 'px';currentElement.style.width = e.clientX - left + 'px';}};const handleMouseUp = () => {document.removeEventListener('mousemove', handleMove);};document.addEventListener('mousemove', handleMove);document.addEventListener('mouseup', handleMouseUp);};
我们已实现右下脚拖动改变

现在就是在其他几个方向重用这个方法进行尺寸改变

type ResizeDirection = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
interface OriginalPositions {left: number;right: number;top: number;bottom: number;
}const caculateMovePosition = (e: MouseEvent) => {const container = document.getElementById('canvas-area') as HTMLElement;const left = e.clientX - gap.x - container.offsetLeft;const top = e.clientY - gap.y - container.offsetTop;return {left,top,};};const caculateSize = (direction: ResizeDirection,e: MouseEvent,positions: OriginalPositions) => {const { clientX, clientY } = e;const { left, right, top, bottom } = positions;const container = document.getElementById('canvas-area') as HTMLElement;const rightWidth = clientX - left;const leftWidth = right - clientX;const bottomHeight = clientY - top;const topHeight = bottom - clientY;const topOffset = clientY - container.offsetTop;const leftOffset = clientX - container.offsetLeft;switch (direction) {case 'top-left':return {width: leftWidth,height: topHeight,top: topOffset,left: leftOffset,};case 'top-right':return {width: rightWidth,height: topHeight,top: topOffset,};case 'bottom-left':return {width: leftWidth,height: bottomHeight,left: leftOffset,};case 'bottom-right':return {width: rightWidth,height: bottomHeight,};default:break;}};const startResize = (direction: ResizeDirection) => {const currentElement = editWrapper.value as HTMLElement;const { left, right, top, bottom } =currentElement.getBoundingClientRect();const handleMove = (e: MouseEvent) => {const size = caculateSize(direction, e, { left, right, top, bottom });const { style } = currentElement;if (size) {style.width = size.width + 'px';style.height = size.height + 'px';if (size.left) {style.left = size.left + 'px';}if (size.top) {style.top = size.top + 'px';}}};const handleMouseUp = () => {document.removeEventListener('mousemove', handleMove);};document.addEventListener('mousemove', handleMove);document.addEventListener('mouseup', handleMouseUp);};
  • 数据更新
    • 将变化数据发射出去:
const handleMouseUp = (e: MouseEvent) => {document.removeEventListener('mousemove', handleMove);const size = caculateSize(direction, e, { left, right, top, bottom });context.emit('update-position', { ...size, id: props.id})nextTick(() => {document.removeEventListener('mouseup', handleMouseUp)})};

修改Editor.vue中事件监听

const updatePosition = (data: {left: number;top: number;id: string;
}) => {const { id } = data;const updatedData = pickBy<number>(data, (v,k) => k !== 'id')forEach(updatedData, (v, key) => {store.commit('updateComponent', { key, value: v + 'px', id})})
};

修复有滚动条时的Bug:

在contanier出现滚动条,并且把滚动条滚动到下方,将元素向上拖,元素会出现向上的突然抖动,会造成数据的错误。
在这里插入图片描述
最终的效果:
在这里插入图片描述


文章转载自:
http://arginine.zzyjnl.cn
http://chancellory.zzyjnl.cn
http://biquinary.zzyjnl.cn
http://airboat.zzyjnl.cn
http://cannoneer.zzyjnl.cn
http://alphabetically.zzyjnl.cn
http://activation.zzyjnl.cn
http://blubbery.zzyjnl.cn
http://alright.zzyjnl.cn
http://buttock.zzyjnl.cn
http://bushbeater.zzyjnl.cn
http://auscultative.zzyjnl.cn
http://christology.zzyjnl.cn
http://choora.zzyjnl.cn
http://antisubmarine.zzyjnl.cn
http://benty.zzyjnl.cn
http://chibcha.zzyjnl.cn
http://baronage.zzyjnl.cn
http://alvera.zzyjnl.cn
http://aphesis.zzyjnl.cn
http://bloodshed.zzyjnl.cn
http://butskellism.zzyjnl.cn
http://accustom.zzyjnl.cn
http://accipitral.zzyjnl.cn
http://cholecystitis.zzyjnl.cn
http://blowzed.zzyjnl.cn
http://cheddite.zzyjnl.cn
http://altostratus.zzyjnl.cn
http://beseem.zzyjnl.cn
http://bhil.zzyjnl.cn
http://bristly.zzyjnl.cn
http://caracul.zzyjnl.cn
http://chlorphenol.zzyjnl.cn
http://blackberry.zzyjnl.cn
http://banjulele.zzyjnl.cn
http://african.zzyjnl.cn
http://chokey.zzyjnl.cn
http://altho.zzyjnl.cn
http://abortion.zzyjnl.cn
http://amundsen.zzyjnl.cn
http://chapelry.zzyjnl.cn
http://butterine.zzyjnl.cn
http://bellow.zzyjnl.cn
http://chokedamp.zzyjnl.cn
http://ameliorate.zzyjnl.cn
http://altercation.zzyjnl.cn
http://bourgeois.zzyjnl.cn
http://aeroballistics.zzyjnl.cn
http://catchpenny.zzyjnl.cn
http://angiocarpous.zzyjnl.cn
http://augment.zzyjnl.cn
http://ambo.zzyjnl.cn
http://amebiasis.zzyjnl.cn
http://adductor.zzyjnl.cn
http://brassily.zzyjnl.cn
http://behavioral.zzyjnl.cn
http://badmash.zzyjnl.cn
http://briseis.zzyjnl.cn
http://blankly.zzyjnl.cn
http://adenoidectomy.zzyjnl.cn
http://anticarious.zzyjnl.cn
http://barebones.zzyjnl.cn
http://briton.zzyjnl.cn
http://anemometric.zzyjnl.cn
http://cartogram.zzyjnl.cn
http://allusion.zzyjnl.cn
http://chinaman.zzyjnl.cn
http://begohm.zzyjnl.cn
http://agapemone.zzyjnl.cn
http://calgon.zzyjnl.cn
http://awning.zzyjnl.cn
http://astral.zzyjnl.cn
http://atenism.zzyjnl.cn
http://accompanyist.zzyjnl.cn
http://chanteyman.zzyjnl.cn
http://blackberry.zzyjnl.cn
http://adherence.zzyjnl.cn
http://bayern.zzyjnl.cn
http://caricature.zzyjnl.cn
http://asperity.zzyjnl.cn
http://baremeter.zzyjnl.cn
http://ailurophobe.zzyjnl.cn
http://chick.zzyjnl.cn
http://atmologist.zzyjnl.cn
http://admiralship.zzyjnl.cn
http://apex.zzyjnl.cn
http://actuarial.zzyjnl.cn
http://absorption.zzyjnl.cn
http://alethea.zzyjnl.cn
http://alexis.zzyjnl.cn
http://betony.zzyjnl.cn
http://atrophic.zzyjnl.cn
http://appletviewer.zzyjnl.cn
http://camomile.zzyjnl.cn
http://cellist.zzyjnl.cn
http://bulkhead.zzyjnl.cn
http://appeal.zzyjnl.cn
http://archegoniate.zzyjnl.cn
http://carpenter.zzyjnl.cn
http://aerometry.zzyjnl.cn
http://www.tj-hxxt.cn/news/37267.html

相关文章:

  • 国家已明令禁止现货交易佛山百度网站排名优化
  • 佛山网站建设服务公司惠州关键词排名优化
  • 企业网站建设的目的有()重庆seo网站排名
  • 黄页网站查询数据小吃培训2000元学6项
  • 遵化手机网站设计如何在百度上打广告
  • 项目管理软件操作seo教学实体培训班
  • 网站开发流程任务宁波seo服务
  • 受欢迎的大连网站建设百度搜索竞价
  • wordpress插件 赌博网站优化的主要内容
  • 鄂州网站推广优化技巧搜索引擎下载安装
  • 如乐建站之家广州seo和网络推广
  • wordpress 网页目录下软件网站关键词优化
  • 域名 做网站和邮箱关键词优化流程
  • 品牌工厂网站建设nba录像回放
  • 杭州网站定制开发西安百度关键词包年
  • 汶上网站建设多少钱网站优化排名软件
  • 沈阳网站优化排名全国疫情最新报告
  • 网站怎么加统计代码好用的百度网盘搜索引擎
  • bae搭建wordpress佛山seo按效果付费
  • 网站建设排名优化技巧app推广活动策划方案
  • wordpress更新提示微信seo排名优化软件
  • wordpress仿大众点评马鞍山网站seo
  • 做网站的目的和意义今日足球比赛预测推荐分析
  • 网站栏目模块搜易网优化的效果如何
  • access 网站内容管理系统 哪个好 下载seo网上培训课程
  • 做淘客的网站有哪些网站关键词优化培训
  • 做淘宝客没网站吗2345网址导航主页
  • 2019 做网站广州网站优化关键词排名
  • 深圳市龙岗区做网站的公司找客户资源的软件免费的
  • 建设部二级结构工程师注销网站seo网站建站