シンプルに使えるツールチップス
petitips(ぷちっぷす):PetitとTipsの合成語で、プチップスと呼称するものとします。
シンプルな使い勝手を目指しました。その要件は下記の通りです。
・HTMLタグのtitle属性の拡張機能*1
・別途cssを用意する必要がない
・特定のライブラリに依存しないので汎用的
・当該モジュールをimportしてインスタンス化するだけ
・class(Prototype糖衣構文)で複数属性のTooltips設定可
・チップス表示はカーソルの右下に表示
・window枠に収まらない場合は表示位置が自動調整される
・title属性本来のTooltipsは抑止
*1:HTMLタグで以下の条件を満たす場合にマウスオーバーでポップアップ表示
・HTMLタグのclass属性に'petitips'が設定されている、独自名称も可
・title属性に表示内容が記述されている
・title属性への記述は矛盾しないHTMLタグも可
license: MIT
author: booskanium
プチップスの利用方法
title属性とclass属性を記述したHTMLコード
留意箇所
・type="module"
・class="petitips"
・title="xxxxxxxxxxxxxx"
<!DOCTYPE html>
<html lang="jp">
<head>
<meta charset="UTF-8">
<title>プチップス利用のHTML例</title>
<script defer src="./index.js" type="module"></script>
</head>
<body>
<div>
<p>ツールチップスを拡張するのが<span class="petitips" title="ここの記述がTooltips表示される">プチップス</span>です。
</div>
</body>
</html>
index.jsのコード
留意箇所
・import
・newのタイミングはDOM生成が完了している事
'use strict';
import __Petitips from "./petitips.js";
const petitips = new __Petitips();
プチップスのモジュール(petitips.js)
留意箇所
・class構文でリエントラント
・constructorの初期設定
・showで表示
・hideで非表示
・setConfigで動的に属性変更
/*
* petitips(ぷちっぷす):PetitとTipsの合成語で、プチップスと呼称するものとする
*
* シンプルに使えるツールチップス
* ・HTMLタグのtitle属性の拡張機能*1
* ・別途cssを用意する必要がない
* ・特定のライブラリに依存しないので汎用的
* ・当該モジュールをimportしてインスタンス化するだけ
* ・class(Prototype糖衣構文)で複数属性のTooltips設定可
* ・チップス表示はカーソルの右下に表示
* ・window枠に収まらない場合は表示位置が自動調整される
*
* *1:HTMLタグで以下の条件を満たす場合にマウスオーバーでポップアップ表示
* ・HTMLタグのclass属性に'petitips'が設定されている
* ・title属性に表示内容が記述されている
* ・title属性への記述は矛盾しないHTMLタグ可
*
* license: MIT
* author: booskanium
*
*/
export default class __Petitips {
//Tipsポップアップ欄の初期設定
constructor(cnf) {
//config
this.config = {
targetClass: 'petitips',
//Tipsを仕込むエレメントの属性
targetBgcolor: '#eeeeff',
targetColorTarget: 'inherit',
targetDecoration: 'underline',
targetDecorationColor: '#aaaaff',
//Tipsを表示するポップアップ欄の属性
border: 'solid 1px navy',
borderRadius: '5px',
boxShadow: '5px 5px 5px #b7b7ff',
maxWidth: '200px',
minWidth: '100px',
padding: '5px',
backgroundColor: '#eeeeff',
font: '12px sans-serif',
color: 'black',
zIndex: 1000
}
if (cnf) {
if ('targetClass' in cnf) this.config.targetClass = cnf.targetClass;
}
//pop Element
this.eleTips = document.createElement('DIV');
document.body.appendChild(this.eleTips);
this.eleTips.id = this.config.targetClass;
this.eleTips.style.position = 'absolute';
this.eleTips.style.display ='none';
this.setConfig(cnf);
}
//Tipsポップアップ欄の属性を動的に変更
setConfig(cnf) {
if (cnf) {
//ポップアップを仕込むエレメントの独自属性
if ('targetBgcolor' in cnf) this.config.targetBgcolor = cnf.targetBgcolor;
if ('targetColor' in cnf) this.config.targetColor = cnf.targetColor;
if ('targetDecoration' in cnf) this.config.targetDecoration = cnf.targetDecoration;
if ('targetDecorationColor' in cnf) this.config.targetDecorationColor = cnf.targetDecorationColor; //ポップアップTips欄の独自属性
if ('border' in cnf) this.config.border = cnf.border;
if ('borderRadius' in cnf) this.config.borderRadius = cnf.borderRadius;
if ('boxShadow' in cnf) this.config.boxShadow = cnf.boxShadow;
if ('maxWidth' in cnf) this.config.maxWidth = cnf.maxWidth;
if ('minWidth' in cnf) this.config.minWidth = cnf.minWidth;
if ('padding' in cnf) this.config.padding = cnf.padding;
if ('backgroundColor' in cnf) this.config.backgroundColor = cnf.backgroundColor;
if ('font' in cnf) this.config.font = cnf.font;
if ('color' in cnf) this.config.color = cnf.color;
if ('zIndex' in cnf) this.config.zIndex = cnf.zIndex;
}
// test クラスを持つすべての要素に対して処理する
let targets = document.getElementsByClassName(this.config.targetClass);
targets = Array.from(targets); //HTMLCollectionを配列に変換
targets.forEach((target) => {
if (target.title) {
target.dataset.petitips = target.title; //titleをdata属性にコピー、petitpsはこれを表示する
target.title = ''; //titleを空にしてHTML本体のTooltip表示を抑止
target.addEventListener( "mouseover", (e) => {
this._show(e);
});
target.addEventListener( "mouseout", (e) => {
this._hide(e);
});
target.style.backgroundColor = this.config.targetBgcolor;
target.style.color = this.config.targetColor;
target.style.textDecoration = this.config.targetDecoration;
target.style.textDecorationColor = this.config.targetDecorationColor;
}
});
//ポップアップTips欄の属性を設定
this.eleTips.style.border = this.config.border;
this.eleTips.style.borderRadius = this.config.borderRadius;
this.eleTips.style.font = this.config.font;
this.eleTips.style.color = this.config.color;
this.eleTips.style.maxWidth = this.config.maxWidth;
this.eleTips.style.minWidth = this.config.minWidth;
this.eleTips.style.height = 'auto';
this.eleTips.style.padding = this.config.padding;
this.eleTips.style.backgroundColor = this.config.backgroundColor;
this.eleTips.style.zIndex = this.config.zIndex;
this.eleTips.style.boxShadow = this.config.boxShadow;
}
//Tipsポップアップ欄を表示
_show(e) {
//表示位置を求める
let st = document.body.scrollTop || document.documentElement.scrollTop; //画面上のスクロールされた縦軸起点
let sl = document.body.scrollLeft || document.documentElement.scrollLeft; //画面上のスクロールされた横軸起点
let leftPos = e.clientX + 5; //マウスオーバーされた横軸起点+5px
let topPos = e.clientY + 5; //マウスオーバーされた縦軸起点+5px
//吹き出し表示位置設定
this.eleTips.innerHTML = e.currentTarget.dataset.petitips;
this.eleTips.style.left = leftPos + sl + 'px';
this.eleTips.style.top = topPos + st + 'px';
//ポップ表示
this.eleTips.style.display='block'
//吹き出し表示コンテンツセット後に規定の横幅を超えてていたら左側に表示位置を調整
if (leftPos + sl + this.eleTips.clientWidth > document.documentElement.clientWidth) {
leftPos = leftPos - (leftPos + sl + this.eleTips.clientWidth - document.documentElement.clientWidth);
let lPos = leftPos + sl - 30;
if (lPos < 0) iPos = 0;
this.eleTips.style.left = lPos + 'px';
}
//吹き出し表示コンテンツセット後に規定の縦幅を超えてていたら上側に表示位置を調整
if (topPos + st + this.eleTips.clientHeight > document.documentElement.clientHeight) {
topPos = topPos - (topPos + st + this.eleTips.clientHeight - document.documentElement.clientHeight);
let tPos = topPos + sl - 25;
this.eleTips.style.top = tPos + 'px';
}
}
//Tipsポップアップ欄を隠す
_hide(e) {
this.eleTips.style.display='none'
}
}
CodeSandboxで動きを確認