ボタン長押し
2023年9月6日
みなさんこんにちは。
ケミストのWeb担当みやのです。
「Web」記事では、これまでに得たWebに関する知識を記録として残していきたいと思います。
今回は「ボタン長押し」に挑戦してみました。
下準備
iPhoneでは画面を長押し(ロングタップ)すると「コピー」「すべてを選択」「選択部分を検索」などのメニューが出てしまうので、このページでは無効化しておきます。
body {
-webkit-touch-callout: none;
-webkit-user-select: none;
}
別に必要ありませんが(ないんかい)ボタンのsvgを2通り作っておきます。
何秒押されたかわかる
参考:iwb.jp|JavaScriptでマウス(タップ)ボタンの長押しイベントを実装する方法
まずボタンと、秒数の出力欄を作ります。
<div id="button"></div>
<p id="r">赤い部分をマウスかタップで長押し</p>
#button {
width: 300px;
height: 100px;
margin: 0 auto 20px;
background: #a00;
position: relative;
cursor: pointer;
}
#button.active {
background: #f00;
}
さっき作ったsvgを疑似要素で追加します。
#button::before {
content: "";
background-color: #fff;
display: block;
height: 3rem;
width: 4rem;
-webkit-mask: url("img/button-off.svg");
mask: url("img/button-off.svg");
-webkit-mask-size: cover;
mask-size: cover;
margin : auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
#button.active::before {
content: "";
background-color: #fff;
display: block;
height: 3rem;
width: 4rem;
-webkit-mask: url("img/button-on.svg");
mask: url("img/button-on.svg");
-webkit-mask-size: cover;
mask-size: cover;
margin : auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
そしてスクリプトを記述します。
let count = 0;
let timer;
const ua = navigator.userAgent.toLowerCase();
const isSP = /iphone|ipod|ipad|android/.test(ua);
const b = document.getElementById('button');
const r = document.getElementById('r');
const eventStart = isSP ? 'touchstart' : 'mousedown';
const eventEnd = isSP ? 'touchend' : 'mouseup';
const eventLeave = isSP ? 'touchmove' : 'mouseleave';
b.addEventListener(eventStart, e => {
e.preventDefault();
b.classList.add('active');
timer = setInterval(() => {
count++;
r.textContent = (count / 100) + '秒';
}, 10);
})
b.addEventListener(eventEnd, e => {
e.preventDefault();
if (count) {
b.classList.remove('active');
clearInterval(timer);
r.textContent = (count / 100) + '秒長押しされました';
count = 0;
}
});
b.addEventListener(eventLeave, e => {
e.preventDefault();
let el;
el = isSP ? document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY) : b;
if (!isSP || el !== b) {
b.classList.remove('active');
clearInterval(timer);
r.textContent = '処理を中断';
count = 0;
}
});
参考元のサイトで非常に丁寧に説明してくれていますが、まだ全然理解できていません。
赤い部分をマウスかタップで長押し
加算されていく
参考:Qiita|javascriptでクリックやタップの長押し処理をする方法
ボタンと出力欄を作ります。
さっきのsvgを疑似要素で追加します。
buttonタグはダブルタップしたら拡大されたり、長押ししたままスワイプするとずっと押しっぱなし判定になったりしてしまうので、いろいろ追記しておきます。
<button id="btn" style="touch-action: none; user-select: none;" oncontextmenu="return false;"></button>
<p id="target">0</p>
#btn {
display: block;
width: 300px;
height: 100px;
margin: 0 auto;
padding: 10px;
border: 0;
box-shadow: none;
color: #ffffff;
background-color: #0a0;
cursor: pointer;
position: relative;
}
#btn:active {
background: #0f0;
}
#btn::before {
content: "";
background-color: #fff;
display: block;
height: 3rem;
width: 4rem;
-webkit-mask: url("img/button-off.svg");
mask: url("img/button-off.svg");
-webkit-mask-size: cover;
mask-size: cover;
margin : auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
#btn:active::before {
content: "";
background-color: #fff;
display: block;
height: 3rem;
width: 4rem;
-webkit-mask: url("img/button-on.svg");
mask: url("img/button-on.svg");
-webkit-mask-size: cover;
mask-size: cover;
margin : auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
スクリプトを記述します。
document.getElementById('btn').addEventListener('pointerdown', () => {
const intervalId = setInterval(increment, 50)
document.addEventListener('pointerup', () => {
clearInterval(intervalId)
}, { once: true })
})
const increment = () => {
const target = document.getElementById('target')
let targetNum = Number(target.textContent)
targetNum++
target.textContent = targetNum
}
50ミリ秒につき1カウント増えていくということでしょうか。
どうやったらさっきのように秒数(小数点)にできるんだろう。
0
規定の秒数押したらイベント
参考:Into the Program|【JavaScript】クリック・タッチの長押しを判定する
参考:かちびと.net|JavaScriptでロングタップイベントを実装する
long-press-eventというライブラリがあるようなので使ってみたいと思います。
まずは上記のサイトからlong-press-event.min.jsをダウンロードしてヘッダー内で読み込みます。
<script src="js/long-press-event.min.js"></script>
スクリプトを記述します。
document.addEventListener('long-press', function(e) {
e.target.setAttribute('data-editing', 'true');
});
ボタンとゲージを作ります。
data-long-press-delayで「何ミリ秒押し続けたらイベントが起きるか」を設定します。今回は1秒にしてみました。
「ボタンを1秒間押し続けるとゲージが右端まで溜まる」というイベントにしてみました。
<div class="charge" data-long-press-delay="1000"></div>
<div class="gauge"></div>
.charge {
width: 300px;
height: 100px;
margin: 1.5rem auto;
padding: 10px;
border: 0;
box-shadow: none;
color: #ffffff;
display: block;
cursor: pointer;
position: relative;
background:#00a;
}
.charge::before {
content: "";
background-color: #fff;
display: block;
height: 3rem;
width: 4rem;
-webkit-mask: url("img/button-off.svg");
mask: url("img/button-off.svg");
-webkit-mask-size: cover;
mask-size: cover;
margin : auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.charge[data-editing="true"]{
background: #00f;
}
.charge[data-editing="true"]::before {
content: "";
background-color: #fff;
display: block;
height: 3rem;
width: 4rem;
-webkit-mask: url("img/button-on.svg");
mask: url("img/button-on.svg");
-webkit-mask-size: cover;
mask-size: cover;
margin : auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.gauge{
position: relative;
width: 100%;
height: 20px;
background: #eee;
}
.gauge:before{
content: '';
width: 100%;
height: 20px;
background: rgb(0,255,0);
background: linear-gradient(90deg, rgba(0,255,0,1) 0%, rgba(255,255,0,1) 50%, rgba(255,0,0,1) 100%);
position: absolute;
left: 0;
bottom: 0;
}
.gauge:after{
content: '';
width: 100%;
height: 20px;
background: #333;
position: absolute;
right: 0%;
bottom: 0;
}
@-webkit-keyframes gaugeGo {
0% {
width: 100%;
}
50% {
width: 50%;
}
100% {
width: 0;
}
}
@keyframes gaugeGo {
0% {
width: 100%;
}
50% {
width: 50%;
}
100% {
width: 0;
}
}
.charge[data-editing="true"] +.gauge:after{
animation: gaugeGo 2s forwards;
animation-timing-function: linear;
}
なんか微妙なものができましたが、いつかどこかで使いたいと思います。
まとめ
これでロッ〇バスターや波〇砲が作れますね!いや作れねーだろ
「押している間だけゲージが溜まる」「離したらゲージが空になる」ようにするにはどうしたらいいんでしょう。