20200414のJavaScriptに関する記事は19件です。

HTML / CSS から Nuxt.js で webアプリを開発するまでのロードマップ

はじめに

この記事では、HTML / CSS から学び、Nuxt.js で webアプリを開発するまでの過程を紹介します。

本記事は、以下のような方が対象です。同じ初学者を意識しています。

  1. web開発に興味がある。
  2. HTML / CSS を学んだが、そこからどうすれば良いか謎。不可思議。
  3. フレームワークとは何ぞや。フレームワークのフレームワーク?
  4. どこまでやれば、どういうものができるのか具体的に知りたい。
  5. とりあえず、web開発に興味はあるよ。

その道の方でも、「趣味で学ぼうとする人は、こういう学び方をしているんだな」と参考になるかもしれません。

筆者であるうたかたは、web開発を始めて早2ヶ月ですが、わからないことでいっぱいです。基本的に表面的な理解に終始しています。ただ「初学者でも、今あるものを使うと、こういうものができるよ」という具体例とその学習過程を紹介することで、何か少しでもお役に立てたらと思います。Qiita も利用し始めたばかりなので、何かありましたら色々とご指摘いただけると助かります。

開発中の音楽SNS「UTAKATA」の紹介・解説動画を YouTube に投稿しているので、「この記事で紹介しているもの(Vue.js・Vuetify.js・Nuxt.js・Firebase)を学ぶと、少なくともこういう webアプリを作ることができるよ」という具体例として参考にしていただければと思います。近日中にベータ版(?)を公開する予定です。

最後に、本記事は各言語・フレームワークについて詳細な解説をするものではありません。「何を学べば良いかわからない」「何を学べば、何ができるかわからない」という方に、一つの指針を提供することが目的です。

少し前置きが長くなりましたが、最後までお読みいただけると嬉しいです。

ロードマップ

これまでの学習の軌跡を振り返りつつ、web開発のロードマップを紹介します。

学習の流れは、HTML / CSS → JavaScript → Vue.js & Firebase → Vuetify.js → Nuxt.js でした。

学習期間と内容は、概ね以下の通りです。

  • 前半(1ヶ月):HTML / CSS / JavaScript の基本を学び、その後何を学べば良いか調べてた。もはや「web開発」とは何ぞや状態。そして今も。
  • 後半(1ヶ月):Vue.js → Firebase → Vuetify.js → Nuxt.js の存在を辿り、動画を見て、公式ドキュメントを見ながらコードを書いた。

主に前半は The Net Ninja さんの動画(YouTube & Udemy)、後半は公式ドキュメントを頼りにしています。

The Net Ninja さんについては、偶然見つけただけで、特に深い理由はありません。運命の出会いでした。英語ですが、とてもわかりやすいです。このわかりやすさに慣れると、少しつらいものもあります。ストリートファイターの春麗(Chun Li)が好きみたい。マリオも出てくる。ほぼ全て無料で見ることができるのには、感謝しかないです。謝謝。

「どこまでやれば、どういうものができるのか」が想像もできなかったので、一度動画を(コードを書かないで)見るだけみて、Nuxt.js に行き着いてから、公式ドキュメントを参照しつつ、コードを書き始めました。

この記事を参考にする場合も、一度最後まで読み通して見通しをつけてから、各言語・フレームワークを学習し始めると良いと思います。知らない用語が出ても、「そういうものがあるんだね」と思って進んでください。知らないことばかりですもん。

学習項目は以下の通りです。

  • HTML
  • CSS
  • JavaScript
  • Vue.js:JavaScript のフレームワーク。
  • Vuetify.js:Vue.js のデザイン担当。
  • Nuxt.js:Vue.js の開発環境・機能強化担当。
  • Firebase:ユーザー認証(登録・ログイン)やデータベースを管理。

1. HTML / CSS

自分は「Flexbox とは何ぞや」という人間だったので、以下の動画も見ました。あとで紹介する Vuetify.js で採用されている Grid システムをそのまま理解することができます。

動画が洗練されていくのを肌で感じることができるのは、複数見た人の特権です。

今回紹介している動画は有料(Udemy)2つを含みますが、それ以外はほぼ全て無料なので、ぜひ覗いてみてください。

最近では、Firebase Functions に関するシリーズ(無料)が投稿されていたようです。まだ見ていませんが、きっと参考になると思います。

2. JavaScript

フルバージョンは Udemy(有料) で公開されています。動画の説明欄にクーポン付きのリンクがあるので、そちらからご利用ください。

基本的な文法(「こうやって書くよ」)・関数(「こういうことがしたい時、こういう機能があるよ」)・概念(「こういう考え方で、コードを組み立てるよ」)を一通り学ぶことができます。

学習の指針としては、動画を見て基本的な概念を理解しつつ、文法・関数(の存在)を何となく知っておきます。実際にコードを書く段階で、その関数名やしたいことで検索して、例を見ながら書きます。「検索できるようになる」こと、そして「書かれている内容を理解できるようになる」ことが大事だと思います。全てのコードを覚えておく必要はありません。未だに何でも調べてます。

この後も基本的に、動画を見て何となく理解する → ドキュメントを参照してコードを書くという流れです。

3. Vue.js & Firebase

Udemy(有料)で公開されている動画の紹介動画です。動画の説明欄にクーポン付きのリンクがあるので、そちらからご利用ください。

web開発を学ぶのにかけた費用は、以上の動画2つ分(約2400円)です。
安いと思います。感謝しかないです。

Vuex については、以下の動画(無料)を参考にしました。

Vue については、以下のサイトも参考になりました。Vuex についての記事を載せておきます。目を通せてはいないですが、初学者にも、とてもわかりやすい解説です。謝謝。

一応、Firebase [Firestore/Storage] セキュリティルールの具体例を以下の記事で紹介しています。とても参考になったブログ・記事についても触れているので、いつの日か覗いてみてください。喜びます。

4. Vuetify.js

使用しているコンポーネント(デザインを形作るパーツ。Buttonコンポーネントなど)や使い方が古い場合もありましたが、コメント欄で有志により全て補足されていました。

コードを書くときには公式ドキュメントの例を見ながら書くので、まずは動画で雰囲気を掴めれば良いと思います。その点で、とても参考になりました。

5. Nuxt.js

存在は Vuetify.js の公式ドキュメントで知りました。

Nuxt.js については、はじめから公式ドキュメントのガイドに沿って何となく理解していきました。一応、Vue School の動画も見たと思います。

Vue.js・Vuetify.js・Nuxt.js・Firebase は、いずれも日本語の公式ドキュメントが充実しているので、動画を見て雰囲気を掴んだら、そのまま公式ドキュメントを読むと何となく理解できます。どんなにわかりやすいサイトがあっても、参照しているのは最終的に公式ドキュメントのはずなので、それを読むことで安心感を得るのです。公式ドキュメントのわかりにくいところは、検索すれば先人が知恵を貸してくれます。

おわりに

この記事では、HTML / CSS から学び、Nuxt.js で webアプリを開発するまでの過程を紹介してきました。

「何があるかわからない」「何から手をつけていいかわからない」という方の参考になれたら幸いです。

web開発を学ぶ上で、数多くのサイト・記事を参考にさせていただいています。本記事では全て列挙することはできませんが、この場を借りてお礼申し上げます。いつもありがとう。謝謝。

趣味で NCS 等の和訳を YouTube に投稿しているので、よければそちらもご覧ください。
YouTube チャンネル:うたかた / UTAKATA

少し長くなりましたが、ここまで読んでいただきありがとうございました。ではでは!

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

謎解き用メモ#1 パスワード

脱出ゲームの謎解きでよくある、3つの数字を入れると進めるやつ

nazotoki.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="nazotoki.css">
    <title>謎解きWEB</title>
</head>

<body>
    <div id="app">
        <input type="text" v-model="keyWord">
        <button v-on:click="onclick">ボタン</button>
        {{message}}
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="nazotoki.js"></script>
</body>
</html>
vue.js
new Vue({
    el: '#app',
    data: {
        message: 'hello',
        keyWord: ''
    },
    methods: {
        onclick: function(){
            if (this.keyWord === '000'){
                this.message = 'good';
            }else{
                this.message = 'bad';
            };
        }    
    }
});


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

生JavaScriptでFizzBuzz問題とナベアツ問題を解く方法【jQuery未使用】

JavaScriptで分からないことを調べてもjQueryを使用した例ばかりしか出てこずに困った経験があったので、生のJavaScriptでナベアツ問題を解く方法についてまとめます。

FizzBuzz問題

JavaScriptを使って1から100までの数字を順番にconsole.logで出力する。
ただしその数が3で割り切れるなら"Fizz“、5で割り切れるなら"Buzz“、両方で割り切れるなら"FizzBuzz"をそれぞれ数字の代わりに出力する。

FizzBuzz問題の解答コード

function fizzbuzz() {
    for (let i = 1; i <= 100; i++) {
        if(i % 3 === 0 && i % 5 === 0) {
            console.log("FizzBuzz");
        } else if(i % 3 === 0) {
            console.log("Fizz");
        } else if(i % 5 === 0) {
            console.log("Buzz");
        } else {
            console.log(i);
        }
    }
}
fizzbuzz();

ナベアツ問題

ナベアツ問題とは、FizzBuzz問題のように1-100までの数字で、3がつく数字と、3の倍数のときに「!」を表示させる学習のための練習問題です。

ナベアツ問題の解答コード

まずは解答となる生JavaScriptでのコードをお見せします。

なんでもそうですが、コード記述方法は他にもありますので、あくまでも一例としてご参考ください。

'use strict'
const nabeatsu = () => {
    for (let i = 1; i <= 100; i++) {
        if(i % 3 === 0) {
            console.log(i + "!");
        } else if(i.toString().match(/3/)) {
            console.log(i + "!");
        } else {
            console.log(i);
        }
    }
}
nabeatsu();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ド素人がLINE botを公開してみた

プロトアウトスタジオという、プログラミングスクールではなく、プロトタイピングをアウトプットするというスクールに参加し始めた人の記事です。

授業にて、「heroku」というPaaSサービスにソースコードをのせて動かす体験をしました。
サーバとかOSとか、プログラムを動かすための環境づくりに必要な知識をすっ飛ばしていきなりサービスを無料で動かせる時代になっているのですね。

今回の宿題は「HerokuでNode.jsの仕組みをURLを公開しチャットボットを移植しアウトプットする」です。以前の宿題「LINEbot+API」に挑戦した際のコードに少し手を加えて、「いぬ」とリクエストすると犬の画像をレスポンスするLINEbotをherokuに乗せて公開します。

QR.png

'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
const PORT = process.env.PORT || 3000;

const config = {
    channelSecret: 'ここにはLINEbotのチャンネルシークレットを書く',
    channelAccessToken: 'ここにはLINEbotのチャンネルアクセストークンを書く'
};

const app = express();
let requetText='';

app.post('/webhook', line.middleware(config), (req, res) => {
    requetText=req.body.events[0].message.text;
    Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

const client = new line.Client(config);

function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  let mes = 'ちょっとまってね'; // 待ってねってメッセージだけ先に処理

  getQiitaTag(event.source.userId , event.message.text); // スクレイピング処理が終わったらプッシュメッセージ

  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: mes
  });
}

const getQiitaTag = async (userId,tag) => {
    let mes = '';
    try {
        if(requetText==="いぬ"){
        const res = await axios.get('https://random.dog/woof.json');
        const item = res.data.url;
        mes = item;
        }else if(requetText==="しばいぬ"){
        const res = await axios.get('http://shibe.online/api/shibes?count=1&urls=true&httpsUrls=true');
        const item = res.data[0];
        mes = item;
        }else{     
        mes = "いぬしかわかりません";
        }


    } catch (error) {
        // 該当しないものは404でエラーになる
        const {
            status,
            statusText
        } = error.response;
        console.log(`Error! HTTP Status: ${status} ${statusText}`);
        if( status == 404 ){
            mes = 'Qiitaのタグ「' + tag + '」の記事はありませんでした';
        } else {
            mes = `Error! HTTP Status: ${status} ${statusText}`;
        }
    }

    await client.pushMessage(userId, {
        type: 'text',
        text: mes,
    });
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);

リクエストが「しばいぬ」だった場合には柴犬APIを呼んで柴犬画像をレスポンスするif文も入れてみました。

今回授業にて、ExpressにおいてHTTPSのpostリクエストを投げる際の処理を学んだことから、LINE上で何か打ち込まれた際それがwebhookに対するpost通信であるため、

app.post('/webhook', line.middleware(config), (req, res) => {
    requetText=req.body.events[0].message.text;
    Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

という関数が実行されるのだと気づきました。
一方で「Promise~」以降のコードが何を表しているのかサッパリなので、Promiseについて調べてみます。

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

元に戻せるほうのカリー化入門

想定読者

高階関数、カリー化、部分適用、クロージャ
などの言葉を目にするたび不安になってしまい
それぞれの意味を何度も調べてしまう人へ1

カリー化の反対にあたる逆カリー化に焦点を当て、
もう忘れないように理解をまとめておきたい。

高階関数

引数もしくは戻値が関数であるとき
その関数を高階関数と呼ぶらしい。

高階関数
const apply = f => x => f(x)

関数 apply は1引数関数 f を引数に取って
関数 x => f(x) を返すので高階関数と言える。

関数の関数という構造は何となく神秘的で
特別な名前を付けたくなる気持ちは分かる。

しかし、本質的に重要なのは
数値などと同じように関数を扱えること2
なのではないかと個人的には思う。


引数もしくは戻値が数値であるとき
その関数を数値関数と呼んでみよう。

数値関数
const succ = n => n + 1

関数 succ は数値 n を引数に取って
数値 n + 1 を返すので数値関数と言える。

それはそうであると感じるのではないだろうか。
高階関数もその程度の理解で良いと思われる。

カリー化と逆カリー化

カリー化と逆カリー化は
変換と逆変換の関係に相当する。

変換してから逆変換すると元に戻る3
カリー化とは元に戻せる変換である。

変換

カリー化とは次のような変換のことだ。

カリー化
const curry = f => x => y => f(x, y)

高階関数 curry は2引数関数 f
高階関数 x => y => f(x, y) に変換する。

例として、次の2引数関数 add を考える。

足し算
const add = (x, y) => x + y

当然ではあるが add(2,3) $=$ 5 となる。
カリー化された高階関数 curry(add)
同様に curry(add)(2)(3) $=$ 5 である。

逆変換

逆カリー化とは次のような逆変換のことだ。

逆カリー化
const uncurry = g => (x, y) => g(x)(y)

高階関数 uncurry高階関数 g
2引数関数 (x, y) => g(x)(y) に逆変換する。

例として、次の高階関数 add を考える。

足し算
const add = x => y => x + y

当然ではあるが add(2)(3) $=$ 5 となる。
逆カリー化された2引数関数 uncurry(add)
同様に uncurry(add)(2, 3) $=$ 5 である。

変換と逆変換

再び例として、次の2引数関数 add を考える。

足し算
const add = (x, y) => x + y

変換 curry逆変換 uncurry に対して
add(2, 3) $=$ uncurry(curry(add))(2, 3) $=$ 5
が成り立つことを確認できるだろう。

これは任意の引数 (x, y) に対して成り立ち、
add $=$ uncurry(curry(add)) である4


任意の2引数関数 f に対して、
カリー化された関数 curry(f)
逆変換 uncurry で元の関数 f に戻せる。

カリー化

2引数関数
const add      = (x, y) => x + y
const mul      = (x, y) => x * y
const constant = (x, _) => x

変換により fcurry(f)1対1対応する。

部分適用

部分適用とは次のような変換のことだ。

部分適用
const papply = (f, x) => y => f(x, y)

高階関数 papply は2引数関数 f と引数 x
(f, x) を1引数関数 y => f(x, y) に変換する。

例として、次の2引数関数 mulconstant を考えよう。

掛け算と定数
const mul      = (x, y) => x * y
const constant = (x, _) => x

第1引数に 0 を部分適用すれば以下となる。

部分適用
const mul0      = papply(mul, 0)
const constant0 = papply(constant, 0)

この関数 mul0 は全てを 0 にする。
[1, 2, 3].map(mul0) $=$ [0, 0, 0]

また関数 constant0 も全てを 0 にする。
[1, 2, 3].map(constant0) $=$ [0, 0, 0]


上記の関数 mul0constant0
変換 curry を用いて次のようにも書ける。

部分適用
const mul0      = curry(mul)(0)
const constant0 = curry(constant)(0)

変換 papplycurry は、確かに似て見えて、
同じことをしていてるように感じるかもしれない。

ここで注目すべきは mul0constant0
元の (mul, 0)(constant, 0) に戻せるかどうかだ。


関数 mul0constant0 は全てを 0 にする。
つまり mul0 $=$ constant0 であることに注意しよう。

例えば部分適用された関数 mul0 の逆変換を試みても、
(mul, 0)(constant, 0) のどちらに移せば良いか
分からないため、元の (mul, 0) に戻せない。

部分適用

2引数関数
const add      = (x, y) => x + y
const mul      = (x, y) => x * y
const constant = (x, _) => x

変換と逆変換で見たような1対1対応こそが
元に戻せるという性質をあらわしている。

クロージャ

環境とラムダ式(アロー関数)の両者を
合わせたものをクロージャと呼ぶらしい5

クロージャ
{
  let a = 2
  let b = 1
  const closure = x => a*x + b
}

関数 closure の中では宣言されておらず
外の環境で宣言されているような変数 ab
関数の宣言時に閉じ込めるイメージだろうか。

変数 ab をグローバル変数だと思えば、
次のような関数もクロージャと考えられるだろう。

クロージャ
const closure = x => a*x + b

変数の数はいくつでも良いと思うので、
たまたま0個な次のような関数もクロージャだろう。

クロージャ
const closure = x => 2*x + 1

クロージャと関数を同一視してしまっても
実用上はなんの問題もないような気がする。


狭義には次のような高階関数 enClosure の戻値
すなわち関数 closure をクロージャと呼ぶだろう。

エンクロージャとクロージャ
const enClosure = (a, b) => {
  const closure = x => a*x + b
  return closure
}

これを次のように書けば、単なる高階関数に見える。

エンクロージャとクロージャ
const enClosure = (a, b) => x => a*x + b

やはりクロージャと関数を同一視しても良さそうだ。


クロージャの例としてよく見るカウンターを考えよう。

カウンター
const newCounter = count => {
  const counter = del => {
    count = count + del
    return count
  }
  return counter
}

これまでと異なり変数 count は可変だが、
高階関数 newCounter の戻値 counter
クロージャと呼んでいるに過ぎないだろう。

少し苦しいが次のように書けば、単なる高階関数だ。

カウンター
const newCounter = count => del => count = count + del

クロージャとは関数だと理解しておくことにする。
そのほうが覚えるべきことが減って簡単なはずだ。

まとめ

カリー化と部分適用の違いについては
分かりやすい解説がたくさんあるけれど、
特に1対1対応を重視したような解説は
見つけることができなかったので書いてみた。

タイトルに関しては次記事のリスペクトです。
「食べられないほうのカリー化入門」(2013-07-22)

食べ物のカレーを元の材料には戻せないので、
元に戻せるかどうかでもカレー化とカリー化の
両者を区別することが可能だと思いました。


  1. おもに自分のためであり、言うまでもないが、記述の正しさは保障できない。 

  2. 関数が第一級オブジェクトであること。関数の集まりが型であること。 

  3. 逆変換してから変換すると元に戻る。どちらを逆と呼ぶかは趣味の問題だろう。 

  4. 任意の引数に対して戻値が等しいとき2つの関数は等しい。 

  5. 檜山正幸のキマイラ飼育記 (はてなBlog)「結局、クロージャって」(2007-05-29) 

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

Webを使った新人研修 ~SQL基礎編・SELECTクエリでデータ検索~

Webを使った新人研修 ~SQL基礎編~

SELECTクエリでデータ検索

細かい説明をしていては果てしないので、「習うより慣れろ」の精神で
まずは、「実践」してみましょう。

実践する

Ideoneをブラウザで開いてみましょう。

右下の緑色ボタン「Run」を押してみましょう。

create table tbl(str varchar(20));
insert into tbl values('Hello world!');
select * from tbl;

これをforkしてみても良いです。

解説

例題を示して記憶の定着を図ってみます。

例題

1.〜


~本日はここまで

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

[超感覚C3講座] Webで掲示板を作ろう

新入生のみなさん.
こんにちは.
rkun( @rkunkunr )と申します.

クルマとバイクとアニメが好きなキモオタです.よろしくおねがいいたします.あずにゃんぺろぺろ.

突然ですが

みなさん.2ちゃんねるって知ってますか?

掲示板ですね.まあ最近私もあんまり見ることないです.Twitterでいいよねってなります.

Twitterは「会員制交流サイト」と言われる通り,アカウントを作ってそのアカウントから投稿するというプロセスを取りますが,
掲示板はその都度名前を決め(というか決めずにランダム生成させることもある),ただただ投稿するというシンプルな構造をしていますね.

Twitterみたいなアカウント制のWebアプリを作るのは手間がかかりますが,掲示板は比較的簡単に作ることができます.

というわけで,今回は皆さんに
JavaScriptを使って
C3超感覚掲示板の一部を作ってもらいたいと思います.

JavaScriptのおべんつよ

JavaScriptとはプログラミング言語です.Web上で動かせるやつで,阿部寛のホームページみたいな骨董品じゃなければ大体どんなサイトでも使われています.

とりあえずちょっと簡単に書き方を説明したいと思います.

コードの中の行頭が//のやつはコメントというやつで,実行するときには無視されるやつです!

文字や数字の表現の仕方

// 整数
123

// 小数
123.456

// 文字列
"今日も一日,がんばるぞい!!"

変数の宣言・代入

変数とは,値を入れる箱です.

// 変数の宣言
var text;

// 変数への値の代入
text = "hogehoge";

// 宣言と代入を同時に
var text = "hogehoge"

if文

if文は,条件分岐をするときの書き方です.

var age = 18;
if(age >= 20) {
  // 20歳以上
  console.log("飲酒OK!!");
}else{
  // 20歳未満
  console.log("飲酒NG!!");
}

// Console: 飲酒NG!!

この
today >= 20は,「todayが20以上」という意味です.

関数

関数とは,引数を受け取り,返り値を返す(返さなくてもいいよ)処理の塊である.

// 関数を作る
function add(a, b) {
  console.log("Called!!");
  return a + b;
}

// 関数を利用する
var result = add(4, 5);

console.log(result);
// Console: 9

配列

配列とは,変数がいっぱい列になって入っているもの

// 作り方(a, b, cを入れておく場合)
var array = ["a", "b", "c"];
// 作り方(何も入れておかない場合)
var emptyArray = [];

// (注意!!) 最初は0から始まる
array[0];
> "a"
array[1];
> "b"
array[2];
> "c"

配列のforEach()

JavaScriptの配列には面白い機能がある.

var members = ["", "", "", "", ""];

keionClub.forEach(function(m) {
  console.log(m + "ちゃんカワイイ!!");
});

// Console:
//   唯ちゃんカワイイ!!
//   律ちゃんカワイイ!!
//   澪ちゃんカワイイ!!
//   紬ちゃんカワイイ!!
//   梓ちゃんカワイイ!!

DOM

さっき,JavaScriptはWebサイトに動きをつけるものだといいましたね.あれは嘘ではありません.
HTMLの中にこんな要素があったとします.

<div id="title">CompositeComputerClub</div>

これをJavaScript上で操作するために,この要素と対応したJavaScriptのオブジェクトが用意されています.

var titleElem = document.getElementById("title")

で取得ができます.

このオブジェクトにはたくさんの変数と関数が入っており,例えば

titleElem.innerHTML = "CompositeConstructionClub"

とすることでHTMLの表示を変更できます.部室とか自作してそうですね.

JQuery(時間余ったら話す)

ボタンを押したら入力しておいたメッセージを出すコードをJavaScriptで書いてみましょう.

HTML

<input type="text" id="msg_text"></input>
<button id="msg_button">Message</button>

JavaScript

document.getElementById("msg_button").addEventListener(function(e) {
  alert(document.getElementById("msg_text").value);
});

このgetElementByIdとかaddEventListenerが長くて書く気が失せますよね.

そこでどこかのえらいひとがJQueryというものを作りました.これを使うと,

$("#msg_button").click(function(e) {
  alert($("#msg_text").val());
});

となります.短いですね.
ほかにもJQueryを使うととても便利なので,掲示板にも採用しています.

C3超感覚掲示板

作り方

あらかた作っておいたので,皆さんには一部を考えて実装してもらいます.

CodePenについて

今回はCodePenというサービスを利用します.
https://codepen.io
ここのアカウントを作っておいてください.

(Forkせずにそのまま編集することも可能ですが,間違えてブラウザのタブを削除したときになにもかもどうでもよくなるので,ログインしてやることをおすすめします!!)

[超感覚Discordを参照]

ここにアクセスし,右下のForkボタンを押します.
ForkButton.png

これで,未完成のC3超感覚掲示板のコピーが自分のアカウントに作られます.

Consoleを活用しよう

Codepenの左下にConsoleというボタンがあるので,クリックしてみましょう!!

scrot-20200424_223023.png

こういうのが出ましたか?

これは,Consoleというやつです.

ここにJavaScriptでconsole.log("メッセージ”)したものが表示されます.

開発のときにとても便利なので表示した状態で作っていきましょう!!

実装

実際に実装していきましょう!!!
右側の「JS」画面を使っていきます.

投稿を表示する機能(30行目)

ここで実装してほしい機能

  1. var postBox = generatePostBox(username, created_at, text) を呼び出して投稿Boxを新しくつくり postBox 変数へ代入する.
  2. prependPostBox(postBox)を呼んで
  3. 挿入後,postBox.hide().fadeIn() をつかってフェードインさせる.

投稿を送信する機能(57行目)

ここで実装してほしい機能
  • 変数 username : 投稿ユーザー名
  • 変数 text : 投稿内容
  1. もし内容が""であれば,(if文)

    • showEmptyAlert() を行う.
  2. 内容が空でなければ送信してOKなので,(else)

    • db.post(username, text)で送信する.
    • makePostFormEmpty()でフォームを空にする. ```
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

画像ファイルのアップロード時に複数のプレビュー画像を表示する【Vue.js】

ファイルアップロード時に複数の画像プレビューを表示する

題名の通りですが、今回は備忘録として、
画像アップロードを行う際に複数の画像プレビューを
Vue.jsを利用して表示する方法について書いていこうと思います。

FileAPI

FIleAPIについては以下のドキュメントを参照してください。
https://developer.mozilla.org/ja/docs/Web/API/File

実装例

<template>
  <div>
    <input
      @change="inputFileList($event)"
      multiple="multiple"
      accept="image/*"
    >
    <div
      v-for="(uploadFile, index) in updatedFileList"
      :key="index"
    >
      <p>ファイル名: {{ uploadFile.fileName }}</p>
      <p>ファイルタイプ: {{ uploadFile.fileType }}</p>
      <p>サイズ: {{ uploadFile.size.width }}×{{ uploadFile.size.height }}</p>
      <img :src="uploadFile.url">
    </div>
  </div>
</template>
<script>
export default {
  data: {
    uploadFileList: []
  }
  computed: {
    // this.uploadFileListに変更が加わった際に検知するためです
    uploadFileList() {
      return this.uploadFileList
    }
  }
  methods: {
    async inputFileList(event) => {
      // event.target.filesはファイルデータが格納されたリストです
      const fileList = event.target.files
      if (fileList === 0) {
        return
      }
      // FileAPIは、APIなので複数ファイルを扱う時は、
      // for文の中でawaitする必要があります
      for (file of fileList) {
        // ファイルデータ用のオブジェクトを用意します
        const fileData = {
          name: '',
          type: '',
          size: { width: 0, height: 0 },
          url: ''
        }
        const image = new Image()
        const fileReader = new FileReader()
        // 即時関数をawaitすることで処理の完了までループが終わりません
        await (async () => {
          fileReader.onload = async () => {
            image.src = fileReader.result
            // ファイルURL取得
            fileData.url = fileReader.result
            // 即時関数をawaitすることでfileData.sizeのデータを担保します
            await (() => {
              image.onload = () => {
                // ファイルサイズ取得
                fileData.size = { width: image.naturalWidth, height: image.naturalHeight }
              }
            })()
          }
          // FileAPIの起動
          fileReader.readAsDataURL(file)
        })()
        // 取得したファイルデータのオブジェクトをuploadFileListにpushします
        this.uploadFileList.push(fileData)
      }
    }
  }
}

おわりに

間違いや質問などありましたらコメントお願いします。

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

jQueryとeach()とreturn false

なんてないことですけど備忘録。
$('hoge').each()
なんてので総当たりする。
ifを使って判定して条件にマッチしたときに処理を止めるとき

$('.hoge').each(function(){
 if(!$(this).hasClass('active')){
  $('.fuga').removeClass('active');
  return false;
 } else {
  $('.fuga').addClass('active');
 }
});

と、「return false;」を入れる。
もしページ内の.hogeに.activeが無ければそこで処理を止める。
ページ内の.hogeに全部.activeがあればelseを通ります。

忘れていたのでここに書いとく。

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

スクロール位置でクラスを付与してくれるDelighters

delighters.png
Delighters公式サイト

スクロール位置によって、表示要素に動きを付けたい際利用できるライブラリです。
散々流行った今更のパララックスかもしれませんが、まだちょっと需要はありそうです。

この演出をGoogle先生に聞いてみたところ、jQueryを利用したライブラリばっかりがヒットしてしまいました:cry:
Delightersはピュアなjsで実装できる貴重なライブラリだと思います。

Delighters Good Points :point_up:

◉ 軽量
◉ レスポンシブ対応 - タブレット、スマホもどんとこい!!
◉ スクロール位置で指定した要素にクラスが付与されるだけ。導入がシンプルで簡単。
◉ jsによる動きの定義がない。使い慣れたCSSを利用してこちらで細かな設定が自由に定義できて嬉しい。

Delighters 使い方 :point_up:

ざっくりとした使い方です。
※慣れてる方は飛ばして下さい。Delighters公式サイトのUsageをみていただくのが一番です。

:one: scriptファイルを読み込む
公式のGitHubから落としてこれます。

<script type="text/javascript" src="delighters.js">

:two: 動かしたい要素のhtmlにdata-delighterという属性を追加する

<div class="xxxクラス名は自由" data-delighter>

:three: 自分で自由にスタイルシートで動きをつける
センスが出る腕の見せどころw ダサくなりたくない…
アニメーションの設定をします。ここでは公式のクラスを引用してます。

/* delighters.jsが読み込まれると、 [data-delighter] 属性を持っている要素それぞれに .delighter が付与されます。*/

.foo.delighter {
  transition: all .3s ease-out;
  transform: translateX(-100%);
  opacity: 0;
}

/* スクロールしてターゲットが画面上部(初期設定)から75%(初期設定)の位置にきた際 .started が設定されます。*/

.foo.delighter.started {
  transform: none;
  opacity: 1;
}

/* スクロールしてターゲットが画面下部(初期設定)から75%(初期設定)の位置にきた際 .ended が設定されます。 */

.foo.delighter.started.ended {
  border: solid red 10px;
}

Delightersカスタマイズ :point_up:

属性名や、スクロール位置で設定されるクラス名、上部もしくは下部からどれくらいの位置にするかなど変更できるそうです。

options = {
  attribute:  'data-delighter',
  classNames: ['delighter', 'started', 'ended'],
  start:      0.75, // default start threshold
  end:        0.75, // default end threshold
  autoInit:   true  // initialize when DOMContentLoaded
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nuxt.jsで初めて作成したポートフォリオをGitHub Pagesで公開しました

この記事は、「Nuxt.js ってなんですか?」な状態の人間が、やりたいことを盛り込んで作成したポートフォリオについて書いたものです。

作成したポートフォリオ

https://tayuta.github.io/portfolio/
GitHub Pages に公開しています。

https://github.com/tayuta/portfolio
ソースコードです。

キャプチャ4.PNG
キャプチャ5.PNG
キャプチャ6.PNG
キャプチャ7.PNG
キャプチャ8.PNG

作成に至った動機

ポートフォリオを作成することになったのは、社内でポートフォリオ部(正式名称:そうだポトフを作ろう! 略称:ポトフ)が発足されたことがきっかけです。
もともと業務では、JavaScriptやHTML、CSSなど、フロント系はほとんど触れあったことがなかったので、勉強になるかと思い、入部しました。

プロジェクトの作成

ポートフォリオの研究

ポートフォリオが一体どういったものか知らなかったので、ほかの人が作成しているものを片っ端から見あさりました。
また、ポートフォリオの作成だけでなく、自分でレイアウトを考えたりすることも初めてだったので、デザイン手法などについても学習しました。

【学習に利用した記事】
全部知ってる?主要なWebデザイン手法のまとめ

ポートフォリオ概要決め

つぎに、どのようなポートフォリオを作るか、なんとなく決めました。

  • SPA
  • Nuxt.jsで作成する
  • テーマは、海の中(最終的には全く違うものができました。←)
  • 以下のコンテンツを縦に並べる
    • プロフィール
    • スキル
    • これまで作ったもの(ほぼありませんが...)
    • 愛犬について(あまりにコンテンツが少なかったので後から追加)

Nuxt.js プロジェクトの作成

以下の記事を参考に、Nuxt.js プロジェクトを作成しました。
Nuxt.js を導入しよう

設定内容が少し変わっていたので、こちらの記事も参考になります。
Nuxt.js の導入 -2.8.1ver-

画面が表示できたので、あとは自分がやりたいことを好きなように盛り込みました。

盛り込んだこと

背景に泡をぷかぷかさせる

当初のテーマは海だったので、背景に泡をぷかぷかさせたいと思いました。

導入方法

bubbly-bg.js をポートフォリオに組み込みます。
GitHub : https://github.com/tipsy/bubbly-bg

※Nuxt.js の場合、JavaScriptファイルをどこに置いて、どこで読み込めばいいのか分からなかったので有識者に質問したところ、ファイルの内容を mounted にぶち込むように教わったので、そうしました。
※mounted が何なのかはもちろん分からなかったので、以下の記事を読んでなんとなく理解しました。
Vueのライフサイクルを完全に理解した

想定通りに動くことを確認した後、?ソースなので、整理をします。

index.vue
<template>
  <section class="container">
    <canvas id="bubbly"></canvas>
    <div class="body">
      <!-- 省略 -->
    </div>
  </section>
</template>
<script>
export default {
  mounted() {
    const canvas = document.getElementById('bubbly')
    const width = (canvas.width = window.innerWidth)
    const height = (canvas.height = window.innerHeight)
    const context = canvas.getContext('2d')
    context.shadowColor = '#c9ffbf'
    context.shadowBlur = 4
    const gradient = this.setGradient(context, width, height)
    const bubbles = this.setBubbles(width, height)

    const draw = () => {
      requestAnimationFrame(draw)
      this.anim(context, gradient, bubbles, width, height)
    }
    draw()
  },
  methods: {
    // メソッド内省略
  }
}
</script>
<style lang="scss">
#bubbly {
  position: fixed;
  z-index: -5;
  top: 0;
  left: 0;
  min-width: 100vw;
  min-height: 100vh;
}
</style>

以下の記事を参考にしました。
背景のグラデーションや、泡の数・動く速度を変更したい場合も、こちらが参考になります。
【JavaScript】美しい泡が漂う[Beautiful bubbly backgrounds]の使い方

背景を斜めにする

背景が斜めだとおしゃれかと思い、背景を斜めにしました。

導入方法

背景を斜めにするためには、要素全体を回転させ、その内側の要素を反対に回転させます。
ただ要素を回転させると、左右に空白ができてしまうため、横幅を大きめに指定します。

sample.vue
<template>
  <section class="container">
    <div class="contents">
      <div class="inner">
        コンテンツ
      </div>
    </div>
  </section>
</template>

<style scoped lang="scss">
.contents {
  -webkit-transform: rotate(10deg) translate3d(0, 0, 0);
  transform: rotate(10deg) translate3d(0, 0, 0);
  background-color: #ffdadf;
  width: 200%;
  margin-left: -180px;    
  .inner {
    -webkit-transform: rotate(-10deg) translate3d(0, 0, 0);
    transform: rotate(-10deg) translate3d(0, 0, 0);
    max-width: 50%;
    margin-left: 157px;
  }
}
</style>

また、このままでは、背景が横にはみ出てしまい、横スクロールが発生してしまいます。
そのため、はみ出た部分を非表示にする必要があるので、親要素である container に「overflow-x: hidden;」を指定します。

sample.vue
<style scoped lang="scss">
.container {
  overflow-x: hidden;
}
</style>

以下の記事を参考にしました。
斜めの背景を作るためのCSSは「回転させて元に戻す」で書く!

スクロールにより、要素をふわっと表示させる

要素が画面に表示されてからアニメーションを発火させるために、カスタムスクロールディレクティブを作成しました。

導入方法

まずは、plugins フォルダ内に以下のファイルを作成します。

scroll.js
import Vue from 'vue'
Vue.directive('scroll', {
  inserted: function(el, binding) {
    const f = function(evt) {
      if (binding.value(evt, el)) {
        window.removeEventListener('scroll', f)
      }
    }
    window.addEventListener('scroll', f)
  }
})

nuxt.config.js の plugins キー内にファイルパスを追加します。

nuxt.config.js
export default {
  plugins: ['~/plugins/scroll']
}

mixin.js に handleScroll メソッドを定義します。

mixin.js
export default {
  methods: {
    handleScroll: (evt, el) => {
      const top = el.getBoundingClientRect().top
      if (window.scrollY > top + window.pageYOffset - 600) {
        el.classList.add('isView')
        return true
      }
      return false
    }
  }
}

ふわっと表示させたい要素に、v-scroll ディレクティブを追加し、アニメーションを設定します。
アニメーションを変更することで、ふわっと表示以外にも、横から表示・回転しながら表示などもできるかと思います。

sample.vue
<template>
  <div v-scroll="handleScroll" class="fade-in">ふわっと表示</div>
</template>

<script>
import mixin from './mixin'
export default {
  mixins: [mixin]
}
</script>

<style scoped lang="scss">
.fade-in {
  opacity: 0;
}
.fade-in.isView {
  animation-name: fade-in;
  animation-duration: 2s;
  animation-timing-function: ease-out;
  animation-delay: 0.2s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: both;
}
@keyframes fade-in {
  0% {
    opacity: 0;
    transform: translate3d(0, 20px, 0);
  }
  100% {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}
</style>

以下の記事を参考にしました。
Nuxt.js でスクロールでふわっと要素が出現するやつを「カスタムディレクティブ」で実装する

また、handleScroll メソッドに関しては、sample.vue に記述しても問題ありませんが、私は複数コンポーネントで利用する予定だったので、mixinに記述しました。
mixin については、以下が参考になります。
ミックスイン

スクロールしながら画面遷移を行う

メニューのリンクをクリックした際に、スクロールしながら指定場所を表示させたいと思い、「vue-scrollto」を導入しました。

導入方法

まずは、プロジェクトディレクトリで下記のコマンドを実行します。

npm i vue-scrollto

その後、plugins フォルダ内に以下のファイルを作成します。

vue-scrollto.js
import Vue from 'vue'
import VueScrollTo from 'vue-scrollto'

Vue.use(VueScrollTo, {
  duration: 700,           // スクロール継続時間
  easing: [0, 0, 0.1, 1],  // 速度の緩急
  offset: -70              // 遷移後の位置調整
})

nuxt.config.js の plugins キー内にファイルパスを追加します。

nuxt.config.js
export default {
  plugins: ['~/plugins/vue-scrollto']
}

あとは、以下のように、v-scroll-to に遷移先の要素の id を指定することで画面内遷移が可能です。

sample.vue
<template>
  <nuxt-link v-scroll-to="'#bottom'" to>Scroll to bottom</nuxt-link>
  <div id="bottom">bottom</div>
</template>

以下の記事を参考にしました。
スクロール継続時間などのオプションについても、こちらが参考になります。
「vue-scrollto」を使ってイージングスクロールを実装する

写真をスライダーで表示

コンテンツが少なかったので、愛犬の写真を表示することにしました。
複数の写真を見てもらうため、自動で写真が切り替わるようにしたかったので、実現することができそうな「vue-awesome-swiper」を導入しました。

導入方法

まずは、プロジェクトディレクトリで下記のコマンドを実行します。

npm install vue-awesome-swiper --save

その後、plugins フォルダ内に以下のファイルを作成します。

vue-awesome-swiper.js
import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper'
import 'swiper/css/swiper.css'

Vue.use(VueAwesomeSwiper)

nuxt.config.js の plugins キー内にファイルパスを追加します。

nuxt.config.js
export default {
  plugins: ['~/plugins/vue-awesome-swiper']
}

以下のように、スライダーを組み込みます。

sample.vue
<template>
  <swiper :options="swiperOption" ref="mySwiper1">
    <swiper-slide v-for="(item, index) in items" :key="index">
      <img :src="item.img" alt="..." />
    </swiper-slide>
    <div class="swiper-pagination" slot="pagination"></div>
    <div class="swiper-button-prev" slot="button-prev"></div>
    <div class="swiper-button-next" slot="button-next"></div>
  </swiper>
</template>

<script>
export default {
  data: function() {
    return {
      items: [
        { img: require('~/static/img_1.jpg') },
        { img: require('~/static/img_2.jpg') }
      ],
      swiperOption: {
        autoplay: {
          delay: 2500,
          disableOnInteraction: false
        },
        pagination: {
          el: '.swiper-pagination',
          clickable: true
        },
        navigation: {
          nextEl: '.swiper-button-next',
          prevEl: '.swiper-button-prev'
        }
      }
    }
  }
}
</script>

<style scoped lang="scss">
.swiper-container {
  height: 300px;
  width: 100%;
}
.swiper-slide {
  text-align: center;
  font-size: 38px;
  font-weight: 700;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  border-left:1px solid #fff;
}
</style>

以下の記事を参考にしました。
「swiperOption」のその他の設定についても、こちらが参考になります。
モバイルタッチスライダー「vue-awesome-swiper」の使い方

注意点

フェードアニメーションと複数カラムスライドは同時に設定できませんでした。
以下の記述の場合、「slidesPerView: 3」の設定が無視されます。

sample.vue
swiperOption: {
  effect: 'fade',
  slidesPerView: 3,
  ...
}

パララックス

パララックスを利用しているサイトかっこいい!と思い導入しましたが、どこに使えばいいか分からず、ひっそりと利用しています。
私が今回導入したプラグインは、「vue-prlx」ですが、その他に、「vue-parallax-js」などがあるようです。以下が参考になるかと思います。
nuxt.jsでパララックスをするならvue-parallax-jsがお手軽。Cool!

細かい挙動の設定が「vue-prlx」のほうが分かりやすかったので、今回は「vue-prlx」を選択しましたが、気が向いたら「vue-parallax-js」も使ってみようかな、と思っています。(思っているだけです。

導入方法

まずは、プロジェクトディレクトリで下記のコマンドを実行します。

npm i vue-prlx

その後、plugins フォルダ内に以下のファイルを作成します。

vue-prlx.js
import Vue from 'vue'
import VuePrlx from 'vue-prlx'

Vue.use(VuePrlx)

nuxt.config.js の plugins キー内にファイルパスを追加します。

nuxt.config.js
export default {
  plugins: ['~/plugins/vue-prlx']
}

あとは、パララックス効果を追加したい要素に対して、v-prlx ディレクティブを追加するだけです。

sample.vue
<template>
  <img src="sample.png" alt="" v-prlx>
</template>

以下の記事を参考にしました。
細かい挙動の設定についても、こちらを参照してください。
vue-prlxを使ってさくっとパララックス体験をしてみる

ファビコンの作成

キャプチャ3.PNG
私は、「X-Icon Editor」を利用して、作成しました。
簡単なデザインだったので、問題なく作成できました。

GitHub Pagesに公開

ポートフォリオなので、ゆくゆくは人目に触れるようにしたいと思い、ひとまず手軽にできると聞いた GitHub Pages に公開することにしました。

公開方法

まず、nuxt.config.js の router の base と favicon のパスにリポジトリ名を記述。
※ router の base を編集することにより、localhostのパスが「localhost:3000/リポジトリ名」になります

nuxt.config.js
export default {
  router: {
    base: '/リポジトリ名/'
  },

  head: {
    title: pkg.name,
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: pkg.description }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/リポジトリ名/favicon.ico' }
    ]
  }

次に、ローカルにgh-pagesブランチを作成し、gitignoreからビルド先フォルダを外します。

# Nuxt generate
# dist

ビルドコマンドを実行します。

npm run generate

dist フォルダが作成されるので、ローカルのgh-pagesブランチにコミットします。(masterブランチにコミットする必要はありません。)
最後に、以下のコマンドを実行し、dist フォルダのみを gh-pages ブランチに切り離してリポジトリに push します。

git subtree push --prefix dist/ origin gh-pages

うまく公開できている場合、GitHub の Setting から公開されたページを確認することができます。
キャプチャ1.PNG
キャプチャ2.PNG

以下の記事を参考にしました。
Nuxt.jsで作ったWebサイトをささっとGithub Pagesに公開する

悩んだこと・大変だったこと

無名関数内で this を利用する

無名関数内で、this を利用する際に、以下のように記述していました。

sample.vue
<script>
export default {
  data: function() {
    return {
      count: 0,
    }
  },
  methods() {
    increment: function() {
      const a = function() {
        this.count++
      }
      a()
    }
  }
}
</script>

この記述では、Vueインスタンスが参照できないため、「Cannot read property 'count' of undefined」というエラーが発生します。

対応方法① this を別の変数に代入しておく

sample.vue
<script>
export default {
  data: function() {
    return {
      count: 0,
    }
  },
  methods() {
    increment: function() {
      const me = this
      const a = function() {
        me.count++
      }
      a()
    }
  }
}
</script>

余分に me という変数が出現するため、個人的にはあまり好きではないと思いました。

対応方法② アロー関数を利用する

sample.vue
<script>
export default {
  data: function() {
    return {
      count: 0,
    }
  },
  methods() {
    increment: function() {
      const a = () => {
        this.count++
      }
      a()
    }
  }
}
</script>

私が実際に採用した方法です。
余分に変数が増えない分、すっきりしました。

モバイルルータで画像が表示されない

流行りのコロナウイルスによりテレワークになった際に、会社から支給されたモバイルルータが少し遅めだったこともあり、画像が表示されないという事件が発生しました。
原因は、画像サイズが大きすぎたことでした。

対応方法① png ファイルを jpeg ファイルに変更

なんとなく png ファイルにそろえていましたが、容量的には jpeg ファイルの方が良いということを初めて知りました。
今後は、透過画像以外は jpeg ファイル、と心に刻みました。

対応方法② 画像サイズを縮小

そもそも、高画質である必要がない画像ばかりだったので、画像サイズを縮小しました。

斜めレイアウトの調整

marginの調整などの際、斜めに移動するため、思い通りにレイアウトできるまでに時間がかかりました。
数学が得意であれば、計算でもう少しスムーズにできたのかもしれないです...

これからやりたいこと

  • Netlifyで正式にリリース
    • それっぽいドメインにできるそうなので、気が向いたら変えたい。
  • Lighthouseを使ってチューニング
    • 画像サイズ以外にも改善できるところを改善したい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

cookieを再設定するとexpiresの値が削除される

cookie操作時に気づいたので共有します。

以下のようなexpires(有効期限)の設定されたcookie情報があった場合に
key=valA; expires=2020-04-15T14:00:00.000Z;

以下のように値だけ入れ直したところ
document.cookie = 'key=valB;'

予想では以下のように値だけ変更される想定でしたが、
key=valB; expires=2020-04-15T14:00:00.000Z;

実際には以下のように値は変更されるが、
同時に有効期限の値が失われてしまった
key=valB;

なので、有効期限を設定されていた場合は、
以下のように値だけの更新であっても、有効期限も設定し直す必要があることが分かった
document.cookie = key=valB; expires=2020-04-15T14:00:00.000Z;

以上。
あまり、この事に触れた記事を見かけたことがなかったので投稿してみました。
ご参考まで!

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

Yarnでローカルのパッケージをaddする方法

この投稿ではyarnコマンドで、ローカルのパッケージをインストールする方法を紹介します。

通常yarn addはnpmjs.comで公開されたパッケージをダウンロードしてきてインストールしますが、ここで説明するのはローカルにのみ存在する自作のライブラリをaddする方法です。

(npmで同様のことをする方法は、「npmでローカルのパッケージをinstallする方法」をご覧ください)

やりかた

ローカルのパッケージをインストールには、単純にインストールしたいパッケージのファイルパスをyarn addの引数にします:

yarn add インストールしたいパッケージのパス

node_modulesにインストールされるパッケージをシンボリックリンクにしたい場合:

yarn add link:インストールしたいパッケージのパス

ローカルパッケージをインストールする具体例

少し具体例をもとに説明します。

以下の図のように、myappパッケージとmylibパッケージがあり、myappからmylibを使いたい例を見てみましょう。

mylibindex.jsでは、helloWorld変数が提供されていて、myappmain.jsでそれを使いたいとします。

このとき、myappパッケージにてyarn add ../mylibを実行するとこれが実現します:

$ yarn add ../mylib

yarn add v1.22.4
info No lockfile found.
[1/4] ?  Resolving packages...
[2/4] ?  Fetching packages...
[3/4] ?  Linking dependencies...
[4/4] ?  Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ mylib@1.0.0
info All dependencies
└─ mylib@1.0.0
✨  Done in 0.08s.

インストールされると、package.jsonmylibへの依存設定が追加されます:

package.json
{
  "name": "myapp",
  "version": "1.0.0",
  "license": "MIT",
  "dependencies": {
    "mylib": "../mylib"
  }
}

main.jsを実行してみます:

$ node main.js
Hello World!

しっかりとmylibの変数が使われているが分かります。

ちなみに、インストールされたmyapp/node_modules/mylibmylibをごっそりコピーしたものになります。../../mylibへのシンボリックリンクではないので注意です。

シンボリックリンクにしたい場合はファイルパスの頭にlink:を付けます:

yarn add link:../mylib

最後までお読みくださりありがとうございました。Twitterでは、Qiitaに書かない技術ネタなどもツイートしているので、よかったらフォローお願いします:relieved:Twitter@suin

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

npmでローカルのパッケージをinstallする方法

この投稿ではnpmコマンドで、ローカルのパッケージをインストールする方法を紹介します。

通常npm intallはnpmjs.comで公開されたパッケージをダウンロードしてきてインストールしますが、ここで説明するのはローカルにのみ存在する自作のライブラリをinstallする方法です。

(yarnで同様のことをする方法は、「Yarnでローカルのパッケージをaddする方法」をご覧ください)

やりかた

ローカルのパッケージをインストールには、単純にインストールしたいパッケージのファイルパスをnpm intallの引数にします:

npm install インストールしたいパッケージのパス

ローカルパッケージをインストールする具体例

少し具体例をもとに説明します。

以下の図のように、myappパッケージとmylibパッケージがあり、myappからmylibを使いたい例を見てみましょう。

mylibindex.jsでは、helloWorld変数が提供されていて、myappmain.jsでそれを使いたいとします。

このとき、myappパッケージにてnpm install ../mylibを実行するとこれが実現します:

$ npm install ../mylib

+ mylib@1.0.0
added 1 package and audited 1 package in 0.74s
found 0 vulnerabilities

インストールされると、package.jsonmylibへの依存設定が追加されます:

package.json
{
  "name": "myapp",
  "version": "1.0.0",
  "license": "MIT",
  "dependencies": {
    "mylib": "file:../mylib"
  }
}

main.jsを実行してみます:

$ node main.js
Hello World!

しっかりとmylibの変数が使われているが分かります。

ちなみに、インストールされたmyapp/node_modules/mylib../../mylibへのシンボリックリンクになります:

$ ls -la myapp/node_modules
lrwxr-xr-x 11 suin 14 Apr  9:35 mylib -> ../../mylib
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

商品一覧ページ内のカートに入れる機能の実装(非同期通信)

はじめに

商品一覧ページ内の各商品に割り振られているカートに入れるボタンが押された際にuser_idとeffector_id(現在作成中のアプリケーションではエッフェクターが商品のため各所でeffectorを使用していく)にログイン中のuserのidとクリックされた商品のidを保存することを目指す。今回は非同期通信を使用したい。

テーブル、コントローラー、APIの作成

cartsテーブルの作成

ターミナル
アプリケーションのディレクトリ$ rails g model cart

cartモデルの作成

(migrateファイル)create_carts.rb
class CreateCarts < ActiveRecord::Migration[5.0]
  def change
    create_table :carts do |t|
      t.references :user, foreign_key: true
      t.references :effector, foreign_key: true
      t.timestamps
    end
  end
end

マイグレーションファイルの編集

ターミナル
アプリケーションのディレクトリ$ rails db:migrate

マイグレーションの実行

(modelファイル)cart.rb
class Cart < ApplicationRecord
  belongs_to :effector
  belongs_to :user
end
(modelファイル)effector.rb
class Effector < ApplicationRecord
  belongs_to :genre
  has_many :users, through: :carts
  #今回はcartsコントローラーのshowアクションを使用するため上の記述は不要
  has_many :carts
end
(modelファイル)user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  has_many :boards
  has_many :effectors, through: :carts
  #今回はcartsコントローラーのshowアクションを使用するため上の記述は不要
  has_many :carts
end

各モデル内にリレーションを記載

APIの準備

app/controller/api/carts_controller.rbを作成

app/controller/api/carts_controller.rb
class Api::CartsController < ApplicationController
  def create
    Cart.create(user_id: params[:user_id], effector_id: params[:effector_id])
    #json形式で送られてきたデータからparams[:user_id]をuser_idカラムにparams[:effector_id]をeffector_idカラムに保存
  end
end

ルーティング設定

routes.rb
Rails.application.routes.draw do
  root to: "effectors#index"
  devise_for :users
  resources :users, only: [:show, :edit, :update]
  resources :boards
  resources :effectors do
    resources :genres
  end
  resources :carts, only: [:show, :destroy]
  namespace :api do
    resources :carts, only: :create, defaults: { format: 'json'}
  end
  #cartsコントローラーとapp/controller/api/carts_controller.rbのルーティング設定
end

ここまで設定が終わったら商品一覧のカートに入れるボタンが押された際にcartsテーブルにuser_idとeffector_idが保存されるようにjsを記述していく。

商品一覧のカートに入れるボタンが押された時の処理

カートに入れるボタンが押された時onclick:を用いてjs内の関数を発火できるように記述する。

app/views/effectors/index.html.haml
.main
  .main__list
    - @effectors.each do |effector|
      .main__list__effector{data: {genre: effector.genre.id}}
        .main__list__effector__info
          .main__list__effector__info__visual
            %h.main__list__effector__info__visual__name
              = effector.name
            .main__list__effector__info__visual__image
              %img{alt: "image1", class: "main__list__effector__info__visual__image__file", src: "#{- effector.image1}"}
              %img{alt: "image2", class: "main__list__effector__info__visual__image__file", src: "#{- effector.image2}"}
          .main__list__effector__info__text
            %h.main__list__effector__info__text__genre
              = effector.genre.genre
            %h.main__list__effector__info__text__point
              = effector.point
              pt
            %br 
            %h.main__list__effector__info__text__detail
              = effector.text
          .main__list__effector__info__btns
            - if effector.youtube != nil
              .main__list__effector__info__btns__video
                %button.main__list__effector__info__btns__video__btn{onclick: "test(#{effector.youtube})"}
                  動画を視聴
            - if effector.link != nil
              .main__list__effector__info__btns__official
                = link_to "#{effector.link}", class: "main__list__effector__info__btns__official__btn" do
                  .main__list__effector__info__btns__official__btn__text
                    公式サイト
            - if user_signed_in?
              .main__list__effector__info__btns__cart
                %button.main__list__effector__info__btns__cart__btn{onclick: "createCart(#{current_user.id},#{effector.id})"}
                  -#クリックされた時関数名createCartを引数(current_user.id,effector.id)とし発火
                  カートに入れる
  .popup
    .popup__content
      .popup__content__youtube
        %iframe(width="560" height="315" id = "youtube_test" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen)
      %button#close
        閉じる

発火される関数の記述

effectors.js
function createCart(userId, effectorId) {
  var param = {
    user_id: userId,
    effector_id: effectorId
    //受け取った引数をuser_id:とeffector_id:として変数paramに格納
  }
  ajaxRequest("api/carts",'post',param)
  //非同期通信する際の関数を複数回の利用を見越して外出しして呼び出す(引数をapi/carts,post,paramとし呼び出し)
}

function ajaxRequest(url,type,data) {
  $.ajax({
    url: url,
    //url: api/cartsと同義
    type: type,
    //type: postと同義
    dataType: 'json',
    data: data
    //data: paramと同義
    //引数で持ってきた仮引数url,type,dataを使用しajaxの記述をする
  })
  .done(function() {
    alert('商品をカートに入れました')
  })
  .fail(function() {
    alert('error');
  });
}

ここまできたらjson形式で送られたデータをapi側のコントローラーで保存してあげるだけである。
先ほど記述したapp/controller/api/carts_controller.rbを見てみる

app/controller/api/carts_controller.rb
class Api::CartsController < ApplicationController
  def create
    Cart.create(user_id: params[:user_id], effector_id: params[:effector_id])
    #json形式で送られてきたデータからparams[:user_id]をuser_idカラムにparams[:effector_id]をeffector_idカラムに保存
  end
end

すでに記載している通りにjosn形式で送られてきたデータからcartsテーブルのuser_idカラムにparams[:user_id]をeffector_idカラムにparams[:effector_id]を保存する記載をする。
これにてカートに入れるボタンの実装が完了します。

終わりに

今回はカートに入れるボタンというショッピングサイトには欠かせない機能を非同期通信にて行えるように実装した。
ユーザーと商品という多対多という関係性、非同期通信でのデータの保存など初学者が苦労する機能の実装を行うことで力がつくのを感じました。
この機能はいいね機能などにも流用できると思うので学習する価値ありだと感じます。
2回目の投稿のため拙い文章が眼に余るかと思いますがご精読ありがとうございました。駆け出しエンジニアのみなさん一緒に頑張っていきましょう。

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

商品一覧ページ内のカートに入れるボタンの実装(非同期通信)

はじめに

商品一覧ページ内の各商品に割り振られているカートに入れるボタンが押された際にuser_idとeffector_id(現在作成中のアプリケーションではエッフェクターが商品のため各所でeffectorを使用していく)にログイン中のuserのidとクリックされた商品のidを保存することを目指す。今回は非同期通信を使用したい。

テーブル、コントローラー、APIの作成

cartsテーブルの作成

ターミナル
アプリケーションのディレクトリ$ rails g model cart

cartモデルの作成

(migrateファイル)create_carts.rb
class CreateCarts < ActiveRecord::Migration[5.0]
  def change
    create_table :carts do |t|
      t.references :user, foreign_key: true
      t.references :effector, foreign_key: true
      t.timestamps
    end
  end
end

マイグレーションファイルの編集

ターミナル
アプリケーションのディレクトリ$ rails db:migrate

マイグレーションの実行

(modelファイル)cart.rb
class Cart < ApplicationRecord
  belongs_to :effector
  belongs_to :user
end
(modelファイル)effector.rb
class Effector < ApplicationRecord
  belongs_to :genre
  has_many :users, through: :carts
  #今回はcartsコントローラーのshowアクションを使用するため上の記述は不要
  has_many :carts
end
(modelファイル)user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  has_many :boards
  has_many :effectors, through: :carts
  #今回はcartsコントローラーのshowアクションを使用するため上の記述は不要
  has_many :carts
end

各モデル内にリレーションを記載

APIの準備

app/controller/api/carts_controller.rbを作成

app/controller/api/carts_controller.rb
class Api::CartsController < ApplicationController
  def create
    Cart.create(user_id: params[:user_id], effector_id: params[:effector_id])
    #json形式で送られてきたデータからparams[:user_id]をuser_idカラムにparams[:effector_id]をeffector_idカラムに保存
  end
end

ルーティング設定

routes.rb
Rails.application.routes.draw do
  root to: "effectors#index"
  devise_for :users
  resources :users, only: [:show, :edit, :update]
  resources :boards
  resources :effectors do
    resources :genres
  end
  resources :carts, only: [:show, :destroy]
  namespace :api do
    resources :carts, only: :create, defaults: { format: 'json'}
  end
  #cartsコントローラーとapp/controller/api/carts_controller.rbのルーティング設定
end

ここまで設定が終わったら商品一覧のカートに入れるボタンが押された際にcartsテーブルにuser_idとeffector_idが保存されるようにjsを記述していく。

商品一覧のカートに入れるボタンが押された時の処理

カートに入れるボタンが押された時onclick:を用いてjs内の関数を発火できるように記述する。

app/views/effectors/index.html.haml
.main
  .main__list
    - @effectors.each do |effector|
      .main__list__effector{data: {genre: effector.genre.id}}
        .main__list__effector__info
          .main__list__effector__info__visual
            %h.main__list__effector__info__visual__name
              = effector.name
            .main__list__effector__info__visual__image
              %img{alt: "image1", class: "main__list__effector__info__visual__image__file", src: "#{- effector.image1}"}
              %img{alt: "image2", class: "main__list__effector__info__visual__image__file", src: "#{- effector.image2}"}
          .main__list__effector__info__text
            %h.main__list__effector__info__text__genre
              = effector.genre.genre
            %h.main__list__effector__info__text__point
              = effector.point
              pt
            %br 
            %h.main__list__effector__info__text__detail
              = effector.text
          .main__list__effector__info__btns
            - if effector.youtube != nil
              .main__list__effector__info__btns__video
                %button.main__list__effector__info__btns__video__btn{onclick: "test(#{effector.youtube})"}
                  動画を視聴
            - if effector.link != nil
              .main__list__effector__info__btns__official
                = link_to "#{effector.link}", class: "main__list__effector__info__btns__official__btn" do
                  .main__list__effector__info__btns__official__btn__text
                    公式サイト
            - if user_signed_in?
              .main__list__effector__info__btns__cart
                %button.main__list__effector__info__btns__cart__btn{onclick: "createCart(#{current_user.id},#{effector.id})"}
                  -#クリックされた時関数名createCartを引数(current_user.id,effector.id)とし発火
                  カートに入れる
  .popup
    .popup__content
      .popup__content__youtube
        %iframe(width="560" height="315" id = "youtube_test" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen)
      %button#close
        閉じる

発火される関数の記述

effectors.js
function createCart(userId, effectorId) {
  var param = {
    user_id: userId,
    effector_id: effectorId
    //受け取った引数をキーuser_id:とキーeffector_id:にそれぞれのバリューとして変数paramに格納
  }
  ajaxRequest("api/carts",'post',param)
  //非同期通信する際の関数を複数回の利用を見越して外出しして呼び出す(引数をapi/carts,post,paramとし呼び出し)
}

function ajaxRequest(url,type,data) {
  $.ajax({
    url: url,
    //url: api/cartsと同義
    type: type,
    //type: postと同義
    dataType: 'json',
    data: data
    //data: paramと同義
    //引数で持ってきた仮引数url,type,dataを使用しajaxの記述をする
  })
  .done(function() {
    alert('商品をカートに入れました')
  })
  .fail(function() {
    alert('error');
  });
}

ここまできたらjson形式で送られたデータをapi側のコントローラーで保存してあげるだけである。
先ほど記述したapp/controller/api/carts_controller.rbを見てみる

app/controller/api/carts_controller.rb
class Api::CartsController < ApplicationController
  def create
    Cart.create(user_id: params[:user_id], effector_id: params[:effector_id])
    #json形式で送られてきたデータからparams[:user_id]をuser_idカラムにparams[:effector_id]をeffector_idカラムに保存
  end
end

すでに記載している通りにjosn形式で送られてきたデータからcartsテーブルのuser_idカラムにparams[:user_id]をeffector_idカラムにparams[:effector_id]を保存する記載をする。
これにてカートに入れるボタンの実装が完了します。

終わりに

今回はカートに入れるボタンというショッピングサイトには欠かせない機能を非同期通信にて行えるように実装した。
ユーザーと商品という多対多という関係性、非同期通信でのデータの保存など初学者が苦労する機能の実装を行うことで力がつくのを感じました。
この機能はいいね機能などにも流用できると思うので学習する価値ありだと感じます。
2回目の投稿のため拙い文章が眼に余るかと思いますがご精読ありがとうございました。駆け出しエンジニアのみなさん一緒に頑張っていきましょう。

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

discord.js + Klasa を使ったBotの作成覚え書き

参考 : discord.jsのフレームワークKlasaが強すぎる
合わせて読んでください。

準備

  • 環境
    • Win10
    • Node.js 12.13.0
    • npm 6.12.0

適当にプロジェクトフォルダを作成し discord.js と Klasa をインストール

npm install --save discordjs/discord.js dirigeants/klasa

コーディング

最初の一歩

app.js を作成

app.js
const secret = require('./secret.js'); // BOTトークンはここに記述
const token = secret.token;

const {Client} = require('klasa');

new Client({
  prefix: '!!', // ボットのPrefix
  language: 'ja-JP', // 言語コード
}).login(token);

この状態で一度 node app.js から起動し、危険なログが出てなければとりあず成功。

コマンドの作成

commands/general 配下に以下のソースを作成。Klasaはファイル名がそのままコマンド名になる。
ディレクトリ名はヘルプのカテゴリ名になる。
なお、下のソースに書かれている usage は単なる説明文ではなく引数のマッチャを参照するための記述なので注意。(これで30分ぐらい潰した……)

commands/general/hello.js
const {Command} = require('klasa');

module.exports = class extends Command {
  /**
   * @constructor
   * @param  {...any} args
   */
  constructor(...args) {
    // コマンドのオプション: https://klasa.js.org/#/docs/klasa/master/typedef/CommandOptions
    super(...args, {
      description: '挨拶を返す',
      usage: '<name:string>', // <>は必須引数、[]はオプション引数、<名前:型>のように書く
    });
  }

  /**
   * @param {*} message
   */
  async run(message,[name]) {
    return message.sendMessage(`${name}さんこんにちは!`);
  }
};

参考 :
Klasa : CreatingArguments
Klasa : CreatingCommands

BOTの反応はこんなかんじ

コメント 2020-04-14 002903.png

コメント 2020-04-14 002903_.png

データストアの作成

providers ディレクトリにプロバイダを作成する。公式を見るとなんか適当に書いてよさそうだったので適当に書いてみる。

providers/datas.js
const {Provider} = require('klasa');

module.exports = class extends Provider {
  /**
   * @constructor
   * @param  {...any} args
   */
  constructor(...args) {
    super(...args, {name: 'datas'});
    this.counter = 0;
  }

  /**
   * init
   */
  init() {
    this.counter=1;
  }

  /**
   * countup
   * @return {Number} count
   */
  countup() {
    this.counter++;
    return this.counter;
  }
};

hello.jsから動作確認してみる。

const {Command} = require('klasa');

module.exports = class extends Command {
  /**
   * @constructor
   * @param  {...any} args
   */
  constructor(...args) {
    // コマンドのオプション: https://klasa.js.org/#/docs/klasa/master/typedef/CommandOptions
    super(...args, {
      description: '挨拶を返す',
      usage: '<name:string>',
    });
    this.data = this.client.providers.get('datas');
  }

  /**
   * @param {*} message
   */
  async run(message, [name]) {
    return message.sendMessage(`${name}さんこんにちは!${this.data.countup()}回めの挨拶ですね!`);
  }
};

コメント 2020-04-14 005829.png

本当に適当に動いてしまった。

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

RailsでGoogleAnalyticsを設定する

Railsで作成したアプリにGoogleAnalyticsを設定することがたくさんあると思う。
google-analytics-railsという便利なgemがあるそうだが、PRを見てみると2017年10月で終わっている…
多分メンテナンスされていないし、gemを使うほどでもないので自分で設定することにしたが、RailsからJavascriptへの変数の渡し方に手間取ったので残しておく。

Analyticsタグの設置

GoogleAnalyticsタグはheadに書いていく。今回はログインしている場合は変数current_userをJavascriptに渡してあげて、ログインしていない場合は変数を渡さないという仕様にする。
このcurrent_userをRailsからJavascriptに渡す時にかなり工夫した。

コード

コードを書いていく。テンプレートエンジンはslimを使っている。

app/views/layouts/application.slim.html
doctype html
html
  head
    meta content=("text/html; charset=UTF-8") http-equiv="Content-Type"
    = csrf_meta_tags
    = stylesheet_link_tag 'application', media: 'all'
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
    - if Rails.env.production?
      = render './google_analytics'

Analyticsは本番環境だけで動かしたいのでif Rails.env.production?の中に入れる。
Analyticsスクリプトは他のファイルでも使う可能性があり使いまわしたいので、部分テンプレートで共通化しておく。
先に答えを出すと、下記のようなコードになる。

app/views/layouts/_google_analytics.slim.html
script async="" src="https://www.googletagmanager.com/gtag/js?id=#{トラッキングID}"
javascript:
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'トラッキングID');
  if (#{raw current_user.to_json}) {
    gtag('set', {'user_id': #{raw current_user.to_json}.id});
  }

RailsからJavascriptに変数を渡す場合、その変数のデータ型がintegerの場合はそのまま渡して問題ないが、それ以外の場合はcurrent_user.to_jsonというようにto_jsonをつけてあげないといけない。
また、エスケープ処理をさせないために、ActionView::Helpers::OutputSafetyHelperで用意されているrawメソッドを使用する。
こうすることで、Railsのcurrent_usergonなどを使わずに渡すことが出来た。

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

ReactでLIFFアプリケーションをつくる 〜その1 VSCode+Docker+Reactの環境構築する〜

はじめに

最初に、今回は環境構築なので、LIFFは登場しません

LINEってワードをよく聞くし、キャッシュレスの流れも強めなので、
「LINE連携したアプリケーション(MessagingAPI、LIFF、LINE Pay)を作れたら結構強い人なんじゃないか?」
と最近思い始めました。
(LINE Payって個人利用できたりするのだろうか?)

Messaging APIは少し触ったので、今回はReactでLIFFアプリケーションを作ります。
この記事では、VSCode+Docer+Reactの環境構築〜HelloWorldまでやります。

※ちなみに、LIFFとは以下のことです
https://developers.line.biz/ja/docs/liff/overview/

VSCode

Install

https://azure.microsoft.com/ja-jp/products/visual-studio-code/
からダウンロード&インストールしてください。

Macユーザで、Homebrew導入済であれば、以下コマンドでインストールできます。

brew cask install visual-studio-code

Setting : 設定

setting.json

editorやら、formatやらの設定ファイルです。
以下サイトを参考にとりあえず設定してみました。

Command + ,で設定を開き、右上にあるアイコン(↓のようなアイコンがあります)を押すとsettings.jsonを編集できます。
setting-icon.png

そして、内容は以下のように設定しました。

settings.json
{
  // see. Customizing IntelliSense
  // The contents described below have been copied
  // https://code.visualstudio.com/docs/editor/intellisense#_customizing-intellisense
  // from here
  // Controls if quick suggestions should show up while typing
  "editor.quickSuggestions": {
    "other": true,
    "comments": false,
    "strings": false
  },
  // Controls whether suggestions should be accepted on commit characters. For example, in JavaScript, the semi-colon (`;`) can be a commit character that accepts a suggestion and types that character.
  "editor.acceptSuggestionOnCommitCharacter": true,
  // Controls if suggestions should be accepted on 'Enter' - in addition to 'Tab'. Helps to avoid ambiguity between inserting new lines or accepting suggestions. The value 'smart' means only accept a suggestion with Enter when it makes a textual change
  "editor.acceptSuggestionOnEnter": "on",
  // Controls the delay in ms after which quick suggestions will show up.
  "editor.quickSuggestionsDelay": 10,
  // Controls if suggestions should automatically show up when typing trigger characters
  "editor.suggestOnTriggerCharacters": true,
  // Controls if pressing tab inserts the best suggestion and if tab cycles through other suggestions
  // タブでサジェクト内容の切替できるようにする
  "editor.tabCompletion": "on",
  // Controls whether sorting favours words that appear close to the cursor
  "editor.suggest.localityBonus": true,
  // Controls how suggestions are pre-selected when showing the suggest list
  // 直近利用したワードが一番最初に選択されるようにサジェクトされる
  "editor.suggestSelection": "recentlyUsed",
  // Enable word based suggestions
  "editor.wordBasedSuggestions": true,
  // Enable parameter hints
  "editor.parameterHints.enabled": true,
  // to here
  "diffEditor.renderSideBySide": false,
  "editor.colorDecorators": false,
  // see.
  // [VSCodeで爆速コーディング環境を構築する(主にReactJS向け設定)](https://qiita.com/teradonburi/items/c4cbd7dd5b4810e1a3a9)
  // [Visual Studio Code の初期設定と最低限必要な拡張機能 - フロントエンド向け -](https://qiita.com/hi85/items/eaede5ebb509f21f27f5)
  // format
  "editor.formatOnPaste": true,
  "editor.formatOnSave": true,
  "html.format.extraLiners": "",
  "html.format.unformatted": null,
  "html.format.wrapLineLength": 0,
  // editor
  "editor.minimap.enabled": false,
  "editor.multiCursorModifier": "ctrlCmd",
  "editor.renderControlCharacters": true,
  "editor.renderLineHighlight": "all",
  "editor.tabSize": 2,
  "editor.wordWrap": "on",
  // emmet
  "emmet.showSuggestionsAsSnippets": true,
  "emmet.triggerExpansionOnTab": true,
  "emmet.variables": {
    "lang": "ja"
  },
  // confirm when deleting files.
  "explorer.confirmDelete": true,
  // files
  "files.exclude": {
    "**/.git": true,
    "**/.DS_Store": true,
    "**/node_modules": true
  },
  "files.insertFinalNewline": true,
  "files.trimFinalNewlines": true,
  "files.trimTrailingWhitespace": true,
  "search.exclude": {
    "**/.git": true,
    "**/node_modules": true
    // @TODO: List files to exclude from search.
  }
}

keybinding.json

キーバインドの設定です。
Command + k -> Command + sで設定を表示し、また右上にある以下アイコンを押すとkeybindings.jsonを開けます。

設定値は本家の内容をまるパクリしました。

keybinding.json
// Place your key bindings in this file to override the defaults
[
  // see Key bindings
  // https://code.visualstudio.com/docs/editor/intellisense#_key-bindings
  {
    "key": "ctrl+space",
    "command": "editor.action.triggerSuggest",
    "when": "editorHasCompletionItemProvider && editorTextFocus && !editorReadonly"
  },
  {
    "key": "ctrl+space",
    "command": "toggleSuggestionDetails",
    "when": "editorTextFocus && suggestWidgetVisible"
  },
  {
    "key": "ctrl+alt+space",
    "command": "toggleSuggestionFocus",
    "when": "editorTextFocus && suggestWidgetVisible"
  }
]

Extension

プラグインの導入です。
以下サイトを参考にインストールさせていただきました。

install-extension.bash
## see
## [インストールするだけでVSCodeをカッコよくする拡張4つ - Qiita](https://qiita.com/ksakiyama134/items/8ca98295897dc1280644)

## Bracket Pair Colorizer
## see. https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer
code --install-extension CoenraadS.bracket-pair-colorizer

## Dracula Theme
## see. https://draculatheme.com
code --install-extension gerane.Theme-Dracula

## Indent Rainbow
## see. https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow
code --install-extension oderwat.indent-rainbow

## Material Icon Theme
## see. https://marketplace.visualstudio.com/items?itemName=PKief.material-icon-theme
code --install-extension PKief.material-icon-theme

## see
## [VSCodeのオススメ拡張機能 24 選 (とTipsをいくつか)](https://qiita.com/sensuikan1973/items/74cf5383c02dbcd82234)

## GitLens
## see. https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens


## REST CLIENT
## see. https://marketplace.visualstudio.com/items?itemName=humao.rest-client
code --install-extension humao.rest-client

## Partial Diff
## see. https://marketplace.visualstudio.com/items?itemName=ryu1kn.partial-diff
code --install-extension ryu1kn.partial-diff

## React snippets
code --install-extension dsznajder.es7-react-js-snippets

## Babel JavaScript
code --install-extension mgmcdermott.vscode-language-babel

## Marp for VSCode
## see. https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode
code --install-extension marp-team.marp-vscode

confirm installed extension : インストール済の確認

インストールしたExtensionはcode -list-extensionsで確認できます

ちなみに

設定ファイル類はこちらにコミットしましたがなんだか見辛かったので、それぞれ記載しました。
https://github.com/ken-araki/env/tree/master/vscode

node

Install

まずはnodeをインストールするのですが、今回はdockerを利用します。
なので、作業ディレクトリに以下ファイルを作成してください。(dockerについてはあまり触れません)

docker-compose.yml

docker-compose.yml
version: "3"
services:
  node:
    build: ./docker/node
    volumes:
      - ./:/home/node
    ports:
      - "3000:3000"

その後、以下コマンドでDockerイメージを作成しておきます。

docker-compose build

docker/node/Dockerfile

docker/node/Dockerfile
FROM node:13.12.0-slim
WORKDIR /home/node

React

基本的に、React Tutorial 2: ローカル開発環境に沿って進めます。

Node.jsのインストールが終わっているので、「2. Create React App のインストールガイドに従って新しいプロジェクトを作成する。」から始めます。

2. Reactアプリケーションの作成

以下コマンドでDocker containerでnpx create-react-app my-appを実行します。
my-app部分はよしなに変更してください)

docker-compose run --rm node sh -c "npx create-react-app app"

3~6. srcの改修

チュートリアルにしたがって、src配下にindex.jsindex.cssを作成してください。
(と言ってもコピペ)

Reactアプリケーションの開始

以下コマンドでDocker containerでnpm startを実行します。

docker-compose run --rm --service-ports node sh -c "cd app; npm start"

その後http://localhost:3000にアクセスすると空の三目並べの盤面が表示されます。

コード

コードはこちらにコミットしています
https://github.com/ken-araki/line-liff

おわりに

まずは、これでいい感じにコーディングできるか試してみようと思います。
Reactチュートリアルやりながら、イケていない部分を少しずつ直していきます。
「もっとこうした方がいいよ!」があったら教えてもらえると嬉しいです!

次は、チュートリアル終わらせつつ、LIFFアプリケーション登録までやろうと思います。
そのあと、kotlin-reactも触ってみたいのですが、業務で使う機会なさそうだな、とも思ったり。。。
どうなんですかね?

と言うので、今回は終わりです。

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