出版日: 2024年5月31日
私はRikaiKunというChrome拡張機能を使っています。これは、日本語の単語にカーソルを合わせるだけでその意味を表示してくれるものです。
単語を選択する必要はなく、単語にカーソルを合わせるだけでその単語の意味を表示してくれます。
このブログ投稿では、同じことを実装してみましょう。
まず、現在ホバーされている要素を見つけて、そのテキストを取得するコードを書きましょう:
ホバーされた単語: -
これを達成するためのコードは以下の通りです:
<script>
import { onMount } from 'svelte';
let hoveredWord;
let text = `All states and governments that ever ruled over men have been either republics or monarchies. Monarchies may be hereditary, if the ruler’s family has governed for generations, or new. New monarchies can either be entirely new, as when Francesco Sforza captured Milan, or they could be territories a ruler has added to his existing hereditary state by conquest, as when the King of Spain took Naples. An additional territory won by conquest will be accustomed either to living under a monarch or to the freedom of self government and may be conquered by the new ruler’s own army or that of a third party, by luck or deservedly.`;
onMount(async () => {
document.addEventListener('mouseover', function (e) {
document.querySelectorAll('.textContainer span').forEach((node) => {
node.style.color = '';
});
let target = e.target.closest('.textContainer span');
if (target) {
target.style.color = 'red';
hoveredWord =
target.innerText.replace(',', '').replace('.', '') ||
target.textContent.replace(',', '').replace('.', '');
}
});
});
</script>
<p class="text-center font-bold">Hovered word: {hoveredWord ? hoveredWord : '-'}</p>
<div class="textContainer px-4 text-sm">
{#each text.split(' ') as word}
<span class="italic">{`${word} `}</span>
{/each}
</div>
上記のコードを見てわかるように、私たちは現在簡単なモードで作業しています。これは、テキスト内の各単語がspan要素で囲まれているため、どの要素がハイライトされ、その要素が持つ単語を取得するのが非常に簡単だからです。
それでも、mouseoverイベントを通じてマウスの位置を識別する方法を理解するのは良い練習です。
さて、少し難しくして楽しくしてみましょう。
次に、同じテキストを大量に、一語一語に分かれていない状態で持つことにします。これで、マウスがこの大量のテキストの中でどの単語の上にあるのかを見つける必要があります。
開発した関数がどのように機能するか見てみましょう:
テキストにカーソルを合わせると、テキスト全体がハイライトされるのがわかりますが、これは私たちが望むものではありません。私たちは、マウスがホバーしている単語だけをハイライトしたいのです。では、どのようにしてホバーされている正確な単語を見つけることができるのでしょうか?私はこれを行う方法が3つあると仮定しました。
PCでテキストをダブルクリックすると、マウスがホバーしている単語だけが自動的にハイライトされることをご存知でしょう。これを自動的に発火させることができれば、その単語が選択されると考えました。
単語が選択された後、以下のコードを使って選択された単語を取得できます:
// When mouse is hovered on a word, trigger double click to select that word
document.addEventListener('mouseover', function (e) {
var event = new MouseEvent('dblclick', {
view: window,
bubbles: true,
cancelable: true
});
// Programatically fire it for the element we are interested in
document.getElementById('textContainer').dispatchEvent(event);
});
// Get the selection when souble click fires
document.addEventListener('dblclick', function (e) {
let target = e.target.closest('#textContainer');
// Check if it is firing for the textContainer
if (target) {
let selectedWord =
(document.selection && document.selection.createRange().text) ||
(window.getSelection && window.getSelection().toString());
// Do something (E.g. Show meaning of that word)
}
});
悪いニュース! 残念ながら、ダブルクリックイベントを発火させても単語は自動的に選択されません。
要素がホバーされたとき、その幅と高さ、テキスト内容と行の高さを取得し、これと要素に対するマウスの位置を組み合わせて、マウスの位置を推測することができます:
document.addEventListener('mouseover', function (e) {
let target = e.target.closest('.textContainer span');
// Get width and height of container as this will be different depending on viewport
if (target) {
let targetRect = target.getBoundingClientRect();
let height = targetRect.height;
let width = targetRect.width;
// ...
}
});
このアプローチは非常に複雑で、良いアルゴリズムを書いたとしても、エッジケースに関しては誤りが生じる可能性が高いため、コードを完成させませんでした。このオプションはスキップしましょう。
このアプローチは、この記事の最初で使用したものです。ターゲット要素を取得し、そのテキスト内容を個別のspan要素に分割します。
これにより、各単語を個別のスパン要素として再生成し、そのイベントを制御することができます。
最初に話し合った内容よりも少し難しくするために、ターゲット要素にdiv, p, anchor, spanなどのサブ要素が含まれていると仮定しましょう。これらのサブ要素を含む親要素をテキストだけを操作して個別のスパン要素に変換し、クラス、ID、タグを元のまま保持する方法を見てみましょう。
New monarchies can either be entirely new, as when Francesco Sforza captured Milan, or they could be territories a ruler has added to his existing hereditary state by conquest, as when the King of Spain took Naples.
以下は目的を達成するためのコードです:
<script>
// Get the container we want to modify
let container = document.getElementById('textContainer');
// Check if there is any text that is directly under the container
let firstBit = container.innerHTML[0] !== '<' ? container.innerHTML.split('<')[0] : '';
let lastBit =
container.innerHTML.slice(-1) !== '>' ? container.innerHTML.split('>').slice(-1) : '';
// Add those text to a span element
if (firstBit) {
container.innerHTML = `<span>${firstBit}</span>` + container.innerHTML.replace(firstBit, '');
}
if (lastBit) {
container.innerHTML = container.innerHTML.replace(lastBit, '') + `<span>${lastBit}</span>`;
}
// Get children of the container
let children = getAllDescendants(container);
// Get texts of children that do not have any further children
let texts = children.filter((c) => c.childNodes.length === 0).map((c) => c.textContent);
// For each text block, split it into words and convert each word to a span element
texts.forEach((t) => {
container.innerHTML = container.innerHTML
.replace(
`>${t}<`,
`>${t
.split(' ')
.map((t) => `<span class="hover">${t}</span> `)
.join('')}<`
)
.replace(
`>"${t}"<`,
`>${t
.split(' ')
.map((t) => `<span class="hover">${t}</span> `)
.join('')}<`
);
});
</script>
// This is the HTML container we will be manipulating
// With manipulation, we mean we are going to divide its text into words
// And enclose each word with span element
<div class="px-4 text-sm" id="textContainer">
All states and governments that ever ruled over men have been either republics or monarchies. Monarchies
may be hereditary, if the
<a class="font-bold text-sky-500" href="javascript:void(0)">ruler’s family</a> has governed for
generations, or new.
<p>
New monarchies can either be entirely new, as when Francesco Sforza captured Milan, or they
could be territories a ruler has added to his existing hereditary state by conquest, as when
the King of Spain took Naples.
</p>
<div><div><span class="font-bold">An additional territory</span></div></div>
won by conquest will be accustomed either to living
<span class="italic">under a monarch</span>
or to the freedom of self government and may be conquered by the new ruler’s own army or that of
a third party, <span class="text-lg">by luck</span> or deservedly.
</div>
</div>
// Add hover class for highlighting each word
<style>
:global(.hover:hover) {
background: yellow;
} </style>
適用すると、下のテキストにカーソルを合わせると、各単語がホバーされたときにハイライトされるかどうかを確認できます。うまくいきますね?
New monarchies can either be entirely new, as when Francesco Sforza captured Milan, or they could be territories a ruler has added to his existing hereditary state by conquest, as when the King of Spain took Naples.
このブログ投稿では、ユーザーが各単語にホバーしたときにその単語をハイライトする方法を開発しました。このコードは、単語の意味を表示したり、その単語に関する情報を表示するモーダルを開くなど、他の目的にも使用できます。
エッジケースでコードが機能するかどうかはテストしていませんが、問題が発生した場合はお知らせください。
それでは、コーディングを楽しんでください!
このブログは英語からChatGPTによって翻訳されました。不明な点がある場合は、お問い合わせページからご連絡ください。
コメントを残す
コメント
その他のブログ
2024/06/19
SvelteとJavaScriptを使用してシンプルで動的なツールチップを作成する
2024/06/17
JavaScriptを用いて東京都のインタラクティブな地図を作成する
2024/06/14
Matplotlibで日本語文字化けを解決できる簡単な方法
2024/06/13
書評 | トーキング・トゥ・ストレンジャーズ 「よく知らない人」について私たちが知っておくべきこと by マルコム・グラッドウェル
2024/06/07
日本語で最もよく使われる3000字の漢字
2024/06/07
VSCodeでRegexを使用してReplaceする方法
2024/06/06
SvelteではReadable Storeを使用するな
2024/06/05
GzipとPakoでデータを圧縮してWebサイトのローディング速度を上げる方法
2024/05/29
SvelteとSVGを用いてインタラクティブな地図を作成する
2024/05/28
書評 | Originals 誰もが「人と違うこと」ができる時代 by アダム・グラント & シェリル・サンドバーグ
2024/05/27
Javascriptを使用して数独を解く方法
2024/05/26
ウェブサイトへのトラフィックを1か月で10倍に増やした方法
2024/05/24
人生はサイクリングに似ている
2024/05/19
JavaScriptでバックトラッキング・アルゴリズムを用いて完全な数独グリッドを生成する
2024/05/16
Tailwindが素晴らしい理由とWeb開発をいかに楽にするか
2024/05/15
PythonとGitフックを使用してサイトマップを自動的に生成する
2024/05/14
書評 | Range (レンジ) 知識の「幅」が最強の武器になる by デイビッド・エプスタイン
2024/05/13
SvelteとSvelteKitはなんですか?
2024/05/12
SvelteKitで国際化(多言語化)
2024/05/11
SvelteでCachingを用いてDeploy時間を短縮する方法
2024/05/10
SvelteとIntersection Oberverによるレイジーローディング
2024/05/10
遺伝的アルゴリズムで最適な株式ポートフォリオを作る方法
2024/05/09
Pythonを用いてShapeFileをSVGに変換できる方法
2024/05/08
Svelteの反応性:変数、バインディング、およびキー関数
2024/05/07
書評 | 孫子の兵法
2024/05/06
スペシャリストは終了。ゼネラリスト万歳!
2024/05/03
トルコ人の有権者の投票行動をPythonでの分析
2024/05/01
Seleniumを用いてトルコ投票データベースを作る方法
2024/04/30
SvelteとTailwindを使用してInfinite Scrollできる方法
2024/04/29
1年間以内で日本語を駆使できるようになるための方法
2024/04/25
SvelteとTailwindを用いたWebサイトテンプレート
2024/01/29
怠惰なエンジニアとひどいデザイン
2024/01/28
偉大さについて
2024/01/28
MacBook で PDF を PNG に変換する
2023/12/31
2023年振り返り:24冊の読んだ本のまとめ
2023/12/30
Python PILを使用して写真コラージュを作成する方法
2024/01/09
ウェブサイトの訪問者のデバイスとブラウザを検出する方法
2024/01/19
ChatGPT回答の解析