Heim  >  Artikel  >  Web-Frontend  >  So implementieren Sie die Grid-Layout-Funktion mit Vue

So implementieren Sie die Grid-Layout-Funktion mit Vue

亚连
亚连Original
2018-06-13 15:52:334045Durchsuche

Dieser Artikel stellt hauptsächlich die Code-Erklärung zur Verwendung von Vue zur Implementierung der Grid-Layout-Funktion vor.

Klonen Sie zuerst das Projekt lokal.

2. Der Befehl git reset --hard commit kann den aktuellen Head auf einen Commit verweisen.

Vervollständigen Sie das Grundlayout von HTML

Klicken Sie auf die Schaltfläche „Kopieren“, um die gesamte Commit-ID zu kopieren. Führen Sie dann git reset im Projektstammpfad aus. Öffnen Sie index.html mit einem Browser, um eine Vorschau des Effekts anzuzeigen. Die wichtigsten HTML-Ergebnisse des Plug-Ins lauten wie folgt:

<!-- 节点容器 -->
<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>

Verwenden Sie Vue, um das einfache Layout von Knoten zu vervollständigen

Wechseln Sie zuerst das Commit, installieren Sie das erforderliche Paket und führen Sie den folgenden Befehl aus:

git reset --hard 83842ea107e7d819761f25bf06bfc545102b2944
npm install
<!-- 启动,端口为7777,在package.json中可以修改 -->
npm start

Der erste Schritt besteht darin, die Umgebung einzurichten. Schauen Sie sich dazu einfach die Konfigurationsdatei webpack.config.js an.

Das andere ist die Anordnung der Knoten. Die Hauptidee besteht darin, den Knotencontainer als Gitter zu betrachten Die Koordinate in der oberen linken Ecke ist (0, 0); die Knotengröße wird durch Breite (w) und Höhe (h) gesteuert. Jeder Knoten muss außerdem eine eindeutige ID haben. Auf diese Weise ist die Datenstruktur des Knotenknotens:

{
 id: "uuid",
 x: 0,
 y: 0,
 w: 6,
 h: 8
}

wobei die Werte von w und h die Anzahl der Zellen im Raster sind. Beispielsweise beträgt der Container 24 Zellen und die Breite 960 Pixel und die Breite jeder Zelle beträgt 40 Pixel. Der obige Knoten wird dann als 240 Pixel * 320 Pixel gerendert und befindet sich in der oberen linken Ecke des Containers.

Werfen wir einen Blick auf die entsprechende Logik von 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 + &#39;px&#39;,
  height: node.h * this.cfg.cellH + &#39;px&#39;,
  transform: "translate("+ node.x * this.cfg.cellW +"px, "+ node.y * this.cfg.cellH +"px)"
 };
 }
}

wobei cellW und cellH die Breite und Höhe jedes Gitters sind, sodass es einfach ist, die Breite, Höhe und zu berechnen Verschiebung des Knotens.

Vollständiges Ziehen eines einzelnen Knotens

Drag-Ereignis

1. Verwenden Sie Mousedown, Mousemove, Mouseup, um das Ziehen zu implementieren .

2. Diese Ereignisse sind an das Dokument gebunden und müssen nur einmal gebunden werden.

Der Ausführungsprozess ist ungefähr wie folgt:

Wenn die Maus auf den Ziehgriff gedrückt wird, wird die onMouseDown-Methode ausgelöst. Nach dem Speichern einiger Werte im EventHandler wird die Mausbewegung ausgelöst Bei der ersten Eingabe ist eventHandler.drag false und die isDrag-Methode bestimmt anhand der Verschiebung (5 Pixel horizontal oder vertikal verschieben). Ziehen Sie das Attribut auf „true“ und führen Sie die Methode „dragdrop.dragStart“ aus (einmal). Das Ziehverhalten wird nur einmal ausgeführt. Anschließend bewegt sich die Maus weiter und die Methode „dragdrop.drag“ wird ausgeführt. Nachdem die Maus losgelassen wurde, wird schließlich die Methode onMouseUp ausgeführt, um einige Zustände auf den Ausgangszustand zurückzusetzen, und gleichzeitig wird die Methode dragdrop.dragEnd ausgeführt.

Knoten ziehen

Die Logik des Ziehens von Knoten ist in der Datei Dragdrop.js gekapselt. Die Hauptmethoden sind DragStart, Drag und DragEnd.

dragStart

Bei einem Ziehverhalten wird diese Methode nur einmal ausgeführt, sodass sie für einige Initialisierungsarbeiten geeignet ist. Zu diesem Zeitpunkt lautet der Code wie folgt :

dragStart(el, offsetX, offsetY) {
 // 要拖拽的节点
 const dragNode = utils.searchUp(el, &#39;dragrid-item&#39;);
 // 容器
 const dragContainer = utils.searchUp(el, &#39;dragrid&#39;);
 // 拖拽实例
 const instance = cache.get(dragContainer.getAttribute(&#39;name&#39;));
 // 拖拽节点
 const dragdrop = dragContainer.querySelector(&#39;.dragrid-dragdrop&#39;);
 // 拖拽节点id
 const dragNodeId = dragNode.getAttribute(&#39;dg-id&#39;);
 // 设置拖拽节点
 dragdrop.setAttribute(&#39;style&#39;, dragNode.getAttribute(&#39;style&#39;));
 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;
}

1. Der Parameter el ist das Ziehgriffelement, offsetX ist der horizontale Versatz der Maus vom Ziehgriff und offsetY ist der vertikale Versatz der Maus vom Ziehgriff.

2. Über el können Sie den Drag-Knoten (dragNode) und den Drag-Container (dragContainer) rekursiv finden.

3. Das Dragdrop-Element ist ein echter mausgesteuerter Ziehknoten, und der entsprechende Layoutknoten wird zu einem Platzhalterknoten, der visuell als Schatteneffekt angezeigt wird.

4. Durch Festlegen des Drag-Knotens wird tatsächlich das innereHTML des angeklickten DragNode auf den Drag-Drop festgelegt und auch der Stil darauf angewendet.

5. Die Drag-Instanz ist eigentlich die Dragrid.vue-Instanz. Sie speichert ihre Instanz im Cache der erstellten Hook-Funktion. Hier können Sie die Instanz aus dem Cache abrufen Rufen Sie die Methode in der Instanz auf.

6.instance.current = dragNodeId; Nach dem Festlegen werden die Stile des Dragdrop-Knotens und des Platzhalterknotens angewendet.

7. OffsetX und OffsetY in den zwischengespeicherten Daten sind die Offsets des Ziehpunkts relativ zur oberen linken Ecke des Knotens.

Ziehen

Nachdem das Ziehverhalten aufgetreten ist, führt die Mausbewegung diese Methode aus und der Knoten wird verschoben, indem der Stil des gezogenen Knotens ständig aktualisiert wird.

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 += &#39;;transform:translate(&#39;+ x +&#39;px, &#39;+ y +&#39;px)&#39;;
}

Berechnet hauptsächlich den Versatz des Knotens relativ zum Container: den Abstand zwischen der Maus und der Seite – den Versatz des Containers – den Abstand zwischen der Maus und dem Knoten Container ist der Abstand zwischen dem Knoten und dem Container.

dragEnd

Hauptsächlich Reset-Status. Die Logik ist relativ einfach, daher werde ich nicht auf Details eingehen.

An dieser Stelle kann ein einzelner Knoten mit der Maus verschoben werden.

Aktivieren Sie, dass der Platzhalter der Bewegung des gezogenen Knotens folgt.

In diesem Abschnitt geht es darum, wie sich der Platzhalterknoten (der Schattenteil des Platzhalters) zusammen mit dem gezogenen Knoten bewegt . Die Hauptidee ist:

Durch Ziehen des Knotenversatzes aus dem Container (x, y bei der Ziehmethode) kann dieser in die Koordinaten des entsprechenden Gitters umgewandelt werden.

Wenn sich die konvertierten Koordinaten ändern, aktualisieren Sie die Koordinaten des Platzhalterknotens.

Der in der Drag-Methode hinzugefügte Code lautet wie folgt:

// 坐标转换
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;
}

Knoten neu anordnen und nach oben verschieben

In diesem Abschnitt gibt es zwei Kernpunkte:

Verwenden Sie ein zweidimensionales Array zur Darstellung des Gitters, damit die Standortinformationen der Knoten in diesem zweidimensionalen Array markiert werden können.

Solange sich ein Knoten in Knoten ändert, muss er neu angeordnet werden und jeder Knoten muss so weit wie möglich nach oben verschoben werden.

Konstruktion eines zweidimensionalen Arrays

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 += &#39;;width:&#39; + w + &#39;px;height:&#39; + h + &#39;px;&#39;;
 // 坐标转换
 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. 拖拽控制滚动条。

  3. 拖拽边界的限制。

  4. 向下拖拽,达到碰撞节点1/2高度就发生换位。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在JavaScript中如何实现读取和写入cookie

在vue中scroller返回页面并且记住滚动位置如何实现

vue+springboot如何实现单点登录跨域问题(详细教程)

Das obige ist der detaillierte Inhalt vonSo implementieren Sie die Grid-Layout-Funktion mit Vue. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn