CSS-Grid-Generator的实现分析

651 阅读1分钟

CSS-Grid-Genrator 简介

CSS-Grid-Generator体验地址
话不多说,先上图

image.png 点击按钮后,会给到我们左边布局的 CSS 代码

image.png

其中最核心的代码是 div1 的 grid部分 1 / 1 / 2 / 3是怎么得到的

看一下 grid-area 的概念

image.png 嗯,也就是说我们需要获取到【当前选中区域】的 row-start , column-start, row-end, column-end 这四个属性.

如何获取上述属性

先看看代码中的【事件监听】部分

<section
    class="grid"
    :style="{ gridTemplateColumns: colTemplate, gridTemplateRows: rowTemplate , gridColumnGap: columngap + 'px', gridRowGap: rowgap + 'px' }"
    @touchstart.prevent="delegatedTouchPlaceChild"
    @touchend.prevent="delegatedTouchPlaceChild"
  >
    <div
      v-for="(item, i) in divNum"
      :key="i"
      :class="'box' + i"
      :data-id="item"
      @mousedown="placeChild(item, 's')"
      @mouseup="placeChild(item, 'e')"
    ></div>
</section>

元素的层级关系如下 image.png 所有的 【box元素】都设置了 mousedownmousemove 的事件监听,而【父元素】设置了 touchstarttouchend 的事件监听。
【box元素】的事件监听是为了用户在 单击鼠标 的时候能拿到 当前元素
【父元素】的事件监听是为了用户在 拖动鼠标 的时候能拿到 头尾元素

一个 row(2) X column(3) 的布局如下

image.png

图中 【红色】代表 column数, 【绿色】代表 row数,每一个块用黄色标明了【当前块的 grid-area属性】, 每一个块有一个自定义属性 data-id, 也就是在 v-for 循环的 index.

css-grid-generator 就是通过这个 indexrow, column 之间的关系得到 startRow , endRow, startColumn, endColumn


是一个数学推算,也是整个项目最为核心的部分,具体如下代码中的 placeChild 部分

// elementFromPoint 方法可以获取 【当前坐标所在的dom元素】
delegatedTouchPlaceChild(ev) {
  const target = document.elementFromPoint(
    ev.changedTouches[0].clientX,
    ev.changedTouches[0].clientY
  );
  const startend = ev.type === "touchstart" ? "s" : "e";
  this.placeChild(target.dataset.id, startend);
},
    placeChild(item, startend) {
      //built an object first because I might use this for something else
      this.child[`${startend}row`] = Math.ceil(item / this.columns);
      this.child[`${startend}col`] =
        item - (this.child[`${startend}row`] - 1) * this.columns;

      //create the children css units as a string
      if (startend === "e") {
        // flip starts and ends if dragged in the opposite direction
        let [startRow, endRow] =
          this.child.srow <= this.child.erow
            ? [this.child.srow, this.child.erow]
            : [this.child.erow, this.child.srow];
        let [startCol, endCol] =
          this.child.scol <= this.child.ecol
            ? [this.child.scol, this.child.ecol]
            : [this.child.ecol, this.child.scol];

        let childstring = `${startRow} / ${startCol} / ${endRow +
          1} / ${endCol + 1}`;
        console.log(childstring);
        this.$store.commit("addChildren", childstring);
      }
    },