20200519のJavaScriptに関する記事は21件です。

結局for文を使うのか?while文を使うのか?for文とwhile文の使い分け

※この記事はCやJavaなどCライクな構文のfor文を持つ言語向けの記事です。Python等foreachな言語は対象外です。

今更のようですが、for文とwhile文の使い分け、プログラミングを始めたての頃には誰しも疑問に思ったことでしょう。

世の中の一般的な文献には、for文は繰り返し回数が明らかなときに使用するなどと書かれていることが多いようです。

しかしながら、自分としてはこの説明があまり腑に落ちませんでした。

今日プログラムを書いていて、この違いについてやっと自分の中で一つの落としどころが見つかったので、ここに記録しておこうと思います。

以下、JavaScriptで記述します。

class Iterator {
  index = 0;
  constructor(list) {
    this.list = list;
  }
  next() {
    return this.list[this.index++];
  }
}

const iterator = new Iterator([1, 2, 3, 4, 5]);

以上のような実装のIteratorクラスを用意します(実際にはファイルリストなどをイメージしてもらえれば良いです)。ここで、すべての要素を出力しつつ、要素の個数を数える処理を記述したいとします。当初、私は次のようなコードを書きました1

let count = 0, item;
while (item = iterator.next()) {
  console.log(item);
  count++;
}
console.log(`個数: ${count}`);

コードをより読みやすくするため、以下のように書き換えてみます。

let count, item;
for (count = 0; item = iterator.next(); count++) {
  console.log(item);
}
console.log(`個数: ${count}`);

書き換えてみたのですが・・・このコード、確かに短くはなっているのですが、非常に読み辛いと感じませんか?

恐らくこの理由は、私たちが

for (A; B; C) {}

という文を見たとき、無意識に

For A, while B, do C.

つまりAについて、Bの間、Cしなさいと読んでいるためだと思うのです。このため、実際の式をここに当てはめたとき、文章として成り立たないと強い違和感を覚えます。

もう少し踏み込んだ表現をするのであれば、意識する必要があるのはAの文、つまり初期設定式です。「for」という単語(=~について)が使われている以上、BやC、そしてブロック内の文は嫌でもこのAの部分に束縛を受けます。

先ほどのfor文の例に違和感があったのは、初期設定式は変数countの初期化に使用されているにもかかわらず、継続条件式やブロック内の文がcountと全く関係のないものだったからなのです。

まとめ

while文で表現可能な繰り返しのうち、for文で表現するべきものは

  • 繰り返し初期に実施すべき式が存在する
  • その式の主たる対象が継続条件や再設定式、ループ内の処理においても主要な要素である

を満たすものだということができると思います。

極端な例

逆に言えば、上のルールを満たしさえしていれば、一般に言われる「繰り返し回数がわかっている」を満たさない場合においても、for文を使って書けるものが存在することになります。以下の例はどうでしょうか。

class Iterator {
  index = 0;
  constructor(list) {
    this.list = list;
  }
  get currentItem() {
    return this.list[this.index];
  }
  next() {
    this.index++;
  }
}

let count = 0;
for (
  const iterator = new Iterator([1, 2, 3, 4, 5]);
  iterator.currentItem;
  iterator.next()
) {
  console.log(iterator.currentItem);
  count++;
}
console.log(`個数: ${count}`);

あまり違和感はない・・・ですよね???


  1. JavaScriptでは、配列の範囲外のインデックスにアクセスがあった場合、エラーとはならずundefinedというfalsyな値を返します。このため、nextメソッドは実行されるたびに要素を1つずつ返却し、全て終わるとundefinedを返すという挙動を示します。 

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

JavaScript、jQuery個人的まとめ

JavaScript

?DOMとは
HTMLを解析しデータを作成する仕組み
DOMツリーやドキュメントツリーとも言う

?ノード(オブジェクト)とは
HTML1つ1つのタグがDOMツリーの中ではノードと呼ばれる
例)body, header, side_barとか

js_foundation

window.addEventListener("load", function () {処理}
window.onload = function() {処理}

ロード時に全てのDOM要素を取得する

  let btn = document.querySelector("Button");

変数btnにセレクタButton(idのやつ)を代入
(“p”)だったり(“#Button2”)とかでも書く。

  btn.addEventListener("click", function () {処理}

btnがクリックされた時に{}内の関数を実行するイベントを追加

btn.innerHTML = “hoge”

指定したセレクタにhogeというHTMLを代入

btn.classList.add(“red”)

指定したセレクタにCSS要素を代入する

btn.classList.remove(“blue”)

指定したセレクタからblueというクラスを削除する

js_tabの解説

  let tabs = document.getElementsByClassName("menu_item");
  let tabsAry = Array.prototype.slice.call(tabs);

tabsAry.forEach(function (value) {
    value.addEventListener("click", tabSwitch);
  });

の処理の流れを解説。

変数tabsAryにtabsの中身を配列に変換して代入する。
tabsAryをforEachでvalueという変数に代入して全て繰り返す。
valueの値がクリックされたらイベントが発火される
console.log();で配列の中身を確認したらとてもよく分かる。
他の部分はコメント解説の内容通りなので省略

jQuery

?IDセレクタ
IDセレクタとは、HTML要素のid属性で指定するセレクタのことです。IDセレクタは、取得したいHTML要素のid属性の値に#(ハッシュ)を付けたものをセレクタとして利用します。
idセレクタの例
1 $("#idSelector") // idがidSelectorの要素を取得
クラスセレクタ
クラスセレクタとは、HTML要素のclass属性で指定するセレクタのことです。クラスセレクタは、取得したいHTML要素のclass属性の値に.(ドット)を付けたものをセレクタとして利用します。
クラスセレクタの例
1 $(".classSelector") // classがclassSelectorの要素をすべて取得
要素セレクタ
要素セレクタとは、h1やpのようなHTML要素を対象としたセレクタのことです。要素セレクタは取得したいHTML要素の要素名をそのままセレクタとして利用します。
要素セレクタの例
1 $("h1") // h1要素をすべて取得
属性セレクタ
HTMLのタグの属性値を指定したい場合、$("[ 属性 = '値' ]")で属性セレクタを取得できます。
属性セレクタの例
1 $("input[ type='radio' ]"); // のHTML要素を取得する

?removeClass()、addClass()
クラスを追加したり消す。最初に0を指定しなくても自動的に最初の要素を指定してくれる

?index()
配列に変換しなくても、集合したDOM要素から引数に指定(thisとか)したDOMと同じ要素番号を戻す

?eq()
引数に要素番号を取って、集合したDOM要素から選択できる

分からない事はいきなり検索しないで、紙に実装できる流れを仮説立ててから調べる!

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

【初心者】ChromeDevToolsを使ってJavaScriptで簡単に要素を取得する方法

はじめに

会社で毎日ポチポチ画面操作していることをJavaScriptを使って自動化することにしました。値を取得や値のセットをするために、試行錯誤していたところ、簡単に出来るやり方がわかりました。

  • document.querySelector()
  • document.querySelectorAll()

メソッドが簡単に要素の取得や値のセットがしやすく、
ChromeDevToolsを使うことで、更に簡単に対応することが出来ました。

ChromeDevToolsでDOMノード参照

以下のサイトで使い方をgifで説明しており、一瞬で使い方がわかります。

Chrome DevTools: Generate a JavaScript expression to get a DOM node

コード

今回実際に使った使い方

// 値のセット
document.querySelector("#tabTopics1 > a").value="test"

// 値の取得
document.querySelector("#tabTopics1 > a").value

// innerText取得
document.querySelector("#tabTopics1 > a").innerText

参考

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

Denoとはなにか - 実際につかってみる

はじめに

Denoというものが面白そうだったので、これを書きたいと思います。

Denoとはなにか

deno.png

↑かわいい

Deno(ディーノ)という名前について、聞いたことがありますでしょうか。私も最近まで知りませんでしたが、実はv1.0がリリースされたのが2020/5/13とごく最近のことです。開発自体は2年前から行われておりましたが、結構新しめの技術です。
その証拠(?)にDenoでググると担々麺ばっかりでてきます。(2019/5/18現在)

スクリーンショット 20200518 0.02.53.png

結局Denoってなんなの?

Denoは、Node.jsの製作者であるRyan Dahlによって作られた、新しいJS/TSランタイムです。すっごい雑に説明すると、Node.jsのイケてなかったところを改良したものがDenoになります。Denoって文字を並べ替えるとNodeになりますね。

const deno = 'node'.split('').sort().join('')

Denoがつくられた背景

DenoはJSConf EU 2018でのRyan Dahlによる講演「Node.jsに関する10の反省点」において発表されました。

10 Things I Regret About Node.js - Ryan Dahl - JSConf EU
Node.js における設計ミス By Ryan Dahl

Ryan Dahlは講演の中で、自身が開発しNode.jsにおける10個の後悔している点について言及しました。それらの設計ミスに基づいて開発されたのが、Denoです。

実際にDenoを使ってみる?

なにはともあれ、実際にDenoを使ってみてNode.jsとの違いについて見ていきましょう。

インストール

まずはインストールをします。私はMacを使っているので、Homebrewを使用してインストールしました。

$ brew install deno

以下のコマンドで正しくインストールされたか確認してみましょう。

$ deno -V
deno 1.0.0

Denoを実行する

Denoを簡単に実行してみるために、公式のサンプルコードを利用してみます。

$ deno run https://deno.land/std/examples/welcome.ts
Download https://deno.land/std/examples/welcome.ts
Warning Implicitly using master branch https://deno.land/std/examples/welcome.ts
Compile https://deno.land/std/examples/welcome.ts
Welcome to Deno ?

恐竜さんが出てきました。可愛いですね?

2回目以降の動作は、初回と変わってきます。

$ deno run https://deno.land/std/examples/welcome.ts
Welcome to Deno ?

DownloadCompileなどの行がなくなっていますね。
今回のように、リモートのURLを実行した場合にはローカルにキャッシュされ2回目以降は素早く実行することができます。
これは後ほど出てくるimportでパッケージを読み込むときと同じです。

変更点1 TypeScriptをそのままサポート

先程実行したプログラム自体はとても簡単なものでしたが、早速Node.jsとの変更点が含まれています。
先程実行したプログラムhttps://deno.land/std/examples/welcome.tsの拡張子を見ると、TypeScriptのコードであることがわかります。
従来では、TypeScriptを実行するには、npmでインストールして、ルート配下にtsconfig.jsonを設置して、コンパイルして...といった作業が必要でした。
しかし、Denoならそのような設定はすべて必要ありません。デフォルトでTypeScriptをサポートしているので、そのまま実行することができます。

サンプルコードを見てみる

簡単なプログラムだけではつまらないので、次はローカルにサーバーを立ててみます。以下のコードは公式サイトからのコピペで持ってきました。
8000ポートでサーバを立てて、Hello Worldと表示させます。

import { serve } from "https://deno.land/std@0.50.0/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
  req.respond({ body: "Hello World\n" });
}

次に、下記のコードがNode.jsで書いた同じようなコードです。

const http = require('http');

const server = http.createServer((req, res) => {
  res.end('Hello World');
});

server.listen(8000)

この2つのコードを比べていきましょう。

変更点2 npmがない

と、先にコードの方を提出しましたが、その前にやることがありましたね。
まずはnpm initpackage.jsonを作ってそれから...えっDenoでは必要ないって?

そうなんです、Denoはインストールさえ済ませれば先に見たようにそのままコードを実行することができます。
驚くなかれ、そもそもDenoにはnpmがありません
npmがないということは当然node_modulespackage.jsonなんてものも存在しません。

node_moduelsってかなり巨大なファイルでしたし、こいつがなくなるだけでフォルダ構成が結構スッキリしてくるんじゃないでしょうか。
node_moduelspackage.jsonの採用は、Node.jsの設計ミスとしても上げれていた点です。

では、npmを使用しないとなれば、どのようにして外部モジュールを使用するのでしょうか。
その答えは、サンプルコードにもあるように、importにURLを渡します。

import { serve } from "https://deno.land/std@0.50.0/http/server.ts";

これは、Denoで外部モジュールを使用する唯一の方法です。もうnpm installは必要としません。
ダウンロードは実行時に行われ、結果はキャッシュされます。

変更点2 requireがなくなった

関連して、今までNode.jsで利用されてきたrequireが廃止されました。

Node.js

const http = require('http');

Deno

import { serve } from "https://deno.land/std@0.50.0/http/server.ts";

CommonJAの代わりにES Module(importexport)をデフォルトのモジュールとシステムとして使用します。

変更点3 トップレベルのawait

あ!サンプルコードのこの部分、間違ってますよ!ほら!

for await (const req of s) {
  req.respond({ body: "Hello World\n" });
}

awaitasync関数の中でしか動作できないんですよー、ほらVSCodeだって怒ってる。

スクリーンショット 20200518 1.40.50.png

...え、これができるようになった?

そうです、もうawait使いたさにわざわざasync関数で囲む必要はありません。やったね。

実行してみる

コードベースでの変更点はここまでにして、実際にコードを実行してローカルサーバを立ち上げてみましょう。
deno runで実行できます。

$ deno run server
$ deno run server.js
Download https://deno.land/std@0.50.0/http/server.ts
Compile https://deno.land/std@0.50.0/http/server.ts
Download https://deno.land/std@0.50.0/encoding/utf8.ts
Download https://deno.land/std@0.50.0/io/bufio.ts
Download https://deno.land/std@0.50.0/testing/asserts.ts
Download https://deno.land/std@0.50.0/async/mod.ts
Download https://deno.land/std@0.50.0/http/_io.ts
Download https://deno.land/std@0.50.0/io/util.ts
Download https://deno.land/std@0.50.0/path/mod.ts
Download https://deno.land/std@0.50.0/path/win32.ts
Download https://deno.land/std@0.50.0/path/posix.ts
Download https://deno.land/std@0.50.0/path/common.ts
Download https://deno.land/std@0.50.0/path/separator.ts
Download https://deno.land/std@0.50.0/path/interface.ts
Download https://deno.land/std@0.50.0/path/glob.ts
Download https://deno.land/std@0.50.0/path/_constants.ts
Download https://deno.land/std@0.50.0/path/_util.ts
Download https://deno.land/std@0.50.0/fmt/colors.ts
Download https://deno.land/std@0.50.0/testing/diff.ts
Download https://deno.land/std@0.50.0/path/_globrex.ts
Download https://deno.land/std@0.50.0/async/deferred.ts
Download https://deno.land/std@0.50.0/async/delay.ts
Download https://deno.land/std@0.50.0/async/mux_async_iterator.ts
Download https://deno.land/std@0.50.0/textproto/mod.ts
Download https://deno.land/std@0.50.0/http/http_status.ts
Download https://deno.land/std@0.50.0/bytes/mod.ts
error: Uncaught PermissionDenied: network access to "0.0.0.0:8000", run again with the --allow-net flag
    at unwrapResponse ($deno$/ops/dispatch_json.ts:43:11)
    at Object.sendSync ($deno$/ops/dispatch_json.ts:72:10)
    at Object.listen ($deno$/ops/net.ts:51:10)
    at listen ($deno$/net.ts:152:22)
    at serve (https://deno.land/std@0.50.0/http/server.ts:261:20)
    at file:///Users/asaiippei/deno-test/server.js:2:11

外部モジュールをインストールするとことまでは良かったのですが、エラーが発生してしまいました。

変更点4 セキュリティルールの変更

なぜエラーが発生したのでしょうか。
実は、Denoデフォルトでセキュアであり、明示的に有効にしない限り、ファイル、ネットワーク、環境変数等にアクセスすることができません。

ネットワークを許可するには--allow-netフラグを付与して実行する必要があります。
もう一度やってみましょう。

$ deno run --allow-net  server.js
http://localhost:8000/

無事成功しましたね。
http://localhost:8000/にアクセスすると次のように表示されているはずです!
スクリーンショット 20200518 1.56.19.png

変更点5 Web APIの実装によるブラウザとの互換性の向上

Web APIはWebブラウザに組み込まれている機能です。ブラウザやコンピュータの環境の情報を取得し、これを使って役に立つややこしい事を行えるようにするものです。
代表的なものでいえば、DOM,Canvas API,Storage,fetch APIなどがあります。

これらのAPIは日常的に使用していて、JavaScriptを覚えたての頃はJavaScript標準のモノだと思いこんでしまうほどですが、Node.jsではこれらを使用することはできません。理由は簡単で、これらのAPIはブラウザ(Google Chrome, Firefox)で利用できるものであり、Node.jsはブラウザではないからです。

Node.jsの場合

例えば、次のようにNode.jsFetch APIを利用使用とすると失敗します。

fetch('https://pokeapi.co/api/v2/pokemon/')
  .then(res => res.json())
  .then(data => console.log(data) )
$ node node-fetch.js
node-fetch.js:2
fetch('https://pokeapi.co/api/v2/pokemon/1')
^

ReferenceError: fetch is not defined
    at Object.<anonymous> (/Users/asaiippei/deno-test/node-fetch.js:2:1)
    at Module._compile (internal/modules/cjs/loader.js:955:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:991:10)
    at Module.load (internal/modules/cjs/loader.js:811:32)
    at Function.Module._load (internal/modules/cjs/loader.js:723:14)
    at Function.Module.runMain (internal/modules/cjs/loader.js:1043:10)
    at internal/main/run_main_module.js:17:11

fetchが定義されていないと怒られていますね。
これを解決するには、外部モジュールであるnode-fetchをインストールする必要があります。

npm i node-fetch
// これを追加
const fetch = require('node-fetch')

fetch('https://pokeapi.co/api/v2/pokemon/')
  .then(res => res.json())
  .then(data => console.log(data) )
$ node node-fetch.js

{
  count: 964,
  next: 'https://pokeapi.co/api/v2/pokemon/?offset=20&limit=20',
  previous: null,
  results: [
    { name: 'bulbasaur', url: 'https://pokeapi.co/api/v2/pokemon/1/' },
    { name: 'ivysaur', url: 'https://pokeapi.co/api/v2/pokemon/2/' },
    { name: 'venusaur', url: 'https://pokeapi.co/api/v2/pokemon/3/' },
    { name: 'charmander', url: 'https://pokeapi.co/api/v2/pokemon/4/' },
    { name: 'charmeleon', url: 'https://pokeapi.co/api/v2/pokemon/5/' },
    { name: 'charizard', url: 'https://pokeapi.co/api/v2/pokemon/6/' },
    { name: 'squirtle', url: 'https://pokeapi.co/api/v2/pokemon/7/' },

Denoの場合

Denoの場合には、標準でFetch APIがサポートされているため、インストールすることなく使用することができます。

const res = await fetch('https://pokeapi.co/api/v2/pokemon/1')
const json = res.json()
const data = await json
console.log(data)

おっと、実行するときには--allow-netフラグを渡すことを忘れないでください!

$ deno run --allow-net fetch.js

{
 count: 964,
 next: "https://pokeapi.co/api/v2/pokemon/?offset=20&limit=20",
 previous: null,
 results: [
    { name: "bulbasaur", url: "https://pokeapi.co/api/v2/pokemon/1/" },
    { name: "ivysaur", url: "https://pokeapi.co/api/v2/pokemon/2/" },
    { name: "venusaur", url: "https://pokeapi.co/api/v2/pokemon/3/" },
    { name: "charmander", url: "https://pokeapi.co/api/v2/pokemon/4/" },
    { name: "charmeleon", url: "https://pokeapi.co/api/v2/pokemon/5/" },
    { name: "charizard", url: "https://pokeapi.co/api/v2/pokemon/6/" },
    { name: "squirtle", url: "https://pokeapi.co/api/v2/pokemon/7/" },

fetch APIの他にも幅広いWeb APIを実装していることにより、ブラウザとの互換性を向上させました。

Denoによるテスト

Denoにはテストランナーも含まれています。

Deno.testを呼ぶことでテストをすることができます。

Deno.test("hello world", () => {
  const x = 1 + 2;
  if (x !== 3) {
    throw Error("x should be equal to 3");
  }
});

標準テストモジュールから、アサーションを使用することができます。

import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

Deno.test("hello world", () => {
  const x = 2 + 2;
  assertEquals(x, 3);
});

テストを実行するときは、Deno testです。

$ deno test test.js
Download https://deno.land/std/testing/asserts.ts
Warning Implicitly using master branch https://deno.land/std/testing/asserts.ts
Compile https://deno.land/std/testing/asserts.ts
Download https://deno.land/std/fmt/colors.ts
Download https://deno.land/std/testing/diff.ts
Warning Implicitly using master branch https://deno.land/std/testing/diff.ts
Warning Implicitly using master branch https://deno.land/std/fmt/colors.ts
Compile file:///Users/deno-test/.deno.test.ts

running 1 tests
test hello world ... FAILED (5ms)

failures:

hello world
AssertionError: Values are not equal:


    [Diff] Actual / Expected


-   4
+   3

    at assertEquals (https://deno.land/std/testing/asserts.ts:167:9)
    at test.js:5:3
    at asyncOpSanitizer ($deno$/testing.ts:36:11)
    at Object.resourceSanitizer [as fn] ($deno$/testing.ts:70:11)
    at TestApi.[Symbol.asyncIterator] ($deno$/testing.ts:264:22)
    at TestApi.next (<anonymous>)
    at Object.runTests ($deno$/testing.ts:346:20)

failures:

        hello world

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out (5ms)

初回なのでダウンロードとコンパイルが入りますね。
テストも失敗しているので修正しておきましょう。

import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

Deno.test("hello world", () => {
  const x = 1 + 2;
  assertEquals(x, 3);
});

2回目以降のテストはすぐに実行できます。

$ deno test test.js
running 1 tests
test hello world ... ok (6ms)

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (8ms)

これでOKですね。

おわりに

新しいJavaScriptのランタイムであるDenoについてざっくりと触れてみました。
いつの日か、Node.jsに取って代わる日が来るのでしょうか、とても気になりますね。

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

【Nuxt.js】アプリ開発実践編:Nuxt + Vuex + firebaseでログイン付きToDoリスト①

前置き

Loginfinish.gif

前回のTODOリストに
オプション機能をつけていきます♪
https://note.com/aliz/n/n8411db2c9a20

今回はログイン機能を追加?
実際にサービスを運用するには
必須の機能ですね!?
以前の記事をやっていない方でも
仕組みと書き方が分かれば大丈夫です?‍♀️

内容が濃いのでお知らせした通り、
有料記事になりました?

【使うもの】
・Firebase Authentication
・Vuex(ログイン状態の保持)

【流れ】
ボリュームがあるため2回に分けます!
・ログイン画面の作成
・新規アカウント作成画面の作成
・ログイン時とログアウト時の
 表示の出し分け
・+a
 メールアドレス以外のログイン
 エラー時の処理や
 アカウント作成時にメール送信

❓公式guides, Referenceの読み方
基本的にfirebaseのreferenceは
英語の状態で表示し、
自分でgoogle翻訳で翻訳しましょう??

言語を日本語にすると
古いバージョンだったりするので、
最新の英語を翻訳していくのがベスト!⭕️
ただいきなり全部英語だと
欲しい情報がどこにあるか分からないので
最初は日本語で表示させて
ある程度検討をつけてから英語にしてます?
(英語も理解できるように頑張ろう…?)

Step1: firebaseAuthの準備

まずはfirebaseで既に作成したプロジェクトに
ログイン方法の設定をしていきます?
簡単にできるメールアドレスから!✉️
ログインできるかどうか判断するため
firebase上でアカウントを作成してみます?

?後からアカウント作成画面も作ります
?Googleアカウントでの
 ログインなども追加していきます

・プロジェクトの概要ページから
 サイドメニューのAuthenticationを選択
 ログイン方法を設定を選択

auth1.png

・メールを選択

Frame 2.png

・メールでのログインを有効にし、保存

Frame 3.png

・usersタブに戻りユーザーを追加

Frame 4.png

登録できるとユーザー情報が表示されます?

Frame 5.png

Step2: ログイン機能の実装

Login1.gif

続きはこちら♪
https://note.com/aliz/n/n882048f66734

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

自己紹介

こんにちは。初投稿です。
投稿の練習がてら自己紹介をします。

私は現在高校で数学の教員をやっています。
数学の授業で使えるようなソフトやページを作っています。

私がプログラミングと出会ったのは大学2年生の時に受けた授業でした。そこではRubyを扱い、全く理解できなかった私はプログラミングに興味を持つことはありませんでした。
しかし大学3年生の春、某大手通信制高校の長期インターンを始めたら、そのインターンではプログラミングを扱う機会がとても多く、扱う教材も面白く私はプログラミングへのめり込んでいきました。
インターンでは主に、HTML、CSS、JavaScript、python、Unity(C#)などを扱いました。紹介しているものも、ここら辺中心に作っています。

以下にインターン時代に作ったものを載せておきます。
円周率πの近似~モンテカルロ法~(HTML、JavaScript)
mc.png
polygons.png

教員になってから作ったものは以下のものです。
サイコロを振りまくったら本当に1/6になるのか(Unity)
ダウンロード.gif
数学の展開、因数分解をひたすらやるゲーム(Unity)
これはまだ制作途中なので画像だけです。
S__89874440.jpg
S__89874442.jpg
S__89874443.jpg
S__89874444.jpg

サイコロと数学のゲームに関しては別記事でもう少し詳しく紹介できたらなと思います。
コメントやアドバイスをいただけると幸いです。

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

JavaScript文法総復習

目的

HackerRankをやりながら忘れそうな文法を記載していきます。

配列の合計値の計算

配列の中身を一つ一つ処理して合計を計算する。

昔風

sample.js
const array=[1,2,3,4,5];
let sum=0;

for(let i; i<array.length: i++){
 sum+=array[i];
}

ちょっと今風

sample.js
array.forEach((num) => {sum+=num})

そのほか

sample.js
let sum = array.reduce((a, c) => {return a + c})
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

○未満の数値を表示する方法

備忘録のため記述します。

  <script>
     var data = [59, 39, 100, 2, 15, 40, 84, 97];

    /* 以下に課題処理を追加 */
    var i =0;
    for (i=0; i< data.length; i++){
        document.write("<div>"+data[i]+"</div>");
    }

    var count =0; //人数の把握をします
    var j =0;
    for (j=0; j<data.length; j++) {
        if (data[j]< 40) {
            count++
        }
    }
    document.write("<div>40点未満の人は"+count+"人です</div>");


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

JavaScriptでドラゴンボールを見つけるためにfor,if文書こう!

はじめに

  • そもそもJavaScriptの動かし方
  • for文
  • if文
  • 最後に

そもそもJavaScriptの動かし方

JavaScriptには様々な動かし方があります。私が書いている記事のようにhtmlに埋め込んで動かす方法もありますが、ただ動かして見たいだけならブラウザから直接動かしてみましょう!chromeなどのブラウザにはJavaScriptを動かす機能が元々備わっているのでちゃんと動いてくれます。試しに簡単な文章を書いて動くか見てみましょう!!まずはchromeでデベロッパーツールを選択しconsoleに記入しましょう!ここに記入しenterを押せばしっかり動きます。

console.log("hello!!")

image.png

こんな感じで動いてくれます。
alertも動かしてみましょう!

alert("hello!")

image.png

よく見るポップアップが表示されましたね!!

for文

今回は簡単な基本文法であるfor文を紹介したいと思います。簡単とはいえよく使う便利な文法ですのでしっかり覚えましょう!
10回繰り返してconsoleするものを書いてみます。

for (var i = 0; i < 10; i++) {
    console.log(i)
}

これで実行すると
image.png
こんな感じで0~9まで書き出してくれます。
これが基本的なfor文の書き方です。三つの要素は左が最初の数字、真ん中が続く条件、右が増え方です。++は一つずる増えるという意味です。ここらへんの数値をいじることで、for文の細かな設定をしていきます。

if文

if文もfor文同様によく使う文法です。簡単ですが応用のきく文法ですので基本をおさえておきましょう!!
今回はhtmlに埋め込んで動かしますね。

<html>
    <head>
        <meta charset="utf-8">
        <title>jstest</title>
    </head>
    <body>
        <script>
            var i = 10;
            if (i > 10) { 
                document.write("10より大きい")
            } else {
                document.write("10以下")
            }
        </script>
    </body>
</html>

scriptタグの中にJavaScriptを書くことで実行することができます。今回はconsoleではなくdocument.writeを使います!
このhtmlを開くと
image.png

こんな感じで表示されます!
今回はiが10だったためelseの中が作動し10以下と表示されました。この書き方意外にもelseifなどで条件を増やすことができます。

最後に

いかがだったでしょうか?if文for文の基本的な書き方を紹介しました。これだけの知識だとあまり使い物になりませんが、応用させることでより複雑なプログラムを書くことができます。私が載せているgoogle maps APIでもfor,if文を活用しています。是非ご覧になってください!
https://qiita.com/Ryunosuke-watanabe/items/958ed12471effc8fd778

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

JavaScript 学習記録 #2 Dateオブジェクト

12時間時計にする方法:point_up:

24時間表記で表示されるのは、getHoursメソッドで取得できる数字をそのまま出力しているためです。
Dateオブジェクトに12時間表記の時間を取得できるメソッドはないため、加工が必要です。

15:13 を 3:13 p.m とするためには・・・?:thinking:

方法はいくつかあります。

①コードの書き方はこんな感じ:point_down:

date.js
<script>
    'use strict';

    const now = new Date();
    const year = now.getFullYear();
    const month = now.getMonth();
    const date = now.getUTCDate();
    const hour = now.getHours();
    const min = now.getUTCMinutes();
    let ampm = '';
    if(hour < 12){
        ampm = 'a.m.';
    }else{
        ampm = 'a.m.';
    }

    const output = `${year}/${month + 1}/${date} ${hour}:${min}`;
    document.getElementById('time').textContent = output;
</script>

②処理の流れ:point_down:

24時間表記を12時間表記にするには、大きく分けて2つの処理が必要である。

1⃣ 現在時刻は午前「a.m.」なのか「p.m.」なのか判別する

プログラムの最初の部分で変数ampmを定義し、空の文字列(文字数が0個の文字列)を代入する。そして、定数hourに保存されている数値が12より小さい、現在時間が0時~11時の場合、変数ampmに「a.m.」を代入する。定数hourの値が12以上の場合は「p.m.」を代入する。

2⃣ 0~23の数字を0~11に変換する

定数outputに代入するときには、24時間表記の時間を12で割った余りを計算すれば良い。
 ${hour % 12 }

※ 「どう処理すれば良いか」を考えることが大切:point_up:
 

 

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

javascriptメモ2

Node.jsのステップ実行

VSCで出来る。
VS201xでも昔試した記憶あるけど何も覚えていない。。

Promise

      var btn_promise = cube.getButtonStatus()
      btn_promise.then((value) => {
          console.log(value);  // 1
          //cube.playPresetSound( 4);
            //console.log("btn = " , String(btn))
      }, (error) => {
        console.error("error:", error.message);
      });

sleep

侍エンジニア塾の最初のロゴ、すごい邪魔なんですけど(怒)

// ビジーwaitを使う方法
function sleep2(waitMsec) {
  var startMsec = new Date();

  // 指定ミリ秒間だけループさせる(CPUは常にビジー状態)
  while (new Date() - startMsec < waitMsec);
}

function sleep(waitSec, callbackFunc) {
    // 経過時間(秒)
    var spanedSec = 0;
    // 1秒間隔で無名関数を実行
    var id = setInterval(function () {
        spanedSec++;
        // 経過時間 >= 待機時間の場合、待機終了。
        if (spanedSec >= waitSec) {
            // タイマー停止
            clearInterval(id);
            // 完了時、コールバック関数を実行
            if (callbackFunc) callbackFunc();
        }
    }, 1000);
}

enum

JavaScriptにはない、TypeScriptにはある。

enum Color {
Red,
Green,
Blue
}
var col = Color.Red;
col = 0; // Effectively same as Color.Red

 format

function test()
{
var str = "もじれつ";
var num = 555;
var flo = 1.7320508075;

console.log('Stringの出力 : %s', str);
console.log('Numberの出力 : %d', num);
console.log('Floatの出力  : %f', flo);

console.log('複数出力 : %s %d %f',str,num,flo);

}

メモ

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

グラフとBFS(幅優先探索)・DFS(深さ優先探索)をJSで実装してみる

この記事で言うグラフは、折れ線グラフなどのグラフでは無く「データ構造」のグラフです。
ノード(頂点)群とノード間の連結関係を表すエッジ(枝)群で構成されるデータ型です。

500px-6n-graf.svg.png

:computer: 実際のコード

class Graph {
    constructor() {
        this.connectedList = {};
    }

    addVertex(vertex) {
        this.connectedList[vertex] = []
    }

    addEdge(v1, v2) {
        this.connectedList[v1].push(v2);
        this.connectedList[v2].push(v1);
    }

    removeEdge(vertex1, vertex2) {
        this.connectedList[vertex1] = this.connectedList[vertex1].filter(
            v => v !== vertex2
        );

        this.connectedList[vertex2] = this.connectedList[vertex2].filter(
            v => v !== vertex1
        );
    }

    removeVertex(vertex) {
        while (this.adjacencyList[vertex].length) {
            const adjacentVertex = this.adjacencyList[vertex].pop();
            this.removeEdge(vertex, adjacentVertex);
        }

        delete this.adjacencyList[vertex];
    }

    dfs(start) {
      //ノードを格納するスタック
      const stack = [start];

      //訪れた順番を格納
      const result = [];

      //訪れたフラグ
      const visited = {};

      //現在のノード
      let currentVertex;

      //訪問済みフラグを立てる
      visited[start] = true;

      while (stack.length) {
        // stackの最後尾を取得&削除
        currentVertex = stack.pop();

        // resultに現在の頂点を追加
        result.push(currentVertex);

        // 繋がっている頂点を探索して訪問済みにする
        // そして、stackにその頂点を追加
        this.connectedList[currentVertex].forEach(neighbor => {
          if (!visited[neighbor]) {
            visited[neighbor] = true;
            stack.push(neighbor);
          }
        });
      }
      return result;
    }

    bfs(start) {
      // これから探索する予定のものの配列
      const queue = [start];

      // 訪問順番の結果
      const result = [];

      // 探索済みであるか
      const visited = {};

      let currentVertex;
      visited[start] = true;

      while (queue.length) {
        // 先頭から取り出す
        currentVertex = queue.shift();

        // 現在地点を探索済みに
        result.push(currentVertex);

        this.connectedList[currentVertex].forEach(neighbor => {
          if (!visited[neighbor]) {
            visited[neighbor] = true;
            queue.push(neighbor);
          }
        });
      }
      return result;
    }
}

const graph = new Graph;

// 頂点の追加
graph.addVertex(1)
graph.addVertex(2)
graph.addVertex(3)
graph.addVertex(4)
graph.addVertex(5)
graph.addVertex(6)
graph.addVertex(7)

// エッジ(繋がり)の追加
graph.addEdge(1, 2)
graph.addEdge(1, 3)
graph.addEdge(2, 4)
graph.addEdge(4, 6)
graph.addEdge(3, 6)
graph.addEdge(4, 6)
graph.addEdge(4, 5)
graph.addEdge(5, 7)

// 幅探索を行う
console.log(graph.dfs(1)) // 1, 3, 6, 4, 5, 7, 2

// 深さ探索を行う
console.log(graph.bfs(1)) // 1, 2, 3, 4, 6, 5, 7

:book: 使いどころ

町1から町2に道が繋がっていてお互いを行き来出来るなどといった関係性を表すのに使うやつです。
Twitterのフォローフォロワーとかもグラフみたいなものなので意外と色々なところで使われます。

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

GAS スプレッドシートの内容をもとにGoogleフォームのリストボックスの内容をダイナミックに更新する。

やりたいこと

GAS スプレッドシートの内容をもとにGoogleフォームのリストボックスの内容をダイナミックに更新したい、という要望がありましたので方法について検討してみました。

やろうとしたけど出来なかった

フォームのonOpenトリガーを使って、開いたときに自動更新すればいいんじゃない。
と、簡単に考えたのですが出来ないみたいです。
理由はonOpenは回答時には実行されないようです。公式に記載がありました。

GAS 公式ドキュメント
https://developers.google.com/apps-script/guides/triggers/#onopene

結論

結果として私がたどりついた方法は、
フォームを更新するスクリプトを分ベースのタイマーで回すというものです。
(ちょっとダサい方法なので、他にベターな方法があれば教えていただけますとうれしいです。)

手順

1.スタンドアローンスクリプトを作成する

スタンドアローンスクリプトを作成します。フォームに紐づくスクリプトは時間ベーストリガーに対応していません。

2.コード書く

GAS
const formId = "フォームのid"
const stId = "シートのid"

function formUpdate(){

  var form = FormApp.openById(formId)
  //リストボックスタイプのフォームアイテムを取得する。
  var items = form.getItems(FormApp.ItemType.LIST);

  //対象のスプレッドシート開く
  var st = SpreadsheetApp.openById(stId).getSheetByName("シート名");
  var maxrow = st.getLastRow();
  //①リストアイテムに追加したい列のデータを取得する。
  var data = st.getRange(1, 10 , maxrow , 1).getValues(); 

  //①で取得したデータは2次元配列なのでそのままリストアイテムに代入できないので1次元配列にする。  
  var listitems = [];  
  for (i = 0 ; i < data.length ; i ++   ){
    listitems.push(data[i][0]);
  }

  //リストアイテムに追加する。
  //リストボックスタイプのフォームアイテムがフォーム内に複数ある場合は、
  //items[0]のインデックス番号を適切に変更してください。
  items[0].asListItem().setChoiceValues(listitems);
}

3.トリガーを作成する

1分間隔でトリガーを設定します。

「現在のプロジェクトのトリガー」→ 「トリガーを追加」→「分ベースのタイマー」
image.png

image.png

image.png

4.おわり

参考にしました

Google Apps Script試行錯誤Blog
https://www.pre-practice.net/2019/09/google-formonopen.html

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

Reactでメディアクエリを良い感じに処理する

Reactでメディアクエリ

メディアクエリを良い感じにしてくれるreact-responsiveなる物が存在するが、微妙になんか使いにくい。
もっとなんか良い感じに使えるようにラッパーした物を定義してみる。

定数定義

なんか良い感じに使えるようにまず良い感じに定数定義をしておく。

constants.tsx
export const BreakPoint = {
  sm: 640,
  md: 768,
  lg: 1024,
  xl: 1280,
} as const;
export type BreakPoint = typeof BreakPoint[keyof typeof BreakPoint];

export const WidthCriteria = {
  max: 'max-width',
  min: 'min-width',
} as const;
export type WidthCriteria = typeof WidthCriteria[keyof typeof WidthCriteria];

Criteriaってワードなんか微妙な感じがするけどまぁ。。。いいか。。。

良い感じな奴を定義

定数を引数に取る良い感じの関数を再定義する。

useMediaQuery.tsx
import { useMediaQuery } from 'react-responsive'
import { BreakPoint, WidthCriteria } from "constants";

export default (breakpoint: BreakPoint, criteria: WidthCriteria): boolean => {
  const emSize = breakpoint / 16;
  return useMediaQuery({
    query: `(${criteria}: ${emSize}em)`
  });
};

使い方はこんな感じ

import React from 'react';
import { BreakPoint, WidthCriteria } from 'constants';
import useMediaQuery from 'useMediaQuery';

const Component: React.FC = () => {
  const isMobile = useMediaQuery(BreakPoint.sm, WidthCriteria.max);
  return (
    <div>
      {isMobile ? 'mobile' : 'desktop'}
    </div>
  );
};

export default Component;

これでなんかもっと良い感じに使えるようになった。

だがまだ良い感じには程遠い

Styled-Componentsでこんな感じに使えるようにしたいが、世の中そんなに甘くない。
Hooksの外でuseを使うなってガチギレされる。

import { BreakPoint, WidthCriteria } from 'constants';
import useMediaQuery from 'useMediaQuery';

const Wrapper = styled.div`
  #{useMediaQuery(BreakPoint.md, WidthCriteria.min) && `
    background-color: red;
  `};
  #{useMediaQuery(BreakPoint.lg, WidthCriteria.min) && `
    background-color: blue;
  `};
`;

const Component: React.FC = () => {
  return (
    <Wrapper>
      responsive
    </Wrapper>
  );
};

Styled-Components用に良い感じな奴を定義

良い感じにメディアクエリを処理できるMixin的な物を定義する。

mediaQuery.tsx
import { css, FlattenSimpleInterpolation } from "styled-components";
import { BreakPoint, WidthCriteria } from "constants";

export default (breakpoint: BreakPoint, criteria: WidthCriteria) => {
  const emSize = breakpoint / 16;
  return (style: FlattenSimpleInterpolation) => css`
    @media (${criteria}: ${emSize}em) {
      ${style};
    };
  `;
};

使い方はこんな感じ

import mq from 'mediaQuery';

const Wrapper = styled.div`
  ${mq(BreakPoint.md, WidthCriteria.min)(css`
    background-color: red;
  `)};
  ${mq(BreakPoint.lg, WidthCriteria.min)(css`
    background-color: blue;
  `)};
`;

const Component: React.FC = () => {
  return (
    <Wrapper>
      responsive
    </Wrapper>
  );
};

おわり

コード全文 https://gist.github.com/Karibash/15bfc974a76bca4ad6e69dfe6fc8f2c7
良い感じにメディアクエリを処理できる物が完成したが、
React初めて1週間くらいなんで、ぶっちゃけこれが正解なのか良くわからない。
マサカリ大歓迎です、待ってます。

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

PHPとJavaScriptの違いまとめ(主要項目の対比表)

PHPとJavaScriptの違いまとめ(主要項目の対比表)

PHPとJacaScriptのメソッドなど主要項目の違いまとめ。
どっちがどっちかわからくなるの防止。

「←」はPHPの記述と同じ。


項目 PHP JavaScript
変数 *1 $変数名 var/let/const 変数名
関数 function 関数名(){} function 関数名(){};
アロー関数 *2 fn()=>処理 ()=>{};
引数 $仮引数名 仮引数名
処理の終わり ;
コメントアウト // or /* */
クラス定義 class クラス名{}
コンストラクタ アクセス権 function __construct(){} constructor(){}
インスタンス new クラス名()
プロパティ アクセス権 $プロパティ名 const オブジェクト名 = {プロパティ名:値}
プロパティの呼び出し インスタンス->プロパティ名 オブジェクト.プロパティ名
プロパティに関数をセット なし {プロパティ名:()=>{処理}};
メソッド アクセス権 function メソッド名() メソッド名(){}
インスタンス自身(メソッドのみ) $this this
自身のプロパティ呼び出し $this->プロパティ名 this.プロパティ名
メソッド呼び出し インスタンス->メソッド名() インスタンス.メソッド名()
継承 class クラス名 extends 親クラス名{}
クラスの使用許可 不要 export default クラス名
クラス読込み require_once('ファイル名.拡張子') import クラス名 from "./ファイル名"
コンストラクタのオーバーライド *3 parent::__construct(); super()
出力 echo/print console.log()
配列の要素数 count(配列) 配列.length
配列 array() []
キーあり配列 array(キー名=>値) {キー名:値}
キーあり配列の値取得 *4 配列[キー名] 配列.キー名
キーあり配列呼び名 連想配列 オブジェクト
for文 for($変数=初期値: 条件式: ステップ){}
配列からひとつずつ抜き出す foreach($変数名 as 配列) 配列.forEach((変数名)=> {処理});
if文 if(条件式){}
else if elseif (条件式){} else if (条件式){}
switch文 switch(){case 条件: 処理; break;,,, default:}
変数展開 *5 "${変数}" `${変数}`
and &&/and
or パイプ2本/or
等しい == ===/==
異なる != !==/!=
インクリメント演算子 ++
デクリメント演算子 --
整数型に変換 intval() perseInt()/Number()
文字列型に変換*6 strval() String()/ .toString() / +''
小数点に型変換 floatval() parseFloat()
3桁区切り number_format() 数値.toLocaleString()

*1. let:再宣言NG、const:定数(再宣言・再代入NG)
*2. PHP:アロー関数は1行のみ。
  JS:複数行OK。代入した変数が関数名になる(phpも)。
*3. JS:super()の引数は親クラスのコンストラクタの引数と合わせる
*4. JS:プロパティと呼ぶ
*5. PHP:シングルクオテーションだと文字列として出力
  JS:バッククオート(shift+@)
*6. JS:空の文字列を足すと自動で文字列型に変換

JSはES6からクラスが使えるようになった。PHPと同じ処理で設定されている(クラスの生成、クラスの継承)。



PHPとJSは、PHPとPythonよりも似ている部分が多い。その分ちょっとした違いに注意が必要。(elseif と else ifとか)

>ご参考:phpとpythonの違いまとめ(対比表)

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

2ステップで実装!Next.js初心者のための画面遷移

1.はじめに

Next.jsを使い始めると「画面遷移処理ってどうするん?」って思って手が止まる人が多いのではないでしょうか?
なのでこの記事はNextの画面遷移がしっかり扱えるようにまとめておきました。

2.なぜNext.jsで画面遷移を設定するのか?

まず初めにNextでなぜ画面遷移を設定するのでしょうか?
別に「aタグで記述しておけば、画面遷移するでしょう!」って考える人もいると思いますが実は違いがあるのです。

aタグはHTMLファイルを取得して全画面を表示していますが、Nextは前の画面と比較して異なる部分だけを入れ替えています。
そのため、Nextの画面遷移のほうが軽く、動きが滑らかに感じます。

3.Next.jsで画面遷移する方法

それでは具体的にNextで画面遷移する方法を見ていきましょう!
Nextで画面遷移する方法は2種類あります。
1. Linkコンポーネントを使う
2. Router.pushを使う

LinkコンポーネントはJSXでHTMLのように記述する方法でRouter.pushはイベントハンドラーなどの処理の中で設定する方法です。
JSXを使うかどうかで使い分けることができ、JSXを使う場合はLinkコンポーネント、イベントハンドラの場合はRouter.pushを使います。

  • JSXの場合:Linkコンポーネント
  • イベントハンドラの場合:Router.push

3-1.Linkコンポーネント

Linkコンポーネントはaタグをラップすることで使うことができ、特徴はJSXでタグとして扱えることです。
Linkコンポーネントは2ステップで実装できます。

  1. Linkコンポーネントのインポート
  2. Linkコンポーネントでaタグを包む

次のソースは、/から/NextPageに遷移する方法です

リンクの設定.gif

Linkコンポーネントでの画面遷移
//①Linkコンポーネントのインポート
import Link from "next/link";

export default function Index() (
  <div style={{textAlign: "center"}}>
    <h1>遷移元</h1>
    {/* ②Linkコンポーネントでaタグを包む */}
    <Link href="/NextPage">
      <a>次のページへ進む</a>
    </Link>
  </div>
);

①でLinkコンポーネントを使うために必要なモジュールを取り込み、②でaタグをLinkコンポーネントでラップして遷移先を設定するだけの処理です。
この2ステップでNextでの画面遷移を実装できます。

ちなみにリンクにCSSクラスなどのオプションを設定する場合はaタグに設定します。
例えば、別のタブで画面を開きたいときはtaget属性をaタグに設定します。
aタグのオプション.gif

aタグにオプションを設定
<Link href="/NextPage">
  <a target="_blank">新しいページを開く</a>
</Link>

3-2.Router.push

次はRouter.pushで遷移する方法です。
Router.pushは処理の中に埋め込めるので柔軟なページ遷移が可能です。
イベントハンドラなどに実装できるのが特徴で、Router.pushでの実装も2ステップで設定できます。

  1. Routerオブジェクトのインポート
  2. 遷移先の設定

次のソースは/NextPageから/に遷移するプログラムです。

Router.pushでの画面遷移
//①Routerオブジェクトのインポート
import Router from 'next/router'

export default function NextPage() {
  function clickHandler() {
    //②遷移先の設定
    Router.push('/')
    return
  }

  return (
    <div style={{textAlign: "center"}}>
      <h1>遷移先</h1>
      <button onClick={clickHandler}>前のページへ戻る</button>
    </div>
  );
}

①でRouterオブジェクトをインポートして、②のpushメソッドで遷移するパスを設定しています。
Next.jsのindex.jsは特殊なページで/indexでなくて/でも遷移できます。
また、Pagesフォルダーを基準にパスを設定するので今回の場合だとpagesフォルダーの直下にあるindex.jsファイルのコンポーネントに遷移しています。

4.まとめ

この記事ではNextで画面遷移する方法を2種類解説しました

JSXでの画面遷移はLinkコンポーネント
イベントハンドラーでの画面遷移はRouter.push

画面遷移はNext.jsでもよく使う機能なので覚えていて損はないです。

5.参考文献

Next.js公式サイト

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

Rails で HTTP DELETE メソッドを使える条件

はじめに

Rails では RESTful な設計とするために各種 HTTP リクエストメソッドを使い分けていて、config/routes.rb では当たり前に DELETE メソッドを定義すると思います。

が、このルーティング、正しく機能するためには条件があります。その条件を満たしていないと正しく動作しません。

結論

jquery-ujs.js もしくは rails-ujs.js が読み込まれていることが条件です。これら JavaScript がトリックによって DELETE をエミュレートしています。

トリックの正体と有効/無効

一般的にブラウザでは GET と POST しか使えません。DELETE リクエストは送信されないので、当該ルートが発現することはありません。例えば link_to method: :delete と書いたとしてもブラウザの素の能力では GET が送信されてしまい、最悪誤動作を引き起こします。

そこで前述 JavaScript が上手いことやって「DELETE のつもりでリクエストするんだぜ」というのを伝えることで、DELETE メソッドではないものの DELETE ルートを発現させています。具体的には form オブジェクトを作って「本来の意図は DELETE だよ」というパラメータを添えて POST しています。

そしてこのトリックは普通に rails new すれば自動的にお膳立てされ有効になります。

が、rails new --skip-javascript すると無効になります。JavaScript に依存しているんだから当たり前ですね。そして前述のように link_to method: :delete は GET になってしまうのです。

手作業でトリックを有効にする方法

何らかの事情で rails new --skip-javascript しなければならない場合に手作業でトリックを有効にする方法は、下記です。各ファイルに各行を追記します。

app/assets/javascripts/application.js
//= require rails-ujs
app/views/layouts/application.html.erb
    <%= javascript_include_tag 'application' %>

別法あります

ここまでは前置きです。
ここからが本題です。

JavaScript を使わなくても DELETE ルートを使うことは出来ます。button_to method: :delete です。

JavaScript が生成している form を静的に生成すればいいわけです。

より link_to ぽく

button_to では input type='submit' が1つ(と input type='hidden' が幾つか)の form が生成されますが、class='button_to' になっています。さらに例えば button_to class: :anchor とすると input type='submit' class='anchor' になります。

生成される.html
<form class="button_to" method="post" action="/logout">
  <input type="hidden" name="_method" value="delete" />
  <input type="hidden" name="authenticity_token" value="ナイショ" />
  <input class="anchor" type="submit" value="LOGOUT" />
</form>

なので、下記のような CSS (SCSS) を書いてやれば、機能も見た目も link_to の代わりに使うことが可能です。

app/assets/stylesheets/custom.scss
form.button_to {
  display: inline;

  input.anchor[type='submit'] { |
    border-style: none;
    padding: 0;
    font-size: 1em;
    cursor: pointer;
    background-color: $bg-color;
    color: $link-color;
  }
}

終わりに

もともと --skip-javascript なんて使ってなかったんですが、Rails 6 が Webpacker で yarn や node_modules 必須になってたものの取り急ぎ小さく new したかったので --skip-javascript したら一旦良さそうだったけど logout 出来ず「!?」となって、、、ここに至りました。

静的最高♪

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

シンプルなプログレスバーを作成してみた

簡素な物ですが、
シンプルなプログレスバーのCSSスニペットを作ってみたので投稿。

プログレスバーとは?

プログレスバー(英: Progress Bar)とは、長時間かかるタスクの進捗状況がどの程度完了したのかを視覚的・直感的に表示するもので、グラフィカルユーザインタフェースの要素(ウィジェット)の一つである。(Wikipediaより)

youtubeの再生時間を表示しているバー、ファイルのダウンロード中の「~%完了」のバー等が代表的ですね!
今回はjQueryを使用せずにページ全体のフォームの入力状態の進捗を表す、入力フォーム用のプログレスバーを作成してみました。

作成したCSSスニペットのサンプル

下部のタブから表示を「0.5x」(スマホの場合は横画面にすると表示されると思います)に小さくしてサンプルの入力欄に文字を入力してみて下さい。


See the Pen
Simple ProgressBar
by torajiro_u (@torajiro_u)
on CodePen.


文字を入力すると、上部のバーが動きフォームの入力の進捗度合を示してくれます。
これが今回作成した機能となります。
また、上のサンプルから全体のソースの確認が可能です。

HTML部分機能内容

Javascriptのファイルを読み込ませ、「body」に「onload="taisyou()"」を設定するのみです。
「body」が読み込まれると自動でプログレスバーの動作に必要な処理が行われます。
CSSスニペットとして、導入を簡単にすることを意識して作成しました。

CSS部分機能内容

下の部分がプログレスバーに関係するcssです。

.css
/* progressbar部分
-------------------------------*/
body {
  margin: 0px;
}
.app {
  width: 100%;
  padding: 0px;
  background-color: white;
}
.progress {
  width: 100%;
  height: 10px;
  background-color: #F5F5F5;
  border-radius: 4px;
  box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
}
.progress-bar {
  transition: width 0.5s linear;
  height: 100%;
  background-color: #337AB7;
}

■「.app」がプログレスバーを配置する場所

■「.progress」がプログレスバーを表示する為の枠部分
 ・背景が白のページなので色をホワイトスモークに設定しています。

■「.progress-bar」が動作するバー部分
 ・transitionがバーが伸び縮みする際のアニメーションの設定です。
 ・フォーム入力時のjsの処理の結果、ここにwidthの%を設定することでバーを伸び縮みさせています

JS部分機能内容

処理部分です。

.js
var step;
var forms = document.querySelectorAll("form");
var allinp = 0;
var p;

function taisyou(){
  p = new Progress(0);
  for(var i = forms.length;i--;){
    var inp = forms[i].querySelectorAll("input[type='text'],textarea,select");
    allinp += inp.length; //プログレスバーの進捗の対象を数える
    for(var j = inp.length;j--;){
      inp[j].setAttribute("onChange","koushin(this)");
    }
  }
  step = 100/allinp;//プログレスバーが一度の進捗で進む%
}

function koushin($this){//入力内容が更新されるたびにプログレスバーの進捗の状態を再計算する
  var elem = $this;
  if($this.value){
    var text = $this.value;
    elem.className = 'up';//入力内容がnullではない場合にクラス名を変更
  }else{
    elem.className = '';
  }
  var nowUp = document.getElementsByClassName('up');//変更したクラス名の数を計算
  var status = allinp - (allinp - nowUp.length);
  p = status*step;
  new Progress(p);//バーに反映させるファンクションを呼び出す
}


var Progress = (function () {
  function Progress (p) {
      this.bar = document.querySelectorAll('#prog-bar > .progress-bar')[0];
      this.p = p;
      this.update();
    };
    Progress.prototype.update = function () {
      this.bar.style.width = this.p + '%';
    };
    return Progress;
}());

■「taisyou()」ファンクション
 ・bodyが読み込まれると同時に処理が走ります。
 ・バーの進捗を初期化(0%)します。
 ・form配下のinput等バーの進捗に影響を与えさせる要素の数を算出します。
 ・100をバーの進捗に影響を与える要素の数で割り1進捗で何%進むか設定します。
 ・バーの進捗に影響を与える要素に「onChange="koushin(this)"」イベントを設定します。

■「koushin($this)」ファンクション
 ・onChangeイベントが設定された箇所に入力が行われる度に処理を実行し入力
内容を確認します。
 ・入力内容がnullではない時にクラス名を「up」に変更します。
 ・ページ内の「up」と名前のついたクラスの数を確認し、その時バーは何%の進捗か計算します。
 ・バーに進捗を反映させるファンクションに算出した%を渡します。

■「Progress(p)」ファンクション
 ・「koushin($this)」ファンクションで算出したバーの進捗率(p%)を「.progress-bar」のwidthに設定することでバーを動作させます。

最後に

今回作成した機能はとてもシンプルかつ、ほぼ最低限度動作するだけのものなので
入力の進捗率によってバーの色を変えてみたり等色々改修を加えていくのも面白そうだなと思いました。

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

【html】共通パーツを別ファイル化してjQueryで読み出し+パーツにjsを効かせる方法

はじめに

htmlでヘッダーやフッターを共通パーツ化する方法

こうしたことは最近ではVue.jsなどでラクに実現できてしまいますが、今回はプログラマじゃなくても保守できるように。。ということが推奨されたため、できるだけ簡素な方法で実装しました。
そして、ヘッダー部分で必要なjsが何故か読み込めず相当ハマってしまったのでその解決法もあわせて記述します。

手順

以下の方の記事が一番わかりやすく実行しやすかったです。
https://qiita.com/sho11hei12-1998/items/e9c81db697fb5d51e2af

切り分けた先の共通パーツでは、idをあらためて指定しなくてもindex.html内で指定しておけばいい感じに読み込んでくれるようです。
header内のmenuWrap部分をクリックすることで、メニュー(panel内の部分)を開閉できるようにしたい、というのが主に実現したいことです。

index.html
<!DOCTYPE HTML>
<head>
  <link rel="stylesheet" media="all" href="css/style.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"> </script>
  <script src="js/script.js"></script>
</head>
<html>
  <body>
    <!-- header.html -->
    <header id="header"></header>
    <div>
      <h1>中身(コンテンツ)</h1>
    </div>
    <!-- footer.html 今回は使いません -->
    <footer id="footer"></footer>
  </body>
</html>
header.html
<!-- header共通ファイル -->
<div id="headerWrap">
    <h1><a href="index.html"><img src="images/logo.png" width="284" height="160" alt="logo"></a></h1>
    <nav id="mainnav">
        <p id="menuWrap">
          <a id="menu"><span id="menuBtn"></span></a>
        </p>
        <div class="panel">
            <ul>
                <li><to><a href="index.html">トップページ"</a></to></li>
                <li><to><a href="about-us.html">ご挨拶</a></to></li>
                <li><to><a href="archives.html">業績</a></to></li>
                <li><to><a href="contact.html">お問い合わせ</a></to></li>
            </ul>
        </div>
    </nav>
</div>
style.css
    .panel {
        width: 100%;
        display: none;
        overflow: hidden;
        position: relative;
        left: 0;
        top: 0;
        z-index: 100;
    }
    #menuBtn {
        display: block;
        position: absolute;
        top: 60%;
        left: 50%;
        width: 18px;
        height: 2px;
        margin: -1px 0 0 -7px;
        background: #000;
        transition: .2s;
    }
    #menuBtn:before, #menuBtn:after {
        display: block;
        content: "";
        position: absolute;
        top: 50%;
        left: 0;
        width: 18px;
        height: 2px;
        background: #000;
        transition: .3s;
    }
    a#menu .close {
        background: transparent;
    }
    a#menu .close:before, a#menu .close:after{
        margin-top: 0;
    }
    a#menu .close:before {
        transform: rotate(-45deg);
        -webkit-transform: rotate(-45deg);
    }
    a#menu .close:after {
        transform: rotate(-135deg);
        -webkit-transform: rotate(-135deg);
    }
script.js
$(function(){
    // html 共通部分読み込み
    $("#header").load("header.html");
    $("#footer").load("footer.html");

    // 中略

    $('#menuWrap').on('click', function() {
        $(this).next().slideToggle();
        $('#menuBtn').toggleClass('close');
    },
    function() {
        $(this).next().slideToggle();
        $('#menuBtn').removeClass('close');
    });
});

上記では概ね必要最低限のソースのみ記述していますが、画面右側に開閉できるハンバーガーメニューのついたヘッダーを生成しました。いや、そのつもりでした。

さて、パーツ切り分けはできたけど

jsが効かなくなってしまった

ここまで書いたところでメニューの開閉が出来なくなってしまいました。あらやだ!
headerファイルを切り分ける前は正常にscript.jsを読み込み動いており、パーツを切り分けて$("#header").load("header.html");を追記した部分も正常に動いてくれるので、js全体を読み込んでいないわけではなさそう。

作業途中でjQueryのバージョンを変えた(1.8.0->1.9.1)こともあり、廃止メソッドのせいかな?と思い色々試してみるも効果なし。
あと何故かブラウザのデバッグにも引っかからず(理由はわかりません)

解決

https://webdesign-abc.com/tech/easy-edit/

大元のhtmlで使用しているjsの機能を使いたい場合は、共通パーツ内の最初に、必要なjsファイルを記述する必要があります。

大元のhtmlで読み込んでいるjsはheaderでは読み込んでくれないようです。
cssは何もしなくても正常に読み込んでくれるのでjsもそんなかんじとうっかり思い込んでました……。

jsを直接記述する

header.html
<!DOCTYPE HTML>
<!-- header共通ファイル -->
<script>
    $('#menuWrap').on('click', function() {
        $(this).next().slideToggle();
        $('#menuBtn').toggleClass('close');
    },
    function() {
        $(this).next().slideToggle();
        $('#menuBtn').removeClass('close');
    });
</script>
<div id="headerWrap">
    <h1><a href="index.html"><img src="images/logo.png" width="284" height="160" alt="logo"></a></h1>
    <nav id="mainnav">
        <p id="menuWrap"><a id="menu"><span id="menuBtn"></span></a></p>
        <div class="panel">
            <ul>
                <li><to><a href="index.html"><img src="images/toppage.png" width="130" alt="トップページ"></a></to></li>
                <li><to><a href="about-us.html"><img src="images/introduce.png" width="130" alt="楽団紹介"></a></to></li>
                <li><to><a href="archives.html"><img src="images/archives.png" width="130" alt="過去の演奏会"></a></to></li>
                <li><to><a href="contact.html"><img src="images/inquiry.png" width="130" alt="お問い合わせ"></a></to></li>
            </ul>
        </div>
    </nav>
</div>

開閉できた!

見やすくするため画像にグレー背景をつけています
menu_openアートボード 1.png

所感

今回のようにファイル切り分けてjs読み込むとか、DOM操作して生み出したパーツにjsを当てるときの特殊なお作法とか、js(およびjQuery)はわりと引っかかりやすいポイントありますね……。
慣れなのかな。

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

AnalyserNodeのサンプルを動かしてみた

MDN の AnalyserNode のサンプルコードは入力の部分が省略されていたため、マイクから音を拾うようにして動かしました。

あ.png

埋め込みだとマイクがうまく動かないので、動作確認は CodePen を開いてください。

【追記】 同時に getByteFrequencyData による周波数分析を行うサンプルを作成しました。

概要

MDN に AnalyserNode のサンプルコードが掲載されています。

var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var analyser = audioCtx.createAnalyser();

  ...

analyser.fftSize = 2048;
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
analyser.getByteTimeDomainData(dataArray);

(略)

Voice-change-O-matic デモからの引用だと記載されていますが、残念ながらそのデモは使い方が分かりませんでした。

【追記】 MDN 日本語版の情報が古いようです。英語版からリンクされている https の方は動きました。

そこで ... の部分を補って動くコードにします。

【追記】 少し違う API ですが、英語版に完全な形でのサンプルがありました。MP3 を読み込む仕様です。

追加箇所

Canvas とボタンとエラーメッセージ用の span を用意します。

<canvas id="canvas" width="500" height="200" style="border:1px solid #000000;"></canvas><br>
<button id="startButton">Start</button>
<span id="errorMessage"></span>

Canvas 関係の変数と、ボタンをクリックするとマイクから入力を開始するコードを補います。

let canvasCtx = canvas.getContext("2d");
let WIDTH = canvas.width;
let HEIGHT = canvas.height;

let stream;
startButton.onclick = async function () {
  if (stream) return;
  try {
    stream = await navigator.mediaDevices.getUserMedia({
      audio: true
    });
    audioCtx.createMediaStreamSource(stream).connect(analyser);
  } catch (err) {
    errorMessage.textContent = err.toString();
  }
};

これでとりあえず動くようになりました。

参考

同じ MDN を参照している記事を参考にしました。

API の変更に伴い、以下の個所を修正する必要がありました。

    //様々なブラウザでマイクへのアクセス権を取得する
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;

【参考】 「MediaDevices.getUserMedia() 」について

以下の個所で別の API を呼んでいるため、表示される波形が別の形になります。

        analyser.getByteFrequencyData(data);

描画の度にバッファを確保していたため、メモリ使用量がどんどん増加しました。

        var bufLen = analyser.frequencyBinCount;
        var data = new Uint8Array(bufLen);

マイクからの入力がそのまま出力に接続されているため、自分の声がそのまま再生されてハウリングの原因になっていました。

        analyser.connect(audioCtx.destination);

この部分を外しても動作しました。

1つのAnalyzerNodeは必ず1つの入力と出力を持ちます。出力先がなくてもAnalyzerNodeは問題ありません。

色々と書きましたが、まず動くコードが欲しかったので、非常に助かりました。

Python

今回はブラウザで JavaScript を使いましたが、方法を調査しているときに Python を使った記事を見掛けたので、メモしておきます。

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

Laravel Telescopeのタイムゾーンを強制的に日本時間にする

LaravelのTelescopeにおいて、タイムゾーンを指定してるにもかかわらず日本時間表示ができなかったので、強制的に変えてみました!

localTime()を下記のように修正

vendor/laravel/telescope/resources/js/base.js
        localTime(time) {
            return moment.tz(time,'Asia/Tokyo')
                .format('YYYY-MM-DD HH:mm:ss');
        },

   cd /LARAVEL_PATH/vendor/telescope
   npm run prod 
   cd /LARAVEL_PATH
   php artisan telescope:publish --force

cross-envをインストールする必要あり
ない場合は

npm install cross-env

以上です(^^)

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