1
1

More than 3 years have passed since last update.

DOM要素の幅を境界で変えられるようにする【JavaScript】

Last updated at Posted at 2021-08-10

したいこと

Flexで並べた要素の間に境界を設置して、そこをドラッグすることでそれぞれの幅を変えられるようにする。
例えるならVSCodeの分割ウィンドウみたいな感じ。

コード

HTML

<div id="wrapper">
  <div id="one"></div>
  <div id="two"></div>
</div>

CSS

#wrapper {
  display: flex;
  height: 200px;
  width: 300px;
}
#one, #two {
  height: 100%;
}

JavaScript

window.onload = () => {
    let parent = document.getElementById("wrapper");
    colResizeable(parent, 300);
};

let colResizeable = (element, options) => {
    let {totalWidth, borderWidth, borderColor, postProcess} = {
        totalWidth: element.clientWidth,
        borderWidth: 10,
        borderColor: "#ddd",
        postProcess: () => {},
        ...options
    }

    let w1;
    let p1;

    // setup
    let children = Array.prototype.filter.call((element.childNodes), (e) => e.nodeName != "#text");
    let child1 = children[0];
    let child2 = children[1];
    children.forEach((e) => { e.style.width = (totalWidth - borderWidth) / 2 + "px" });

    // insert border between children
    let border = document.createElement("div");
    let borderStyle = {
        width: borderWidth + "px",
        backgroundColor: borderColor,
        cursor: "col-resize"
    }
    Object.keys(borderStyle).forEach((key) => { border.style[key] = borderStyle[key] });
    element.insertBefore(border, child1.nextSibling);

    let resizeChildren = (event) => {
        let w2 = Math.min(Math.max(0, w1 + event.pageX - p1), totalWidth - borderWidth);
        child1.style.width = w2 + "px";
        child2.style.width = totalWidth - w2 - borderWidth + "px";
    };

    border.addEventListener("mousedown", (event) => {
        w1 = Number(/.*?(?=px)/.exec(child1.style.width));
        p1 = event.pageX;

        element.addEventListener("mousemove", resizeChildren);
    });
    window.addEventListener("mouseup", () => {
        element.removeEventListener("mousemove", resizeChildren)
        postProcess;
    });
}

ポイント

  • Array.prototype.filter.call((element.childNodes), (e) => e.nodeName != "#text")で空のテキスト要素を弾ける
  • ドラッグはmousedownしたときのカーソルの座標とmousemoveのときの座標の相対値を取る
  • 面積の小さい要素を動かすときはwindow.addEventListener("mouseup", func)がおすすめ
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1