0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

WebComponents(Custom Elements / ShadowDOM / ESModules)を使用してExcelライクなライブラリを作ってみた

Posted at

はじめに

近年、素のJavaScript(Vanilla JS)の進化は著しく、数々の便利な機能がリリースされています。しかしながら、ネット上の活用事例が未だ充実しておらず大体の人は諦めてフレームワーク(Vue,Angular,React等)を利用してロックインされているのが現状です。

そこで本記事では、実際にWebComponentsを利用して作成をした、Excelライクな表作成ライブラリを用いてWebComponentsの機能を紹介します。(実際に作成したライブラリはGITに公開しています)

WebComponentsのメリットは一言でいうとカプセル化です。WebComponentsの主な機能は以下の通り3つあり(本当は4つですが4つ目は推奨されていないので省略)、WebComponentsの価値はそれらの機能を全て特定のフレームワークに依存せず実現できることにあります。

  • WebComponentsの3機能
    1. CustomElements:タグに紐づいた、そのタグの振る舞いのカプセル化
    2. ShadowDOM : DOMの隠蔽化やCSSの分離といったカプセル化
    3. ESModules : js Objectのカプセル化

実際のソースコードと対応させて見てみよう!

まずは完成した画面です。Excelっぽく複数選択やソート、行追加/削除も可能。
image.png

それでは、HTMLから見ていきます。非常にシンプルだと感じるはず。

excel.html
<!DOCTYPE html> 
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="shortcut icon" href="./images/favicon.ico" type="image/vnd.microsoft.icon">
<link rel="icon" href="./images/favicon.ico" type="image/vnd.microsoft.icon">
<title>excelライクなテーブル</title>
</head>
<body>
  <h3>右クリックで行追加/削除できます</h3>
  <local-sheet></local-sheet>

<script type="module" src="./js/local-sheet.js"></script>

</body>
</html>
  • <local-sheet></local-sheet>がCustom Elementsと呼ばれている部分です。今まではひたすらdivを使っていましたが、独自のタグ名だけで使いまわせるパーツを作れます。
  • 上記の中身(中身はlocal-sheet.jsに記述)が後述しますがShadowDOMというものになっており、通常のDOMツリーの要素の下に隠れたDOMツリーを取り付けています。ShadowDOMを使用するメリットは、何といっても独立したDOMとして扱えるためcssを該当のツリーにのみ適応する等、他のDOMから影響を受けない独立したツリーとして扱える点です。
  • <script type="module" src="./js/local-sheet.js"></script>の部分がESModulesの部分で、local-sheet.jsをモジュールとして呼び出しています。モジュール化のメリットとしてはモジュール化したjsから別のjsを呼び出せるようになる点がありますが、1点注意事項としてローカルではCORS policyに引っかかるようになるため動かなくなります。ブラウザのセキュリティを下げるか、おとなしくサーバ上で動作させてください。

次にHTMLでモジュールとして呼び出したlocal-sheet.jsの中身を見てみます。

local-sheet.js
 //===============================================================
 //  画面表示部分のJS
 //===============================================================
 //===============================================================
 //  ShadowDOM生成
 //===============================================================
class LocalSheet extends HTMLElement {
  constructor() {
    super();
    //HTMLから分離されたノード(ShadowDOM)を作成(親のドキュメントのCSSなどに影響されない)
    const shadowRoot = this.attachShadow({ mode: 'open' });
    shadowRoot.innerHTML = `

<!-- ShadowDOM用css読み込み -->
<link rel="stylesheet" href="./css/local-sheet.css">
<link rel="stylesheet" href="./css/filter.css">

<!-- table構造 -->
<table id="localSheet" style="table-layout:fixed;"">
  <thead id="localSheetThead">
  </thead>
  <tbody id="localSheetTbody">
  </tbody>
</table>

~~~ 中略 ~~~

<div id="tableFilter"></div>
`;
  }
}
 //===============================================================
 //  タグで呼び出せるように設定 + 基幹関数実行
 //===============================================================
(function main() {
  // local-sheetという名前でLocalSheetクラスを登録する
  customElements.define("local-sheet", LocalSheet);

  import ("./local-sheet-function.js")
      .then((obj) => {
          // 各モジュールには、引数objのプロパティからアクセスできる。
          obj.localSheetFunction();
      });
})();
  • customElements.define("local-sheet", LocalSheet);がCustom Elementsの部分。HTMLで<local-sheet></local-sheet>と記載すれば呼び出せるようにしています。
  • class LocalSheet extends HTMLElement {がShadowDOMの部分。
  • import ("./local-sheet-function.js")がESModulesの部分。jsから別のjsをインポートしています。

最後に、local-sheet.jsからインポートされているlocal-sheet-function.jsの中身です。

local-sheet-function.js(抜粋)
 //===============================================================
 //  テーブル構築をする基幹となる関数
 //===============================================================
export function localSheetFunction() {
  if (dbUseFlg == 1){
    let uri = getUri();
    const encodeUri = encodeURI(uri);
    fetch(encodeUri)
      //KAGRA API実行
      .then(function(res){
        return(res.json());
      })
      .then(function(json){
        let arrayData = JSON.stringify(json["return"]);
        arrayData = JSON.parse(arrayData);
        //th入力
        arrayThData = arrayData[0];
        //thを削除
        let exe = [0];
        for(let i=0; i<exe.length; i++){
          arrayData.splice(exe[i]-i, 1);
        }
        //tdを入力
        arrayTdData = arrayData;
        setTableInfo();
        return(json.setDisable);
      })
      .catch(function(err){
        console.log(err);
      });
  } else{
    setTableInfo();
  }
}
  • 見るべき点はfunction先頭についているexportです。別のjsから呼び出されるためには、exportの記載が必要です。

さいごに

いかがだったでしょうか。使い慣れてくると非常に便利で、Vanilla JSのため陳腐化することの無い普遍的な技術なのでWebComponentsの使い手が増えることを祈っています。
また、本記事の説明で使用したソースはGIT上に公開していますので、ご興味があれば以下参照リンクからアクセスしてください。

本記事で使用したコード(GitHub)

参考リンク(WebComponentsのMDNリンク)

WebComponents
CustomElements
ShadowDOM
ESModule

0
3
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
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?