- 投稿日:2020-09-22T23:31:15+09:00
横並びのカードレイアウト実装(BEM使用)
はじめに
コーディングをしているとカード横並びにしたようなレイアウトがよく使われるなぁと感じます。
そこで毎回作るのがめんどくさいのでここにメモ書き程度に残しておきます。使用しているのはBEMですがふつうにcssに置き換えても同じ考え方なので、使いまわせるかと思います。
また、もっと汎用性高くできるだろ!と気付いた方いれば教えていただけれたらと思います。
今回はこんな感じのものを作ります。
横並びにする前にカードの形だけつくる
まず、カードの形だけ作ります。
というのも、サイト制作時に他の場所で4カラムで使いたいとか往々にしてあるからです。
その時に3カラムでしか対応できない作りにしていると同じことを二回も三回もしていくことになり、使い回しが効かないーと嘆くことになります。html
<div class="card"> <div class="card__wrapper"> <div class="card__img-box"> <img src="https://cdn.pixabay.com/photo/2020/08/27/10/24/water-5521696_960_720.jpg" alt="" class="card__img-item" /> </div> <div class="card__content"> <h3 class="card__ttl">ダミーテキスト</h3> <p class="card__txt"> ダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストが入ります。 </p> <p class="card__txt"> ダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストが入ります。 </p> </div> </div> </div>css(scss)
.card { &__wrapper { background-color: #fff; box-shadow: 5px 5px 5px #999; } &__img-box { position: relative; width: 100%; padding-top: 55%; overflow: hidden; } &__img-item { width: 100%; position: absolute; top: 50%; transform: translate(0, -50%); } &__content { padding: 20px; > *:last-child { margin-bottom: 0; } } &__ttl { font-size: 20px; margin-bottom: 15px; font-weight: 700; } &__txt { font-size: 16px; } }というわけでこれがカード本体になります。
- 投稿日:2020-09-22T22:02:33+09:00
【初心者向け】GoogleChromeのリニューアルで目立つようになった黒い線を消す方法
どうも7noteです。開発していると、意図していない場所に黒い太枠線がでてくるようになって、なんだこれって思ってました。こいつを消します。
フォームやマウスカーソルで要素を触ると出てくる・・・
どうやらクロームの初期値として、:focusがある時に出るようです。
消し方
消したい要素に
outline: none;
だけ。とっても簡単。input { outline: none; }まとめ
以前まではあまり気にしていなかったのですが、前回のクロームのアップデートの影響ですごく悪目立ちすることがあったので、必要ない場面では消すようにしています。
※タブキーを使って移動していると、どこにフォーカスしているかわからなくなるので注意!!
おそまつ!
~ Qiitaで毎日投稿中!! ~
【初心者向け】HTML・CSSのちょいテク詰め合わせ
- 投稿日:2020-09-22T12:06:28+09:00
あなたがまだ使っていないかもしれないHTML5の便利機能10選
こんにちは、たかとーです??
こちらは、10 useful HTML5 features, you may not be usingの翻訳記事になります。
当記事は、Tapasさんの許可を得て翻訳しています。Tweet
10 useful HTML5 features, you may not be using
HTML5
は新しいものではありません。最初のリリース(2008年1月)以来いくつかの機能を使用してきました。100DaysOfCode
の取り組みの一環として、HTML5の機能リストをもう一度よく見てみました。何か見つけたかな?私は今のところあまり使っていません。この記事では、過去にあまり使ったことがなかったが、今では便利になった
HTML5
の機能を10個挙げています。また、Netlify
でホストされている、実際に動作する例を作成しました。参考になることを願っています。Detailsタグ
<details>
タグは、ユーザーに必要なときだけ詳細を提供します。ユーザーにオンデマンドでコンテンツを表示する必要がある場合は、このタグを使用します。デフォルトでは、ウィジェットは閉じています。開くと、ウィジェットは展開され、コンテンツが表示されます。
<summary>
タグは、<details>
と一緒に使われ、見出しを指定します。コード
<details> <summary>Click Here to get the user details</summary> <table> <tr> <th>#</th> <th>Name</th> <th>Location</th> <th>Job</th> </tr> <tr> <td>1</td> <td>Adam</td> <td>Huston</td> <td>UI/UX</td> </tr> </table> </details>動作例
ここで実際に触ることができます: https://html5-tips.netlify.app/details/index.html
Tips
GitHubのReadmeで、必要に応じて詳細情報をで表示するために使ってみましょう。これは、Reactコンポーネントの膨大な量のプロパティリストを隠して、クリックされたら表示する例です。
Content Editable属性
contenteditable
は、コンテンツを編集可能にするために要素に設定できる属性です。<div>
、<p>
、<ul>
などで動作します。<element contenteditable="true|false">
のように指定する必要があります。注意: contenteditable属性がその要素に指定されていないとき、親要素から値を受け継ぎます。
コード
<h2>Shoppping List(Content Editable)</h2> <ul class="content-editable" contenteditable="true"> <li>1. Milk</li> <li>2. Bread</li> <li>3. Honey</li> </ul>動作例
ここで実際に触ることができます: https://html5-tips.netlify.app/content-editable/index.html
Tips
この属性を使うことで、
<span>
や<div>
を編集可能にし、CSSを使ってリッチなコンテンツを追加できます。これはinputフィールドを使用するよりもずっと良いでしょう。ぜひお試しください!Mapタグ
<map>
タグはイメージマップの定義に役立ちます。イメージマップとは、1つ以上のクリック可能な領域を持つ画像のことです。<area>
タグでクリック可能な領域を決定します。クリック可能な領域は、矩形、円、多角形の領域のいずれかになります。形状を指定しない場合は、領域を画像全体として考慮します。コード
<div> <img src="circus.jpg" width="500" height="500" alt="Circus" usemap="#circusmap" /> <map name="circusmap"> <area shape="rect" coords="67,114,207,254" href="elephant.htm" /> <area shape="rect" coords="222,141,318, 256" href="lion.htm" /> <area shape="rect" coords="343,111,455, 267" href="horse.htm" /> <area shape="rect" coords="35,328,143,500" href="clown.htm" /> <area shape="circle" coords="426,409,100" href="clown.htm" /> </map> </div>動作例
ここで実際に触ることができます: https://html5-tips.netlify.app/map/index.html
Markタグ
<mark>
タグでテキストをハイライトしてみましょう。コード
<p> Did you know, you can <mark>"Highlight something interesting"</mark> just with an HTML tag? </p>動作例
ここで実際に触ることができます: https://html5-tips.netlify.app/mark/index.html
data-* 属性
data-*
属性は、ページやアプリケーションにプライベートなカスタムデータを保存するために使用されます。保存されたデータはJavaScriptで使用して、さらなるユーザー体験を生み出すことができます。
data-*
属性は2つの部分から構成されますThe data-* attributes consist of two parts:
* 属性名に大文字を含めるべきではなく、またdata-
プレフィックスの後は1文字以上が必要です
* 属性値は任意の文字列になりますコード
<h2>Know data attribute</h2> <div class="data-attribute" id="data-attr" data-custom-attr="You are just Awesome!" > I have a hidden secret! </div> <button onclick="reveal()">Reveal</button>JavaScriptで以下のように操作します。
function reveal() { let dataDiv = document.getElementById('data-attr'); let value = dataDiv.dataset['customAttr']; document.getElementById('msg').innerHTML = `<mark>${value}</mark>`; }注意: JavaScriptでこれらの属性値を読み取るには、完全なHTML名(data-custom-attr)で
getAttribute()
を使用できますが、標準ではもっと簡単な方法を定義しています:dataset
プロパティを使用です。動作例
ここで実際に触ることができます: https://html5-tips.netlify.app/data-attribute/index.html
Outputタグ
<output>
タグは計算結果を表します。通常、この要素は計算結果のテキスト出力を表示するための領域を定義します。コード
<form oninput="x.value=parseInt(a.value) * parseInt(b.value)"> <input type="number" id="a" value="0" /> * <input type="number" id="b" value="0" /> = <output name="x" for="a b"></output> </form>動作例
ここで実際に触ることができます: https://html5-tips.netlify.app/output/index.html
Datalistタグ
<datalist>
タグは、あらかじめ定義されたオプションのリストを指定し、ユーザーはそのリストにさらにオプションを追加することができます。これはautocomplete
機能を提供しており、タイプアヘッドで目的のオプションを取得することができます。コード
<form action="" method="get"> <label for="fruit">Choose your fruit from the list:</label> <input list="fruits" name="fruit" id="fruit" /> <datalist id="fruits"> <option value="Apple"></option> <option value="Orange"></option> <option value="Banana"></option> <option value="Mango"></option> <option value="Avacado"></option> </datalist> <input type="submit" /> </form>動作例
ここで実際に触ることができます: https://html5-tips.netlify.app/datalist/index.html
Range(Slider)値
range
はinputタグのtype属性値で、スライダーのようなセレクタを実現します。コード
<form method="post"> <input type="range" name="range" min="0" max="100" step="1" value="" onchange="changeValue(event)" onchange="changeValue(event)" /> </form> <div class="range"> <output id="output" name="result"> </output> </div>動作例
ここで実際に触ることができます: https://html5-tips.netlify.app/range/index.html
Meterタグ
<meter>
タグを使って、与えられた範囲でデータを測ってみましょう。コード
<label for="home">/home/atapas</label> <meter id="home" value="4" min="0" max="10">2 out of 10</meter><br /> <label for="root">/root</label> <meter id="root" value="0.6">60%</meter><br />動作例
ここで実際に触ることができます: https://html5-tips.netlify.app/meter/index.html
Tips
プログレスバーのようなものを表示する際には
<progress>
タグを使用してください。<label for="file">Downloading progress:</label> <progress id="file" value="32" max="100">32%</progress>Inputsタグ
inputタイプにはいくつか特別な使い方があります。
コード
required
inputフィールドを必須アイテムにします。
<input type="text" id="username1" name="username" required />autofocus
input要素にカーソルを置くと自動でフォーカスします。
ページのローディングが完了し次第、autofocus属性を持つinput要素に自動でフォーカスされます。
(*@otiextさんのコメントにより修正しました!ありがとうございました!)<input type="text" id="username2" name="username" required autofocus />validation with regex
正規表現をつかって入力値をバリデーションできます。
<input type="password" name="password" id="password" placeholder="6-20 chars, at least 1 digit, 1 uppercase and one lowercase letter" pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,20}$" autofocus required />Color picker
シンプルなカラーピッカーです。
<input type="color" onchange="showColor(event)" /> <p id="colorMe">Color Me!</p>訳者感想
Reactなど、JavaScript関連の新しい情報はキャッチアップするようにしているのですが、HTMLに関しては全くできておらず、目からウロコな記事でした。
いままでJavaScriptを使って実現していたようなものをHTMLのみで表現できるのは、開発者にとっても楽で最高ですよね!
素晴らしい記事をありがとうございました Tapas✨
訳者について
2019年5月よりバンクーバーを拠点に移し、現在スタートアップの開始に向けて試行錯誤しているソフトウェアでデベロッパーです。
近頃は、VCの方と話しながらアイディアのブラッシュアップなどを行いながらMVPの検証を進めています。
フリーランス案件も募集し始めました!React、NodeJs、TypeScript等フロント、バックエンド問わず行えます。是非宜しくお願い致します。
もしよろしければ、以下SNSもよろしく願いします!
Twitter: @taishikat0_Ja
Note: 日本人でも英語圏で戦えることを証明したい。28歳が会社を辞め、個人開発者としてカナダでひたすらもがき続けた一年間とこれから
Linkedin: Taishi Kato
- 投稿日:2020-09-22T11:36:02+09:00
html/templateメモ
html/templateメモ
目次
html/templateの概要
htmlのテンプレートにこちらのプログラムで処理したデータを埋め込み返す。webサービスには必須の技術だが、それをgolangを実現するにはテンプレートエンジンであるhtml/templateを使う
正確には汎用テンプレートエンジンであるtext/template標準ライブラリと、さらにHTML専用のテンプレートエンジンであるhtml/templateライブラリの二種類があるが、ここでは後者を扱う
templateとは
template(テンプレート) とは予め用意されたhtmlのひな型
テンプレートエンジン とはテンプレートとデータ 1を組み込んで、クライアントに返す最終的なhtmlを生成するプログラム
通常、ハンドラがテンプレートエンジンを呼び出してデータをテンプレートに組み込み、できあがったHTMLをクライアントに返す
イメージ図12
基本文法
Go言語のテンプレートはテキストドキュメントであり(Webアプリの場合、通常はHTML
ファイル)、アクション と呼ばれる何らかのコマンドが埋め込まれたものテンプレートはファイル全体であることもあれば、ファイルの一部しかテンプレートとして宣言されていないこともある
アクションが埋め込まれたテキスト、すなわちテンプレートがテンプレートエンジンによって解析(構文解析)され、「実行」されて新たなテキストが生成される
Go言語では任意のアクションは
{{...}}
で囲って記述するプレーンなアクション
- 単純なテンプレートの例を示す
templ.html<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Go Web Programming</title> </head> <body> {{ . }} </body> </html>
{{ . }}
の中のドット「.
」 がアクションであり、テンプレートエンジンがテンプレートを実行したときに、「その部分をデータで置換える」という意味を持つコマンド次は上で定義したテンプレートから、最終的なhtmlを作成するgoスクリプトの方を見てみる
main.gopackage main import ( "net/http" "html/template" ) func process(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles("tmpl.html") t.Execute(w, "hoge") } func main() { server := http.Server{ Addr: "127.0.0.1:8080", } http.HandleFunc("/process", process) server.ListenAndServe() }
t, _ := template.ParseFiles("tmpl.html")
関数ParseFilesでテンプレートファイルtmpl.htmlを解析(コンパイル)する。
この関数は解析済みテンプレート(Template型)とエラーを返す因みに、errorではなくパニックに変換するためにMust()を合わせて利用することもある
var t = template.Must(template.ParseFiles("index.html"))
t.Execute(w, "hoge")
Executeメソッドを呼び出してデータ(この例では「hoge」)をコンパイル済みテンプレートに当てはめている。
生成されたhtmlはt.Execute()の第一引数で指定したio.Writerであるhttp.ResponseWriter
に書き込まれる。
Fprint系の関数とやっていることは似ている├── main.go
└── templ.html
以上二つのファイルを上のようなディレクトリ構成にしておくと、ビルド後に無事htmlファイルを返せるようになる渡されるデータが構造体である場合
上の例で見たのは文字列"hoge"をデータとして渡す方法だった。「
.
」はそのまま"hoge"と置き換えられるので分かりやすいしかし一般的なのは構造体を渡すことで、そのメンバ変数がデータとして使われる。例えば先ほどのmain.goを次のように変えた場合だとどうするか
main.go... type Person struct{ Name:string Sex:string } var person Person = { Name:"HOGE" Sex:"Male" //personのメンバ変数NameとSexをテンプレートに埋め込みたい } func process(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles("tmpl.html") t.Execute(w, person) //構造体personが渡されている ...
- 答えは次のようになる
template.html<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Go Web Programming</title> </head> <body> {{ .Name }} {{ .Sex }} </body> </html>
ドット「
.
」単体では構造体そのものとの置き換えを指すが、.Name
,.Sex
とすることで特定のメンバ変数との置き換えという意味になる
構造体名.メンバ変数名
でメンバ変数の値にアクセスできるのと近いものを感じるその他アクション
テンプレートに渡されたデータと置き換えるドット「
.
」のコマンドは最も基本的なアクションだった。
しかし「.
」以外にもアクションは存在する。それらは単純な置き換えとは違う、よりプログラム寄り(条件文やループ)の処理を行う条件アクション
- 条件アクションとは、多数のデータ評価値の中から引数の値に応じて1つを選択するものである。次の形式で表せる。(ただしargは任意の引数)
{{ if arg }} コンテンツ {{ end }}
- もう1つのタイプは次の形式。
{{ if arg }} コンテンツ {{ else }} 他のコンテンツ {{ end }}イテレータアクション
- イテレータアクションとは、配列やスライス、マップ、チャネルの要素ごとに反復処理を行うアクション。反復ループの内部では、ドットに配列やスライス、マップ、チャネルの要素が次々に設定される。 書式は次の通り
{{ range array }} #arrayは大抵データとして渡されたスライスやマップのイメージ {{ . }} #range内でドットに要素が設定される {{ end }}
- arrayがnilだった場合のフォールバックも存在する
代入アクション
代入アクションを使うと、そのアクションで囲まれたセクション内でargに指定した有効な値をドット「
.
」の値として設定できる。書式は次の通り{{ with arg }} このセクション内でドットにargが設定される {{ end }}
- argが空白だった場合のフォールバックも存在する
インクルードアクション
- テンプレートに別のテンプレートを差し込むことができる。書式は次の通り
{{ template "name" }}
- このアクションは次の章で詳しく説明する
テンプレートを分割したい
テンプレートAとテンプレートBがあったとき、bodyの要素は違ってもヘッダーは共通にしたい
というような、テンプレートを部品化して再利用する需要が出てくる。
この場合、共通部品であるヘッダーをテンプレートCとして作成してそれぞれのテンプレートに埋め込めばよい静的なテンプレートの追加方法
インクルードアクション
{{ template "name" }}
を使えばテンプレートに別のテンプレートを差し込むことができる。単純な例を見る。
2つのテンプレートファイル、t1.htmlとt2.htmlを作成する。この例ではテンプレートt1.htmlがt2.htmlをインクルードする。t1.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=9"> <title>Go Web Programming</title> </head> <body> <div> ここは、t1.html(インクルードの前)</div> <div>t1.html内でのドットの値 - [{{ . }}]</div> <hr/> {{ template "t2.html" }} <hr/> <div> ここは、t1.html(インクルードの後)</div> </body>t2.html<div style="background-color: yellow;"> ここはt2.htmlです<br/> </div>
- ハンドラは次のようにする
main.gopackage main import ( "html/template" "net/http" ) func process(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles("template/t1.html", "template/t2.html") t.Execute(w, "こんにちは") } func main() { server := http.Server{ Addr: "127.0.0.1:8080", } http.HandleFunc("/", process) server.ListenAndServe() }
t, _ := template.ParseFiles("template/t1.html", "template/t2.html")
に注目すると、
今までと違い、ParseFilesメソッドの引数が二つになっている。
ParseFilesメソッドは可変長引数関数であり、コンパイルするファイルを複数指定することができるParseFiles関数の引数が可変長でも、返り値としてのコンパイル済みテンプレートは一つしかなく、それは最終的にレスポンスとして返すhtmlのテンプレートである。
その主要素はもちろん親の(ここではt1.html)テンプレートであり、親のテンプレートは必ず第一引数に指定しなくてはならない。逆にインクルードされる部品としてのテンプレートは第二引数以降に指定するディレクトリ構成はこのようになっている
├── main.go
└── template
└── t2.html
└──t1.html
http://127.0.0.1:8080/process
にアクセスすると以下のページが表示される動的なテンプレートの追加方法
先ほどの例では部品テンプレート(t2.html)は静的だった
部品テンプレートにも動的なデータを含みたい場合は次のような書式になる
{{ template "name" arg}}
{{template "name"}}と違うのは後ろに引数argがくっついている点
こうすることで、インクルードされるテンプレートに渡すデータを指定できるさきほどの例を変更して、t2.htmlにもデータが渡るようにしてみる
t1.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=9"> <title>Go Web Programming</title> </head> <body> <div> ここは、t1.html(インクルードの前)</div> <div>t1.html内でのドットの値 - [{{ . }}]</div> <hr/> {{ template "t2.html" . }} #argにアクション「.」が指定されている <hr/> <div> ここは、t1.html(インクルードの後)</div> </body>t2.html<div style="background-color: yellow;"> ここはt2.htmlです<br/> t2.htmlに渡された値 - [{{ . }}] </div>スコープの話
アクション「
.
」はt.Execute(w, テンプレートに渡すデータ)
で指定したデータと置き換えられること、そのデータが構造体であれば「.メンバ変数
」とするとそのメンバ変数と置き換えられることを既に伝えたその性質を利用して入れ子の構造体を自在に扱えたりもする
次のようなt1.html,t2.html,main.goを作成する
t1.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=9"> <title>Go Web Programming</title> </head> <body> <div> ここは、t1.html(インクルードの前)</div> <div>性別 - [{{ .Sex }}]</div> <hr/> {{ template "t2.html" .Name }} <hr/> <div> ここは、t1.html(インクルードの後)</div> </body>t2.html<div style="background-color: yellow;"> ここはt2.htmlです [{{ .Givenname }}] [{{ .Familyname }}] </div>main.gopackage main import ( "html/template" "net/http" ) type Name struct { Givenname string Familyname string } type Person struct { Name Name Sex string } func process(w http.ResponseWriter, r *http.Request) { person := Person{ Name: Name{ Givenname: "小町", Familyname: "烏丸", }, Sex: "Famale", } t, err := template.ParseFiles("template/t1.html", "template/t2.html") if err != nil { print(err) } t.Execute(w, person) } func main() { server := http.Server{ Addr: "127.0.0.1:8080", } http.HandleFunc("/", process) server.ListenAndServe() }
main.goで入れ子になった構造体を定義し、親の構造体のメンバ変数はt1.htmlへ、入れ子の構造体のメンバ変数はt2.htmlに渡している
t1.htmlの
{{ template "t2.html" .Name }}
に注目すると、t2.htmlに渡されるデータが.Name
になっているこうすることでt2.htmlでは「
.
」のスコープはName構造体に限定されるため、t2.htmlでは入れ子になっている構造体のメンバ変数へのアクセスは[{{ .given_name }}]
とスマートになっている
http://127.0.0.1:8080/process
にアクセスすると以下のページが表示される余談
頭文字が大文字であれば外部から参照できる、というのがGo言語の特徴
先ほどの例ではアクション「
.
」を通じて構造体を渡しているが、その過程でこちらのパッケージを外部に参照させる処理が含まれているのか
main.go
でtype Name struct { givenname string familyname string }
- のようにName構造体のメンバ変数の頭文字を小文字に変更すると、テンプレートに値が渡らない
参考
Go の html/template でヘッダーやフッター等の共通化を実現する方法
Goプログラミング実践入門 ―標準ライブラリでゼロからWebアプリを作る―
大抵はクライアントから渡される情報を指す。ユーザ名など。テンプレートは既に用意されたものであるため静的で、データはクライアントによって変わるものであるため動的(ただしこれから見ていく例では単純化するためサーバサイドで定義した文字列等を使っている) ↩
ハンドラがテンプレートエンジンを呼び出して、使用するテンプレートを通常はテンプレートのリストとして、動的なデータと一緒に渡します。テンプレートエンジンはHTMLを生成して、ResponseWriterにそれを書き込み、さらにResponseWriterはクライアントに送り返すHTTPレスポンスにそれを追加します。(イメージ図共に『Goプログラミング実践入門』より引用) ↩
- 投稿日:2020-09-22T09:09:46+09:00
HTMLチュートリアル
HTMLの紹介
HTMLとは?
- HTMLはハイパーテキストマークアップ言語
- HTMLはWebページを作成するための標準的なマークアップ言語
- HTMLはWebページの構成を記載
- HTMLは一連の要素からなる
- HTMLはコンテンツをどのように表示するかをWebブラウザに指示
- HTMLは見出し・段落・リンクなどのような一連の要素を含む
シンプルなHTMLドキュメント
Example
<!DOCTYPE html> <html> <head> <title>Page Title</title> </head> <body> <h1>My First Heading</h1> <p>My first paragraph.</p> </body> </html>サンプル文の説明
- <!DOCTYPE html> : このドキュメントがHTML5で記載されることを宣言
- <html> : HTMLページのルート要素
- <head> : HTMLのメタ情報を含む要素
- <title> : HTMLのタイトル(ブラウザのタイトルバーあるいはタブに表示)
- <body> : ドキュメントのボディを定義
- <h1> : 最も大きな見出しの要素
- <p> : 段落を表す要素
HTML要素とは?
HTML要素は、開始ダグ及びいくつかのコンテンツ、終了タグで定義される。
<tagname>Content goes here...</tagname>
HTML要素はすべて開始タグで始まり終了タグで終わる。
<h1>My First Heading</h1>
<p>My first paragraph.</p>
開始タグ 要素の内容 終了タグ <h1> 最初の見出し </h1> <p> 最初の段落 </p> <br> なし なし いくつかのHTML要素は<br>要素のようにコンテンツを持たないものがある。
これらの要素は空要素と呼ばれ、終了タグを記載しないWebブラウザ
Webブラウザ(chorome,edge,firefox,safari etc)は、HTMLドキュメントを読み込み画面に正確に表示する目的で使用されている。WebブラウザはHTMLタグを表示しないが、どのようにドキュメントを表示するかを決めるために使用する。
HTMLページの構造
- 投稿日:2020-09-22T01:08:54+09:00
カウントダウンタイマーの実装
はじめに
ポートフォリオで実装予定のカウントダウンタイマーを実装する。
タイマーを実装するにはjQueryが必要と書いてある記事もあるが、今回はjQueryを利用せずに実装を進めていくことにする。カラムの作成
まずは、いつものように
rails generate migration Addカラム名Toテーブル名 カラム名:データ型でマイグレーションファイルを作成する。
今回の場合、制限時間を表示させる場所を表示させたいのでdeadlineをカラム名として、rails generate migration AddDeadlineToMission deadline:datetimeとする。
class CreateMissions < ActiveRecord::Migration[6.0] def change create_table :missions do |t| t.integer :user_id t.text :content t.string :penalty t.datetime :deadline t.timestamps end end end上記のマイグレーションファイルの7行目に
t.datetime :deadline
を追加する。
そして、親の顔より見た$ rails db:migrateを実行して、データベースに保存する。
タイマーの実装
HTMLの記述
上記のような赤字のタイマーを設定するには、
app/views/missions/new.html.erb<p> <%= f.hidden_field :deadline, :id => "deadline.id" %> <input type="text" id="userYear" >年 <input type="text" id="userMonth">月 <input type="text" id="userDate" >日 <input type="text" id="userHour" >時 <input type="text" id="userMin" >分 <input type="text" id="userSec" >秒 </p> <p id="RealtimeCountdownArea" ></p> #ここにタイマーが表示されるとする。
ここで、:id => deadline.id
は後のjavascriptの記述において効果を発揮するため、記述している。javascriptの記述
今回は、
app/views/missions/new.html.erb
のscriptタグにjavascriptを記述することとする。
以下の通りである。app/views/missions/new.html.erb<script> function set2fig(num) { // 数値が1桁だったら2桁の文字列にして返す var ret; if( num < 10 ) { ret = "0" + num; } else { ret = num; } return ret; } function isNumOrZero(num) { // 数値でなかったら0にして返す if( isNaN(num) ) { return 0; } return num; } function showCountdown() { // 現在日時を数値(1970-01-01 00:00:00からのミリ秒)に変換 var nowDate = new Date(); var dnumNow = nowDate.getTime(); // 指定日時を数値(1970-01-01 00:00:00からのミリ秒)に変換 var inputYear = document.getElementById("userYear").value; var inputMonth = document.getElementById("userMonth").value - 1; var inputDate = document.getElementById("userDate").value; var inputHour = document.getElementById("userHour").value; var inputMin = document.getElementById("userMin").value; var inputSec = document.getElementById("userSec").value; var targetDate = new Date( isNumOrZero(inputYear), isNumOrZero(inputMonth), isNumOrZero(inputDate), isNumOrZero(inputHour), isNumOrZero(inputMin), isNumOrZero(inputSec) ); var dnumTarget = targetDate.getTime(); // 表示を準備 var dlYear = targetDate.getFullYear(); var dlMonth = targetDate.getMonth() + 1; var dlDate = targetDate.getDate(); var dlHour = targetDate.getHours(); var dlMin = targetDate.getMinutes(); var dlSec = targetDate.getSeconds(); var msg1 = "期限の" + dlYear + "/" + dlMonth + "/" + dlDate + " " + set2fig(dlHour) + ":" + set2fig(dlMin) + ":" + set2fig(dlSec); // 引き算して日数(ミリ秒)の差を計算 var diff2Dates = dnumTarget - dnumNow; if( dnumTarget < dnumNow ) { // 期限が過ぎた場合は -1 を掛けて正の値に変換 diff2Dates *= -1; } // 差のミリ秒を、日数・時間・分・秒に分割 var dDays = diff2Dates / ( 1000 * 60 * 60 * 24 ); // 日数 diff2Dates = diff2Dates % ( 1000 * 60 * 60 * 24 ); var dHour = diff2Dates / ( 1000 * 60 * 60 ); // 時間 diff2Dates = diff2Dates % ( 1000 * 60 * 60 ); var dMin = diff2Dates / ( 1000 * 60 ); // 分 diff2Dates = diff2Dates % ( 1000 * 60 ); var dSec = diff2Dates / 1000; // 秒 var msg2 = Math.floor(dDays) + "日" + Math.floor(dHour) + "時間" + Math.floor(dMin) + "分" + Math.floor(dSec) + "秒"; // 表示文字列の作成 var msg; if( dnumTarget > dnumNow ) { // まだ期限が来ていない場合 msg = msg1 + "までは、あと" + msg2 + "です。"; } else { // 期限が過ぎた場合 msg = msg1 + "は、既に" + msg2 + "前に過ぎました。"; } // 作成した文字列を表示 document.getElementById("RealtimeCountdownArea").innerHTML = msg; document.getElementById("deadline.id").value = targetDate; #最重要記述 } // 1秒ごとに実行 setInterval('showCountdown()',1000); </script>ここで、先程の
:id => deadline.id
が活きてくる。このような記述を追加することで初めて、
javascriptで処理された結果をvalue(値)として受け取り、それを画面上で表示させることができる。これでようやく、タイマーを実装することができる。タイマーだけを表示させたい場合
なお、日時の記入欄を表示させたくない場合も考えられる。下の写真のように期限とタイマーの残り時間だけを表示させたいという場合には、
app/views/missions/show.thml.erb<p>期限 <%= @mission.deadline %> <br> <input type="hidden" id="userYear" value = "<%= @mission.deadline.year %>" > <input type="hidden" id="userMonth"value = "<%= @mission.deadline.month %>" > <input type="hidden" id="userDate" value = "<%= @mission.deadline.day %>" > <input type="hidden" id="userHour" value = "<%= @mission.deadline.hour %>" > <input type="hidden" id="userMin" value = "<%= @mission.deadline.min %>" > <input type="hidden" id="userSec" value = "<%= @mission.deadline.sec %>" > </p> <p id="RealtimeCountdownArea" ></p> <script> function set2fig(num) { // 数値が1桁だったら2桁の文字列にして返す var ret; if( num < 10 ) { ret = "0" + num; } else { ret = num; } return ret; } function isNumOrZero(num) { // 数値でなかったら0にして返す if( isNaN(num) ) { return 0; } return num; } function showCountdown() { // 現在日時を数値(1970-01-01 00:00:00からのミリ秒)に変換 var nowDate = new Date(); var dnumNow = nowDate.getTime(); // 指定日時を数値(1970-01-01 00:00:00からのミリ秒)に変換 var inputYear = document.getElementById("userYear").value; var inputMonth = document.getElementById("userMonth").value - 1; var inputDate = document.getElementById("userDate").value; var inputHour = document.getElementById("userHour").value; var inputMin = document.getElementById("userMin").value; var inputSec = document.getElementById("userSec").value; var targetDate = new Date( isNumOrZero(inputYear), isNumOrZero(inputMonth), isNumOrZero(inputDate), isNumOrZero(inputHour), isNumOrZero(inputMin), isNumOrZero(inputSec) ); var dnumTarget = targetDate.getTime(); // 表示を準備 var dlYear = targetDate.getFullYear(); var dlMonth = targetDate.getMonth() + 1; var dlDate = targetDate.getDate(); var dlHour = targetDate.getHours(); var dlMin = targetDate.getMinutes(); var dlSec = targetDate.getSeconds(); var msg1 = "期限の" + dlYear + "/" + dlMonth + "/" + dlDate + " " + set2fig(dlHour) + ":" + set2fig(dlMin) + ":" + set2fig(dlSec); // 引き算して日数(ミリ秒)の差を計算 var diff2Dates = dnumTarget - dnumNow; if( dnumTarget < dnumNow ) { // 期限が過ぎた場合は -1 を掛けて正の値に変換 diff2Dates *= -1; } // 差のミリ秒を、日数・時間・分・秒に分割 var dDays = diff2Dates / ( 1000 * 60 * 60 * 24 ); // 日数 diff2Dates = diff2Dates % ( 1000 * 60 * 60 * 24 ); var dHour = diff2Dates / ( 1000 * 60 * 60 ); // 時間 diff2Dates = diff2Dates % ( 1000 * 60 * 60 ); var dMin = diff2Dates / ( 1000 * 60 ); // 分 diff2Dates = diff2Dates % ( 1000 * 60 ); var dSec = diff2Dates / 1000; // 秒 var msg2 = Math.floor(dDays) + "日" + Math.floor(dHour) + "時間" + Math.floor(dMin) + "分" + Math.floor(dSec) + "秒"; // 表示文字列の作成 var msg; if( dnumTarget > dnumNow ) { // まだ期限が来ていない場合 msg = "Mission終了まで、あと" + msg2 ; } else { // 期限が過ぎた場合 msg = msg1 + "は、既に" + msg2 + "前に過ぎました。"; } // 作成した文字列を表示 document.getElementById("RealtimeCountdownArea").innerHTML = msg; document.getElementById("deadline.id").value = targetDate; } // 1秒ごとに実行 setInterval('showCountdown()',1000); </script>上記のように
input type = "hidden"
とすれば、記入欄が画面上に表示されないものの、
<input type = ・・・>
の6つが削除されている訳ではないためこれで正常に起動する。まとめ
なかなか難易度が高かったが、達成感はすごかった。少しでも参考にしていただけたら幸いである。
参考記事
https://www.nishishi.com/javascript-tips/realtime-countdown-deadline.html