20211224のHTMLに関する記事は6件です。

templateタグを使ってフォームを複製

はじめに 以前、「cloneNode()で入力フォームを複製してみた」という記事で入力フォームをcloneNode()を使って複製する記事を投稿した。 しかしその記事内のコードではフォーム内のテキストまで複製されてしまう。 ここではHTML5より追加されたtemplateタグを使ってフォームのテンプレートを作成し、それを複製することで、何も入力されていないフォームを追加していく。 要件 「追加」ボタンをクリックし、名前、年齢、性別を入力するフォームを複製したい。(最大8人)            ⇓ templateタグとは Javascriptで操作するDOM要素をテンプレート化するHTML要素。 templateタグで囲まれた要素は、ページの読み込み時には描画されない。 templateタグの要素を複製する方法 template要素内の内容を複製し、ブラウザに表示するために必要な処理は以下の3つ。 ①template要素を取得 ②取得したtemplate要素の内容を複製 ③DOMに追加 使用例 // template要素を取得 const template = document.getElementById('template'); // template要素の内容を複製 const clone = template.content.cloneNode(true); // div(id="container")の中に追加 document.getElementById('container').appendChild(clone); 実際にフォームを複製してみる 今回は「追加」ボタンをクリックすることで、HTML内のtemplateタグ内の内容を複製し、親要素であるid="input-form"のdivタグ内に追加していく。 また、フォームで受け取った値を扱う場合を考慮して、inputタグのname属性にインデント番号を付与し、複製するタイミングで1ずつ足していく。 フォームのHTML index.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <script type="text/javascript" src="addForm.js"></script> </head> <body> <!--親要素--> <div class="input-form" id="input-form"> <!--テンプレート作成--> <template id="form-template"> <div class="member" id="member"> <!--name属性にはフォーム追加時にインデント番号を付与--> <input type="text" size="20" name="" placeholder="名前"> <input type="text" size="3" name="" placeholder="年齢"> <label for="male"> <input type="radio" value="男性" id="male">男性 </label> <label for="female"> <input type="radio" value="女性" id="female">女性 </label> </div> </template> </div> <!--ボタンをクリックしたらJavascriptファイル内の関数addForm()を実行する--> <div class="bt_addForm"> <input type="button" value="追加" onclick="addForm()"> </div> </body> </html> Javascriptで実装 ページ読み込み時にaddFormを一度実行し、フォームを一人分生成しておく。 addForm.js //インデント番号を初期化 let i = 1 function addForm() { // 8人以上なら処理を終了する if (i > 8) { return; } else { // HTMLからtemplate要素を取得 const template = document.getElementById("form-template"); // templateの内容を複製 const new_form = template.content.cloneNode(true); // 子要素を指定しname属性の値を変更 const new_form_name = new_form.children[0].children[0]; new_form_name.name = 'name-'+i; const new_form_age = new_form.children[0].children[1]; new_form_age.name = 'age-'+i; //親要素を取得し 複製した要素を追加 const parent = document.getElementById("input-form"); parent.appendChild(new_form); //インデント番号を更新 i++; } } //ページ読み込み時に関数addForm()を実行 window.addEventListener('DOMContentLoaded', addForm); まとめ 複製したいコンポーネントをテンプレートとしてHTML内に用意しておけるので、初期化されたフォームを簡単に追加することができた。 記事の内容に間違いや改善点などございましたら、ぜひコメントでご指摘ください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HTMLフォームにjQuery Validation Engineでバリデーションを走らせたり連打対策してみる

本投稿は株式会社ピーアールオー(あったらいいな!を作ります) Advent Calendar 2021の12日目の予定でした 昨年に引き続き「でした。」になっちゃいました。遅延は昨年より更にひどい。 絶賛年末進行中&緊急対応してたんで許してくださいwww ここ数年は、ほとんどコーディングをせずに過ごしているんですが、久々にHTMLフォームを作ったので覚書として記事を書きます。 どちらが「吸収するか」問題 フォームを設置する場合、デザイナーとプログラマーで「どこまでを担当する」問題というのがありまして、今までの経験では「エラーがどこに出るか、内容を全出ししてコーディングして」までがほとんど。 バリデーションを走らせたり、状態を変化させる仕組みまでは考えない。 とはいえ。 仕事をしていると、簡易のバリデーションを走らせたり、状態を変化させたりする仕組みを作らなくてはいけないこともある。 フォームを作る まあ、普通にコーディングします。IEは当然ガン無視1です。 本当はアクセシビリティを考慮した内容にもしたかったけど、時間がないので普通にコーディング。 今回は裏側なしなので、「送信」ボタンを押下してもエラー表示が出てくるだけですw ターゲットによりますが、モバイルファーストで画面を作るのがデフォなので、今回もスマホで使うことを前提にコーディングします。 指でタップしやすいよう、セレクトボックスやラジオボタンもCSSを使って装飾♪装飾♪ HTML自体は何の変哲もない姿をしていますが、CSSは嫌な感じになりますw HTML <dl class="contactForm"> <dt class="contactForm_term"> <label for="approach"> 連絡方法 <span class="contactForm_term_requiredMark"> 必須 </span> </label> </dt> <dd class="contactForm_desc contactForm_desc-radio"> <input type="radio" name="otherContact" value="メールアドレス" id="approach01"> <label for="approach01">メールアドレス</label> <div class="contactForm_desc_comments"> <input type="radio" name="otherContact" value="電話番号" id="approach02"> <label for="approach02">電話番号</label> <div class="contactForm_desc_comments_input"> <input type="tel" name="otherContactComent"> </div> </div><!-- /.contactForm_desc_comments --> <div class="contactForm_desc_comments"> <input type="radio" name="otherContact" value="その他" id="approach03"> <label for="approach03">その他</label> <div class="contactForm_desc_comments_input"> <input type="text" name="otherContactComent"> </div> </div><!-- /.contactForm_desc_comments --> </dd> </dl> デフォルトのラジオボタンを消して、label要素に::beforeやら::afterやらでラジオボタンぽいものを作ります。 HTMLやCSSに強いプログラマーもいますが、これを探したり・書いたり・改善したりなんて無理だよねえ。デザイナーでも「無茶な!」って思うことがありますw CSS .contactForm_desc { position: relative; padding: .5rem; margin-bottom: .5rem; background: #edf0f5; } .contactForm_desc-radio [type="radio"] { visibility:hidden; position: absolute; top: 1rem; left: .5rem; } .contactForm_desc-radio label { display:block; position: relative; padding: 1rem 1rem 1rem 2.8rem; margin-top: .5rem; text-align: left; cursor: pointer; } .contactForm_desc-radio label::before, .contactForm_desc-radio label::after { content: ""; display: block; border-radius: 50%; position: absolute; transform: translateY(-50%); top: 50%; } .contactForm_desc-radio label::before { width: 1.5rem; height: 1.5rem; left: .5rem; background: #fff; border: 1px solid #ddd; border-radius: 50%; } .contactForm_desc-radio label::after { width: 0; height: 0; background: #80bced; border-radius: 50%; opacity: 0; } .contactForm_desc-radio [type="radio"]:checked + label::after { width: 1rem; height: 1rem; left: .8rem; opacity: 1; -webkit-transition: all .12s, border-color .08s; transition: all .12s, border-color .08s; } .contactForm_desc-radio [type="radio"]:checked + label { background: #80bced; color: #fff; font-weight: bold; } .contactForm_desc_comments_input { padding: calc(0.65rem - 2px); } .contactForm_desc-radio [type="radio"]:checked + label + .contactForm_desc_comments_input { background: #80bced; } バリデーションはjQueryのプラグインで 一部でオワコン言われているけど私は使うぞ。 jQuery Validation Engine 言語ファイルも用意されているので、他言語化されたサイトでも利用可能。 今回のような、ボタンの状態に合わせてテキストフォームにエラーを出すとかもできる。 HTML <head> <!-- CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jQuery-Validation-Engine/2.6.4/validationEngine.jquery.min.css"> <!-- Javascript --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/posabsolute/jQuery-Validation-Engine@3.1.0/js/jquery.validationEngine.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/posabsolute/jQuery-Validation-Engine@3.1.0/js/languages/jquery.validationEngine-ja.js"></script> </head> 必要なjsとcssを読み込んで、最低限こう書けば良い。 Javascript $(document).ready(function(){ $("#contact").validationEngine(); }); #contactはformタグについているID。フォームががひとつだけならformタグを直接入れてもいいかもしれないけど、あまりお勧めしない。 後でフォームが複数になったら超面倒だからw あとは必須項目にCLASSを追加する。 HTML <input type="radio" name="otherContact" value="メールアドレス" id="approach01" class="validate[required]"> <label for="approach01">メールアドレス</label> CLASSのvalidate[required]はベーシックなエラーが表示されます。 オプションも色々あるので、詳しくはjQuery Validation Engineを確認されたし。 いにしえのテーブルコーディング時代2からHTMLを書いているので、ちょっとしたコーディングはまあまあできると思いますが、jQueryとそのプラグインを使えばメロっとこんな感じまではできる。 バリデーションのテキストを変更したい 「*必須項目です」の頭の「*」が気になるし、「選択してください」「名前を入れてください」に変えたいところもある。 jQuery Validation Engineは痒いところに手が届くので、オプションを書いてみます。今回は外部jsに書く方法。 個別にテキストを変えたい場合は、IDを割り振って、それに対してテキストを変更します。 Javascript $("#contact").validationEngine('attach', { promptPosition : "topLeft: 0", // エラーの位置指定 showArrowOnRadioAndCheckbox: true, // ラジオボタンやチェックボックスのエラーに吹き出しを付ける "custom_error_messages": { //エラーテキストオプション "required": { //デフォルトのエラーテキスト "message": "必須項目です" }, "#contactDetail": { "required": { "message": "選択してください" } }, "#name": { "required": { "message": "名前を入れてください" } }, "#approach01": { "required": { "message": "選択してください" } }, "custom[email]": { "message": "正しいメールアドレスを入れてください" }, "#agree": { "required": { "message": "確認してください" } } } }); 1箇所だけとかならdata-errormessageを使う方法がいいかも。 HTML <input type="email" name="userMail" id="email" class="validate[required, custom[email]]" data-errormessage="メールアドレスが間違っていますよ"> フォーム部品に装飾を施すとちょっと面倒になる すんなり実装できた風ですが、実際は違います。 フォーム部品に装飾を施すと、プラグインがうまく動かないことがあります。 今回のプラグインの場合、inputに対してエラーを表示するので、inputを不用意に消すとエラーが表示されなくなります。 そのため、ちょっとした工夫が必要。 CSS .contactForm_desc { position: relative; padding: .5rem; margin-bottom: .5rem; background: #edf0f5; } .contactForm_desc-radio [type="radio"] { visibility: hidden; position: absolute; top: 1rem; left: .5rem; } 装飾したいがために、本来のラジオボタンをvisibility: hidden;で不可視にしています。 こういう場合はdisplay: none;で消すことがほとんどなのですが、今回のjQueryプラグインでは、不用意に要素を消すと「エラーが表示されない」というドツボにハマります。 なぜなら、見た目はどちらも「消えてる」のですが、その「消え方」に違いがあります。 レイアウトを変更せず要素を不可視にする visibilityプロパティ visibility は CSS のプロパティで、文書のレイアウトを変更することなく要素を表示したり非表示にしたりします。このプロパティは <table> の行や列を隠すこともできます。 要素を不可視にしてレイアウトから除去するには、 visibility を使用する代わりに display プロパティを none に設定してください。 引用:visibility - CSS: カスケーディングスタイルシート | MDN レイアウトから除去してしまうdisplay: none;を使うとinputが存在しないことになり、エラーが表示されなくなります。 それではまずいので、不可視になるvisibility: hidden;を使います。 これで解決するかと思いきや…なかなかうまくいかない。 レイアウトから除去してしまうdisplay: none;とは違い、visibility: hidden;は要素が見えないだけでしっかり存在します。 存在するということは、その要素の大きさ分の空白ができるということです。 レイアウトのくびきから解き放つ positionプロパティ さて参ったね。 エラーを表示するにはvisibility: hidden;しか使えない。けれどこれを使ったらレイアウトが崩れる。 レイアウトを直すにはdisplay: none;を使うのが一番だけど、これを使うとエラーが出なくなる。 どちらの要件も維持するには、本来のラジオボタンをレイアウトのくびきから解き放つしかない。 それがposition: absolute;という設定。 HTMLの場合、レイアウトは相対で作られます。同じレイヤー上に存在するので、要素同士は隣り合っています。 しかし、position: absolute;を設定した要素は、他の要素とは異なるレイヤーに配置され、ブラウザの左上を原点とした絶対値でレイアウトを制御することが可能になります。 イメージとしては、相対でレイアウトされている他要素の上に浮かんでいる感じです。 ただ、フリーダムすぎると制御不能になるので、従うべき親分を教えます。 毎回ブラウザの左上を親分にされると制御が難しいので、親要素にposition: relative;を与えて「ワタシが親分です」と教えてあげると、素直に従ってくれます。 この場合、position: relative;を持つ親要素の左上を原点として絶対値でレイアウトを作るので、制御は非常に簡単になります。 今回のレイアウトの都合上、上位の要素<article class="contents">にtext-align: center;があるため、何もせずにいるとチェックボックスは画面の中央に配置されます。 jQuery Validation Engineはinput要素にエラーを表示します。 そのため、position: absolute;だけでなく、leftとtopに数値を入れて、擬似的に作り上げたラジオボタンの近くにレイアウトされるようにし、あたかもエラーが疑似ラジオボタンの上に出ている風を装います。 参考:position - CSS: カスケーディングスタイルシート | MDN レイアウトもどうにかなったし、デフォルトの機能だけならこれでいいんです。バリデーションも走るし。エラーテキストも変更できるし。 でも、まだ足りない。ちょっと仕様が足りないから、このままじゃダメ。 …自ら面倒くさい地獄を呼び込むことに。 ラジオボタンと入力フォームを連動させたい問題 連絡方法の項目に関しては、以下の事がしたいなーって思います。 項目を選択したら入力フォームに入力させたい(項目未選択の場合は入力フォームもDisabled) 別の項目を選択したら入力した内容を消したい(見えなくしたい) HTMLは手っ取り早いですな。初期値はdisabledにしておきます。 HTML <div class="contactForm_desc_comments">   <input type="radio" name="otherContact" value="電話番号" id="approach02"><label for="approach02">電話番号</label>   <div class="contactForm_desc_comments_input">     <input type="tel" name="otherContactComent" class="validate[condRequired[approach02]]" disabled="disabled">   </div> </div><!-- /.contactForm_desc_comments --> このままだと永遠にdisabledなので、jQueryの力を借ります。 Javascript //ラジオボタンと入力エリア連動 $("[name='otherContact']").change(function(){ if ($("input:radio[id='approach02']:checked").val() == "電話番号") { $("#approach02").nextAll(".contactForm_desc_comments_input").children("input[type=tel]").removeAttr("disabled"); } else { $("#approach02").nextAll(".contactForm_desc_comments_input").children("input[type=tel]").attr("disabled", "disabled"); } if ($("input:radio[id='approach03']:checked").val() == "その他") { $("#approach03").nextAll(".contactForm_desc_comments_input").children("input[type=text]").removeAttr("disabled"); } else { $("#approach03").nextAll(".contactForm_desc_comments_input").children("input[type=text]").attr("disabled", "disabled"); } }).trigger('change'); チェックボックスが対象の場合は、こんな書き方で動くはず(今回のソースコードでは検証していない)。 Javascript $(".contactForm_desc_comments").change(function(){ $("input[type=text]").attr("disabled", "disabled"); $(":checked").nextAll(".contactForm_desc_comments_input").children("input[type=text]").removeAttr("disabled"); }).trigger("change"); これをやらず、わざわざval() == "電話番号"みたいな書き方をしてるのは、ラジオボタンの場合、他の項目を執拗にタップすると関係ない入力フォームがActiveになるからw テスト中は、執拗にタップし続けるのは大事ですねー ここまででもいいんですが、入力フォームに記入した後に別の項目を選択してDisabledになっても、入力された文字が見えちゃいますw ここはCSSで簡単に消します。 CSS .contactForm_desc input[disabled="disabled"] { color: transparent; } 透明にしただけなので、再び項目を選択すると入力内容が復活します jQueryで消しちゃってもいいんですが、この時はテストする時間が少な過ぎたので「見えなくする(透明にする)」だけにしました。 項目がActiveにならない限り、入力フォームはdisabled="disabled"なので、内容が送信されることはありません。 連打禁止 イタズラされるのが嫌なので、できる限り連打できないようにしたい。 「送信」ボタンをタップした後に、ボタンカラーを透過して「押しましたよ」という状況変化をつけるのもいいし、pointer-eventsプロパティ使って、1度タップしたらポインターイベントを無効にしちゃってもいい。 ただ、pointer-eventsは注意が必要。 バリデーションが走ってエラーになった後、なにかのタイミングで復帰させないと、必須項目を全て入力しても内容を送れないwwww Javascript //連打緩和 $("#submit").on("click", function(){ $(this).css({"opacity":" .5" ,"pointer-events": "none"}); }); $("form").change(function(){ //フォーム内の要素に変更があると適用 $("#submit").css({"opacity":" 1" ,"pointer-events": "auto"}); }); バリデーションが走った後は、未入力を無くすためにタップなり記入なりするはずなので、フォーム内の要素に変更があったら、ボタンの透過をやめて、ポインターイベントを有効にします。 一応動くなにか jQuery Validation Engineは非常に有名なバリデーションプラグインで、Qiita上でも様々な人が記事を書いています。 しかし、フォーム部品に装飾を施した場合の事例は少ないように思います。 装飾を施していないフォームで利用する場合は、そう大きな問題はないと思いますが、色々装飾をした瞬間、ドツボにハマる可能性は極めて高いです。 そして、だいたいが「しょうもない理由」でハマってしまうので、判明した時の落ち込み方はひとしおですw CodePenで検索すると古いバージョンしか出てこず、jQuery Validation EngineのCDNを探すのにちょっと苦労しましたorz CDNはjsDelivrにあったので助かった See the Pen Contact Form HTML by Mari Takahashi (@mrd-takahashi) on CodePen. やっと解放されるね⭐️やっほーい!参考:Microsoft 社 Internet Explorer のサポート終了について:IPA 独立行政法人 情報処理推進機構 ↩ 若い世代が知らない2000年代のHTMLコーディングの地獄…これをお読みいただければ、地獄加減はわかっていただけるであろう。バグやハックで朝までコースはザラ。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HTML完全初心者が勉強してみた

こんにちは:-) KONICHIWA JAPAN と表示させてみる <!DOCTYPE html> <html> <head> <meta charaset="utf-8" /> <title> KONICHIWA JAPAN </title> </head> <script> document.write("KONICHIWA!") </script> </html> これを実行すると以下のようになる。 作成手順 1,Visual Studio Code を起動する 2,新しいファイルを作成する、名前を 〇〇.html とする  3,上記のプログラムを書く 4,保存する 5,ファイル名の上で右クリック→”エクスプローラーで表示する”をクリック 6,結果がブラウザ上で保存される 語句の意味 Javascript初心者なので、一つ一つのプログラムの意味を知ろうと思い、調べてみた <!DOCTYPE html>: Document Type Definitionの略  HTMLの仕様をブラウザに認識させるための宣言 C言語での#include < stdio.h > だと思った <html>:HTMLの文書を書くために基底となる要素 <!DOCTYPE html>以外の要素は全てこのタグの内側に入れる必要がある <head>~</head>:機械可読な情報を入れる、題名など <meta charaset="utf-8" />:文字コードを指定し文字化けを防ぐ meta要素により情報を指定する。charaset属性でHTMLファイルの文字コードを指定する <script>~</script>:Javascriptをドキュメントに埋め込む、実行するコードをここに入れる この中だけJavaScriptで残りはHTMLかな? ボタンで画像を表示させてみる 色んなサイトを見て、5枚の画像を1枚ずつ表示させる。 ボタンを2個作成し、前からも後ろからでも見れるようにした。 注釈のつけ方がわかったので、よくわからない部分についてはコードの中にコメントを書いた。 <!DOCTYPE html> <html> <head> <meta charaset="utf-8" /> <title> USAGI </title> </head> <body> <!--width=ボタン幅、height=ボタン高さ、font-size=ボタンの文字の大きさ onclickはクリック時の処理-->> <button style = "width:500px; height:100px; font-size:80px " onclick="foward()">次</button> <button style = "width:500px; height:100px; font-size:80px " onclick="back()">戻る</button> <br><!--改行要素--> <img id="image_place" src="image1.jpg"> <script> //指定したidに合ったドキュメント要素を取得する let img = document.getElementById("image_place") //画像番号 let idx = 1; //画像切り替える関数 function foward(){ idx++; if(idx > 5){ idx = 1; } //scrに画像ファイル名を設定 img.src = "image" + idx + ".jpg"; src.height = 100; } function back(){ idx--; if(idx < 1){ idx = 5; } img.src = "image" + idx + ".jpg"; src.height = 100; } </script> </body> </html> 表示させた画像は以下の通り image1 image2 image3 image4 image5 感想 ボタンの大きさや文字の大きさの変更はできたが、画像自体の比率や大きさが変更できなかった。ボタン自体のデザインを変更するのにはCSSがいると様々なサイトに載っていたので、それも少し見てみたいと思った。 Javascriptも全然わかっていない状況だし、Qiitaの投稿自体も特殊でめちゃくちゃ難しい。でもたのしいからOK^^ 参考文献 【HTML】意外と重要なDOCTYPE宣言についてわかりやすく解説。 < html >: HTML 文書 / ルート要素 ELEMENT meta 要素 ページに関する情報を表す要素 JavaScriptで画像を表示する方法を現役エンジニアが解説【初心者向け】
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iframeの中のaタグをクリックした際に、iframeの高さを遷移したページの高さ分に変更させる

iframe内のaタグをクリック iframe内のページ遷移 ページの高さによって、元ページでの高さを変更 のような挙動を実装した時にiframeについて理解することができたので、その時に行ったことを記載します。 注意!! クロスドメイン(親ページと子ページのドメインが異なる)の場合、この方法は適用できない可能性があります。 参考 iframeタグとは <IFRAME>はInline Frameの略です。<IFRAME>を使用すると、 <FRAMESET>のようにウィンドウを水平・垂直に分割する形式だけではなく、 ウィンドウの中に独立して表示される形式のインラインのフレームが作成できます。 <IFRAME>タグは<BODY>~</BODY>内で使用します。 src属性でフレーム内に表示する内容を指定します。name属性でフレームに名前を付けることで、 そのインラインフレームをリンクの表示先として指定することができます。 制作したもの 検証したこと iframe内のスタイルとtop内のスタイルの!importantのどちらが優先されるのか検証 iframe内のリンクを押すと、iframe内のページ遷移をしiframeのbodyの高さ分要素の高さを変更 制作したコードについて HTML iframe外のhtml <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="./css/top.css"> <script src="./js/top.js" defer></script> <title>iframe - sample</title> </head> <body> <p>トップ</p> <div> <iframe class="js-iframe" src="./move/page1.html" frameborder="0"></iframe> </div> <p>テキスト</p> </body> </html> iframe内のhtml(page1.html) <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="../css/page1.css"> </head> <body> <p>page1</p> </body> </html> iframe内のhtml(page2.html) <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="../css/page2.css"> </head> <body> <p>page2</p> </body> </html> CSS iframe内のcss p { color: #333 !important; } iframe外のcss(page1.css) * { margin: 0; box-sizing: border-box; } .border { border: 1px solid #f0f } a { color: inherit; } p { color: #f00; } iframe外のcss(page2.css) * { margin: 0; box-sizing: border-box; } .border { height: 100px; border: 1px solid #f00 } a { color: inherit; } p { color: #00f; } JavaScript // iframeのコンテンツの要素取得 function getIframeElem() { const elemIframe = document.querySelector('.js-iframe') return { elemIframe } } // iframeの要素の中にあるbodyの高さを取得 function getIframeHeight(elemIframe) { const iframeBodyHeight = elemIframe.contentWindow.document.body.clientHeight return { iframeBodyHeight } } // iframeの中にあるリンクタグの要素一覧を取得 function getElemIframeLink(elemIframe) { const elemIframeLinks = elemIframe.contentWindow.document.querySelectorAll('.js-link') return { elemIframeLinks } } // iframe内の要素をクリックした時の処理 function clickEvent(elemIframe) { elemIframe.addEventListener('load', loadEvent) } // ページが読み込まれた時の処理 function loadEvent() { const { elemIframe } = getIframeElem() const { iframeBodyHeight } = getIframeHeight(elemIframe) const { elemIframeLinks } = getElemIframeLink(elemIframe) elemIframe.height = iframeBodyHeight + 2 + 'px' elemIframeLinks.forEach(function(link) { link.addEventListener('click', clickEvent(elemIframe)) }) } window.addEventListener('load', function() { loadEvent() }, false) 行ったこと 1. iframe内のスタイルとtop内のスタイルの!importantのどちらが優先されるのか検証 /* ページ全体 */ p { color: #333 !important; } /* iframe内 */ p { color: #f00; } 結果 結果として、iframe内のスタイルはページ全体のスタイルと競合しない iframe外のpタグ iframe内のpタグ 2. iframe内のリンクを押すと、iframe内のページ遷移をしiframeのbodyの高さ分要素の高さを変更 行いたいことは表題の通りだが、jsでの実行の手順については以下になります。 2-1. iframeの要素を取得 後々管理しやすいようにhtml側にjs-iframeのclass名を付与、js側で要素の取得 <iframe class="js-iframe" src="./move/page1.html" frameborder="0"></iframe> // iframeのコンテンツの要素取得 function getIframeElem() { const elemIframe = document.querySelector('.js-iframe') return { elemIframe } /** * 以下の結果になる * <iframe class="js-iframe" src="./move/page1.html" frameborder="0"></iframe> */ } ここまでで以下のような要素が取得されます。 2-2. iframe内にあるbodyタグ・aタグの一覧の要素を取得 /** * elemIframeについては`2-1`で取得したiframeの要素 */ // iframeの要素の中にあるbodyの高さを取得 function getIframeHeight(elemIframe) { const iframeBodyHeight = elemIframe.contentWindow.document.body.clientHeight return { iframeBodyHeight } /** * 以下の結果になる * 24 */ } // iframeの中にあるリンクタグの要素一覧を取得 function getElemIframeLink(elemIframe) { const elemIframeLinks = elemIframe.contentWindow.document.querySelectorAll('.js-link') return { elemIframeLinks } /** * 以下の結果になる * NodeList [a.js-link] */ } HTMLIFrameElement.contentWindowを使用することで、iframe内のwindowオブジェクトにアクセスすることができます。 2-3. iframeの高さを変更 2-2で取得したiframeBodyHeightをiframeの高さに設定 // 今回の場合はiframe内のページ内のborder分もプラスしたいため、2pxの追加も行っている。 elemIframe.height = iframeBodyHeight + 2 + 'px' 2-4. 2-2で取得したaタグにeventを追加 イベントを付与 elemIframeLinks.forEach(function(link) { link.addEventListener('click', clickEvent(elemIframe)) }) 2-5. iframeのload時に処理を行う // iframe内の要素をクリックした時の処理 function clickEvent(elemIframe) { elemIframe.addEventListener('load', loadEvent) } 詰まったところ 1. addEventListenerを意識しないと読み込み回数がおかしくなる addEventListenerの第2引数を無名関数にすると複数回実行した時に処理が無駄に走ってしまう。 // NG elemIframe.addEventListener('load', function() { loadEvent() }) // OK elemIframe.addEventListener('load', loadEvent) NGの動き OKの動き
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クリスマス・イブなのでクリスマスツリーを作る

この記事は ゆめみ Advent Calendar 2021 の24日目の記事です。 はじめに みなさまは「クリスマス」と聞いて何を思い浮かべますか?サンタクロースでしょうか。それともイルミネーションでしょうか。 私の場合は家の中に飾っていたクリスマスツリーを思い浮かべます。 我が家では、毎年クリスマスの日にクリスマスツリーの前にプレゼントとサンタさんからの手紙が置いてありました。もうクリスマスツリーは飾っていませんが、あの頃を思い出して HTML + CSS でクリスマスツリーを作ろうと思います。 星 昔は擬似要素( ::before / ::after )を使用して作成していましたが、 IE のサポートが終了するので clip-path を使用して作成します。 clip-path に関しては、 Clippy というサイトがおすすめです。 See the Pen star.html by takashi (@takashimelon) on CodePen. ツリー 星と同じく clip-path を使用して作成します。葉の部分は polygon でもよかったのですが、少し丸みを帯びさせるために path で作成しています。 See the Pen tree.html by takashi (@takashimelon) on CodePen. オーナメント clip-path の circle でも作成できますが、慣れ親しんだ border-radius で作成しています。 また、オーナメントは基本光りませんが、アニメーションさせたくなったので光らせます。 See the Pen ornament.html by takashi (@takashimelon) on CodePen. クリスマスツリー 星・ツリー・オーナメントを配置すれば完成です。 See the Pen christmas-tree.html by takashi (@takashimelon) on CodePen. おわりに メリークリスマス! おまけ ~SVG編~ 丸みをつけたいと思い、 SVG でも実装しました。ベジェ曲線を完全に理解すれば clip-path でも実装できますが、今回はシンプルかつ簡単に実装するために stroke-linejoin="round" で丸みを表現しました。 See the Pen christmas-tree.svg by takashi (@takashimelon) on CodePen.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】buttonタグのsubmitした値がPOSTされなかった話

クリックしたボタンによって処理を分ける formでpostする際において複数のボタンを設置している場合、クリックしたボタンの値を受け取って処理を分岐できる。 例えばメールフォームなどで、確認画面から入力画面に戻るか、送信するかという場合、以下のような処理で実現できる。 <form action="post.php" method="post"> <button type="submit" name="action" value="back">戻る</button> <button type="submit" name="action" value="send">送信</button> </form> $action = (string)filter_input(INPUT_POST, 'action'); if ($action === 'back') { // 入力画面に戻る処理 // リダイレクトとか } // 送信処理 なんてことない、よくある実装だ。 buttonの値が送信されない 上記のようなフォームを実装して、実際に動かしてみたところどちらのボタンをクリックしても、送信処理だけが実行されてていた。$actionのチェックがすり抜けているようだ。 $_POSTをダンプすると、actionの値そのものが送信されていない。 原因 しばらく原因がわからず、さまざまな検証をしたが、JavaScriptでこのようなコードを記述していた。 $(function($) { $('form').submit(function() { $('.submit', this).prop('disabled', true); }); }); disabled…? このコードを削除すると、buttonタグの値が送信された。 これなに? いわゆる多重送信を防ぐために、サブミット後にボタンを無効化する処理。 さいきょうの二重サブミット対策 - Qiita disabledの要素の値が送信されないことは承知だが、submit後に変更してもダメなのか? と、この記事を書いている途中に以下の記事を見つけた。 Chromeの場合、submitボタン押下時にボタンをdisabledにすると、フォームデータが送信されない。 - Qiita なるほど…、Chrome特有の問題なのか? しかし、改善後の内容と現在の記述は(私はjQueryだが)同じものと思われる。 結論(未解決) 記述を変更したが、二重送信防止のためのdisabed処理を実装している場合、Chromeでは値が送信されなかった。 二重送信については、これにおいては直接の問題にはならないので、該当コードを削除して対応した。 ググって出てきた参考リンク(忘備録) Google Chromeでsubmitボタンの多重送信防止対策に対する対策【JavaScript】 JQueryでsubmitボタン連打禁止 送信ボタンの二重クリック防止を目的とするボタン無効化の推奨される対応方法について
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む