20200321のCSSに関する記事は5件です。

[Javascript] 要素の外側をクリックした時にremoveする

概要

例えばモーダルウインドウには×で閉じるボタンがレイアウトされている事が一般的ですが、
ユーザビリティを考えると、ボタン以外でも閉じられるようにしている事が望ましいですよね。
だからといって、どこでもクリックすれば閉じられるような処理では、
そもそも閉じるボタンの意味がなくなってしまいます。

今回はクリックイベントで付与したクラスを、
反応させたくない要素の外側かを判定して取り除く処理になります。
あくまで私が調べた結果ですので、もっとスマートな書き方があるかもしれません。

制御部分のコード

Javascript
const docOpen = document.getElementById('クラスを付与した要素');
const elemBody = document.querySelector('body');

elemBody.addEventListener('click', e => {
  if(e.target !== docOpen) {
    docOpen.classList.remove('active');
  }
});

解説

elemBody.addEventListener('click', e => {
  if(e.target !== docOpen) {
     docOpen.classList.remove('active');
  }
});

今回は全体の指定をbodyにしています。
body要素をクリックした時に、
event.targetプロパティでクリックした要素を取得し、
開いているdocOpenの要素と違う要素なのかを判定しております。

こうする事で、例えば、ドロワーメニュー等を開いた時に、
メニュー部分までクリックしたら閉じてしまうといった動作を防いでいます。

要素が違うのならばremoveされます。

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

初心者によるプログラミング学習ログ 268日目

100日チャレンジの268日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
268日目は、

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

チーム開発 3/20

最終課題3日目
トップページ担当

これはメモです

contentとは
contentはCSSで指定できるプロパティです。
要素の直前または直後に、文字列や画像などのコンテンツを挿入する際に使用します。contentプロパティを適用することができるのは、:before擬似要素および:after擬似要素のみです。
擬似要素とは、要素の一部にスタイルを適用するために、擬似的に設定される「要素のようなもの」のことです。
:before擬似要素および:after擬似要素は、要素の直前および直後に、文字列や画像などのコンテンツ(内容)を挿入するために擬似的に設定されます。
https://web-camp.io/magazine/archives/10930
参考サイト

link_toにh3などタグをネストして書く時は

=link_to “リンク” do
=“名前”
=%h3
と記述

ブラウザを小さくしても
大きさを変えたくないブロックに使用
Margin部分は真ん中に設定
max-width: 700px;
margin: 0 auto;

ボックスに影を作る時使用
box-shadow
http://www.htmq.com/css3/box-shadow.shtml
参考サイト
https://ferret-plus.com/8961
↑ブロックの形によって変わるプロパティ

リンクする所をブロック全体にしたい
ブロックには
position: relative;
インライン要素(link_to)
display: block
height: 100%;
これでブロック全体がリンクできるようになる

商品の写真登録は最大4枚に設定


復習

JavaScript
window.alert()
ブラウザでアラートを表示させるメソッドです。引数としてアラートに表示させる情報を渡します。

console.log()
ブラウザのコンソールにテキストを表示させるメソッドです。引数としてコンソールに表示させる情報を渡します。

letは、後で書き換えることができる変数宣言です。
constは、後で書き換えることができない変数宣言です。

if文
if (条件式1) {
// 条件式1がtrueのときの処理
} else if (条件式2) {
// 条件式1がfalseで条件式2がtrueのときの処理
} else {
// 条件式1も条件式2もfalseのときの処理
}

配列
let list = ['Ruby', 'Ruby on Rails', 'JavaScript', 'HTML', 'CSS'];
1. 配列の要素を取得する
console.log(list[2]);
=Ruby on Rails
2. 配列の要素数を取得する
console.log(list.length);
=5
3. 配列の要素を追加する
list.push('GitHub');
6番目にgithubが入る
4. 配列の要素を削除する
list.pop();
index.htmlを開いているブラウザのコンソールを確認して、CSSという文字列が消えていれば成功です。
popメソッドは配列の最後の要素を取り除きます。Rubyの場合は
popメソッドの引数に数字を渡すことで「何個分要素を取り除くか」という数を指定できますが、
JavaScriptのpopメソッドではそれができません。

list.shift();
index.htmlを開いているブラウザのコンソールを確認して、Rubyという文字列が消えていれば成功です
。こちらもpopメソッド同様、Rubyでは取り除く要素数を指定できますが、JavaScriptではできません。

オブジェクト
オブジェクトを作成するには波カッコ{}を用います。
オブジェクトの定義1
1 let obj = {};
オブジェクトはデータを名前と値をセットで管理します。このセットをプロパティと言います。
プロパティを持った状態でオブジェクトを定義することもできます。

オブジェクトの定義2
1 let obj = { name: 'yamada' };
変数objはnameプロパティを持っています。プロパティは必ず属性名である"プロパティ名"とデータである"値"をセットで持ちます。
したがって、nameはプロパティ名、'yamada'は対応する値です。

 for文
for文を用いた、繰り返しの基本

for (let i = 0; i < 繰り返す回数; i = i + 1) {
// 繰り返す処理の内容
}

num = 1;
for (let i = 0; i < 10; i += 1) {
console.log(num + '回目の出力')
num += 1
}

関数を定義
Rubyでは def ~ end で囲むことで関数を定義しましたが、
JavaScriptで関数を定義するにはfunction文を使います。

function 関数名(引数) {
// 処理の内容
}

return
Rubyでは関数における最後の戻り値が関数の戻り値として処理されましたが、
JavaScriptではreturnを用いて明示する必要があります。

function calc(num1,num2){
num1*num2;
}

let num1 = 3;
let num2 = 4;
console.log(calc(num1,num2));

function calc(num1,num2){
return num1*num2;
}

let num1 = 3;
let num2 = 4;
console.log(calc(num1,num2));

無名関数を定義

// 関数宣言
function hello(){
console.log('hello');
}

// 関数式(無名関数)
let hello = function(){
console.log('hello');
}
関数式の方は、関数自体に名前が無いため無名関数と呼ばれます。
関数宣言と関数式では読み込まれるタイミングが異なります。

JavaScriptにおいては関数宣言は先に読み込まれる。
一方で、関数式であれば先に読み込まれることはありません。

DOM
DOMとはDocument Object Model(ドキュメントオブジェクトモデル)の略です。HTMLを解析し、
データを作成する仕組みです。
HTMLで書かれたファイルは結局ただの文字情報なので、そのまま表示しても意味がありません。HTMLを解析し、
CSSやJavascriptによる装飾を行ってから画面に映すという工程が必要なはずです。これを行っているのが、
Google ChromeやSafariといったブラウザです。ブラウザがHTMLやCSS、
JavaScriptを受け取ってユーザーに届けるまでには、以下のような手順を踏んでいます。

HTMLは階層構造になっていることが特徴です。
DOMによって解析されたHTMLは、階層構造のあるデータとなります。これを、DOMツリーやドキュメントツリーと呼びます。
DOMツリーはデータとして階層構造になっていることで、階層構造を扱うためのアルゴリズムを使い操作できます。

ノード
HTML1つ1つのタグが、DOMツリーの中ではノードと呼ばれます。

ノードの取得
JavaScriptを使ってHTML要素のid名やクラス名を指定することで、マッチするノードを取得できます
document.getElementById("id名");
documentは、開いているWebページのDOMツリーが入っているオブジェクトです。
documentに対していくつかのメソッドを利用することで、DOMツリーに含まれる要素を抽出して取得することができます。
.getElementById("id名")はDOMツリーから特定の要素を取得するためのメソッドの1つです。引数に渡したidを持つ要素を取得します。
document.getElementsByClassName("class名");
classを指定して取得する際はこちらを利用します。ここで気をつけたいのは、getElementsと複数形になっていることです。
id名はhtml上に必ず一つしか存在しないのに対して、class名を指定するgetElementsByClassName("class名")の場合は、
同じclassを持つ要素を全て取得することが可能です
document.querySelector("セレクタ名");
セレクタ名とは、CSSでスタイルを適用するために指定している要素です。
セレクタ名を指定してDOMを取得する場合、querySelectorメソッドを使用します。
HTML上から、引数で指定したセレクタに合致するもののうち一番最初に見つかった要素1つを取得します。

イベント
JavaScriptにおけるイベントとは、HTMLの要素に対して行われた処理要求のことをいいます。例えば「ユーザーがブラウザ上のボタンをクリックした」
「テキストフィールドでキー入力をした」「要素の上にマウスカーソルを乗せた」などがいずれもイベントです。
また、イベントを起こすのはユーザーだけでなく、「ドキュメントの読み込みが終わった」などブラウザが発生させるものもあります。

イベント駆動
JavaScriptはイベント駆動という概念に基づいて設計されています。
これは、「イベント」が発生したら、それをきっかけにコードが実行される仕組みです。
JavaScriptはもともとブラウザに搭載するための言語として開発されており、
ユーザーが行う様々な操作に対応できるイベント駆動の仕組みが適しているためです。
イベントを取得するためには、先に取得したノードに対して処理を書きます。
addEventListener
addEventListenerメソッドはノードオブジェクトのメソッドで、以下のようにして実行します

(ノードオブジェクト).addEventListener("イベント名", 関数);

上記のような記述により、この記述の読み込み以降で「ノードオブジェクト」に「イベント」が起きた時、「関数」を実行するようになります。
一つのイベントと一つの関数を紐付ける仕組みのことをイベントリスナと呼びます。
一つのイベントに複数の関数を紐付ける場合は、関数の数だけイベントリスナが存在します。
addEventListenerは、あるノードオブジェクトに対して、イベントリスナを追加するメソッドです。

ページを読み込まないとイベントが発生しない時があるので
(コードの上から読み込んでいくので)

ページの読み込みをするwindow.onload
「ページの読み込みが終わる」イベントは、windowオブジェクトのloadイベントに対応します。
そこで、windowオブジェクトのloadイベントに対応する関数として上記の一連の処理を定義すれば良いと考えられます。
なお、windowオブジェクトは、元から用意されている、ブラウザの情報を持つオブジェクトです。
記述は2つある
window.onload = function() { 処理 };

window.addEventListener('load', function() { 処理 });

コードを見直す

function func() {}
// 何もしないfunc関数
btn.addEventListener("click", func);

btn.addEventListener("click", function func() {});

省略した書き方ができる

イベント発火の流れ
①DOMツリーからノードを取得する
②JavaScriptでやりたい処理を書く
③イベント発火でHTML側で動かす

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

Electronでカレンダーを作る④

前回まで

前回は月の切り替えボタンを作った。
月を変えても、表示内容の変更だけで同じ画面を使い続けるので微妙。

月を変えたら画面自体を新しく作り直したい

というわけでindex.jsをいじって、読み込みごとにカレンダーを作るように修正。

index.js
'use strict';

const moment = require("moment");
const ipcRenderer = require("electron").ipcRenderer;

window.onload = function() {

    const month = parseURLParam(location.search).month;

    const callendar = new Callendar(month);
    callendar.show();

    //先月ボタン押下時
    document.getElementById('preMonth').onclick = function() {
        ipcRenderer.sendSync('month',this.value);
    }

    //来月ボタン押下時
    document.getElementById('nextMonth').onclick = function() {
        ipcRenderer.sendSync('month',this.value);
    }
}

/**
 * URLパラメータを分解してkey:valueの形式で返す。
 * @param URL 
 */
function parseURLParam(URL) {
    // URLパラメータを"&"で分離する
    const params = URL.substr(1).split('&');

    var paramsArray = [];
    var keyAndValue = null;

    for(var i = 0 ; i < params.length ; i++) {
        // "&"で分離したパラメータを"="で再分離
        keyAndValue = params[i].split("=");

        // パラメータを連想配列でセット
        paramsArray[keyAndValue[0]] = keyAndValue[1];
    }

    // 連想配列パラメータを返す
    return paramsArray;
}

/**
 * カレンダークラス
 * @param month(YYYY-MM) 
 */
const Callendar = function(month) {

    //コンストラクタ
    this._moment = moment(month);

    /**
     * カレンダーを表示する。
     */
    this.show = function() {
        const __moment = this._moment;

        //captionを表示
        document.getElementById('caption').innerText = __moment.format("YYYY年MM月");

        //当月の日数を取得
        const daysOfMonth = __moment.daysInMonth();

        //月初の曜日を取得(index.htmlと合わせるために+1する)
        const firstDayOfManth = __moment.startOf('month').day() + 1;

        //カレンダーの各セルに日付を表示させる
        let cellIndex = 0;
        for(let i = 1; i < daysOfMonth + 1; i++) {
            if(i === 1) {
                cellIndex += firstDayOfManth;
            } else {
                cellIndex++;
            }
            document.getElementById("cell" + cellIndex).innerText = i;
        }

        //6行目の第1セルが空白なら6行目自体を非表示にする。
        if(document.getElementById("cell36").innerText === "") {
            document.getElementById('row6').style.visibility = "hidden";
        }

        //先月
        document.getElementById('preMonth').value = __moment.add(-1,'month').format("YYYY-MM");
        //来月(先月のmomentオブジェクトとなっているので+2ヶ月)
        document.getElementById('nextMonth').value = __moment.add(2,'month').format("YYYY-MM");

    }
}

新しくCallendarクラスを作成し、状態としてmomentオブジェクトを持つようにした。

window.onload = function() {

    const month = parseURLParam(location.search).month;

    const callendar = new Callendar(month);
    callendar.show();

window.onload内で画面読み込み毎にURLパラメータから表示月を読み込んでカレンダーを作成する。

main.jsにも少し手を加える。

main.js
'use strict';

// Electronのモジュール
const electron = require("electron");
// Momentのモジュール
const moment = require("moment");

// アプリケーションをコントロールするモジュール
const app = electron.app;

// ウィンドウを作成するモジュール
const BrowserWindow = electron.BrowserWindow;

// メインウィンドウはGCされないようにグローバル宣言
let mainWindow;

// 全てのウィンドウが閉じたら終了
app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

// Electronの初期化完了後に実行
app.on('ready', function() {
  // 当月をYYYY-MM形式で取得
  const month = moment().format('YYYY-MM');

  // メイン画面の表示。ウィンドウの幅、高さを指定できる
  mainWindow = new BrowserWindow({width: 800, height: 650});
  // 初期表示は当月をパラメータで渡す
  mainWindow.loadURL('file://' + __dirname + '/index.html?month=' + month);

  // ウィンドウが閉じられたらアプリも終了
  mainWindow.on('closed', function() {
    mainWindow = null;
  });

  // ipc通信受信時の処理
  const ipcMain = electron.ipcMain;
  ipcMain.on('month', (event, arg) => {
    // 受信した値をパラメータに渡して画面再読み込み
    mainWindow.loadURL('file://' + __dirname + '/index.html?month=' + arg);
  })
});

ipc通信でメッセージのやり取りを作る

Electronはipc通信とやらでプロセス間のメッセージの送受信機能を実現しているらしい。

使うの自体は簡単。

送信側(index.js)
    //ipcモジュール
    const ipcRenderer = require("electron").ipcRenderer;

    //先月ボタン押下時
    document.getElementById('preMonth').onclick = function() {
        ipcRenderer.sendSync('month',this.value);
    }

    //来月ボタン押下時
    document.getElementById('nextMonth').onclick = function() {
        ipcRenderer.sendSync('month',this.value);
    }

ボタンが押されたらipcRenderer.sendSync('month',this.value)で「month」というキーの値を同期送信している。

受信側(main.js)
  // ipc通信受信時の処理
  const ipcMain = electron.ipcMain;
  ipcMain.on('month', (event, arg) => {
    // 受信した値をパラメータに渡して画面再読み込み
    mainWindow.loadURL('file://' + __dirname + '/index.html?month=' + arg);
  })

ipcMain.on('month', コールバック関数)で「month」キーのメッセージ受信時の処理を記述。
受け取った値はコールバック関数の第二引数(ここではargs)で取得可能。

受信した値(YYYY-MM)をパラメータに設定して画面を読み込みなおす。

$ electron .

image.png
image.png

問題なく月の変更が出来ていそう。

TODO

・月を変える度に画面更新が行われて数秒真っ白画面になっちゃうのが微妙。もっとフレキシブルな切り替えにしたい。
・見た目をどうにかしたい。

あとがき

結局再読み込みになるのでCallendarクラスのメリットがほぼ無い気がしてる。
画面を裏で複数作っておいて、それを切り替えていくとかが良いのかな。

明日、お仕事の方で本番リリースなので寝ます。

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

JavaScriptでプレビュー機能 onKeyup onchange

プレビュー機能作成

プレビュー機能とは(名前が正しいかわかりませんが)、Qiitaの投稿時の右側の画面のように、入力すると非同期で表示がされる機能のことです。

ブログ記事を書く際や、マークダウンでの記述の場合はよく使用されますよね!
今回は基礎ということで簡単なプレビューを作成致します。

完成品
スクリーンショット 2020-03-21 1.26.11.png

HTML5

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
#sampleForm,
#sampleOutput {
    padding: 150px;
    width: 25vw;
    height: 50vh;
    margin: 10px;
    /* padding: 10px; */
    border: 1px solid gray;
    border-radius: 10px;
    display: inline-block;
}
#sampleForm {
    background-color: #f0f8ff;
}
#sampleOutput {
    background-color: #00ffff;
}
#sampleForm * {
    margin: 0 0 0 0;
    vertical-align: text-top;
}
</style>
<body>
    <form id="sampleForm">
        【入力欄】
        <br />
        名前:<input type="text" name="formName" value="">
        <br />
        地域:
            <select name="formArea">
                <option selected>関東</option>
                <option>東海</option>
                <option>関西</option>
            </select>
        <br />
        年齢:
            <select name="formAge">
                <option selected>10代</option>
                <option>20代</option>
                <option>30代</option>
            </select>
        <br />
        コメント:<textarea name="formComent"></textarea>
        <br />
    </form>
    <div id="sampleOutput">
        【出力欄】
        <br />
        名前:<span id="sampleOutputName"></span>
        <br />
        地域:<span id="sampleOutputArea"></span>
        <br />
        年齢:<span id="sampleOutputAge"></span>
        <br />
        コメント:<span id="sampleOutputComent"></span>
        <br />
    </div>
    <script src="js/script.js"></script>
</body>
</html>
// !非同期 フォームの内容の変更を特定の要素に即反映
window.onload = function () { //load イベント発生時に呼び出す関数への参照または関数式
    getValue(); //関数の中にValueを定義します。
    var $formObject = document.getElementById( "sampleForm" ); //id要素の取得
    for( var $i = 0; $i < $formObject.length; $i++ ) { //上記のidの入った変数$formObjectの配列の長さ分for分で回します
        $formObject.elements[$i].onkeyup = function(){
            getValue(); //配列で回したValueに対してKeyupされた時にgetValue関数を起動させます。
        };
        $formObject.elements[$i].onchange = function(){
            getValue();//配列で回したValueに対してKeyupされた時にgetValue関数を起動させます。
        };
    }
    document.getElementById( "sampleOutputLength" ).innerHTML = $formObject.length;
}
function getValue() { //getValue関数を定義します
    var $formObject = document.getElementById( "sampleForm" );
    document.getElementById( "sampleOutputName" ).innerHTML = $formObject.formName.value;
    document.getElementById( "sampleOutputArea" ).innerHTML = $formObject.formArea.value;
    document.getElementById( "sampleOutputAge" ).innerHTML = $formObject.formAge.value;
    document.getElementById( "sampleOutputComent" ).innerHTML = $formObject.formComent.value;
}

 
以上説明は簡単にコメントアウトで行なっております。
簡単な記述になるので是非コピペして変更をして楽しんでみては。

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