忘れられない激○○料理

現在雑談掲示板を作成しており、ヤフー知恵袋のような入力可能な文字数をカウントする機能を考えているのですが、JavascriptのDOM-based XSS対策用にコードを組むのが難しく困っております。HTMLクラスを1つにしてifで分岐表示することは可能でしょうか?
アドバイスお願い致します。

エレメント事作る=そこでDOM要素が発生の原因になるため(無限DOM)、初めは入力文字のカウントを表示させずに入力されたら残りの文字数をカウントして、制限文字数をオーバーしたら超過した文字数を表示させるようにコードを考えました。

画像のアップロードが名前、メッセージの前になるので、参考サイトのどちらのコードを使えばよいのか分からず前者を使うようにしております。

※window.onload = function() {} は動かない原因になりうるため
window.addEventListener('DOMContentLoaded', function() {} を代用するように変更しております。

※参考サイト
https://took.jp/window-onload/

※アドバイス頂いたもの
submit_button_validationだけを使って
innerHTML="残り<span>"+v+"</span>文字入力できます。";
の時と、
innerHTML="span>"+v+"</span>文字超過しています。";
の時を、ifで制御すればOK

※考えたコード
<div class="title-partial parts"> <!-- title-partial + parts -->
<h2>名前(name)<span class="required">※必須</span></h2>
<div class=parts>
<input class=submit_button type="text" type="text" name="name1" id="name" data-length=32 placeholder="未入力の場合は、匿名で表示されます" value="<?php echo $namae; ?>">
<div class="submit_button_validation submit_button_validation"></div>
</div>

<div class="body-partial parts"><!-- body-partial + parts -->
<h2>コメント(comment)<span class="required">※必須</span></h2>
<div class=parts>
<input class=submit_button type="text" name="name2" id="message" data-length=40 placeholder="荒らし行為や誹謗中傷や著作権の侵害はご遠慮ください"><?php echo $message; ?>
<div class="submit_button_validation submit_button_validation"></div>
</div>

<script>
function validation_submit(f) {
const submit = document.getElementById("submit_button");
/* 判定は逆なので、逆に渡す */
/*JavaScriptの要素を活性または非活性にする */
submit.disabled = f?false:true;
};

function validation_text(parts) {
/* このpartsグループの、input=textを抽出 */
/* HTML要素を取得 */
let text=parts.getElementsByClassName('submit_button')[0];
/* バリデーション警告パーツを抽出 */
let validation=parts.getElementsByClassName('submit_button_validation')[0];

validation.style.display = 'none';

/* 例えばのチェック */
/* window.onload = function() {} を window.addEventListener('DOMContentLoaded', function() {} に変更 */
window.addEventListener('DOMContentLoaded', function() {
let wao = document.getElementsByClassName('submit_button_validation');
const left = text.dataset.length-text.value.length;
if (left >= 0) {
/* ひとまずclassは複数配置できる形式なので、見つかった最初の1個目にアタッチ */
wao[0].innerHTML="残り<span>"+v+"</span>文字入力できます。";
text.value.length === 0;
} else {
/* そのまま、2個目にアタッチ */
wao[1].innerHTML="<span>"+v+"</span>文字超過しています。";
}
})
};

/* バリデーション条件判断部分 */
function validation() {
let parts = document.getElementsByClassName('parts');
let submit=true;
for (let i=0;i<parts.length;i++) {
if (validation_text(parts[i])!=true) {
submit=false;
}
}
validation_submit(submit);
};

/* DOM構築が終わってから呼び出される初期化関数 */
function init() {
// let text = document.getElementById('submit_button');
// text.oninput = e_text;

/* ↑これを、idじゃなくてclass対応に変更↓ */

/* class=parts内の class=submit_buttonに対して設定 */
let parts = document.getElementsByClassName('parts');
for (let i=0;i<parts.length;i++) {
parts[i].getElementsByClassName('submit_button')[0].oninput = validation;
}
validation();
};

window.onload = init;
</script>

A 回答 (2件)

No1です。



>function() {} でコードをまとめるよりも教えて頂いたように >document.addEventListener を使い、下記のコードを修正した
>ほうが良いのでしょうか?
documentでイベント処理をするのは、必ずしも効率が良くはありません。
(不要なイベントも拾ってしまうので)
No1の回答は、ご提示のHTMLの文書構造を理解できずわからなかったため、やむを得ず(確実な)documentに設定してあります。
(ですので、注書きしてあります。)

一方で、要素にイベント処理をバインドする場合は、当然ながら、対象要素が解釈された後でないと設定できません。
そのためには、onloadイベントを利用するなり、スクリプトの記述方法で対応するなどの方法をとる必要があります。(記述位置やdefer属性など)
https://developer.mozilla.org/ja/docs/Web/HTML/E …


「お礼」にご提示のスクリプトの場合は、イベント設定以前に要素を取得していますので、そのままの内容であれば、HTML解釈後に実行することが必要になります。

また、複数の要素に同じ処理を何度も設定するよりも、直近の包含要素に1回だけ設定しておくことで、後から要素を追加したりするような場合にも対応できるようにすることが可能です。
(そのようなことを行うのか/行わないのかは知りませんけれど・・)
ただし、この方法はバブリングするイベントでしか使えません。
    • good
    • 1
この回答へのお礼

A.アドバイスありがとうございます、なるほどdocumentでイベント処理した方が適切な場合とそうでない場合があるのですね。
対象要素が解釈された後に設定することを考えてwindow.addEventListener("load", init);を使い、
function init() {} 内に/* カメラ画像をファイルアップロード時に非表示にする */コードをまとめるように考えてみたのですが、
条件にあわせて送信ボタンの使用権限を操作する機能をどのように付け加えるべきか悩んでおります。
内部的に初期のDOM構築の時の値と後から書き換えた値の2つが存在するためテキスト解析させるよりもJS内変数でどのように格納した方が良いと指摘頂いており、
どのように対策すべきか分からず… アドバイスお願い致します。

※修正前のコード
https://wandbox.org/permlink/bEQJfRDHSjkJIwKT

function init() {
/* カメラ画像をファイルアップロード時に非表示にする */
省略
/* 文字数表示 */
document.addEventListener('input', e => {
if (!['name', 'message'].includes(e.target.id)) return;
const
t = e.target,
m = t.nextElementSibling,
n = t.value.length - (t.dataset.length | 0),
c = document.createElement('span');

c.append(Math.abs(n));
m.style.color = n > 0 ? 'red' : 'black';
m.replaceChildren(n > 0 ? '' : '残り', c,
`文字${n > 0 ? '超過してい' : '入力でき'}ます。`);
});
};

window.addEventListener("load", init);

お礼日時:2023/09/27 00:47

こんばんは



なんだか複雑に考えすぎていませんか?

多分、これ(↓)と同じなのだと思いますけれど・・・
https://oshiete.goo.ne.jp/qa/13580015.html
原因となっている「innerHTML」を使用するのをやめれば済むだけのように思われます。
No2様の回答にもあるように内部的にエスケープしてくれる処理を用いれば簡単になります。
(一番気にすべきなのは、クライアント側のスクリプト処理ではなく、サーバー側での受信処理だと思いますけれど・・・)


※ 以下では、処理に直接必要のないクラス等はHTMLから一旦削除してあります。
※ ご提示のHTMLでは、開始-閉じタグの関係がおかしいので、文書構成がよくわからないため、documentにイベントを設定してあります。
(本来なら、直近の包含要素に設定するのが良いでしょう。)
※ また、type属性がダブって設定されていたりもするようです。

<!DOCTYPE HTML>
<html lang="ja">
<head><title>Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<script>
document.addEventListener('input', e => {
if( !['name', 'message'].includes(e.target.id) ) return;
const
t = e.target, m = t.nextElementSibling,
n = t.value.length - (t.dataset.length | 0),
c = document.createElement('span');

c.append(Math.abs(n));
m.style.color = n>0?'red':'black';
m.replaceChildren(n>0?'':'残り', c,
`文字${n>0?'超過してい':'入力でき'}ます。`);
});
</script>
</head>

<body>
<div>
<h2>名前(name)<span>※必須</span></h2>
<input type="text" name="name1" id="name" data-length="32" placeholder="未入力の場合は、匿名で表示されます" value="">
<div></div>
</div>

<div>
<h2>コメント(comment)<span class="required">※必須</span></h2>
<input type="text" name="name2" id="message" data-length="40" placeholder="荒らし行為や誹謗中傷や著作権の侵害はご遠慮ください">
<div></div>
</div>
</body>
</html>
    • good
    • 1
この回答へのお礼

アドバイスありがとうございます、お聞きしたいことがあるのですが実は続きのコードにも問題がありまして、画面表示前にカメラ画像をファイルアップロード時に非表示にするコードが呼ばれると大変なことになるとのアドバイスを頂いているため、DOMツリー構築完了時にしか呼ばないようにしたいと考えて、window.onload = function() {} を使うように考えておりました。

問題の対策としてカメラ画像をファイルアップロード時に非表示にするコードをonloadリスナーにまとめるかonloadの後ろに挿入する必要があるのですが、window.onload = function() {} でコードをまとめるよりも教えて頂いたように document.addEventListener を使い、下記のコードを修正したほうが良いのでしょうか?解決策が分からずアドバイスお願い致します。

/* カメラ画像をファイルアップロード時に非表示にする */
const attach = document.querySelectorAll('.attach');
const del = document.querySelectorAll('.attachdel');
const clear = document.querySelectorAll('.attachclear');
const viewer = document.querySelectorAll('.viewer');
const changeImg = document.querySelectorAll('.changeImg'); // 入力されたら消す画像
for (let i = 0; i < attach.length; i++) {
attach[i].addEventListener('change', () => {
if (attach[i].files[0].size > 15 * 1024 * 1024) {
alert('ファイルサイズが 15MBバイトを超えています');
return;
}
del[i].value = "";
viewer[i].innerHTML = "";

お礼日時:2023/09/26 01:20

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報