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

横並びのカードレイアウト実装(BEM使用)

はじめに

コーディングをしているとカード横並びにしたようなレイアウトがよく使われるなぁと感じます。
そこで毎回作るのがめんどくさいのでここにメモ書き程度に残しておきます。

使用しているのはBEMですがふつうにcssに置き換えても同じ考え方なので、使いまわせるかと思います。

また、もっと汎用性高くできるだろ!と気付いた方いれば教えていただけれたらと思います。

今回はこんな感じのものを作ります。

スクリーンショット 2020-09-22 23.10.01.png

横並びにする前にカードの形だけつくる

まず、カードの形だけ作ります。
というのも、サイト制作時に他の場所で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;
  }
}

というわけでこれがカード本体になります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初心者向け】GoogleChromeのリニューアルで目立つようになった黒い線を消す方法

どうも7noteです。開発していると、意図していない場所に黒い太枠線がでてくるようになって、なんだこれって思ってました。こいつを消します。

focus.png

フォームやマウスカーソルで要素を触ると出てくる・・・

どうやらクロームの初期値として、:focusがある時に出るようです。

f12.png

消し方

消したい要素にoutline: none;だけ。とっても簡単。

input {
  outline: none;
}

まとめ

以前まではあまり気にしていなかったのですが、前回のクロームのアップデートの影響ですごく悪目立ちすることがあったので、必要ない場面では消すようにしています。

※タブキーを使って移動していると、どこにフォーカスしているかわからなくなるので注意!!

おそまつ!

~ Qiitaで毎日投稿中!! ~
【初心者向け】HTML・CSSのちょいテク詰め合わせ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

あなたがまだ使っていないかもしれないHTML5の便利機能10選

こんにちは、たかとーです?‍?
こちらは、10 useful HTML5 features, you may not be usingの翻訳記事になります。
当記事は、Tapasさんの許可を得て翻訳しています。Tweet


10 useful HTML5 features, you may not be using

10 useful HTML5 features, you may not be using

HTML5は新しいものではありません。最初のリリース(2008年1月)以来いくつかの機能を使用してきました。100DaysOfCodeの取り組みの一環として、HTML5の機能リストをもう一度よく見てみました。何か見つけたかな?私は今のところあまり使っていません。

この記事では、過去にあまり使ったことがなかったが、今では便利になったHTML5の機能を10個挙げています。また、Netlifyでホストされている、実際に動作する例を作成しました。参考になることを願っています。

https://html5-tips.netlify.app/

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>

動作例

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>

動作例

Content Editable属性動作例

ここで実際に触ることができます: 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>

動作例

Mapタグ動作例

ここで実際に触ることができます: 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>

動作例

Markタグ動作例

ここで実際に触ることができます: 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プロパティを使用です。

動作例

data-* 属性動作例

ここで実際に触ることができます: 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>

動作例

Outputタグ動作例

ここで実際に触ることができます: 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>

動作例

Datalistタグ動作例

ここで実際に触ることができます: 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>

動作例

Range(Slider)値動作例

ここで実際に触ることができます: 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 />

動作例

Meterタグ動作例g

ここで実際に触ることができます: 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>

progress

Inputsタグ

inputタイプにはいくつか特別な使い方があります。

コード

required

inputフィールドを必須アイテムにします。

<input type="text" id="username1" name="username" required />

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>

Color picker

訳者感想

Reactなど、JavaScript関連の新しい情報はキャッチアップするようにしているのですが、HTMLに関しては全くできておらず、目からウロコな記事でした。

いままでJavaScriptを使って実現していたようなものをHTMLのみで表現できるのは、開発者にとっても楽で最高ですよね!

素晴らしい記事をありがとうございました Tapas

訳者について

2019年5月よりバンクーバーを拠点に移し、現在スタートアップの開始に向けて試行錯誤しているソフトウェアでデベロッパーです。

近頃は、VCの方と話しながらアイディアのブラッシュアップなどを行いながらMVPの検証を進めています。

フリーランス案件も募集し始めました!React、NodeJs、TypeScript等フロント、バックエンド問わず行えます。是非宜しくお願い致します。

もしよろしければ、以下SNSもよろしく願いします!

Twitter: @taishikat0_Ja
Note: 日本人でも英語圏で戦えることを証明したい。28歳が会社を辞め、個人開発者としてカナダでひたすらもがき続けた一年間とこれから
Linkedin: Taishi Kato

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

html/templateメモ

html/templateメモ

目次

html/templateの概要

htmlのテンプレートにこちらのプログラムで処理したデータを埋め込み返す。webサービスには必須の技術だが、それをgolangを実現するにはテンプレートエンジンであるhtml/templateを使う

正確には汎用テンプレートエンジンであるtext/template標準ライブラリと、さらにHTML専用のテンプレートエンジンであるhtml/templateライブラリの二種類があるが、ここでは後者を扱う

templateとは

  • template(テンプレート) とは予め用意されたhtmlのひな型

  • テンプレートエンジン とはテンプレートとデータ 1を組み込んで、クライアントに返す最終的なhtmlを生成するプログラム

  • 通常、ハンドラがテンプレートエンジンを呼び出してデータをテンプレートに組み込み、できあがったHTMLをクライアントに返す

イメージ図12

image.png

基本文法

  • 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.go
package 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.go
package 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にアクセスすると以下のページが表示される

  • image (23).png

動的なテンプレートの追加方法

  • 先ほどの例では部品テンプレート(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>
  • http://127.0.0.1:8080/processにアクセスすると以下のページが表示される

  • image.png

スコープの話

  • アクション「.」は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.go
package 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にアクセスすると以下のページが表示される

image.png

余談

  • 頭文字が大文字であれば外部から参照できる、というのがGo言語の特徴

  • 先ほどの例ではアクション「.」を通じて構造体を渡しているが、その過程でこちらのパッケージを外部に参照させる処理が含まれているのか
    main.go

type Name struct {
    givenname  string
    familyname string
}
  • のようにName構造体のメンバ変数の頭文字を小文字に変更すると、テンプレートに値が渡らない

参考

Go の html/template でヘッダーやフッター等の共通化を実現する方法

Goプログラミング実践入門 ―標準ライブラリでゼロからWebアプリを作る―


  1. 大抵はクライアントから渡される情報を指す。ユーザ名など。テンプレートは既に用意されたものであるため静的で、データはクライアントによって変わるものであるため動的(ただしこれから見ていく例では単純化するためサーバサイドで定義した文字列等を使っている) 

  2. ハンドラがテンプレートエンジンを呼び出して、使用するテンプレートを通常はテンプレートのリストとして、動的なデータと一緒に渡します。テンプレートエンジンはHTMLを生成して、ResponseWriterにそれを書き込み、さらにResponseWriterはクライアントに送り返すHTTPレスポンスにそれを追加します。(イメージ図共に『Goプログラミング実践入門』より引用) 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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ページの構造

HTMLページの構造は以下の図のようになっている。
bodyセクションのみブラウザ上に表示される。
image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カウントダウンタイマーの実装

はじめに

ポートフォリオで実装予定のカウントダウンタイマーを実装する。
タイマーを実装するには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

を実行して、データベースに保存する。

タイマーの実装

スクリーンショット 2020-09-22 0.33.23.png

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(値)として受け取り、それを画面上で表示させることができる。これでようやく、タイマーを実装することができる。

タイマーだけを表示させたい場合

なお、日時の記入欄を表示させたくない場合も考えられる。下の写真のように期限とタイマーの残り時間だけを表示させたいという場合には、
スクリーンショット 2020-09-22 0.49.38.png

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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む