20200626のJavaScriptに関する記事は30件です。

とにかく、つかえるJS?JC?JK?あげるとかいうのいい?

Date.prototype.JST=function(){this.setTime(this.getTime()+(9*60*60*1000));return this}

これ?いいとおもう。

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

プログラミング初心者が人生初のポートフォリオ作りました。

人生初ポートフォリオサイト

https://portfolio.ppmp556.com/

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

Jestでモジュールの特定の関数だけモックする

Jestでモジュールをモックするのは便利ですが、モジュールの一部をモックしたい場合に困ることがあります。

// my-module.js
export function foo() { ... }
export function bar() { ... } // bar だけモックしたい
import { foo, bar } from "./my-module";

jest.mock("./my-module", () => ({
  bar: jest.fn(),
}));

describe("foo", () => {
  it("works", () => {
    expect(foo("yay")).toEqual("wow");
  });
});

上記のように書いた場合に、 TypeError: foo is not a function といったエラーになってしまいます。それを回避するには以下のように書きます。

jest.mock("./my-module", () => ({
  ...jest.requireActual("./my-module"), // foo: jest.requireActual("./my-module").foo でも可
  bar: jest.fn(),
}));

Jest的に認められた書き方なのかは怪しいですがとりあえず bar をモックして foo はモックせず動かせます :sunglasses:

参照

https://github.com/facebook/jest/issues/936#issuecomment-613220940
https://jestjs.io/docs/en/jest-object#jestrequireactualmodulename

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

Reactアプリ - 文章中キーワード黒塗りはがし

はじめに

 Reactを使って文章中の特定のキーワードの黒塗り文字列をクリックして黒塗りをはがして読めるようにするアプリを作りましたので紹介いたします。

 このアプリは単純で、黒塗りをはがすためにはキーワードの黒塗り部分をクリックします。再びキーワードをクリックすると黒塗りに戻ります。

前提条件

 node.jsがインストールされている事が必要です。まだインストールしていない場合には、インストールしておいてください。

Reactプロジェクトを作成します

以下のようにcreate-react-appコマンドを実行します。少し、時間がかかります。

  • macOS
terminal
(base) macpro:dev teruroom$ cd /Users/teruroom/dev/react/
(base) macpro:react teruroom$ npx create-react-app blackout-peeling
  • Windows10
powershell
PS C:\> cd C:\dev\react\
PS C:\dev\react\> npx create-react-app blackout-peeling
macOS実行結果
Creating a new React app in /Users/teruroom/dev/react/blackout-peeling.
・・・・・・・・途中省略・・・・・・・・・・・
Success! Created react-boardgame at /Users/teruroom/dev/react/blackout-peeling
Inside that directory, you can run several commands:
  npm start
    Starts the development server.
  npm run build
    Bundles the app into static files for production.
  npm test
    Starts the test runner.
  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!
We suggest that you begin by typing:
  cd react-boardgame
  npm start
Happy hacking!

デフォルトで生成されたファイルを全て削除します

  • macOS
terminal
(base) macpro:react teruroom$ cd blackout-peeling/src
(base) macpro:src teruroom$ rm -f *
  • Windows10
powershell
PS C:\dev\react> cd .\blackout-peeling\src
PS C:\dev\react\blackout-peeling\src> rm -Force *

必要なJavaScriptとCSSファイルを作成します

  • macOS
terminal
(base) macpro:src teruroom$ touch index.css index.js
  • Windows10
powershell
PS C:\dev\react\blackout-peeling\src> New-Item -type file index.css
PS C:\dev\react\blackout-peeling\src> New-Item -type file index.js

JavaScriptとCSSを実装します

  • VSCodeを起動し、blackout-peelingフォルダを開きます
  • srcフィルダ内のindex.jsindex.cssを以下のように実装します
    image.png

  • index.js

以下のようにクラスの階層構造を設計しました
Pageクラス:ページ
  |
  +--Sentenceクラス:ページ内の文章
       |
       +--Keywordクラス:文章内のキーワード

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

const white = '#fff';
const crimson = '#880E4F';
const marginwidth = '5px';
const fontweight = 'bold';

class Keyword extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      value: null,
      forecolor: blackOutColor,
      backcolor: blackOutColor,
      margin: marginwidth,
      fontweight: fontweight,
    };
    this.changeColor = this.changeColor.bind(this);
  }
  changeColor() {
    const newColor = this.state.backcolor === blackOutColor ? white : blackOutColor;
    this.setState({ forecolor: blackOutColor, backcolor: newColor })
  }
  render() {
    return (
      <span style={{
        color: this.state.forecolor
        , background: this.state.backcolor
        , marginLeft: this.state.margin
        , marginRight: this.state.margin
        , fontWeight: this.state.fontweight
      }}
        onClick={() => this.changeColor()} >
        {this.props.value}
      </span>
    );
  }
}

class Sentence extends React.Component {
  blackOut(keyString) {
    return <Keyword value={keyString} />;
  }

  render() {
    return (
      <div>
        <div className="maintitle">ホゲホゲについて</div>
        <ol>
          <li className="subtitle">FOO</li>
          <ul>
            <li>FOOは、{this.blackOut('BAA')}システムから利用申請し、「{this.blackOut('利用許可')}」を得てから使用する</li>
            <li>FOO{this.blackOut('ホゲ')}やハゲによる攻撃から守るため、BOO対策製品を導入する</li>
          </ul>
        一部省略
        </ol>
      </div>
    );
  }
}

class Page extends React.Component {
  render() {
    return (
      <div className="page">
        <div className="page-sentence">
          <Sentence />
        </div>
        <div className="page-info">
          <div>{/* status */}</div>
          <ol>{/* TODO */}</ol>
        </div>
      </div>
    );
  }
}

ReactDOM.render(
  <Page />,
  document.getElementById('root')
);
  • index.css
index.css
body {
  width: 1100px;
  font: 18px "Meiryo", "Century Gothic", sans-serif;
  margin: 0px;
  cursor: pointer;
}

ol, ul {
  padding-left: 30px;
}

td {
  width: 50%;
}

.maintitle {
  width: 100%;
  font-size: 30px;
  color: #fff;
  background: cornflowerblue;
}
.subtitle {
  width: 95%;
  font-size: 22px;
  font-weight: bold;
  color: rgb(26, 75, 182);
  background: rgb(210, 210, 211);
  margin: 4px;
  padding: 4px;
}

.page {
  display: flex;
  flex-direction: row;
}

.page-sentence {
  margin-left: 20px;
}

.page-info {
  margin-left: 20px;
}

React Webアプリを開発用に起動します

  • VSCodeの TerminalNew Terminalで新規のターミナルを起動します
  • Webアプリを起動コマンドを実行します
    image.png

  • macOS

terminal
(base) macpro:blackout-peeling teruroom$ npm start
  • 実行結果
    image.png

  • Windows10

powershell
PS C:\dev\react\blackout-peeling> npm start

Web ブラウザで http://localhost:3000 が自動的に立ち上がりページが表示されます。以降、VSCodeで実装コードを変更し、保存するたびごとにWeb ブラウザの http://localhost:3000 が自動的に再読み込み(Reload)されるようになります

最適化ビルドを実行します

React Webアプリが完成したら、最適化ビルドを実行してから公開します

  • macOS
terminal
(base) macpro:blackout-peeling teruroom$ npm run build
  • Windows10
powershell
PS C:\dev\react\blackout-peeling> npm run build
  • 実行結果

macOSの場合
省略

Windows10の場合
> security-compliance@0.1.0 build C:\dev\react\blackout-peeling
> react-scripts build
Creating an optimized production build...
Compiled successfully.
File sizes after gzip:
  39.89 KB  build\static\js\2.73f5bc0c.chunk.js
  5.5 KB    build\static\js\main.11e48eb2.chunk.js
  782 B     build\static\js\runtime-main.623a1e28.js
  310 B     build\static\css\main.3c6f1d95.chunk.css
The project was built assuming it is hosted at /.
You can control this with the homepage field in your package.json.
The build folder is ready to be deployed.
You may serve it with a static server:
  npm install -g serve
  serve -s build
Find out more about deployment here:
  bit.ly/CRA-deploy

React Webアプリを本番用に起動します

オプション--host='0.0.0.0'をつけてコマンドを実行し、インバウンドとして全てのIPアドレスからのリクエストを受け付けるようにします

  • macOS ➡️ ubuntsサーバにデプロイ
terminal
(base) macpro:blackout-peeling teruroom$ npm start --host='0.0.0.0'
  • Windows10 ➡️ Windows Server 2016にデプロイ
powershell
PS C:\dev\react\blackout-peeling> npm start --host='0.0.0.0'

React Webアプリを利用します

WebブラウザでURL http://192.168.0.16:3000 (192.168.0.16はWebアプリを動かしているPCのIPアドレス)にアクセスします

macOSの場合

デフォルトWebブラウザのSafariや後からインストールしたChromeで表示されます

image.png

Windows10の場合

 デフォルトWebブラウザのEdgeや後からインストールしたChromeで表示されます。IE11では残念ながらそのままでは表示や動作が上手くいきません。react-app-polyfillライブラリを別途インストールし、index.jsファイルの先頭でimport 'react-app-polyfill/ie11';` のようにインポートする必要があります。

 諸々の都合によりIE11を既定のブラウザにしている場合には、以下のようにWindowsショートカットなどにURLを仕込んでおいてください。ショートカットを開くとEdgeによりReact Webアプリが開かれるようになります

microsoft-edge:http://hoge-foo.ad.baa.co.jp:3000/

  • hoge-foo.ad.baa.co.jp:Active Directry内のReact Webアプリを起動しているPCの端末名

黒塗りをクリックすると剥がれてキーワード文字が読めるようになります

image.png

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

CentOS とOSXでphp, fetch,javascriptの挙動が違う

OSXはこれで行けたが、CentOSではダメ

Javascript

function checkNewOrder(uuid) {
            var res = fetch("./test.php", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({
                    //引数が色々あって...。
                })
            }).then((response) => {
                if (response.ok)
                    return response.json(); // レスポンスをテキストとして変換する
            }).then((rcvData) => {
                console.log("rcvData", rcvData); //とりあえず確認
                if (rcvData.length > 0) {
                    let msg = "新たにデータが入りました<br>\n";
                    //rcvData[i]["NAME"]とかを使って色々処理
                }
            });
        }

php

$dbh->beginTransaction();
$stmt = $dbh->query("select * from TableName;");
$stmt->execute();
$dbh->commit();
$result = $stmt->fetchall(PDO::FETCH_ASSOC);
echo json_encode($result, JSON_UNESCAPED_UNICODE);

CentOSだとJSの console.log("rcvData", rcvData);のところで「rcvDataって何?」ってなってしまう。

結局こうやって対応できた

Javascript

function checkNewOrder(uuid) {
            var res = fetch("./test.php", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({
                    //引数が色々あって...。
                })
            }).then((response) => {
                if (response.ok)
                    return response.text(); // jsonからtextに変更した
            }).then((rcvData) => {
                var rcv = JSON.stringify(rcvData); //JSONオブジェクトに変換
                if (rcv.length > 0) {
                    let msg = "新たにデータが入りました<br>\n";
                    //rcvData[i]["NAME"]とかを使って色々処理
                }
            });
        }

response.json();response.text();にしてJSON.stringifyでオブジェクト化するとCentOSでOKだった。
OSXとCentOS で挙動が違うのはなぜ?

でも、結局こっちかな

function checkNewOrder(uuid) {
    const response = fetch("./checkNewOrder.php", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify({
            "uuid": ???; //パラメータとか
        })
    }).then((response) => {
        if (response.ok)
            return response.json(); // JSON
       // return response.text(); 
    }).then((response) => {
        console.log("response", response);
        //var rcvData=JSON.parse(response); //result.text()  だったらこっち
        //何らかの処理;
    });
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptをすこーし勉強してみたので書き留める④

最低限の知識一応あるけど、復習も兼ねて書いてみることにするの巻その④

関数宣言と関数式(超ざっくり)

  • 関数式
    • 実行が関数式に到達された時に作成される。その後から使用できる。
    • if文外で変数宣言⇨if文内で関数式を使用して代入する⇨あとで使える
  • 関数宣言
    • スクリプト/コードブロック全体で使用できる。
    • 関数宣言は関数式より早く使えるようになる
    • ブロック外だと使えない

アロー関数

アロー関数で書くと...

let func = (arg1, arg2, ...argN) => expression

同じのを関数式で書くと...

let func = function(arg1, arg2, ...argN) {
  return expression;
}

使ってみよう!こんな感じ。

let sum = (a, b) => a + b;

/* アロー関数は次よりも短い形式です:

let sum = function(a, b) {
  return a + b;
};
*/

alert( sum(1, 2) ); // 3

引数一つならかっこ省略でもっと短く。

// 次と同じです
// let double = function(n) { return n * 2 }
let double = n => n * 2;

alert( double(3) ); // 6

引数なしならかっこは必須。

let sayHi = () => alert("Hello!");

sayHi();

アロー関数は引数式と同じように使用できる。

let age = prompt("What is your age?", 18);

let welcome = (age < 18) ?
  () => alert('Hello') :
  () => alert("Greetings!");

welcome(); // ok now

複数行のアロー関数

let sum = (a, b) => {  // 波括弧を使って複数行の関数を書けます
  let result = a + b;
  return result; // 波括弧を使った場合、結果を得るには return を使います
};

alert( sum(1, 2) ); // 3

雑になってしまった....
ちゃんと書けるようになって理解したら書き直そうかね。

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

Kinx Tips - UTF8 文字列のフォーマッティング

Kinx Tips - UTF8 文字列のフォーマッティング

はじめに

「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。Kinx で実装したちょっとした小技を紹介。

そう、ちょっとした小技。

UTF8 文字列のフォーマッティングの問題

C 言語の printf

UTF8 はバイト数と文字幅が一致しないので、"%-20s" とかしても微妙に揃いませんよね。半角カナも試しに使ってみましょう。

#include <stdio.h>

int main()
{
    struct fruits {
        char *name;
        int price;
    } fruits[] = {
        { .name = "りんご", .price = 230 },
        { .name = "みかん(1袋)", .price = 450 },
        { .name = "グレープフルーツ", .price = 120 },
    };
    printf("01234567890123456789\n");
    for (int i = 0; i < sizeof(fruits)/sizeof(fruits[0]); ++i) {
        printf("%-20s ... %3d 円\n", fruits[i].name, fruits[i].price);
    }
    return 0;
}

結果はこうなります。

01234567890123456789
りんご            ... 230 円
みかん(1袋)      ... 450 円
グレープフルーツ ... 120 円

基本的にバイト数なので、日本語 3 バイトであれば 3 消費します。したがって幅が縮みます。

Ruby の sprintf

C と同じかと思いきや、違います。

fruits = [
    ["りんご", 230],
    ["みかん(1袋)", 450],
    ["グレープフルーツ", 120],
]

puts "01234567890123456789"
fruits.each {|name, price|
    puts sprintf("%-20s ... %3d 円", name, price)
}

結果はこうなりました。

01234567890123456789
りんご                  ... 230 円
みかん(1袋)              ... 450 円
グレープフルーツ           ... 120 円

バイト数ではなく文字数です。日本語も(何バイトであろうと) 1 文字で 1 消費します。なので、表示幅が増えます。文字数なので、半角カナだと実は一致します。

Kinx のフォーマッタ

Kinx では UTF8 の文字幅を確認してフォーマット文字列の数値部分を自動調整します。表示幅として機能します。

var fruits = [
    ["りんご", 230],
    ["みかん(1袋)", 450],
    ["グレープフルーツ", 120],
];

System.println("01234567890123456789");
fruits.each(&(e) => {
    System.println("%-20s ... %3d 円" % e[0] % e[1]);
});

結果はこうなります。

01234567890123456789
りんご               ... 230 円
みかん(1袋)          ... 450 円
グレープフルーツ           ... 120 円

Qiita のコードブロックでは等幅で表示されていない感じなので微妙ですが、等幅フォントで見れば縦ラインはきちんと揃っています。東アジア文字幅(East Asian Width)に従って調整するので概ねうまく動くはず 1

多くの人が期待する動作は コレ ではないでしょうか。

おわりに

なかなか忙しくて記事が書けないとき用に、こういった小ネタもストックしておこう。

ではまた、次回。


  1. ここ」に従うと、東アジアの従来文字コードの文脈では Ambiguous Unicode characters は fullwidth 推奨ということでそちらに倒してます。でないと乱れる。 

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

IndexedDB + Dexie.js で CRUDの作成、Vue CLI版

概要

IndexedDB で、Dexie.js ライブラリを使用した
CRUD の作成となります。
vue-router と組み合わせて、ほぼサーバレス的な構成にできるか検討してみました。

・ブラウザ内の、LocalStorageと似ているイメージで
 データは、他のPCから利用できない為。
 オフライン機能で、何か作る場合は。良さそうでした

・開発の面では、通常DBサービス起動も不要で
 Vue-cli サービスのみで。開発できるので準備は楽でした
 

構成

Vue CLI
dexie : 3.0.1
vue: 2.6.11
vue-router

参考

https://developer.mozilla.org/ja/docs/Web/API/IndexedDB_API

https://dexie.org/

https://qiita.com/yamayamasan/items/a4297e724b86f4a00fd2

vuex 追加

npm install --save dexie

package.json

https://github.com/kuc-arc-f/vue_spa3b_1crud/blob/master/package.json


実装など

・db定義
db-name, store ,db-version
storeは、テーブルみたいな扱いのようです

var db = new Dexie("friend_database");
    db.version(1).stores({
    friends: 'name,shoeSize'
});

・書く、読み込み

db.friends.put({name: "Nicolas", shoeSize: 8}).then (function(){
    return db.friends.get('Nicolas');
}).then(function (friend) {
    alert ("Nicolas has shoe size " + friend.shoeSize);
}).catch(function(error) {
    alert ("Ooops: " + error);
});

CRUD の参考

・create
https://github.com/kuc-arc-f/vue_spa3b_1crud/blob/master/src/components/DexieTasks/new.vue

・index
https://github.com/kuc-arc-f/vue_spa3b_1crud/blob/master/src/components/DexieTasks/Index.vue

・show
https://github.com/kuc-arc-f/vue_spa3b_1crud/blob/master/src/components/DexieTasks/show.vue

・edit
https://github.com/kuc-arc-f/vue_spa3b_1crud/blob/master/src/components/DexieTasks/edit.vue


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

お絵かきできるSNSを作りたい!10

お絵かきできるSNSを作りたい後半戦、1つ前に戻すを作っていきます。

筆跡が分るようにjsonで座標を逐一保存しようかとも考えたのですが、管理が大変そうだったので1ストローク毎にcanvasの中身をスクリーンショットを撮る感じにしました。

まず、対処のボタンにイベントを追加します。

<a href="#" class="btn" onclick="doPrevCanvas();">1つ前に戻す</a>

ローカルストレージを用意し、レイヤー1とレイヤー2をそれぞれ1ストローク毎に保存していきます。

// ストレージの初期化
var myStorage = localStorage;

function initLocalStorage(){
    myStorage.setItem("__layer", JSON.stringify([]));
    myStorage.setItem("__layer2", JSON.stringify([]));
}

function setLocalStoreage(){
    var png = $("#canvas")[0].toDataURL();
    var logs = JSON.parse(myStorage.getItem("__layer"));
    setTimeout(function(){
        logs.unshift({png});
        myStorage.setItem("__layer", JSON.stringify(logs));
    }, 0);
    var png2 = $("#canvas2")[0].toDataURL();
    var logs2 = JSON.parse(myStorage.getItem("__layer2"));
    setTimeout(function(){
        logs2.unshift({png2});
        myStorage.setItem("__layer2", JSON.stringify(logs2));
    }, 0);
}

function doPrevCanvas(){
    var logs = JSON.parse(myStorage.getItem("__layer"));
    if(logs.length > 0){
        logs.shift();
        setTimeout(function(){
            myStorage.setItem("__layer", JSON.stringify(logs));
            ct.clearRect(0, 0, $("#canvas").width(), $("#canvas").height());
            if (logs.length == 0) {
                draw("canvas",logs["png"]);
            } else {
                draw("canvas",logs[0]["png"]);
            }
        }, 0);
    }
    var logs2 = JSON.parse(myStorage.getItem("__layer2"));
    if(logs2.length > 0){
        logs2.shift();
        setTimeout(function(){
            myStorage.setItem("__layer2", JSON.stringify(logs2));
            ct2.clearRect(0, 0, $("#canvas2").width(), $("#canvas2").height());
            if (logs2.length == 0) {
                draw("canvas2",logs2["png2"]);
            } else {
                draw("canvas2",logs2[0]["png2"]);
            }
        }, 0);
    }
}

function draw(target,src) {
    var img = new Image();
    img.src = src;
    img.onload = function() {
        if (target == "canvas"){
            ct.drawImage(img, 0, 0);
        } else {
            ct2.drawImage(img, 0, 0);
        }
    }
}

あとは初期化の中でローカルストレージの用意し、線の書き終わりにレイヤー1と2の情報を保存します。

[github]修正内容はこちら

次回は小技(ショートカットの実装)を予定しています。
また気が向いたときにお会いしましょう。

最初:お絵かきできるSNSを作りたい!

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

【Vue】学習開始4週目で覚える内容

4週目で学ぶべきこと

  • フック関数
  • カスタムディレクティブ
  • フィルター
  • ミックスイン
  • Vue Router

フック関数

  • フック関数:プログラムの中に独自の処理を割りこませるために用意されている仕組み。
関数名 詳細
bind 初めて対象のhtmlタグに紐づいた時に、呼ばれる
inserted カスタムディレクティブと紐づいた要素が親Nodeに挿入された際に呼ばれる
update コンポーネント内でデータ更新が行われたタイミングで呼ばれる
子コンポーネント更新される
componentUpdated コンポーネント内でデータ更新が行われたタイミングで呼ばれる
子コンポーネント更新された
unbind htmlタグとの紐付けが解除された時点で呼ばれる

カスタムディレクティブ

  • 引数はel, binding, vnode, oldVnode。 ※基本はel, bindingを使う
  • フック関数の中で、bind, updateは頻出のため、function関数で省略可能
  • elhtmlタグのことを指す。
main.js
//カスタムディレクティブ定義方法①
Vue.directive("sample", {
  bind(el, binding) {
     el.style.color = 'red';
  }
});

//カスタムディレクティブ定義方法②
Vue.directive("sample", function(el, binding) {
  el.style.border = 'red';
});

◆ binding.value

App.vue
<template>
  <!-- "v-sample"は、カスタムディレクティブ -->
  <p v-sample="red">Home</p>
</template>
main.js
Vue.directive("sample", function(el, binding) {
  //v-sample="red"の値を、binding.valueで受け取る
  el.style.color = binding.value;
});

◆ 引数:arg

App.vue
<template>
 <!-- "v-sample:solid"で、引数を指定する -->
  <p v-sample:solid="red">Home</p>
</template>
main.js
Vue.directive("sample", function(el, binding) {
  //"v-sample:solid"の引数を"binding.arg"を用いて取得する
  el.style.samplestyle = binding.arg;
});

フィルター

  • Vue.filterで、フィルターを作成し、パイプを使って適用する
main.js
//フィルター名:"UpperCase" input値を"大文字"に変換する
Vue.filter("UpperCase", function(value) {
  return value.toUpperCase();
});
App.vue
<template>
  <!-- "Vue.filter"で定義した"UpperCase"を挿入する -->
  <h1>{{ answer | UpperCase }}</h1>
</template>

<script>
export default {
  data() {
    return {
     //属性値:answer 初期値:"hello world!"
      answer: "hello world!"
    }
  }
};
</script>

ミックスイン

  • export constを用いてミックスインを定義する
  • ミックスインを定義したファイルをimport, exportを使って反映させる
sample.js
//ミックスイン名:sampleを定義する
export const sample = {
  data() {
    return {
     //属性値:answer 初期値:"hello world!"
      answer: "hello world!"
    }
  }
};
App.vue
<template>
  <p>{{answer}}</p>
</template>

<script>
//ミックスインを定義したファイル名をインポート
import { sample } from "@/sample";

export default {
  //ミックスインで定義した内容をエクスポートし、反映させる
  mixins: [sample]
};
</script>

Vue Router

◆ router.js

router.js
//vue-routerをインポートする
import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";

//Router(プラグイン)を適用する
Vue.use(Router);

//new Routerによって、パスルーティングを指定
export default new Router({
  routes: [
    {
      //path, componentを指定
      path: "/",
      component: Home
    }
  ]
})

◆ main.js

main.js
//vue-routerを追加する
import router from "./router"

new Vue({
  //routerを追加
  router: router,
  render: h => h(App)
}).$mount("#app");

◆ App.vue

App.vue
<template>
  <!-- "router-view"を使用することで、設定したルーティングを適用する -->
  <router-view></router-view>
</template>

同シリーズ

参考文献

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

JSで配列の検索と削除のメモ

よく使う機会あったので備忘メモ
配列のobjectでID一致したらそこを削除するメモ

一致データを削除サンプル

datas = [{id:1,content:"AAA"},{id:2,content:"BBB"},{id:3,content:"CCC"}];

deleteData (id) {
  const result = this.datas.findIndex(
    (item) => item.id === id
  );
  if (-1 < result) {
    this.datas.splice(result, 1);
  }
}

参考サイト

ES6でよく使う、配列の中身を操作・検索する関数
https://qiita.com/pentla/items/a87383903a30d7baa282#findindex
JavaScript - 配列の要素を削除する
https://murashun.jp/blog/20191110-18.html#chapter-3

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

typescriptの導入 + classについてのメモ

TypeScriptのインストール

npm install typescript

typescriptの実行

.tsファイルを.jsファイルにコンパイルし、作成された.jsファイルを実行する。

tsc ファイル名.ts
node ファイル名.js

typescriptでclassの練習

practice.ts
//クラスを作成
class Animal {

    //プロパティ  名前:型
    name: string;
    age: number;  //intではない

    //コンストラクタはインスタンスに引数を持たせる場合に必要    
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

}

//インスタンスを作成
var cat = new Animal("Cat", 7);
console.log(cat.name); //Cat
console.log(cat.age); //7


//コンストラクタは省略が可能
class Animal_no_constructor {

    name: string = "Dog";
    age: number = 3;

}

//コンストラクタを省略した場合は、インスタンスに値を持たせることが出来ない
var dog = new Animal_no_constructor();
//プロパティを出力
console.log(dog.name); //Dog
console.log(dog.age); //3


//メソッドの使い方
class Human {

    name: string;
    score: number;

    constructor(name: string, score: number) {
        this.name = name;
        this.score = score;
    }

    judge() {

        var message: string;

        if (this.score > 50) {
            message = this.name + "は合格";
        } else {
            message = this.name + "は不合格";
        }

        console.log(message);

    }

}

var takeshi = new Human("Takeshi", 100);
takeshi.judge(); //Takeshiは合格

var taro = new Human("Taro", 45);
taro.judge(); //Taroは不合格


//継承
class Oya {

    name: string;

    constructor(name: string) {
        this.name = name;
    }

    hello() {
        console.log("こんちわー");
    }

}

class Kodomo extends Oya {

    constructor(name: string) {
        //Oyaのthis.nameを受け継ぐ
        super(name);
        this.name = name;
    }

    say() {
        //親クラスOyaのhelloメソッド
        super.hello();
        console.log("あの" + this.name + "!?");
    }

}

var yoshida = new Kodomo("yoshida");
yoshida.say(); //こんちわー あのyoshida!?


//デフォルト引数
class Menu {

    item_number: number;

    constructor(item_number: number = 0) {
        this.item_number = item_number;
    }

    say_item_name() {
        var array = ["ラーメン", "うどん", "蕎麦"];
        console.log(array[this.item_number]);
    }

}

var soba = new Menu(2);
soba.say_item_name(); //蕎麦

var wasureta = new Menu();
wasureta.say_item_name(); //ラーメン(引数がないので自動で0に)

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

jsonのPHP、JSでのエンコードとか

php

fetchall(PDO::FETCH_ASSOC) — 結果セットに 返された際のカラム名で添字を付けた配列を返す。
json_decode — JSON形式の文字列をオブジェクトもしくは連想配列に変換する
json_encode — 値をJSON形式にして返す

JSON

JSON.parse — JSON形式で書かれた文字列をJavaScriptのJSONオブジェクトに変換する
JSON.stringfy — JSONオブジェクトを文字列に変換する

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

完成!!初めてReact.jsでWebサイト作った!!

とりあえず完成!

つまずいた点たくさんありました...
ハマったポイントを記事にしたのはまだ1つだけですが,今後作ってきます

一通り完成したので報告致します.<--急にかしこまる
https://shinnosuke7031.github.io/react-test/

意識したのは,ページ遷移しないで表示内容を変えること!

デザインはまだまだですが...

ぜひアドバイスとかいただけると幸いです

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

【Nuxt.js】Nuxt文法編:v-slot(中級)

分割代入

簡単にいうと別の場所で
別の変数名をきめれて
値を代入できること
MDN分割代入

というより見た方が早いですね?
親で子の値を使えちゃいます!

❓どんな時に使うか
 まとまったdataを子で管理したい時に使います!

Text.vue
<template>
 <div class="title title-page">
   <slot v-bind:user="user">
     {{ user.lastName }}
   </slot>
 </div>
</template>

<script>
export default {
 data () {
   return {
     user: {
       firstName: 'first',
       lastName: 'last',
     },
   }
 },
}
</script>
index.vue
<template>
 <div class="page">
   <Text>
     <template #default="sample">
       {{ sample.user.firstName }}
     </template>
   </Text>
 </div>
</template>

<script>
import Text from '~/components/Text.vue'

export default {
 components: {
   Text,
 },
 data () {
   return {
   }
 },
}
</script>

動的なスロット名

まずは動的引数を理解しましょう?
https://jp.vuejs.org/v2/guide/syntax.html#動的引数

【解説/index.vue】
リンク
 これと全く同じです❗️
 リンク

Link.vue
<template>
  <a :[attributeName]="url"> リンク </a>
</template>

<script>
export default {
 data () {
   return {
     attributeName: "href",
     url: "/"
   }
 },
}
</script>
index.vue
<template>
 <div class="page">
   <Link />
 </div>
</template>

<script>
import Link from '~/components/Link.vue'

export default {
 components: {
   Link,
 },
}
</script>

これをslotで…

できるのですが、
簡単な方法があります!笑

v-bind="$attrs"
これを使います!

【解説】
属性自体を親から渡したい時
v-bind="$attrs"を使います?
今回の場合はaタグの
href属性ごと渡してます。

Link.vue
<template>
  <a v-bind="$attrs">リンク</a>
</template>

<script>
export default {
}
</script>
index.vue
<template>
 <div class="page">
   <Link
     href="/"
   />
 </div>
</template>

<script>
import Link from '~/components/Link.vue'

export default {
 components: {
   Link,
 },
}
</script>

まとめ

置き換えのできる3つをまとめました!

slot:テキスト
props:それ以外、クラス付与などに便利
v-bind="$attrs":属性自体

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

ℹ NuxtJS collects completely anonymous data about usage.

ℹ NuxtJS collects completely anonymous data about usage.
  This will help us improving Nuxt developer experience over the time.
  Read more on https://git.io/nuxt-telemetry

? Are you interested in participation? (Y/n)

なんかこういうのが出るようになった。
ちょっと鬱陶しい。

表示されるリンクを見るだけなんだけれども。
https://github.com/nuxt/telemetry#opting-out

3の nuxt.config.js に設定するやり方で出なくなった。

export default {
  telemetry: false
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【javascript】配列メソッド

書籍のアウトプットとして。

Array.fromを使って配列を作成

数値の平均を求める関数お作成しているとして、以下のような関数の定義はうまく実装されません。

function avg() {
  const sum = arguments.reduce(function(a, b) {
    return a + b;
  })
  return sum / arguments.length;
}

なぜならargumentsオブジェクトは配列ではなく、配列のようなオブジェクトだからです。。
"arguments.reduce is not a function"というエラーは、argumentsオブジェクトを配列に変換する必要があるということです。

配列のようなオブジェクトを配列に変換するにはArray.prototypesliceメソッドを適応させます。
sliceを引数無しで呼び出すと、配列のシャローコピーを作成します。これを配列のようなオブジェクトに適応しても、配列が作成されます。
またArray.prototype.applyでもうまくいきます。

配列のようなオブジェクト
配列でないものの、lengthプロパティを持ち、添字によるアクセスができ、forループで処理もできるオブジェクトのこと。

Array.prototype.slice.call(arrayLikeObject);

//または
[].slice.call(arrayLikeObject);

これを使用して先の関数を修正します。

function avg() {
  const args=[].slice.apply(arguments);
  const sum = args.reduce(function(a, b) {
    return a + b;
  })
  return sum / arguments.length;
}

以下はArray.fromを使用してバージョンです。

function avg() {
  const args=Array.from(arguments);
  const sum = args.reduce(function(a, b) {
    return a + b;
  })
  return sum / arguments.length;
}

Array.fromは配列のようなオブジェクトを配列に変換します。

Array.fromdocument.querySelectorAllとの組み合わせ

document.querySelectorAllのオブジェクト型はNodeListであり、配列ではありません。

Array.fromはlengthプロパティを持つオブジェクトであれば、どのオブジェクトでもうまくいきます。
配列にしたい対象がlengthプロパティを持ってさえいれば配列に変換できるということです。

Array.from({length:50})

これによりnew Array(50)と同じ新しい配列が作成されます。
これは長さが50の配列です。

Array.ofを使って配列を作成

以下のコードを執行するとどうなるでしょう。

let a=new Array(1,2,3)
let b=new Array(1,2)
let c=new Array(1)

aとbは普通の配列が作成されるが、cの結果はemptyとなり、1つの値を持った配列を作成できません。
これはArrayのコンストラクタの振る舞いです。
これを回避する方法としてArray.ofファクトリメソッドを使用します。

let a=Array.of(1,2,3)
let b=Array.of(1,2)
let c=Array.of(1)

こうすることで1つの値を持つ配列を作成できます。

「そんなことしなくても配列リテラルをつ開けばよいのでは?」と思うかもしれないです。

let a=[1,2,3]
let b=[1,2]
let c=[1]

しかしこれがうまく行かない状況があります。
その一つは配列のサブクラスを使用しているときです。
AwesomeArrayというArrayのサブクラスを使用しているとします。
するとAwesomeArrayはnew AwesomeArray(1)が使えません。

更に配列リテラルも使用できません。
配列リテラルを使用するとAwesomeArrayではなくArrayのインスタンスになってしまうからです。

しかしArray.ofは使用できるため、1つの値に1つだけ含まれたAwesomeArrayのインスタンスが返されます。

Array.prototype.fillを使って配列を作成

ここでは三目並べゲームを作っていきます。
具体的な構成は以下です。
- 9個のマスは長さ9の配列を使用
- マスにおけるのは"x"と"o"、マスは空("")で表現

配列をboardとするとこのように初期化できる。

const board = new Array(9).map(function(i) {
  return ' ';
})

map() メソッドは、与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成します。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map

new Array(9)で9この値を持つ配列を初期化すると、すべての値がundefinedになるので、mapでundefined値をそれぞれスペースに変換します。
しかしこの方法はうまくいきません。

new Array(9)を実行すると実際には9個のundefinedが追加されるのではなく、lengthプロパティに9が設定された新しい配列が作成されるだけだからです。

どういうことかというと、例えば['a','b','c']という配列を作成したとすると内部ではこうなっています。

{
  length:3
  0:'a',
  1:'b',
  2:'c',
}

new Array(9)を実行すると配列の内部では下記のようになっていると思ってしまいます。

{
  length:9
  0:undefined,
  1:undefined,
  2:undefined,
  3:undefined,
  4:undefined,
  5:undefined,
  6:undefined,
  7:undefined,
  8:undefined,  
}

しかし実際にはこうです。

{
  length:9
}

lengthプロパティが設定されているだけで、値は含まれていません。
欠けている値は(hole)と呼ばれます。
mapには対応しないのはこれが原因です。

配列に特定の値を設定するにはfillを使用します。

const board = new Array(9).fill(' ');

Array.prototype.includeを使って配列を検索する

String.prototype.includeと同様に配列にもincludeが同じように機能します。

Array.prototype.includeメソッドは配列のいずれかのインデックス位置に含まれている値が、指定された値を同じかどうかをチェックします。
これまではindexOfが使用されていました。
indexOfは結果に-1が含まれていた場合の比較を忘れてしまうバグが有りましたが、includeはブーリアンを返します。

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

コールバック関数不要「JSONP」取得関数(webページで複数回JSONPを使いたい人に)

Google Apps Scriptで作った複数の疑似APIからのJSONP取得が面倒(コールバック関数をその分だけ用意する必要があるなど)かつjQuery拡張のjQuery-JSONPを使いたくなかったので、コールバック関数無しにJSONPからJSONを取得する関数をピュアなJavaScriptで作ってみました。この関数を使えば、もう、JSONP取得のためにわざわざコールバック関数を用意する必要はありません。

大元のコード

JavaScript
//引数
//url: jsonpのurl
//cbName: jsonpを起動することになっているはずのコールバック関数の名前
function JSONP(url, cbName="callback") {
    return new Promise(function(_r, _e) {
        window[cbName] = function(j) {
            delete window[cbName];
            _r(j);
        }
        var s = document.createElement("script");
        s.src = url;
        document.head.appendChild(s);
        s.onerror = function(e) {
            delete window[cbName];
            _e(e);
            s.remove();
        }
    });
}

minified版

JavaScript
function JSONP(url,cbName="callback"){return new Promise(function(i,r){window[cbName]=function(n){delete window[cbName];i(n)};var u=document.createElement("script");u.src=url;document.head.appendChild(u);u.onerror=function(n){delete window[cbName];r(n);u.remove()}})}

使い方

JSONP関数はPromiseオブジェクトを返すので、返り値はthenで受けます。

分からない方のために念の為補足すると、thenの中に書かれた処理は、JSONPからJSONを取得した「直後」に起動します。

JSONPのURL

JavaScript
var url = "https://script.google.com/macros/s/XXXXX/exec?callback=cbFunc";
//この例では、"cbFunc"がリクエストしたコールバック関数名
//サーバー側でコールバック関数名が指定されている(ヒエッ…)場合は、その名前を把握しておく

使い方

JavaScript
/*使用例その1*/
JSONP(url, "cbFunc")
.then(function(r) {//jsonp読み込み成功時の処理
    console.log(r);//返り値(r)はJSONオブジェクト
})
JavaScript
/*使用例その2*/
JSONP(url, "cbFunc")
.then(function(r) {
    console.log(r);
})
.catch(function(e) {//jsonp読み込み失敗時の処理
  console.log(e);//返り値(e)はonerrorのイベントオブジェクト
})
JavaScript
/*使用例その3-α*/
//ネストであれば、同じコールバック関数名を使ってもヨシ!
//ネストで無いならば、コールバック関数名は被らないように
JSONP(url, "cbFunc")
.then(function(r) {
    console.log(r);

    JSONP(url, "cbFunc")
    .then(function(r) {
        console.log(r);
    })
})

/*使用例その3-β*/
//IEを気にする必要が無いなら、アロー関数を使うのもアリ
JSONP(url, "cbFunc").then(r=>{console.log(r),JSONP(url, "cbFunc").then(r=>console.log(r))});
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コールバック関数&jQuery不要「JSONP」取得関数(webページで複数回JSONPを使いたい人に)

Google Apps Scriptで作った複数のAPIからのJSONP取得が面倒(コールバック関数をその分だけ用意する必要があるなど)かつjQuery拡張のjQuery-JSONPを使いたくなかったので、コールバック関数無しにJSONPからJSONを取得する関数をピュアなJavaScriptで作ってみました。この関数を使えば、もう、JSONP取得のためにわざわざコールバック関数を用意する必要はありません。

大元のコード

JavaScript
//引数
//url: jsonpのurl
//cbName: jsonpを起動することになっているはずのコールバック関数の名前
function JSONP(url, cbName="callback") {
    return new Promise(function(_r, _e) {
        window[cbName] = function(j) {
            delete window[cbName];
            _r(j);
        }
        var s = document.createElement("script");
        s.src = url;
        document.head.appendChild(s);
        s.onerror = function(e) {
            delete window[cbName];
            _e(e);
            s.remove();
        }
    });
}

minified版

JavaScript
function JSONP(url,cbName="callback"){return new Promise(function(i,r){window[cbName]=function(n){delete window[cbName];i(n)};var u=document.createElement("script");u.src=url;document.head.appendChild(u);u.onerror=function(n){delete window[cbName];r(n);u.remove()}})}

使い方

JSONP関数はPromiseオブジェクトを返すので、返り値はthenで受けます。

分からない方のために念の為補足すると、thenの中に書かれた処理は、JSONPからJSONを取得した「直後」に起動します。

JSONPのURL

JavaScript
var url = "https://script.google.com/macros/s/XXXXX/exec?callback=cbFunc";
//この例では、"cbFunc"がリクエストしたコールバック関数名
//サーバー側でコールバック関数名が指定されている(ヒエッ…)場合は、その名前を把握しておく

使い方

JavaScript
/*使用例その1*/
JSONP(url, "cbFunc")
.then(function(r) {//jsonp読み込み成功時の処理
    console.log(r);//返り値(r)はJSONオブジェクト
})
JavaScript
/*使用例その2*/
JSONP(url, "cbFunc")
.then(function(r) {
    console.log(r);
})
.catch(function(e) {//jsonp読み込み失敗時の処理
  console.log(e);//返り値(e)はonerrorのイベントオブジェクト
})
JavaScript
/*使用例その3-α*/
//ネストであれば、同じコールバック関数名を使ってもヨシ!
//ネストで無いならば、コールバック関数名は被らないように
JSONP(url, "cbFunc")
.then(function(r) {
    console.log(r);

    JSONP(url, "cbFunc")
    .then(function(r) {
        console.log(r);
    })
})

/*使用例その3-β*/
//IEを気にする必要が無いなら、アロー関数を使うのもアリ
JSONP(url, "cbFunc").then(r=>{console.log(r),JSONP(url, "cbFunc").then(r=>console.log(r))});
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クロスオリジンエラーの解決

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

IE11だとNodeListがforEachで回らない問題

はじめに

IEの配布元であるマイクロソフトを始め、 IEが1日も早く滅んでほしい、なぜIE拡散禁止条約がないのか、早くWTOで世界IE禁止宣言を採択してほしい と世界中のweb系エンジニアは強く祈っていることだとは思いますが、様々な事情をお持ちの顧客のために日夜IE対応に心を砕いていることと存じ上げます。
それでもIEの最終バージョンであるIE11はまだマシな方なんだとは思いますが、あらゆるpolyfillをブチ込んでbabelをまわさないとイマドキ文法で書かれたJSは動きません。今宵もそんなフロントエンドエンジニアたちの天を貫く喜び、悲しみ、怒りを抱え、欲望の果へ向かいbabelが唸りをあげます。

BUCK-TICKの宗教ソング「BABEL」の歌詞が、babelを使いの気持ちを余すところなく表現してて最高なので、ぜひご一読ください。
http://j-lyric.net/artist/a0006e7/l0438a2.html

NodeListにforEachメソッドが居ない(ただしIEに限る)

ある時「IEでJSが死んでるぞ」と庭でマンボウが死んでるくらいのテンションで報告を受けました。
しゃーないな、と思ってテスト用のVMを立ち上げて見てみたら見事に死んでいたのですが、どうやら「NodeListにforEachなんてメソッドないで」というやつでした。
マジで?と思ったらマジでした。

image.png
https://developer.mozilla.org/ja/docs/Web/API/NodeList/forEach

孔明先生もショックです。

NodeListって何?

document.querySelectorAll() の戻り値として返ってくるDOMノードの集合体です。
https://developer.mozilla.org/ja/docs/Web/API/NodeList

Arrayで返ってきてもいいんじゃないのか?とは多少思いますが、ActionScriptで言うところのArrayListっぽい作りになっています。なので、Arrayに変換自体は可能です。

jQueryでclassで引っ掛けると配列ではなくてjQueryオブジェクトで返ってきて、そいつに each() しないと走査できないのと感覚は同じです。

解決策

まあ、さっきのページにpolyfillがかいてあるので、それをそのまま入れてもいいのですが、なんか癪なのでnpmにpolifill居るんじゃね?と思って探したらいました。

https://www.npmjs.com/package/nodelist-foreach-polyfill

まあ、なのでこいつをnpmで入れてimportすれば万事解決です。

コマンドライン
$ npm install nodelist-foreach-polyfill --save-dev
import 'nodelist-foreach-polifill'

class Hoge{
    static init() {
        const hogelist = document.querySelectorAll('.hoge');
        hogelist.forEach( e => e.classlist.add('fuga') );
    }
}

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

「Unary operator '++' used」←eslintにこんなこと言われた時

いつもfor文を以下のように書いてました。

for (let i = 0; i < parameters.length; i++)

でもこれではeslintに引っかかってしまいます。

なので以下のように書きましょう。

for (let i = 0; i < parameters.length; i += 1)

これでエラーは解消されるはずです。

参考

https://eslint.org/docs/rules/no-plusplus

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

[Javascript]iframeによって読み込まれているか判別する方法

はじめに

自分がiframeによって読み込まれているときだけ行いたい処理があったので、iframeによって読み込まれているかどうかを判別する方法を調べました。
自分用の備忘録も兼ねてまとめます。

結論

初めに結論です。

window != window.parent

で判別できます。
trueならiframeによって読み込まれているということになります。

解説

簡単に解説を書きます。

まず、iframeについてMDNに書かれていることをまとめると次のようになります。

  • iFrameは閲覧コンテキスト(browsing context)を表現する
  • 閲覧コンテキストは、セッション履歴(History)と文書(Document)をもつ
  • 他の閲覧コンテキストを埋め込んでる閲覧コンテキストは親閲覧コンテキストと呼ばれる
  • 最上位の閲覧コンテキストは、Windowオブジェクトで表される

image.png

つまり、
iFrameによって読み込まれている時、window.parentはiframeの親閲覧コンテキストになるので、windowにはなりません。

間違いや指摘があれば、コメントにお願いします。

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

関数合成とReactコンポーネントとReact hooks

はじめに

Reactが好まれる理由の一つとしてただの関数としてかけるからというのがあります。Reactの関数コンポーネントは関数のように合成できます。React hooksもただの関数ですので合成できます。簡単な例で説明できたら分かりやすいのではないかと思い、書いてみます。

普通のJavaScript

関数がない(一つだけ)の場合は、例えば次のようになります。

const main = (args) => {
  const a = args[0] * 2;
  const b = args[1] * 2;
  console.log([a, b]);
  return a + b;
};

関数は、再利用性を増すために使うことができます。

const double = (x) => x * 2;

const main = (args) => {
  const a = double(args[0]);
  const b = double(args[1]);
  console.log([a, b]);
  return a + b;
};

また、たった一度しか使わない関数であっても、名前をつけて読みやすくするために関数化する場合があります。

const double = (x) => x * 2;
const printForDebug = (x) => console.log(x);

const main = (args) => {
  const a = double(args[0]);
  const b = double(args[1]);
  printForDebug([a, b]);
  return a + b;
};

簡単な例ですが、これが普通のJavaScriptの場合です。

Reactコンポーネント

ReactコンポーネントはReactNodeを返す関数として書くことができます。JSXで書くことが多いので、それにならうと例えば次のようになります。

const App = () => {
  return (
    <div>
      <h1>Hello</h1>
      <h2>World</h2>
    </div>
  );
};

これを関数に分割して合成するには次のように書けます。

const Title = () => <h1>Hello</h1>;
const Subtitle = () => <h2>World</h2>;

const App = () => {
  return (
    <div>
      {Title()}
      {Subtitle()}
    </div>
  );
};

これは完全に同じ結果を生み出します。ただの関数ですから。

しかし、このパターンはあまり見たことがないでしょうし、実際非推奨です。推奨される書き方は、次のようになります。

const Title = () => <h1>Hello</h1>;
const Subtitle = () => <h2>World</h2>;

const App = () => {
  return (
    <div>
      <Title />
      <Subtitle />
    </div>
  );
};

見慣れた書き方かと思われます。こちらが推奨される理由は、TitleやSubtitleの関数を呼び出すタイミングをReactが制御できるからです。

<Title />createElement(Title, null) と同等です。(執筆時点) 参照

この書き方は、Reactコンポーネントを関数合成する際の制約とも言えます。関数として直接合成するのではなく、createElementを介して合成することで、Reactのスケジューリングの恩恵を受けることができます。

React hooks

では、React hooksの場合はどうなるでしょうか。同じように簡単な例を考えます。

const App = () => {
  const [a, setA] = useState(0);
  const incrementA = () => {
    setCountA((c) => c + 1);
  };
  const [b, setB] = useState(0);
  const incrementB = () => {
    setCountB((c) => c + 1);
  };
  useEffect(() => {
    console.log([a, b]);
  });
  return (
    <div>
      {a} <button onClick={incrementA}>+1</button>
      {b} <button onClick={incrementB}>+1</button>
    </div>
  );
};

共通している処理があるので関数に切り出してカスタムフックにしてみましょう。

const useCount = (initialCount) => {
  const [count, setCount] = useState(initialCount);
  const increment = () => {
    setCount((c) => c + 1);
  };
  return [count, increment];
};

const App = () => {
  const [a, incrementA] = useCount(0);
  const [b, incrementB] = useCount(0);
  useEffect(() => {
    console.log([a, b]);
  });
  return (
    <div>
      {a} <button onClick={incrementA}>+1</button>
      {b} <button onClick={incrementB}>+1</button>
    </div>
  );
};

場合によっては、共通処理でなくてもカスタムフックにすることで見通しが良くなるかもしれません。

const usePrintForDebug = (x) => {
  useEffect(() => {
    console.log(x);
  });
};

const App = () => {
  const [a, incrementA] = useCount(0);
  const [b, incrementB] = useCount(0);
  usePrintForDebug([a, b]);
  return (
    <div>
      {a} <button onClick={incrementA}>+1</button>
      {b} <button onClick={incrementB}>+1</button>
    </div>
  );
};

Reactコンポーネントの関数合成に制約があったように、React hooksにおける制約もあります。 Rules of Hooks に詳しく書かれていますが、この制約の範囲内でしかカスタムフックは作れないことになります。

React hooksの制約は直感的ではないと言えるかもしれませんが、Reactコンポーネントの(緩い)制約も決して直感的とは言えないでしょう。制約の数は少ない上、パターン化されているので迷いは少ないと思いますが。React hooksの制約は eslint plugin でほぼチェックできますので、これを使うことが「パターン」として必須と言えるでしょう。

おわりに

React hooksを使う際にどの程度で関数化すなわちカスタムフック化したらいいかは、一言で答えられない問題かと思います。一言で答えるなら、Reactコンポーネントを分割するように分割したらいいのではないかと言います。つまり答えになっていませんが。私自身は関数は小さくしたい派なので、コンポーネントもカスタムフックも小さく分割して合成することを目指します。この辺りはReactとしての制約はなく柔軟なので、プロジェクトでの方針や規約を決めるといいかもしれません。(コンポーネントが大きすぎるとパフォーマンスに影響は出そうです。カスタムフックが大きすぎてもパフォーマンスには関係なさそう)

コンポーネントの場合はAtomic Designなどの方法論があるのでカスタムフックにもそのような方法論があったり、アレンジして適用できるかもしれません。

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

ビルド不要のドキュメントサイトジェネレーター「docsify」の個人的まとめ

この記事は、
ドキュメント静的サイトジェネレーターである docsify の使い方について
個人的にまとめたものです。

はじめに

想定読者

  • Markdown について知っている
  • 開発が活発にされなくなった gitbook-cli の代替を探している
  • 日本語検索に対応している 静的サイトジェネレーター が欲しい

この記事で得られること

  • docsify の基本的な使い方
  • お手軽なドキュメント作成方法

この記事で得られないこと

docsifyの特徴

docsify とは

image.png

「docsify」は、公式を直訳すると 魔法のドキュメントサイトジェネレーター です。

すなわち、ドキュメントを作成するツールです。

どのあたりが魔法かというと、

  • markdown などから html を生成する 静的サイトジェネレーターと違って、ビルド不要
  • シンプルで比較的軽量
  • 全文検索プラグイン付き
  • 複数テーマ有り
  • プラグインシステムが使える
  • 絵文字やIE11のサポート
  • サーバーサイドレンダリングも可能

とのことです。

なぜ docsify 紹介してるの

ことの発端は、ある時、Node.jsのバージョンを上げた際に、開発がもうあまり活発ではない gitbook-cli を使おうとしたら、ついにエラーが起きてしまったんですね。

旧バージョンであれば使えるので、まあいいか、とも思ったのですがこれを機に、新たなツールを模索していた際に出会ったのが docsify でした。

Rust製の mdbook もいい なと思ったので、使い分けしていこうと思っていますが、
docsifyの手軽さと、日本語検索に対応しているという点で魅力を感じ、
使い方を整理しておこう! といった流れで今に至ります。

また、npxを使って、ライブラリのインストール不要で利用できる 点も個人的に高評価ですね。
Node.js が動く環境でさえあれば、利用できるわけです!

さらに言えば、Node.jsが無くても動作します。

docsifyの一番簡単な使い方

説明はこれくらいにして、使い方を見ていきましょう。

一番シンプルな例です。

index.htmlREADME.MDの2つを用意するだけでシングルページを作成できます。

.
├── README.md
└── index.html

index.html

index.htmlは、次の内容で作成します。

index.html
<!-- index.html -->

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <meta charset="UTF-8">
  <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/themes/vue.css">
</head>
<body>
  <div id="app"></div>
  <script>
    window.$docsify = {
      //...
    }
  </script>
  <script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
</body>
</html>

README.md

README.md
# これはサンプルです。

ドキュメント静的サイトジェネレーターである **docsify** の使い方について

個人的にまとめたものです。

## はじめに

### 想定読者

* Markdown について知っている
* 開発が活発にされなくなった gitbook-cli の代替を探している
* 日本語検索に対応している 静的サイトジェネレーター が欲しい

### この記事で得られること

* [docsify](https://github.com/docsifyjs/docsify) の基本的な使い方
* お手軽なドキュメント作成方法

### この記事で得られないこと

* [公式ドキュメント](https://docsify.js.org/#/)に記載されている細かい仕様
* [他の静的サイトジェネレーター](https://www.staticgen.com/)について
* Node.js の環境準備方法

ローカルプレビュー( Python を使用した例)

Pythonを使用した場合の、ローカルサーバープレビューです。

python -m http.server 3000

image.png

めちゃくちゃ簡単ですね。

npx を使った docsify の使い方

npx を使った場合の例です。
上の「一番簡単な使い方」のファイル作成部分をコマンドから自動でやってくれる点で便利です。

※ もちろんインストールして使用することも可能なのでその場合は、公式のわかりやすいクイックスタートを参照してください!

初期化

npx docsify-cli init ./docs
.
└── docs
    ├── .nojekyll
    ├── README.md
    └── index.html
# ./docs/.nojekyll (Github Page用)

docsは任意フォルダです。

ローカルサーバープレビュー

npx docsify-cli serve docs
# http://localhost:3000にアクセスすると、README.mdの内容が表示される

docsifyのカスタマイズ

基本的な使い方は、理解していただけたかと思います。

実際にドキュメントを作成していくと、サイトの表記やデザインなどをカスタマイズしたくなるかと思います。

サイトのデザインやプラグインなどの設定は、index.htmlを編集することでカスタマイズできます。

docsifyの設定

docsifyの設定は、window.$docsify = {} 内で行うようです。

<script>
    window.$docsify = {
      //...
    }
</script>

個人的ベストプラクティスのの方針が固まったら、当記事を随時更新したいと思います。

それまでは、公式ドキュメント - カスタマイズ- を参照くださーい。(手抜き)

デプロイ方法

公式ドキュメント - デプロイ - にいくつか、方法が紹介されています。
わかりやすいので、読めばわかると思いますので、これも手抜きしちゃいます。

おわりに

使いながら、より良い設定値なんかを更新できたらいいなと思います。

以下は、その他の参考です。

参考

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

30行のJavaScriptコードでスマートホームシステムを構築する方法

この記事では、IoTトレンドの成長を探り、わずか30行のコードでスマートホームシステムを構築する方法を紹介します。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

スマートホームをはじめとする多くのIoT(Internet of Things)アプリケーションは、5Gなどの技術の台頭により、今年に入って急速に人気を集めています。スマートウォッチやテレビなど、「スマート」と表示される製品が増えており、人々が「スマート」という言葉を生活様式に変えていることを示しています。

一般的なスマートホームのソリューションには、デバイス(モノ)、クラウド、アプリケーションがあります。ソリューションの中には、ビッグデータやAIも含まれています。従来のIoT開発は「順序」を重視しており、つまり、デバイス、クラウド、アプリケーションでデータを順次処理していく必要がありました。今日では、Alibaba Cloud IoT Platformの「Thing Specification Language(TSL)」に基づいて、IoT開発の両端を並行して実行することができ、人件費や材料費を大幅に節約できるようになっています。

並行して実行することは明らかに魅力的ですが、一歩進んで、すべての開発を一人の人間に任せることはできるのでしょうか?答えはイエスです。私たちが自由に使えるすべての技術があれば、ウェブサイトを構築するのと同じように、スマートホームを自分たちで簡単に設計して構築することができるようになりました。Alibaba Cloud IoT Platformを利用すれば、30行のコードでスマートホームソリューションを完成させることができます。

image.png

現在、多くのインターネット開発者が、C/C++言語の基礎などの組み込み開発能力の不足により、IoTの門戸に足を止めています。アリババクラウドIoTプラットフォームが提供する「Embedded Javascript Tool」を利用することで、JavaScriptを利用したデバイス開発を迅速に行うことができ、これらの開発者が直面している最大の問題をシームレスに解決することができます。また、フロントエンド開発やバックエンド開発に不慣れな組み込み開発者のために、Alibaba Cloud IoT Platformが提供する「Visual Building」アプリケーションなどのクイックスタート機能を利用することで、ゼロコードでのアプリケーション開発が可能となり、学習の手間を大幅に軽減することができます。

サービスを有効にする

まず、Alibaba Cloudアカウントを申請し、ワンストップ開発プラットフォーム「IoT Studio」を有効にしてログインします。

次に、「Create Project」(好きな名前でOK)>「Device Development」>「Add Product」>「Category」を選択します。必要に応じて「Lighting」または「Temperature & Humidity Meter」を選択し、通信方式はWi-Fiを選択し、データ形式はAlinkを選択します。

Device Development>Add Debugging Devicesを選択し、デバイスのトライタプルをメモします。

デバイス開発

組み込みJavaScriptのオンラインワークベンチを開き(開発環境を構築する必要はありません)、新規プロジェクトを作成します。index.jsのコードを置き換えます。

Lighting

var deviceShadow = require('deviceShadow');
var ledHandle = GPIO.open("led1");

deviceShadow.bindDevID({
  "productKey": "123",
  deviceName: "",
  deviceSecret: ""
});

function main(err){
  if(err){
    console.log("failed to connect to the platform");
  }else{
    console.log("the main program started");
    deviceShadow.addDevSetPropertyNotify("LightSwitch", function (lightStatus) {
      GPIO.write(ledHandle, 1-lightStatus);
    });
    var mainLoop = setInterval(function () {
      var ledStatus = GPIO.read(ledHandle);
      deviceShadow.postProperty("LightSwitch", 1-ledStatus);
    }, 2000);
  }
}

deviceShadow.start(main);

Temperature and Humidity Meter

var deviceShadow = require('deviceShadow');
var shtc1 = require('shtc1');
var handle = new shtc1('shtc1');
var ledHandle = GPIO.open("led");

deviceShadow.bindDevID({
  productKey: "a17vi82MmxP",
  deviceName: "0001",
  deviceSecret: "tYUngSMqYeDxODgtX3DNKkQ7920I3t4T"
});

function main(err) {
  if (err) {
    console.log("failed to connect to the platform");
  } else {
    console.log("the main program started");
    var mainLoop = setInterval(function () {
      var val = handle.getTempHumi();
      console.log('shtc1:temp=' + val[0] + ' humi:' + val[1]);
      deviceShadow.postProperty("CurrentTemperature", val[0]);
      deviceShadow.postProperty("RelativeHumidity", val[1]);
    }, 2000);
  }
}

deviceShadow.start(main);

デバイス(ESP32など)をコンピュータに接続し、"Connect "と "Run "をクリックします。起動後、デバイスが自動的にindex.jsを読み込んで実行し、同時にAlibaba Cloud IoT Platformにデータを報告します。

アプリケーション開発の様子

システムはアプリケーションなしでは動作しません。ビジュアルビルディング機能を使えば、コードゼロでアプリケーションを素早く完成させることができます。ダッシュボードにドラッグしてコンポーネントを順番に切り替え、画像を入れ替え、デバイスをバインドするだけですべての操作が完了します。

image.png

わずか30行のコードで構築されたエンドツーエンドのスマートホームシステムが完成し、保存して公開した後、他の人と共有することができます。

Embedded Javascript ToolとIoT Studioを使用することで、開発者は新しいプログラミング言語を習得することなく、シームレスかつ迅速にIoTの開発を開始することができ、Alibaba Cloud IoT Platformの包摂性と独創性を実証しています。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

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

JavaScript中級者になるために参考になるサイトをまとめてみた。

対象者

JavaScript初心者を抜け出したい方
変数やメソッドなどの基礎的なところはわかっている方
progateを終えて次のステップに進みたい方

なぜ書いたか

プログラミングを一通り勉強してきて、初心者という枠を抜け出したいと思い、いろいろ調べている中でとても良いサイトや動画に出逢ったので自分と同じように中級者へステップアップしたい方向けに記事を書こうと思った次第であります。

youtube

いきなり動画かよと思う方がいらっしゃるかもしれませんが、対象が初心者なので学びやすい動画を先に持ってきました。(筆者も初心者から中級者になろうとしている最中なのでとても参考にさせていただいております。)

しまぶーのIT大学さん
プログラミングはもちろんですが、そのほかにもJavaScriptの歴史の背景の部分を解説してくれているので、なぜこの技術が必要となったのか理解することができます。

たにぐちまことさん
JavaScript以外にもたくさんの動画を出されている方でとてもわかりやすく、本当に初心者の方はこの方の動画から入るのが良いのではないでしょうか?

Web万屋エンジニアチャンネルさん
例えが的確すぎてとてもわかりやすいのが特徴です。
特にレキシカル環境を卵に例えた話は目から鱗がボロボロ落ちました笑
動画の対象は初心者から中級者の手前向けといった感じでしょうか。

Code Mafiaさん
JavaScript中級者への道という動画をだしている方で、初心者から中級者になるためにつまずくところをとてもわかりやすく解説してくれています。

Webサイト

MDN(JavaScript)

初心者から上級者までお世話になるサイトです。
初心者を抜け出したければ必ず目を通しましょう。ただ、難しいところも多いです。
初心者の方で読んだことある方は毛嫌いしているサイトであるかもしれません。気持ちはとてもよくわかります。
でも逃げていては初心者から抜け出すことはできません。筋トレと一緒で負荷をかけなければ成長はしません。筋肉痛だと思って頑張りましょう。

現代のJavaScriptチュートリアル
初歩的なところから深いところまで一通り学べるサイトです。
練習問題もあるので理解できたかの確認ができます。
量がとても多く難しいところも多いので少しずつ進めていきましょう。

中上級者になるためのJavaScript

タイトルにあるようにJavaScriptで中上級者を目指すためのサイトになっております。目次をみてみてどういったものがあるか確認してみると良いでしょう。

最後に

JavaScript中級者へのステップアップを目指されている方の参考になれば幸いです。
千里の道も一歩から
がんばっていきましょう!

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

【JavaScript】 js 繰り返し文 for / while

【ゴール】

JavaScriptで使える繰り返し文

【メリット】

■ javascript理解度向上
■ リーダブルコード実現

【開発環境】

■ Mac OS catalina
■ Ruby on Rails (5.2.4.2)
■ Virtual Box:6.1
■ Vagrant: 2.2.7

【コード】

1-100まで1つずつ足されていくという処理を例にします。

while

※()に条件
※{}に出力処理 & 加算処理

hoge.js
while(number <= 100){
 console.log(number);
 number ++ ;
}

for

※forは条件を()内に全て記述、シンプルで◎

hoge.js
for(number = 1; number <= 100; number ++){
 console.log(number);
}

以上!!!
コードライン色付けしてみました!!!

【合わせて読みたい】

■ 【jQuery】初心者でもよく理解できたやつ
https://qiita.com/tanaka-yu3/items/a03734b248c3f2ee8461

■ 【メソッド集】 rails メソッド まとめ 基礎 随時追加
https://qiita.com/tanaka-yu3/items/89abad875187494bec53

■ 【JavaScript】javascriptの基本
https://qiita.com/smkhkc/items/5e3729cffab6591f34c6

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

tusdとtus-js-client, uppyを使ったファイルアップロードをapache2.4のCentOS7で構築する(https編)

目的

  • でかくて一杯ある音データをユーザ毎にサーバにアップロードしたいので、MITライセンスのtusdを使いたい。
  • 実運用にはhttpsが必須です。クッキーでセッション管理して大容量・複数ファイルの処理をユーザ毎に行いたいからです。
  • 前回ではhttpで動くことを確認しました。
  • この記事はhttpsでのトライアルです。クッキーには対応していません。

環境

  • CentOS7
  • apache 2.4.41
  • browser Firefox77 (MacOS)など
  • tusd 1.0
  • tus-js-client v2

参考

注意(この方法はtus.ioで記載されている方法とは違います。参考程度にお願いします)

インプリの概要

  1. uppy/tus-js-clientはCORS(Cross Origin Resource Sharing)が解決しないとブラウザは動いてくれません。そのためのHeaderにいつもの"このサイトは大丈夫だからね!Header always set Access-Control-Allow-Origin "https://www.my-site.net""を記述をします。
  2. tusdはhttpベースでhttp:0.0.0.0:1080を監視しているので、クライアントとサーバのやり取りをhttpsで行う場合、サーバでhttpsからhttpにスキーム変換させるためにリバースプロキシを立てます。このときうまくいったコードでは、リバースプロキシはクライアントからのhttps:/www.your-site.net/filesへの要求をhttp://localhost:1080/files/に渡すので、クライアントはポート番号を指定しないことでうまく行きました。
  3. スキームの変換はapacheのssl.confに記載します。
  4. tusdはproxyの後ろで動いているとオプションを渡して起動させます。

この5つの設定でうまく行きました。うまくいったapach2.4のhttpd.confssl.conftusの起動スクリプト、tus-js-clientのhtmlの例を次に記します。セキュリティのため、適当に書き換えていますので、読み替えてください。記載は本質的なところに限りました。

apache2.4の設定ファイル

  • sslの設定はLet's encryptで動いていますので、そちらを参考にしてください。

httpd.conf(部分)

httpd.conf
Listen 80
...
Include conf.modules.d/*.conf
ServerName www.my-site.net:80

IncludeOptional conf.d/*.conf
...
<Directory /var/www/files>
  Header always set Access-Control-Allow-Origin "https://www.your-site.net"
</Directory>    

この/var/www/filesにupload fileが入ります。

ssl.conf(部分)

ssl.conf
...
<VirtualHost _default_:443>
...
    ServerName www.your-site.net
...
    SSLEngine on
    SSLCertificateFile your-cert.pem
    SSLCertificateKeyFile your-privkey.pem
    Include your-options-ssl-apache.conf
    SSLCertificateChainFile your-chain.pem

    RequestHeader set X-Forwarded-Proto "https"
    ProxyPreserveHost on
    ProxyRequests off
    <LocationMatch "/files">
        ProxyPass http://localhost:1080/files
        ProxyPassReverse http://localhost:1080/files
    </LocationMatch>
</VirtualHost>

SSLProtocol             all -SSLv3
SSLCipherSuite          ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-$:HIGH:MEDIUM:!MD5:!RC4
SSLHonorCipherOrder     on
SSLCompression          off

# OCSP Stapling, only in httpd 2.3.3 and later
SSLUseStapling          on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off

セキュリティの設定(SSLCipherSuite、OCSPなど)は適当です。

tusdの起動スクリプト

tusdを立ち上げる時のログとコマンドをスクリプト化しました。リバースプロキシに対応させるため引数(-behind-proxy)を加えています。

run_tusd.bash
#!/bin/bash -vxeu
# tusdをオプション込みで起動する
exec &> /var/www/log/$(basename $0).$(date '+%y%m%d_%H%M%S').$$.bash
sudo -u apache /usr/local/bin/tusd -upload-dir /var/www/files -behind-proxy &

クライアントサイド

これがtus.ioの方法と一番違います。tus.ioではtttps://www.my-site.net:1080/files/とポート番号を指定してアクセスするように書いていますが、apache2.4ではどうもうまく行きません。サンプルはapache2.2のようなので振る舞いが違うようになったのかもしれませんが私にはわかりません。動いたコードは下記です。

tus-js-clientのindex.html
41行目:オリジナル <input type="text" id="endpoint" name="endpoint" value="https://www.your-site.net:1080/files/">
41行目:変更後   <input type="text" id="endpoint" name="endpoint" value="https://www.your-site.net/files/">

同様にuppyもendpointをポート番号1080を消してhttps:www.you-site.net/files/に指定したらうまく行きました。

uppy.html
var uppy = Uppy.Core() 
...
  .use(Uppy.Tus, { 
      endpoint: 'https://www.your-site.net/files/',
...
 })

参考

apacheのデバックはとても大変です。LogLevelをdebugにしてもよくわかりません。そこで教えてもらったのがcurlです。CORSでOPTIONSの反応が全然わからないのでしたがterminalでpreflightのテストができるようになってからかなり素早く試行することができました。それとサーバのconfファイルの編集はrootでデフォルトのviでなくvimを使うほうが断然早いですね。curlのOPTIONSの反応は下記で見えます。ブラウザからどんな要求が出ているのかは FireFoxの表示メニュー → 開発メニュー → ネットワーク でヘッダを確認できました。

$ curl --verbose https://www.your-site.net/files/ -X OPTIONS -H 'Host: www.your-site.net' -H 'Origin: https://your-site.net' 1> /dev/null

どなたの参考になれば嬉しいですが、これが正しい設定なのかわかりません。apacheの仕組みも正確にわかっておらず多分そうだろうと思って書きました。間違いの指摘などご意見いただけましたら幸いです。

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

Akashic Engine にて作成したニコ生向けゲームをiOSアプリ用に移植する方法

はじめに

本記事では、実質ニコ生ゲーム用のゲームエンジンであるAkashic Engineを使用した
ゲームをiOSアプリに移植したときの備忘録です。
HTML5で作られた他のエンジン製のゲームでも応用できるかと思います。
なお、Akashic Engineのマルチプレイ機能を用いたゲームは対象外です。

※当記事のやり方では審査を通らない可能性が高いです。ご了承ください

AkashicEngine 2.7
XCode 11.5

手順

1.Akashic Engineのゲームをスタンドアローン形式で出力。

https://akashic-games.github.io/tutorial/v2/7-export.html
akashic export html --magnify --output ../mygame

2.XCodeで新規プロジェクト作成

File→New→Project
iOSタグ→Single View App
※User Interface を Storyboardとすること

3.1で作成したファイルをプロジェクト直下に配置する

1で作成したmygameフォルダをそのままドラッグで良い

4.WKWebViewを配置し、ローカルのhtmlを表示する

ViewController.swift
import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {

    var webView: WKWebView!

    override func loadView() {


        let webConfiguration = WKWebViewConfiguration()

        //WKWebView に Configuration を引き渡し initialize
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        //WKUIDelegate の移譲先として self を登録
        webView.uiDelegate = self
        //WKNavigationDelegate の移譲先として self を登録
        webView.navigationDelegate = self
        //view に webView を割り当て
        view = webView

    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // 読み込み開始
        if let html = Bundle.main.path(forResource: "mygame/index", ofType: "html") {
            let url = URL(fileURLWithPath: html)
            let request = URLRequest(url: url)
            webView.load(request)
        }
    }


}

5.横画面表示のみとする

TARGETS→General→Deployment Info
のDeviceOrienttatitonのチェックボックスを
Landscape LeftとLandscape Rightのみとする

これで大体完成です。
アイコン等を設定すればストアに申請できます。
ただし、通りません。

Guideline 4.2 - Design - Minimum Functionality
となってしまいます。
何か機能を追加すれば通るかもしれません。

以上。

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