ps国外教程网站,建设网站人员名单,一个官网,笔记本电脑做网站比较畅快引言
在前端开发中#xff0c;实现可交互的组件能够极大地提升用户体验。本文将介绍一个基于 Vue 封装的可缩放卡片组件#xff0c;从实现思路、代码具体实现以及使用方法等方面进行详细阐述#xff0c;帮助开发者更好地理解和运用这一组件。项目源码地址#xff1a;https…
引言
在前端开发中实现可交互的组件能够极大地提升用户体验。本文将介绍一个基于 Vue 封装的可缩放卡片组件从实现思路、代码具体实现以及使用方法等方面进行详细阐述帮助开发者更好地理解和运用这一组件。项目源码地址https://gitcode.com/Jiaberrr/vue3-pc-template
实现思路
定位与布局通过position: absolute对卡片进行定位利用left、top、right、bottom属性确定其在页面中的位置同时设置width和height来定义卡片的初始大小。缩放控制点在卡片的四个角左上角、右上角、左下角、右下角添加可交互的缩放控制点通过监听这些控制点的鼠标事件mousedown、mousemove、mouseup来实现卡片的缩放功能。状态跟踪使用变量来记录卡片的初始大小、位置以及鼠标的初始位置在缩放过程中根据鼠标的移动距离计算卡片新的大小和位置。
代码实现
模板部分template
templatediv classabsolute :ididName :style{width: width,height: height,top: top px,left: left px,right: right px,bottom: bottom px}slot/slotdiv classresize-handle-tl :classresize-handle idName/divdiv classresize-handle-tr :classresize-handle idName/divdiv classresize-handle-bl :classresize-handle idName/divdiv classresize-handle-br :classresize-handle idName/div/div
/template在模板中外层div通过id和style绑定来设置卡片的位置和大小。slot用于插入卡片的内容四个角的div分别代表缩放控制点通过动态绑定类名来标识不同的控制点。
script 部分script setup
import { onMounted } from vue;const porp defineProps({idName: {Type: String,required: true},width: {type: [Number, String],default: 100%, // 默认宽度},height: {type: [Number, String],default: 100%, // 默认高度},top: {type: Number,default: null,},left: {type: Number,default: null,},bottom: {type: Number,default: null,},right: {type: Number,default: null,}
})let originalWidth 0;
let originalHeight 0;
let originalX 0;
let originalY 0;
let originalMouseX 0;
let originalMouseY 0;
let resizableBox null;
let resizeHandle [];
let resizeType ;onMounted(() {resizableBox document.getElementById(porp.idName);resizeHandle document.querySelectorAll(.resize-handle porp.idName);resizeHandle.forEach((handle) {handle.addEventListener(mousedown, function (e) {e.preventDefault();originalWidth parseFloat(getComputedStyle(resizableBox).width);originalHeight parseFloat(getComputedStyle(resizableBox).height);originalMouseX e.clientX;originalMouseY e.clientY;resizeType this.className;window.addEventListener(mousemove, resize);window.addEventListener(mouseup, stopResize);});});
});
let firstLeft porp.left;
let firstTop porp.top;
let firstBottom porp.bottom;
let firstRight porp.right
let lastTop 0;
let lastLeft 0;
let lastBottom 0;
let lastRight 0;
const resize (e) {const deltaX e.clientX - originalMouseX;const deltaY e.clientY - originalMouseY;resizableBox document.getElementById(porp.idName);if (resizeType.includes(resize-handle-tl)) {if (resizableBox.style.left) {resizableBox.style.left ${originalX deltaX lastLeft firstLeft}px;resizableBox.style.top ${originalY deltaY lastTop firstTop}px;}resizableBox.style.width ${originalWidth - deltaX}px;resizableBox.style.height ${originalHeight - deltaY}px;} else if (resizeType.includes(resize-handle-tr)) {if(resizableBox.style.top) {resizableBox.style.top ${originalY deltaY firstTop lastTop}px;}else {resizableBox.style.right ${ originalX - deltaX firstRight -lastRight}px;}resizableBox.style.width ${originalWidth deltaX}px;resizableBox.style.height ${originalHeight - deltaY}px;} else if (resizeType.includes(resize-handle-bl)) {if( resizableBox.style.left) {resizableBox.style.left ${originalX deltaX firstLeft lastLeft}px;}else {resizableBox.style.bottom ${originalY - deltaY firstBottom - lastBottom}px;}resizableBox.style.width ${originalWidth - deltaX}px;resizableBox.style.height ${originalHeight deltaY}px;} else if (resizeType.includes(resize-handle-br)) {if(resizableBox.style.right) {resizableBox.style.right ${ originalX - deltaX firstRight -lastRight}px;resizableBox.style.bottom ${originalY - deltaY firstBottom - lastBottom}px;}resizableBox.style.width ${originalWidth deltaX}px;resizableBox.style.height ${originalHeight deltaY}px;}
};const stopResize (e) {if(e.target.classList.contains(resize-handle-tl)) {lastTop e.pageY - originalMouseY;lastLeft e.pageX - originalMouseX;}else if(e.target.classList.contains(resize-handle-tr)) {lastTop e.pageY - originalMouseY;lastRight e.pageX - originalMouseX;}else if(e.target.classList.contains(resize-handle-bl)) {lastLeft e.pageX - originalMouseX;lastBottom e.pageY - originalMouseY}else if(e.target.classList.contains(resize-handle-br)) {lastBottom e.pageY - originalMouseYlastRight e.pageX - originalMouseX;}window.removeEventListener(mousemove, resize);window.removeEventListener(mouseup, stopResize);
};属性定义通过defineProps定义组件接受的属性包括idName必选用于唯一标识卡片、width、height、top、left、bottom、right并设置了默认值。变量初始化声明了一系列变量用于跟踪卡片的初始状态和缩放过程中的状态。生命周期钩子在onMounted钩子函数中获取卡片元素和缩放控制点元素并为每个缩放控制点添加mousedown事件监听器。当鼠标按下时记录卡片的初始大小和鼠标位置同时添加mousemove和mouseup事件监听器。缩放函数resize函数根据鼠标移动的距离和缩放控制点的类型来计算并更新卡片的大小和位置。停止缩放函数stopResize函数在鼠标松开时移除mousemove和mouseup事件监听器并更新卡片位置的累计偏移量。
样式部分style scoped
.resize-handle-br {width: 10px;height: 10px;position: absolute;bottom: 0;right: 0;cursor: se-resize;
}
.resize-handle-bl {width: 10px;height: 10px;position: absolute;bottom: 0;left: 0;cursor: sw-resize;
}
.resize-handle-tl {width: 10px;height: 10px;position: absolute;top: 0;left: 0;cursor: nw-resize;
}
.resize-handle-tr {width: 10px;height: 10px;position: absolute;top: 0;right: 0;cursor: ne-resize;
}样式部分定义了四个缩放控制点的大小、位置和鼠标悬停时的光标样式。
使用方法
在 Vue 项目中使用该组件首先确保组件已正确引入和注册。例如在父组件的模板中
templatediv idappScalableCardidNamemyCardwidth300pxheight200pxtop100left100p这是卡片的内容/p/ScalableCard/div
/templatescript setup
import ScalableCard from ./components/ScalableCard.vue;
/script在上述示例中通过传入idName、width、height、top、left等属性来定制卡片的初始状态并在组件内部插入卡片内容。
总结
通过上述的实现思路、代码实现和使用方法介绍我们可以看到这个基于 Vue 的可缩放卡片组件为前端开发中实现可交互的卡片功能提供了一个有效的解决方案。你也可以根据实际需求进一步扩展和优化该组件以满足不同项目的需求。希望本文能对大家有所帮助。