Maison > interface Web > js tutoriel > Comment implémenter un en-tête de tableau déplaçable

Comment implémenter un en-tête de tableau déplaçable

小云云
Libérer: 2018-02-10 15:30:13
original
2338 Les gens l'ont consulté

La première chose à expliquer est que les tableaux utilisés dans notre projet sont grossièrement divisés en deux catégories. L'une est un tableau ordinaire avec un en-tête non fixe, et l'autre est un en-tête fixe, et la partie tbody peut défiler. . de. Il convient de noter que l'en-tête fixe nécessite deux table pour être implémenté, et quiconque l'a fait devrait également comprendre. Le premier semble relativement simple, car la largeur est affectée par le thead dans th, tandis que le second semble difficile à gérer, car si vous utilisez deux tables, la situation suivante se produira :
Comment implémenter un en-tête de tableau déplaçable
emmm, cela devrait être différent de ce que nous avions imaginé. Comment cela peut-il être résolu ? J'ai l'impression que c'est très difficile à gérer. Je me suis souvenu que j'avais vu le tableau dans element-ui, et il semble qu'il y ait une implémentation consistant à faire glisser l'en-tête du tableau. Ouvrons la console et jetons un œil à la structure :
Comment implémenter un en-tête de tableau déplaçableEh bien, c'est tellement long. Je n'ai jamais utilisé les balises
et <colgroup>, mais si je regarde attentivement, il y a un <col> au-dessus, et je sais probablement ce qui se passe quand je vois ça. . J'ouvre MDN et regarde la description des attributs associés, et ce que je pense De même, width peut contrôler la largeur de la colonne actuelle. width Nous avons résolu le contrôle de la largeur, mais il y a un autre problème, à savoir comment modifier la largeur des autres colonnes après avoir fait glisser, comme suit :

Si je fais glisser la colonne a, comment la largeur modifiée doit-elle être distribuée entre b, c et d ? C'est ainsi que je la gère ici. b, c et d ont des attributs pour indiquer si la colonne a été déplacée. si b, c et d n'ont pas été déplacés, alors la largeur modifiée de a est divisée également en largeur des trois colonnes b, c et d. Si b, c et d sont tous modifiés, alors seule la dernière. la largeur de la colonne d est modifiée. Bon, l'idée est là, on peut la mettre en œuvre.
Il s'avère qu'il serait trop stupide de suivre le design ci-dessus. Il a été modifié pour modifier uniquement les colonnes derrière la colonne déplacée et la largeur de ces colonnes n'a pas changé.

Implémentation

Tout d'abord, la structure html est probablement comme ceci :

<table>
  <thead>
    <tr>
      <th>a<th>
      <th>b<th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>1<th>
      <th>2<th>
    </tr>
  </tbody>
</table>
Copier après la connexion

aspect js

  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: [],
    };
  };
Copier après la connexion

Ajouter dom :

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);
Copier après la connexion

Le bloc ci-dessus est destiné à l'ajout de nœuds et au traitement dom Pour la réutilisation, ici nous ne nous soucions pas de savoir si l'en-tête est corrigé ou non. Nous le divisons en deux table et le traitons comme ceci. C'est aussi beaucoup plus pratique.
Déplacez ensuite le doigt vers la droite de la colonne et définissez la valeur de cursor sur 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;
    }
  }
};
Copier après la connexion

Il est à noter que le getBoundingClientRect() obtenu par rigth est la distance jusqu'au côté droit de l'élément. La distance depuis le bord gauche de la page, et non la distance depuis le bord droit de la page. Voici pour ajouter l'événement thead à tr de mousemove Lorsque le pointeur de la souris est à moins de 8 du bord droit, changez la forme du pointeur, puis changez l'état dans store, indiquant que le clic. peut être déplacé à ce moment.
Puis mousedown+mousemove+mouseup gère le glisser :

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

Soit {cible } = evt ;
Si (!target) revient ;

const tableEle = THEADER ;
const tableLeft = tableEle.getBoundingClientRect().left;
const columnRect = target.getBoundingClientRect();
const minLeft = colonneRect.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 = () =>
Document.ondragstart = () =>

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

const handleOnMouseMove = (événement) =>
const deltaLeft = event.clientX - this.store.startMouseLeft ;
Const proxyLeft = this.store.startLeft + deltaLeft ;

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

//La largeur est allouée comme ceci, par exemple
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal