20190302のHTMLに関する記事は2件です。

プログラミング学習記録14〜だいぶ進みました〜

今日やったこと

今日はだいぶ進みました。

  • Udemyの「Web開発入門完全攻略コース - プログラミングをはじめて学び創れる人へ!未経験から現場で使える開発スキルを習得!」のセクション3の22~29
  • セクション4の30~43
  • セクション5の44~55

パートごとにとったメモです。

22.リスト

Progateをやってたら特に問題のないパート。
ulタグで順序なし(非数字)のリストが作れて、olタグで順序あり(数字)のリストが作れます。

入れ子構造のことをネスト構造とも呼びます。

23.演習:リスト

これまでのレッスンの内容を理解できてるかどうかの確認。

山場は強いて言えば、リストを入れ子構造で書くところぐらいかなと思います。
それ以外は楽勝です。

24.演習回答:リスト

23でやった演習の答え合せ。
全問正解で突破。

25.div,span

div→ブロック要素
span→インライン要素

ブロック要素の中にインライン要素を入れることはできますが、インライン要素の中にブロック要素を入れることはできません。

具体例を挙げると、divの中にspanを入れることはできるが、spanの中にdivを入れることができない、ということです。

26.属性(Attiribute)

属性とは例えば、

<a href=“https……”></a>
<img src=“ooo.jpg”>

などのイコールで指定されている部分です。

属性の種類はたくさんあるのですが、ほとんどは覚える必要はなく、必要に応じてMDNで参照すればいいとのことです。

27.リンク

リンクはaタグのhref属性を用いて表します。
ページ内の別の場所に飛ぶ時にもaタグを使います。

<a href=“https:….” target=“_blank”>sss</a>
のようにtaget属性を指定すると、リンクをクリックした時に、新しいタブで開くようになります。

28.演習:HTML基礎

ここまでやってきたことを理解できてるかどうかを確かめる演習を行います。

imgタグとaタグを使います。

29.演習回答:HTML基礎

28の解答です。
全問正解で突破できました。
Progateをやった人は余裕で全問正解できると思います。

セクション3HTML入門 全体の感想

HTMLの歴史を知るとともに、HTMLの基礎について復習できました。
Progateをちゃんとやった人はさらっと見る程度でいいと思います。
まだまだ先は長いので、気を引き締めて次のセクション4に進みます。

セクション4HTMLステップアップ編

30.イントロダクション-HTMLステップアップ編-

セクション4でやる内容の概要を説明した動画です。

31.テーブル

基本的なテーブル(表)の作り方はわかっていたのですが、セルを結合させる方法や表のタイトル(キャプション)をつける方法は知らなかったので、勉強になりました。

セルを横方向に結合する
<td colspan=“結合したいセルの数”>~</td>

セルを縦方向に結合する
<td rowspan=“結合したいセルの数”>~</td>

タイトルをつける→captionタグ

32.補足:HTMlのthタグとtdタグの違いについて

「プログラミング入門ナビ」の以下のページに書いてあることが紹介されました。
https://programmingnavi.com/1586/

そのまま引用します↓

thタグとtdタグの意味
それぞれのタグは、下記の意味を持っています。
* th・・・表のヘッダーのセルを定義
* td・・・表でデータが入るセルを定義

33.行と列の覚え方

行と列の覚え方についてです。
以下のページと同じ図が紹介されていました。
https://lambdalisue.hatenablog.com/entry/2013/07/18/134507

この覚え方だと覚えやすいので、行と列がこんがらがってしまう人は確認しておきましょう。

34.演習:テーブル

テーブルを自分で作れるかどうかの確認です。

35.演習解答:テーブル

34の解答です。
全問正解で突破できました。
特に問題はなさそうです。

36.フォーム

フォームの基本についての動画。
フォームはformタグで作ります。

action→データの送信先。
method→httpリクエストメソッド

httpリクエストメソッドとはブラウザからサーバーに対して依頼する処理の種類のことで、特に重要なのはGETとPOST。

GET→サーバからデータを取得したい時に使う
POST→サーバへデータを送信したい時に使う。

37.シンプルなフォーム

inputタグにplaceholder属性を入れることで、フォームの入力欄に薄い灰色のテキストを表示させることができます。

こんな感じのやつ↓
スクリーンショット 2019-03-02 11.22.42.png

38.いろいろなフォーム部品①

tableタグを併用をして、フォームを作成します。
Titleタグの>を全角の>にしてしまったがために、ブラウザに表示されないトラブルが起きつつもなんとかクリア。

W3Cの文法チェックツールがあると、すぐにどこが悪いのかがわかっていいいですね。
https://validator.w3.org/
スクリーンショット 2019-03-02 11.42.23.png

39.いろいろなフォーム部品②

下にだーって広がっていくやつをプルダウンと言います。ドロップダウンメニューとも言うみたいです。

HTMLではselectタグとoptionタグを使って実装します。

あと、ラジオボタンとチェックボタンについても学習しました。

ラジオボタンとはユーザーに選択してもらうためのチェックボタンです。
チェックボタンはチェックマークでチェックするのですが、ラジオボタンは点でチェックをします。

40.フォームバリデーション

フォームバリデーションの定義については引用させていただきます。

バリデーションとは
・入力された内容が要件を満たしているか、妥当性を確認すること。

フォームでのバリデーションは、具体例を示します。
例えば、必須項目なのに入力されずに送信ボタンが押されてしまった、といった場合、入力されてない項目がありますよーと言って再度入力を促すことです。

HTMLではinputタグにrequieredをつけることで実装することができます。

<input id=“username” name=“username” required>

41.演習:フォーム

フォームを作れるかどうかの確認です。
以下のようなフォームを作りました↓

スクリーンショット 2019-03-02 13.50.21.png

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>アルバイト応募フォーム</title>
  </head>
  <body>
    <h1>アルバイト応募フォーム</h1>
    <form class="" action="#" method="post">
      <table border="1">
        <tr>
          <th>ふりがな *</th>
          <td><input type="text" name="username" value="" required></td>
        </tr>
        <tr>
          <th>生年月日 *</th>
          <td><input type="date" name="birthday" value="" required></td>
        </tr>
        <tr>
          <th>性別</th>
          <td>
            <input type="radio" name="sex" value="男性" checked>男性
            <input type="radio" name="sex" value="女性">女性
          </td>
        </tr>
        <tr>
          <th>電話番号 *</th>
          <td><input type="tel" name="tellnumber" value="" required></td>
        </tr>
        <tr>
          <th>メールアドレス *</th>
          <td><input type="tel" name="mail" value="" required></td>
        </tr>
        <tr>
          <th>現在の職業 *</th>
          <td>
            <select class="" name="" required>
              <option value="" selected>選択してください</option>
              <option value="">学生</option>
              <option value="">アルバイト・パートタイム</option>
              <option value="">正社員</option>
              <option value="">その他</option>
            </select>
          </td>
        </tr>
        <tr>
          <th>お問合せ内容</th>
          <td><textarea name="contact"></textarea></td>
        </tr>
      </table>
      <input type="submit" name="" value="送信">
      <p>*の項目は入力必須となります。</p>
    </form>
  </body>
</html>

42.演習回答:フォーム①

43.演習回答:フォーム②

41の解答です。
細かい部分は違いましたが、構造的に大きな間違いはなかったので、よかったです。

セクション4HTMLステップアップ編 全体の感想

セクション3よりは難易度が上がりましたが、内容は基礎的なものだったと思います。
一部、知らない内容もありましたが、特に問題なくクリアすることができました。
この調子でセクション5に取り組んでいきたいと思います。

セクション5CSS入門

44.CSS入門

CSSの歴史、役割についての解説動画。
CSSは下位互換性があり、昔の記述方法でも動作するのは便利だなと思いました。

45.はじめてのCSS①

CSSの基本的な記述方法に関する動画。
すでに知っているかつやったことのある内容だったので、流し見で視聴しました。

46.はじめてのCSS②

1つのHTMLファイルで複数のCSSファイルを読み込むことができます。
あと、CSSの優先順位に関する話も出てきました。
基本的には外部参照、外部ファイルにCSSを記載するのが望ましいみたいです。

47.HTMLテンプレート配布

CSSの読み込みも記載された新しいHTMLの雛型テンプレートがもらえます。

48.CSSのコメント

CSSは*/ */で囲うことでコメントアウトすることができます。
HTML同様に、Atomでは「commandキー+/キー」でコメントアウトできます。便利ですね。

49.色の指定

今までRGBをなんとなく使用していたのですが、この動画を見て、より深く理解することができました。

RGBは「#ff0000」のように16進数で表現するのですが、#を除いて最初の2桁はred、真ん中の2桁はgreen、最後の2桁はblueを表しています。

これは知らなかったので勉強になりました。

50.背景とボーダー①

背景とボーダー(枠線)についての動画です。

Borderのスタイルはsolidしか使ったことがなかったのですが、いろいろ種類があるみたいですね。
詳しく知りたい方は、MDNのレファレンスを参考にしてください↓
https://developer.mozilla.org/ja/docs/Web/CSS/border-style

51.背景とボーダー②

画像を背景にする方法の解説動画です。
相対パスの話もありましたが、特に問題ありませんでした。

52.セレクター

CSSのセレクターの解説動画です。

h1{
  color:white;
}

CSSにこのような記述があった場合、h1がセレクターになります。

セレクターには3種類あります。

  • エレメント(要素)セレクター
  • IDセレクター
  • クラスセレクター

エレメントセレクターはh1やdiv、aなどのタグに関するセレクターです。

IDセレクターはid=“”というようタグの中で指定したID名に対して使うセレクターです。

クラスセレクターはclass=””というようにタグの中で指定したclass名に対して使うセレクターです。

53.Chromeデベロッパーツール

デベロッパーツールは「commandキー+optionキー+Iキー」で開くこともできます。
これは積極的に使っていきたいですね。

デベロッパーツールの使い方はサルワカさんのブログがわかりやすいです。
https://saruwakakun.com/html-css/basic/chrome-dev-tool

54.演習:CSS基礎

これまでやってきたことを理解しているかどうかの確認テスト。
Progateをやった人は余裕で突破できます。

55.演習回答:CSS基礎

54の回答。
全問正解でした。よかったです。

セクション5CSS入門 全体の感想

一部知らないこともあったのですが、ほとんど知っている内容でした。Progateをしっかりやった人にとっては簡単な内容だと思います。
このまま次のセクションに進みたいと思います。

明日からも引き続き、プログラミング学習頑張ります。

おわり

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

【個人開発】何が何でも魚拓を見つけるChrome拡張を作った

デモ

↓2019/03/02
キャプチャ4.PNG
↓1998/11/11
キャプチャ5.PNG

特徴

  • archive.is, archive.org, gyo.tc, googleのキャッシュ、と計四か所から魚拓のURLを探します!
  • vue.js製(やってみたかった)

なぜ作ったか

ハテブで魚拓コメがトップだったりして、需要を感じた。
後普通に自分が使いたかった。
そして、Qiitaユーザーの皆さんも必要性を感じてくださっている事と思います^^。

どう作ったか

Chorome拡張はHTML+CSS+javascriptの基本セットで作れます。
ファイル構成は以下のようになりました。

  • manifest.json(どの拡張でも必須)
  • popup.js
  • popup.html
  • popup.css
  • jquery
  • vue.js
  • icons(フォルダ。配下にicon16.png, icon48.png, icon128.png)

詳しく見ていきましょう。
manifest.jsonは、Chrome拡張のまとめ役みたいな感じ。

manifest.json
{
    "name": "FindGyotaku in Console",
    "version": "0.0.1",
    "manifest_version": 2,//2で固定する
    "permissions": ["tabs", "http://*/", "http://*/"],//tabsはアクティブなタブのURLを取得するため、http://*/,https://*/はChrome拡張からすべてのサイトへのアクセスを許可するために必要
    "description": "Show all Gyotaku",
    "icons": {
        "16": "icons/icon16.png",
        "48": "icons/icon48.png",
        "128": "icons/icon16.png"
    },
    "browser_action": {
        "default_popup": "popup.html"//ここでpopupのhtmlを指定
    }
}

そして、popup.jsが今回の大事ポイントです。

popup.js
let vue;
//https://gyo.tc/から
function findGyotakuByUrl(url) {
    return new Promise(resolve => {
        console.log("findGyotakuByUrl Started");
        $.get("https://gyo.tc/" + url, null,
            function (data) {
                console.log(data);
                let gyotakuList_ = new DOMParser()
                    .parseFromString(data, "text/html")
                    .querySelectorAll("[id^=fish]");
                resolve(gyotakuList_)
            },
            "html"
        );
    })
}
//https://archive.is/から
function findInternetArchiveByUrl(url) {
    return new Promise(resolve => {
        $.get(`https://archive.is/${url}`, function (data) {
            let rowsList =
                new DOMParser()
                    .parseFromString(data, "text/html")
                    .querySelectorAll("[id^=row]");
            let archivesList = [];
            rowsList.forEach(row => {
                archivesList.push(
                    Array.from(
                        row.querySelectorAll("[style^=text\\-decoration\\:none]")
                    )
                )
            });
            resolve(archivesList.flat());
            console.log(`flatten archivesList is ${archivesList.flat()}`);
        })
    })
}
//googleのwebcacheから
function findGoogleCache(url) {
    return new Promise(resolve => {
        $.get(`http://webcache.googleusercontent.com/search?q=cache:${url}`, function () {
            resolve(`http://webcache.googleusercontent.com/search?q=cache:${url}`);
        })
    })
}
//http://web.archive.orgから
function findWaybackMachineLatest(url) {
    return new Promise(resolve => {
        //limit=-1で最新
        $.get(`http://web.archive.org/cdx/search/cdx?limit=-1&fl=timestamp&url=${url}`, function (timestamp) {
            resolve(`https://web.archive.org/web/${timestamp}/${url}`);
            console.log(`waybackMachine response(latest) is ${timestamp}`);
        })
    })
}
//http://web.archive.orgから
function findWaybackMachineOldest(url) {
    return new Promise(resolve => {
        //limit=1で最古
        $.get(`http://web.archive.org/cdx/search/cdx?limit=1&fl=timestamp&url=${url}`, function (timestamp) {
            resolve(`https://web.archive.org/web/${timestamp}/${url}`);
            console.log(`waybackMachine response(latest) is ${timestamp}`);
        })
    })
}

console.log("popup.jsLoaded");

chrome.tabs.query({
    active: true,
    currentWindow: true
}, function (tabsArray) {
    console.log(`currentUrl is ${tabsArray[0].url}`);

    findGyotakuByUrl(tabsArray[0].url).then((gyotakuList) => {
        console.log(gyotakuList);
        gyotakuList.forEach(element => {
            vue.items.push(element)
        });
        vue.isLoadingGyotaku = false
    }).catch((err) => {
        console.log(err);
        vue.isLoadingGyotaku = false
    });
    findInternetArchiveByUrl(tabsArray[0].url).then((archivesList) => {
        console.log(archivesList);
        archivesList.forEach(element => {
            vue.items.push(element)
        });
        vue.isLoadingArchives = false
    }).catch((err) => {
        console.log(err);
        vue.isLoadingArchives = false
    });
    findGoogleCache(tabsArray[0].url).then((googleCacheUrl) => {
        console.log({
            href: googleCacheUrl
        });
        vue.items.push({
            href: googleCacheUrl
        });
        vue.isLoadingGoogleCache = false
    }).catch((err) => {
        console.log(err)
    });
    findWaybackMachineLatest(tabsArray[0].url).then((waybackMachineUrl) => {
        console.log({
            href: waybackMachineUrl
        });
        vue.items.push({
            href: waybackMachineUrl
        });
        vue.isLoadingWaybackMachine = false
    }).catch((err) => {
        console.log(err)
    });
    findWaybackMachineOldest(tabsArray[0].url).then((waybackMachineUrl) => {
        console.log({
            href: waybackMachineUrl
        });
        vue.items.push({
            href: waybackMachineUrl
        });
        vue.isLoadingWaybackMachine = false

    }).catch((err) => {
        console.log(err)
    });

});

$(function () {
    vue = new Vue({
        el: '#example-1',
        data: {
            items: [],
            isLoadingGyotaku: true,
            isLoadingArchives: true,
            isLoadingGoogleCache: true,
            isLoadingWaybackMachine: true,
        }
    })

});

分割して解説します。

function findGyotakuByUrl(url) {
    return new Promise(resolve => {
        $.get("https://gyo.tc/" + url, null,
            function (
                let gyotakuList_ = new DOMParser()
                    .parseFromString(data, "text/html")
                    .querySelectorAll("[id^=fish]");
                resolve(gyotakuList_)
            },
            "html"
        );
    })
}

↑要するにスクレイピングですね。javascriptではquerySelectorが便利です。
https://gyo.tc/ 以下にURLを投げると魚拓一覧が返るので、開発者ツールから頑張って解析しました。

function findInternetArchiveByUrl(url) {
    return new Promise(resolve => {
        $.get(`https://archive.is/${url}`, function (data) {
            let rowsList =
                new DOMParser()
                    .parseFromString(data, "text/html")
                    .querySelectorAll("[id^=row]");
            let archivesList = [];
            rowsList.forEach(row => {
                archivesList.push(
                    Array.from(
                        row.querySelectorAll("[style^=text\\-decoration\\:none]")
                    )
                )
            });
            resolve(archivesList.flat());
        })
    })
}

↑こちらもhttps://archive.is/ 以下にURLを投げると魚拓一覧が返るので、こちらも開発者ツールから頑張って解析しました。
Array.flat()はMDNで分かるように実験的なヤツで、配列を好きな次元に均せる関数です。デフォルトで一次元なのでそのまま使用しました。

function findGoogleCache(url) {
    return new Promise(resolve => {
        $.get(`http://webcache.googleusercontent.com/search?q=cache:${url}`, function () {
            resolve(`http://webcache.googleusercontent.com/search?q=cache:${url}`);
        })
    })
}

↑言うことなし。思ったより簡単。

function findWaybackMachineLatest(url) {
    return new Promise(resolve => {
        //limit=-1で最新
        $.get(`http://web.archive.org/cdx/search/cdx?limit=-1&fl=timestamp&url=${url}`, function (timestamp) {
            resolve(`https://web.archive.org/web/${timestamp}/${url}`);
        })
    })
}

function findWaybackMachineOldest(url) {
    return new Promise(resolve => {
        //limit=1で最古
        $.get(`http://web.archive.org/cdx/search/cdx?limit=1&fl=timestamp&url=${url}`, function (timestamp) {
            resolve(`https://web.archive.org/web/${timestamp}/${url}`);
            console.log(`waybackMachine response(latest) is ${timestamp}`);
        })
    })
}

↑apiが有って助かりました。
WaybackMachineのアーカイブは膨大なので最古&最新のみ取得しています。
limit=1で最古、limit=-1で最新を指定、fl=timestampでレスポンスをtimestampのみに限定します。
WaybackMachineはtimestampとURLを指定すると(珍しく)個別ページのURLが分かるので、timestampだけで十分なのです。

$(function () {
    vue = new Vue({
        el: '#example-1',
        data: {
            items: [],//以下デフォルト値を指定しています
            isLoadingGyotaku: true,
            isLoadingArchives: true,
            isLoadingGoogleCache: true,
            isLoadingWaybackMachine: true,
        }
    })

});
index.html
<p v-if="isLoadingGyotaku">
    魚拓から読み込んでいます
</p>

↑出ましたvue.js!読み込み中のメッセージを出しています。
vue.jsを使うと、HTMLとjs間でバインディングができます。
例えば、

HTMLのv-if属性にisLoadingGyotakuを指定

js側でvueインスタンス作成(vueのdata属性に、isLoadinGyotakuをメンバにしたオブジェクトを付けたもの)

vue.isLoadingGyotakuにアクセスできるように&
vue.isLoadingGyotakuがv-if="isLoadingGyotaku"とバインドされる

って感じ。
つまり、isLoadingGyotaku=trueならpタグが見えて、falseなら見えなくなる!
これは素晴らしいですね。本当に素晴らしい。
ほかにもいろいろな属性が有ります。だいたいv-が付く。

<ul>
    <li v-for="item in items">
        <a href="{{ item.href }}" target='_newtab'>
            {{ item.href }}
        </a>
    </li>
</ul>

↑v-forとか。見つかったURLを表示するために使っています。
{{}}はテンプレートリテラルみたいに使えます。
↓ラスト

chrome.tabs.query({
    active: true,
    currentWindow: true
}, function (tabsArray) {
    console.log(`currentUrl is ${tabsArray[0].url}`);

    findGyotakuByUrl(tabsArray[0].url).then((gyotakuList) => {
        console.log(gyotakuList);
        gyotakuList.forEach(element => {
            vue.items.push(element)

        });
        vue.isLoadingGyotaku = false
    }).catch((err) => {
        console.log(err);
        vue.isLoadingGyotaku = false
    });
    findInternetArchiveByUrl(tabsArray[0].url).then((archivesList) => {
        console.log(archivesList);
        archivesList.forEach(element => {
            vue.items.push(element)
        });
        vue.isLoadingArchives = false
    }).catch((err) => {
        console.log(err);
        vue.isLoadingArchives = false
    });
    findGoogleCache(tabsArray[0].url).then((googleCacheUrl) => {
        console.log({
            href: googleCacheUrl
        });
        vue.items.push({
            href: googleCacheUrl
        });
        vue.isLoadingGoogleCache = false
    }).catch((err) => {
        console.log(err);
        vue.isLoadingGoogleCache = false
    });
    findWaybackMachineLatest(tabsArray[0].url).then((waybackMachineUrl) => {
        console.log({
            href: waybackMachineUrl
        });
        vue.items.push({
            href: waybackMachineUrl
        });
        vue.isLoadingWaybackMachine = false
    }).catch((err) => {
        console.log(err)
        vue.isLoadingWaybackMachine = false
    });
    findWaybackMachineOldest(tabsArray[0].url).then((waybackMachineUrl) => {
        console.log({
            href: waybackMachineUrl
        });
        vue.items.push({
            href: waybackMachineUrl
        });
        vue.isLoadingWaybackMachine = false

    }).catch((err) => {
        console.log(err)
        vue.isLoadingWaybackMachine = false
    });

});

↑async/awaitで見やすくなるのは分かってるんだけどね……面倒なのでそのまま。
chrome.tabs.queryで今見てるタブのURLを取得後、非同期×5を回しています。
chrome.系はChrome拡張の時しか使えないapiで、ほかにも色々便利です。

はまったポイント

最初

let fuga = true
vue = new Vue({
        el: '#example-1',
        data: {
            isLoadingGyotaku: fuga,
        }
    })
fuga = false//バインドされてるはずなのに動かない!!!

って事が有って大変でしたね。本当は

vue = new Vue({
        el: '#example-1',
        data: {
            isLoadingGyotaku: true,
        }
    })
vue.isLoadingGyotaku = false//バインドされてて動く!!!

で良かったっていう。公式ドキュメントをちゃんと読みましょう。

後、動作確認にevent pagesを使ってしまって、popupのみで動くapiを動かせなかったりとか……
popupページで検証する方法を知らなかったとか……(左クリックでポップアップされたのを右クリ)

計何時間使ったでしょうかね。今はどうでも良いけど。

最後に

2020/04に大学生になる(浪人しなければ!)ので、良かったらインターンに誘ってください。
github:https://github.com/negitorogithub
gmail:bakeratta35@gmail.com

お読み頂きありがとうございました。 ~~旦⊂(・∀・ )

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