Heim  >  Artikel  >  Web-Frontend  >  So implementieren Sie einen ziehbaren Tabellenkopf

So implementieren Sie einen ziehbaren Tabellenkopf

小云云
小云云Original
2018-02-10 15:30:132310Durchsuche

Das erste, was zu erklären ist, ist, dass die in unserem Projekt verwendeten Tabellen grob in zwei Kategorien unterteilt sind: Eine ist eine normale Tabelle mit einem nicht fixierten Header und die andere ist ein fester Header, und der Teil tbody kann gescrollt werden . von. Es ist zu beachten, dass für die Implementierung des festen Headers zwei table erforderlich sind, und jeder, der dies getan hat, sollte dies auch verstehen. Ersteres scheint relativ einfach zu sein, da die Breite durch thead in th beeinflusst wird, während letzteres schwierig zu handhaben zu sein scheint, da bei Verwendung von zwei Tabellen die folgende Situation auftritt:
So implementieren Sie einen ziehbaren Tabellenkopf
emmm, das sollte anders sein, als wir es uns vorgestellt haben. Wie kann man das beheben? Mir fiel ein, dass ich die Tabelle in element-ui gesehen hatte, und es scheint, dass es eine Implementierung zum Ziehen des Tabellenkopfes gibt. Öffnen wir die Konsole und schauen uns die Struktur an:
So implementieren Sie einen ziehbaren Tabellenkopf
Nun, es ist so lang, dass ich die Tags <colgroup> und <col> noch nie verwendet habe, aber wenn ich genau hinschaue, ist da ein width, und ich weiß wahrscheinlich, was los ist Schauen Sie sich die Beschreibung der zugehörigen Attribute an und was ich denke. Ebenso kann width die Breite der aktuellen Spalte steuern.
Wir haben die Breitensteuerung gelöst, aber es gibt noch ein anderes Problem, nämlich wie man die Breite anderer Spalten nach dem Ziehen wie folgt ändern kann:

a b c d

Wenn ich Spalte a ziehe, wie soll die geänderte Breite auf b, c und d verteilt werden? So gehe ich hier mit den Attributen b, c und d um, die angeben, ob die Spalte gezogen wurde. Wenn b, c und d nicht verschoben wurden, wird die geänderte Breite von a gleichmäßig auf die Breite der drei Spalten b, c und d aufgeteilt. Wenn b, c und d alle geändert werden, dann nur die letzte Spalte d wird geändert. Okay, die Idee ist da, wir können sie umsetzen.
Es stellt sich heraus, dass es zu dumm wäre, dem obigen Design zu folgen. Es wurde geändert, um nur die Spalten hinter der gezogenen Spalte zu ändern, und die Breite dieser Spalten hat sich nicht geändert.

Implementierung

Zuallererst sieht die HTML-Struktur wahrscheinlich so aus:

<table>
  <thead>
    <tr>
      <th>a<th>
      <th>b<th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>1<th>
      <th>2<th>
    </tr>
  </tbody>
</table>

js-Aspekt

  constructor (id, options) {
    this._el = document.querySelector(`#${id}`);
    // 实际使用中需要对dom结构进行判断,这里就不做了
    this._tables = Array.from(this._el.querySelectorAll('table'));
    setTimeout(() => this._resolveDom());

    this.store = {
      dragging: false,                 //是否拖动
      draggingColumn: null,            //拖动的对象
      miniWidth: 30,                   //拖动的最小宽度
      startMouseLeft: undefined,       //鼠标点击时的clientX
      startLeft: undefined,            //th右离table的距离
      startColumnLeft: undefined,      //th左离table的距离
      tableLeft: undefined,            //table离页面左边的距离,
      HColumns: [],
      BColumns: [],
    };
  };

Dom hinzufügen:

const [ THeader ] = this._tables;
let TBody;
const Tr = THeader.tHead.rows[0];
const columns = Array.from(Tr.cells);
const Bcolgroup = document.createElement('colgroup');
const cols = columns.map((item, index) => {
  const col = document.createElement('col');
  item.dataset.index = index;
  col.width = +item.offsetWidth;
  return col;
});
cols.reduce((newDom, item) => {
  newDom.appendChild(item);
  return newDom;
}, Bcolgroup);
const HColgroup = Bcolgroup.cloneNode(true);
THeader.appendChild(HColgroup);

//不管是一个table还是两个,都把header和body提出来
if (this._tables.length === 1) {
  const [ , tbody ] = Array.from(THeader.children);
  tbody.remove();
  TBody = THeader.cloneNode();
  TBody.appendChild(Bcolgroup);
  TBody.appendChild(tbody);
  this._el.appendChild(TBody);
} else {
  [ , TBody ] = this._tables;
  TBody.appendChild(Bcolgroup);
}

//拖动时的占位线
const hold = document.createElement('p');
hold.classList.add('resizable-hold');
this._el.appendChild(hold);

Der obige Block dient dem Hinzufügen von Knoten und der Verarbeitung dom Für die Wiederverwendung ist es uns egal, ob der Header fest ist oder nicht. Wir teilen ihn in zwei Teile auf table und verarbeiten ihn so Es ist auch viel bequemer.
Bewegen Sie dann den Finger auf die rechte Seite der Spalte und setzen Sie den Wert von cursor auf col-resize:

handleMouseMove(evt) {
  //...
  if (!this.store.dragging) {
    const rect = target.getBoundingClientRect();
    const bodyStyle = document.body.style;
    if (rect.width > 12 && rect.right - event.pageX < 8) {
      bodyStyle.cursor = &#39;col-resize&#39;;
      target.style.cursor = &#39;col-resize&#39;;
      this.store.draggingColumn = target;
    } else {
      bodyStyle.cursor = &#39;&#39;;
      target.style.cursor = &#39;pointer&#39;;
      this.store.draggingColumn = null;
    }
  }
};

Es ist zu beachten, dass getBoundingClientRect() durch rigth erhalten wird ist der Abstand zur rechten Seite des Elements. Der Abstand vom linken Rand der Seite, nicht der Abstand vom rechten Rand der Seite. Hier ist das thead-Ereignis, das zu trs mousemove hinzugefügt wurde. Wenn der Mauszeiger weniger als 8 vom rechten Rand entfernt ist, ändert sich die Zeigerform und dann wird der Status in store geändert, was darauf hinweist Der Klick kann zu diesem Zeitpunkt gezogen werden.
Dann übernimmt mousedown+mousemove+mouseup das Ziehen:

const handleMouseDown = (evt) =>
if (this.store.draggingColumn) {
This.store.dragging = true;

Sei {target} = evt;
If (!target) return;

const tableEle = THeader;
const tableLeft = tableEle.getBoundingClientRect().left;
const ColumnRect = target.getBoundingClientRect();
const minLeft = columnsRect.left - tableLeft + 30;
Target.classList.add('noclick');

This.store.startMouseLeft = evt.clientX;
This.store.startLeft = ColumnRect.right - tableLeft;
This.store.startColumnLeft = ColumnRect.left - tableLeft;
This.store.tableLeft = tableLeft;

Document.onselectstart = () => false;
Document.ondragstart = () => false;

Hold.style.display = 'block';
Hold.style.left = this.store.startLeft + 'px';

const handleOnMouseMove = (event) =>
Const deltaLeft = event.clientX - this.store.startMouseLeft;
Const ProxyLeft = this.store.startLeft + deltaLeft;

Hold.style.left = Math.max(minLeft, ProxyLeft) + 'px';
};

//Die Breite wird beispielsweise so zugewiesen

Das obige ist der detaillierte Inhalt vonSo implementieren Sie einen ziehbaren Tabellenkopf. 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