vue를 사용하여 그리드 레이아웃 기능을 구현하는 방법
이 글은 주로 vue를 사용하여 그리드 레이아웃 기능을 구현하는 코드 설명을 소개합니다. 필요한 친구가 참고할 수 있습니다.
1. 먼저 프로젝트를 로컬로 복제합니다.
2. git Reset --hard commit
명령은 현재 헤드가 특정 커밋을 가리키도록 할 수 있습니다. git reset --hard commit
命令可以使当前head指向某个commit。
完成html的基本布局
点击复制按钮来复制整个commit id。然后在项目根路径下运行 git reset
html의 기본 레이아웃을 완성합니다
복사 버튼을 클릭하면 전체 커밋 ID가 복사됩니다. 그런 다음 프로젝트 루트 경로에서git Reset
을 실행하세요. 효과를 미리 보려면 브라우저로 index.html을 엽니다. 플러그인의 주요 HTML 결과는 다음과 같습니다. <!-- 节点容器 --> <p class="dragrid"> <!-- 可拖拽的节点,使用translate控制位移 --> <p class="dragrid-item" style="transform: translate(0px, 0px)"> <!-- 通过slot可以插入动态内容 --> <p class="dragrid-item-content"> </p> <!-- 拖拽句柄 --> <p class="dragrid-drag-bar"></p> <!-- 缩放句柄 --> <p class="dragrid-resize-bar"></p> </p> </p>
vue를 사용하여 노드의 간단한 레이아웃 완성
먼저 커밋으로 전환하고 필요한 패키지를 설치합니다. 그리고 다음 명령을 실행하세요:git reset --hard 83842ea107e7d819761f25bf06bfc545102b2944 npm install <!-- 启动,端口为7777,在package.json中可以修改 --> npm start
{ id: "uuid", x: 0, y: 0, w: 6, h: 8 }
dragrid.vue의 해당 로직을 살펴보겠습니다.
computed: { cfg() { let cfg = Object.assign({}, config); cfg.cellW = Math.floor(this.containerWidth / cfg.col); cfg.cellH = cfg.cellW; // 1:1 return cfg; } }, methods: { getStyle(node) { return { width: node.w * this.cfg.cellW + 'px', height: node.h * this.cfg.cellH + 'px', transform: "translate("+ node.x * this.cfg.cellW +"px, "+ node.y * this.cfg.cellH +"px)" }; } }
단일 노드 전체 드래그
Drag 이벤트
1. mousedown, mousemove, mouseup을 사용하여 드래그를 구현합니다. 2. 이러한 이벤트는 문서에 바인딩되며 한 번만 바인딩하면 됩니다.실행 과정은 대략 다음과 같습니다.
드래그 핸들을 마우스로 누르면 onMouseDown 메서드가 트리거됩니다. eventHandler에 일부 값을 저장한 후 마우스 움직임에 대해 onMouseMove 메서드가 트리거됩니다. 처음에는 eventHandler.drag가 false이고, 그 중 isDrag 메소드는 변위(수평 또는 수직으로 5픽셀 이동)를 기준으로 드래그 동작인지 여부를 결정합니다. 드래그 동작인 경우 드래그 속성을 true로 설정하고 실행합니다. dragdrop.dragStart 메소드를 동시에 실행하면(드래그 동작은 한 번만 실행됩니다) 마우스가 계속 움직이고 dragdrop.drag 메소드가 실행되기 시작합니다. 마지막으로 마우스를 놓은 후 onMouseUp 메서드가 실행되어 일부 상태를 초기 상태로 되돌리는 동시에 dragdrop.dragEnd 메서드가 실행됩니다.드래그 앤 드롭 노드
드래그 앤 드롭 노드의 논리는 dragdrop.js 파일에 캡슐화되어 있습니다. 주요 메소드는 dragStart, drag 및 dragEnd입니다.dragStart
드래그 동작에서 이 메서드는 한 번만 실행되므로 일부 초기화 작업을 수행하는 데 적합합니다.dragStart(el, offsetX, offsetY) { // 要拖拽的节点 const dragNode = utils.searchUp(el, 'dragrid-item'); // 容器 const dragContainer = utils.searchUp(el, 'dragrid'); // 拖拽实例 const instance = cache.get(dragContainer.getAttribute('name')); // 拖拽节点 const dragdrop = dragContainer.querySelector('.dragrid-dragdrop'); // 拖拽节点id const dragNodeId = dragNode.getAttribute('dg-id'); // 设置拖拽节点 dragdrop.setAttribute('style', dragNode.getAttribute('style')); dragdrop.innerHTML = dragNode.innerHTML; instance.current = dragNodeId; const offset = utils.getOffset(el, dragNode, {offsetX, offsetY}); // 容器偏移 const containerOffset = dragContainer.getBoundingClientRect(); // 缓存数据 this.offsetX = offset.offsetX; this.offsetY = offset.offsetY; this.dragrid = instance; this.dragElement = dragdrop; this.dragContainer = dragContainer; this.containerOffset = containerOffset; }
6.instance.current = dragNodeId; 설정 후 드래그드롭 노드와 플레이스홀더 노드의 스타일이 적용됩니다.
7. 캐시된 데이터의 offsetX 및 offsetY는 노드의 왼쪽 위 모서리를 기준으로 한 드래그 핸들의 오프셋입니다.drag
드래그 동작이 발생한 후 마우스 이동이 이 메서드를 실행하고 드래그된 노드의 스타일을 지속적으로 업데이트하여 노드가 이동됩니다.
drag(event) { const pageX = event.pageX, pageY = event.pageY; const x = pageX - this.containerOffset.left - this.offsetX, y = pageY - this.containerOffset.top - this.offsetY; this.dragElement.style.cssText += ';transform:translate('+ x +'px, '+ y +'px)'; }
dragEnd
는 주로 상태를 재설정하는 데 사용됩니다. 논리는 비교적 간단하므로 자세히 설명하지 않겠습니다.
이때 마우스를 따라 단일 노드를 이동할 수 있습니다.드래그된 노드의 움직임을 따르도록 플레이스홀더 활성화
이 섹션은 드래그된 노드와 함께 움직이는 플레이스홀더 노드(플레이스홀더의 그림자 부분)에 관한 것입니다. 주요 아이디어는 다음과 같습니다. 컨테이너에서 노드의 오프셋(드래그 방법의 x, y)을 드래그하여 해당 그리드의 좌표로 변환할 수 있습니다.변환된 좌표가 변경되면 자리 표시자 노드의 좌표가 업데이트됩니다.
드래그 메소드에 추가된 코드는 다음과 같습니다.// 坐标转换 const nodeX = Math.round(x / opt.cellW); const nodeY = Math.round(y / opt.cellH); let currentNode = this.dragrid.currentNode; // 发生移动 if(currentNode.x !== nodeX || currentNode.y !== nodeY) { currentNode.x = nodeX; currentNode.y = nodeY; }
노드 재배열 및 위로 이동
이 섹션의 핵심 포인트는 두 가지입니다.2차원 배열을 사용하여 그리드를 표현합니다. 이 2차원 배열에는 노드의 위치 정보가 표시될 수 있습니다.
노드에서 노드가 변경되는 한 재배열되어야 하며 각 노드는 최대한 위로 이동되어야 합니다. 🎜🎜🎜2차원 배열 구축🎜🎜getArea(nodes) { let area = []; nodes.forEach(n => { for(let row = n.y; row < n.y + n.h; row++){ let rowArr = area[row]; if(rowArr === undefined){ area[row] = new Array(); } for(let col = n.x; col < n.x + n.w; col++){ area[row][col] = n.id; } } }); return area; }
按需可以动态扩展该二维数据,如果某行没有任何节点占位,则实际存储的是一个undefined值。否则存储的是节点的id值。
布局方法
dragird.vue中watch了nodes,发生变化后会调用layout方法,代码如下:
/** * 重新布局 * 只要有一个节点发生变化,就要重新进行排版布局 */ layout() { this.nodes.forEach(n => { const y = this.moveup(n); if(y < n.y){ n.y = y; } }); }, // 向上查找节点可以冒泡到的位置 moveup(node) { let area = this.area; for(let row = node.y - 1; row > 0; row--){ // 如果一整行都为空,则直接继续往上找 if(area[row] === undefined) continue; for(let col = node.x; col < node.x + node.w; col++){ // 改行如果有内容,则直接返回下一行 if(area[row][col] !== undefined){ return row + 1; } } } return 0; }
布局方法layout中遍历所有节点,moveup方法返回该节点纵向可以上升到的位置坐标,如果比实际坐标小,则进行上移。moveup方法默认从上一行开始找,直到发现二维数组中存放了值(改行已经有元素了),则返回此时行数加1。
到这里,拖拽节点移动时,占位节点会尽可能地上移,如果只有一个节点,那么占位节点一直在最上面移动。
相关节点的下移
拖拽节点移动时,与拖拽节点发生碰撞的节点及其下发的节点,都先下移一定距离,这样拖拽节点就可以移到相应位置,最后节点都会发生上一节所说的上移。
请看dragrid.vue中的overlap方法:
overlap(node) { // 下移节点 this.nodes.forEach(n => { if(node !== n && n.y + n.h > node.y) { n.y += node.h; } }); }
n.y + n.h > node.y 表示可以与拖拽节点发生碰撞,以及在拖拽节点下方的节点。
在dragdrop.drag中会调用该方法。
注意目前该方法会有问题,没有考虑到如果碰撞节点比较高,则 n.y += node.h 并没有将该节点下沉到拖拽节点下方,从而拖拽节点会叠加上去。后面会介绍解决方法。
缩放
上面的思路都理解之后,缩放其实也是一样的,主要还是要进行坐标转换,坐标发生变化后,就会调用overlap方法。
resize(event) { const opt = this.dragrid.cfg; // 之前 const x1 = this.currentNode.x * opt.cellW + this.offsetX, y1 = this.currentNode.y * opt.cellH + this.offsetY; // 之后 const x2 = event.pageX - this.containerOffset.left, y2 = event.pageY - this.containerOffset.top; // 偏移 const dx = x2 - x1, dy = y2 - y1; // 新的节点宽和高 const w = this.currentNode.w * opt.cellW + dx, h = this.currentNode.h * opt.cellH + dy; // 样式设置 this.dragElement.style.cssText += ';width:' + w + 'px;height:' + h + 'px;'; // 坐标转换 const nodeW = Math.round(w / opt.cellW); const nodeH = Math.round(h / opt.cellH); let currentNode = this.dragrid.currentNode; // 发生移动 if(currentNode.w !== nodeW || currentNode.h !== nodeH) { currentNode.w = nodeW; currentNode.h = nodeH; this.dragrid.overlap(currentNode); } }
根据鼠标距拖拽容器的距离的偏移,来修改节点的大小(宽和高),其中x1为鼠标点击后距离容器的距离,x2为移动一段距离之后距离容器的距离,那么差值dx就为鼠标移动的距离,dy同理。
到这里,插件的核心逻辑基本上已经完成了。
[fix]解决碰撞位置靠上的大块,并没有下移的问题
overlap修改为:
overlap(node) { let offsetUpY = 0; // 碰撞检测,查找一起碰撞节点里面,位置最靠上的那个 this.nodes.forEach(n => { if(node !== n && this.checkHit(node, n)){ const value = node.y - n.y; offsetUpY = value > offsetUpY ? value : offsetUpY; } }); // 下移节点 this.nodes.forEach(n => { if(node !== n && n.y + n.h > node.y) { n.y += (node.h + offsetUpY); } }); }
offsetUpY 最终存放的是与拖拽节点发生碰撞的所有节点中,位置最靠上的节点与拖拽节点之间的距离。然后再下移过程中会加上该offsetUpY值,确保所有节点下移到拖拽节点下方。
这个插件的核心逻辑就说到这里了,读者可以自己解决如下一些问题:
缩放限制,达到最小宽度就不能再继续缩放了。
拖拽控制滚动条。
拖拽边界的限制。
向下拖拽,达到碰撞节点1/2高度就发生换位。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
vue+springboot如何实现单点登录跨域问题(详细教程)
위 내용은 vue를 사용하여 그리드 레이아웃 기능을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











HTML 템플릿의 버튼을 메소드에 바인딩하여 VUE 버튼에 함수를 추가 할 수 있습니다. 메소드를 정의하고 VUE 인스턴스에서 기능 로직을 작성하십시오.

vue.js에서 bootstrap 사용은 5 단계로 나뉩니다 : Bootstrap 설치. main.js.의 부트 스트랩 가져 오기 부트 스트랩 구성 요소를 템플릿에서 직접 사용하십시오. 선택 사항 : 사용자 정의 스타일. 선택 사항 : 플러그인을 사용하십시오.

vue.js에서 JS 파일을 참조하는 세 가지 방법이 있습니다. & lt; script & gt; 꼬리표;; mounted () 라이프 사이클 후크를 사용한 동적 가져 오기; Vuex State Management Library를 통해 수입.

vue.js의 시계 옵션을 사용하면 개발자가 특정 데이터의 변경 사항을들을 수 있습니다. 데이터가 변경되면 콜백 기능을 트리거하여 업데이트보기 또는 기타 작업을 수행합니다. 구성 옵션에는 즉시 콜백을 실행할지 여부와 DEEP를 지정하는 즉시 포함되며, 이는 객체 또는 어레이에 대한 변경 사항을 재귀 적으로 듣는 지 여부를 지정합니다.

vue.js는 이전 페이지로 돌아갈 수있는 네 가지 방법이 있습니다. $ router.go (-1) $ router.back () 사용 & lt; router-link to = & quot;/quot; Component Window.history.back () 및 메소드 선택은 장면에 따라 다릅니다.

CSS 애니메이션 또는 타사 라이브러리를 사용하여 VUE에서 Marquee/Text Scrolling Effects를 구현하십시오. 이 기사는 CSS 애니메이션 사용 방법을 소개합니다. & lt; div & gt; CSS 애니메이션을 정의하고 오버플로를 설정하십시오 : 숨겨진, 너비 및 애니메이션. 키 프레임을 정의하고 변환을 설정하십시오 : Translatex () 애니메이션의 시작과 끝에서. 지속 시간, 스크롤 속도 및 방향과 같은 애니메이션 속성을 조정하십시오.

Pagination은 큰 데이터 세트를 작은 페이지로 나누어 성능 및 사용자 경험을 향상시키는 기술입니다. VUE에서 다음 내장 방법을 페이징에 사용할 수 있습니다. 총 페이지 수를 계산하십시오 : TotalPages () Traversal 페이지 번호 : V-For Directive 현재 페이지를 설정하려면 : CurrentPage 현재 페이지 데이터 가져 오기 : currentPagedAta ()

VUE의 기능 차단은 지정된 기간 내에 기능이 호출되는 횟수를 제한하고 성능 문제를 방지하는 데 사용되는 기술입니다. 구현 방법은 다음과 같습니다. lodash 라이브러리 가져 오기 : 'lodash'에서 import {debounce}; Debounce 기능을 사용하여 인터셉트 기능을 만듭니다. const debouncedfunction = debounce (() = & gt; { / logical /}, 500); 인터셉트 함수를 호출하면 제어 기능이 최대 500 밀리 초 안에 한 번 호출됩니다.
