20190405のJavaScriptに関する記事は26件です。

IE11でReact.jsを動かす

いまだにIE11を使う現場があったり、
個人もいたりするので、IE11でReact.jsを動かしてみたところ、
動かなかったので、解決方法を記録します。

環境

  • windows10
  • Node.js v8.12
  • React.js v16.8.6

まずはそのまま

まずはcreate-react-appでReactプロジェクトを作って実行します。

$ create-react-app ie11-trial
$ cd ie11-trial/
$ npm start

image.png

おなじみのこの画面ですね!

適当にアプリを作る

とりあえずボタン押したらステータスが変わって、
画面表示が変わるアプリを作成します。

src/App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      sample: {
        status: 'OK'
      },
    }
    this.handleClick = this.handleClick.bind(this);
  }

  // ボタンを押されたときによぶ関数
  handleClick = () => {
    // stateからオブジェクトをES6に追加されたassignでコピーしてみる
    const sample = Object.assign({}, this.state.sample);
    // 適当に変更
    sample.status = sample.status === 'OK' ? 'NG' : 'OK';
    // セットする
    this.setState({
      sample: sample,
    });

  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />

          {/* ボタンをおして、上の関数を呼んで、画面上の表示をかえる */}
          <button onClick={this.handleClick}>おしてね</button>
          {this.state.sample.status}

        </header>
      </div>
    );
  }
}

export default App;

GoogleChromeで表示

image.png

ちゃんとボタンを押すと、
OKとNGが入れ替わります。

IE11で表示する

いよいよIE11で実行!

image.png

画面表示はされるものの、
ボタンを押してもステータスが変化しません。

this.setStateや、
Object.assignでコピーしているとこでエラーが出ています。
つまりES6の記述などにIE11が対応していないのです。

解決方法

足りないものはpolyfillをいれて補います。
polyfillとは、
「古いブラウザでも新しいWeb技術を使用できるように、
既にあるWeb技術を用いて擬似的に実装すること」
とのことです。

調べたところ、いろいろ方法があって、
htmlに読み込んだり、babel使ったりありますが、
やってることはほぼ同じでした。

ここはReactの公式polyfillを使います。

再チャレンジ

インストール

$ npm install react-app-polyfill

まずはpolyfillをプロジェクトにインストールします。

読み込み

バンドルされるTOPのjsファイルにインポートします。
createReacAppで作ったWebアプリなら、
デフォルトだとsrc/index.jsになります。

src/index.js
import 'react-app-polyfill/ie11';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();

一番上に、
import 'react-app-polyfill/ie11';
を記述するのみです。

※react-app-polyfill/ie9にするとie9~ie11までサポートしているようです。

IE11にリベンジ!!

image.png

・・・画面はNGになっててなんだか分かりにくいですが、
ちゃんと変化もするしエラーもなくなったので成功です。
(OKとNGを逆にしとけばよかった)

感想

IEで動かなくていいやと割り切ってもいいのですが、
デモならともかく商用化していくのなら、
現状では、まだまだIE11の対応は必要かなと思っています。

おまけ

そういえばEdgeでもうごくよね。。

image.png

よかった、動いた。

おまけ2

safariでも動くよね??

image.png

よかった(笑)

参考

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

React.jsがIE11でエラーで動かない問題を解決する

いまだにIE11を使う現場があったり、
個人もいたりするので、IE11でReact.jsを動かしてみたところ、
動かなかったので、解決方法を記録します。

環境

  • windows10
  • Node.js v8.12
  • React.js v16.8.6

まずはそのまま

まずはcreate-react-appでReactプロジェクトを作って実行します。

$ create-react-app ie11-trial
$ cd ie11-trial/
$ npm start

image.png

おなじみのこの画面ですね!
ちなみにこのままIE11でも表示できます。

適当にアプリを作る

とりあえずボタン押したらステータスが変わって、
画面表示が変わるアプリを作成します。

src/App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      sample: {
        status: 'OK'
      },
    }
    this.handleClick = this.handleClick.bind(this);
  }

  // ボタンを押されたときによぶ関数
  handleClick = () => {
    // stateからオブジェクトをES6に追加されたassignでコピーしてみる
    const sample = Object.assign({}, this.state.sample);
    // 適当に変更
    sample.status = sample.status === 'OK' ? 'NG' : 'OK';
    // セットする
    this.setState({
      sample: sample,
    });
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />

          {/* ボタンをおして、上の関数を呼んで、画面上の表示をかえる */}
          <button onClick={this.handleClick}>おしてね</button>
          {this.state.sample.status}

        </header>
      </div>
    );
  }
}

export default App;

GoogleChromeで表示

image.png

ちゃんとボタンを押すと、
OKとNGが入れ替わります。

IE11で表示する

いよいよIE11で実行!

image.png

画面表示はされるものの、
ボタンを押してもステータスが変化しません。

this.setStateや、
Object.assignでコピーしているとこでエラーが出ています。
つまりES6の記述などにIE11が対応していないのです。

解決方法

足りないものはpolyfillをいれて補います。
polyfillとは、
「古いブラウザでも新しいWeb技術を使用できるように、
既にあるWeb技術を用いて擬似的に実装すること」
とのことです。

調べたところ、いろいろ方法があって、
htmlに読み込んだり、babel使ったりありますが、
やってることはほぼ同じでした。

ここはReactの公式polyfillを使います。

再チャレンジ

インストール

$ npm install react-app-polyfill

まずはpolyfillをプロジェクトにインストールします。

読み込み

バンドルされるTOPのjsファイルにインポートします。
createReacAppで作ったWebアプリなら、
デフォルトだとsrc/index.jsになります。

src/index.js
import 'react-app-polyfill/ie11';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();

一番上に、
import 'react-app-polyfill/ie11';
を記述するのみです。

※react-app-polyfill/ie9にするとie9~ie11までサポートしているようです。

IE11にリベンジ!!

image.png

・・・画面はNGになっててなんだか分かりにくいですが、
ちゃんと変化もするしエラーもなくなったので成功です。
(OKとNGを逆にしとけばよかった)

感想

IEで動かなくていいやと割り切ってもいいのですが、
デモならともかく商用化していくのなら、
現状では、まだまだIE11の対応は必要かなと思っています。

おまけ

そういえばEdgeでもうごくよね。。

image.png

よかった、動いた。

おまけ2

safariでも動くよね??

image.png

よかった(笑)

参考

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

React.jsがIE11で動かない問題を解決する

いまだにIE11を使う現場があったり、
個人もいたりするので、IE11でReact.jsを動かしてみたところ、
動かなかったので、解決方法を記録します。

環境

  • windows10
  • Node.js v8.12
  • React.js v16.8.6

まずはそのまま

まずはcreate-react-appでReactプロジェクトを作って実行します。

$ create-react-app ie11-trial
$ cd ie11-trial/
$ npm start

image.png

おなじみのこの画面ですね!
ちなみにこのままIE11でも表示できます。

適当にアプリを作る

とりあえずボタン押したらステータスが変わって、
画面表示が変わるアプリを作成します。

src/App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      sample: {
        status: 'OK'
      },
    }
    this.handleClick = this.handleClick.bind(this);
  }

  // ボタンを押されたときによぶ関数
  // アロー関数にしておいてみる
  handleClick = () => {
    // stateからオブジェクトをES6に追加されたassignでコピーしてみる
    const sample = Object.assign({}, this.state.sample);
    // 適当に変更
    sample.status = sample.status === 'OK' ? 'NG' : 'OK';
    // セットする
    this.setState({
      sample: sample,
    });
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />

          {/* ボタンをおして、上の関数を呼んで、画面上の表示をかえる */}
          <button onClick={this.handleClick}>おしてね</button>
          {this.state.sample.status}

        </header>
      </div>
    );
  }
}

export default App;

GoogleChromeで表示

image.png

ボタンを押すと、
ちゃんとOKとNGが入れ替わります。

IE11で表示する

いよいよIE11で実行!

image.png

画面表示はされるものの、
ボタンを押してもステータスが変化しません。

this.setStateや、
Object.assignでコピーしているとこでエラーが出ています。
つまりES6の記述などにIE11が対応していないのです。

解決方法

足りないものはpolyfillをいれて補います。
polyfillとは、
「古いブラウザでも新しいWeb技術を使用できるように、
既にあるWeb技術を用いて擬似的に実装すること」
とのことです。

調べたところ、いろいろ方法があって、
htmlに読み込んだり、babel使ったりありますが、
やってることはほぼ同じでした。

ここはReactの公式polyfillを使います。

再チャレンジ

インストール

$ npm install react-app-polyfill

まずはpolyfillをプロジェクトにインストールします。

読み込み

バンドルされるTOPのjsファイルにインポートします。
createReacAppで作ったWebアプリなら、
デフォルトだとsrc/index.jsになります。

src/index.js
import 'react-app-polyfill/ie11';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();

一番上に、
import 'react-app-polyfill/ie11';
を記述するのみです。

※react-app-polyfill/ie9にするとie9~ie11までサポートしているようです。

IE11にリベンジ!!

image.png

・・・画面はNGになっててなんだか分かりにくいですが、
ちゃんと変化もするしエラーもなくなったので成功です。
(OKとNGを逆にしとけばよかった)

感想

IEで動かなくていいやと割り切ってもいいのですが、
デモならともかく商用化していくのなら、
現状では、まだまだIE11の対応は必要かなと思っています。

おまけ

そういえばEdgeでもうごくよね。。

image.png

よかった、動いた。

おまけ2

safariでも動くよね??

image.png

よかった(笑)

参考

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

node.jsを触るために簡単なチャットシステムを作る(環境構築編)

Node.js を触ってみたいと思ったので、備忘録も兼ねて以下に記します。
よりよい方法やバグ等ございましたら、アドバイスいただけると光栄です。

Node.jsをインストールする

コマンド操作でインストールする方法もあるようですが、今回は簡単なインストーラーを使いました。
下記ページにアクセスし、左側の「推奨版」をインストールしました。
https://nodejs.org/ja/

これなら、インストーラのプログラムをダウンロードできるのであとは実行するだけです。

最後に、インストールが無事にできたかを確認するためにターミナルを起動して以下のように入力します。

$ node --version

実行して Node.js のバージョンが表示されれば、完了です。

Node.jsのパッケージ管理の初期化

はじめに、下記コマンドでアプリを作成するためのディレクトリを作成します。
(今回はmychatという名前のディレクトリを作成しました。)

$ mkdir mychat

次に、作成したディレクトリ内に移動します。

$ cd mychat

そして下記を実行し、パッケージ管理の初期化をします。

$ npm init

今回は以下のように指定をして作成しました。

  • package name : そのままエンターキーを押す
  • version : そのままエンターキーを押す
  • description : そのままエンターキーを押す
  • entry point : 「server.js」 と入力しエンターキーを押す
  • test command : そのままエンターキーを押す
  • git repository : そのままエンターキーを押す
  • keywords : そのままエンターキーを押す
  • author : そのままエンターキーを押す
  • license : そのままエンターキーを押す

これで、mychatフォルダに、package.jsonファイルが生成されます。
package.jsonファイルは以下のような内容になっています。

{
  "name": "mychat",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Node.jsのパッケージのインストール

それでは、ExpressSocket.io をインストールします。

$ npm install express
$ npm install socket.io

mychatフォルダに、node_modulesフォルダが生成されており、
フォルダ内に、ExpressSocket.io および関連パッケージがインストールされていれば完了です。

また、package.jsonファイルには、dependenciesセクションが追加され、ExpressSocket.io 関する記述が追加されます。

{
  "name": "mychat",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.4",
    "socket.io": "^2.2.0"
  }
}

以上でアプリを作り始めるための準備が完了です。
次は、定番のHello Worldをしてみます。

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

Tone.jsでピッチシフト(キー変更)

Tone.jsでピッチシフト(曲のテンポを維持したまま、キーを変更する)ができることを知ったので試してみました。
結果を先に言うと、キーを下げるとロボットみたいになって、歌に対して実用的に使える状態にはできませんでした。キーを少し上げるくらいなら良い感じです。

単にTone.jsの関数を呼んでいるだけですが、せっかくなので記録を残しておきます。
実際に動作しているものはこちら(個人的なページ)

Playerにファイルを読み込ませ、PitchShiftを経由してMasterへ流せばOK。

pitchshift.js抜粋
var URL = URL || webkitURL;

let source = null;
let semitones = 0;
let shift = null;

// ファイル選択ダイアログなどで選ばれたものをtargetFileとして取得
function setAudio(targetFile) {
    let src = URL.createObjectURL(targetFile);
    // ボタン押下などでsemitonesの値を変えれば再生中のキーも変わる
    shift = new Tone.PitchShift({
        pitch  : semitones ,
        windowSize  : 0.03 ,
        delayTime  : 0 ,
        feedback  : 0
        }
    );
    source = new Tone.Player(src);
    source.connect(shift);
    shift.toMaster();
    source.autostart = true;
}

うまく調整する方法をご存知の方がいらっしゃれば教えてもらえると幸いです。
WebAudioを使って自力でピッチシフトの実装にも挑戦してみましたが、現状の私には難易度が高くて諦めました。

参考

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

window.location.search(クエリ)を object にする

まえがき

URL の ? 以降の文字列(いわゆる window.location.search )(いわゆるクエリ)を JavaScript の object にする。
大体いつも必要になるので、すぐに引っ張ってきて utils ディレクトリにでも置いておきたいやつ。

? JavaScript

function getSearchObj(searchStr) {
  if (!searchStr) return {};
  return searchStr
    .substr(1)
    .split("&")
    .reduce((acc, cur) => {
      acc[cur.split("=")[0]] = cur.split("=")[1];
      return acc;
    }, {});
}

? TypeScript

function getSearchObj(searchStr: string): { [key: string]: string } {
  if (!searchStr) return {};
  return searchStr
    .substr(1)
    .split("&")
    .reduce(
      (acc, cur) => {
        acc[cur.split("=")[0]] = cur.split("=")[1];
        return acc;
      },
      {} as { [key: string]: string }
    );
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

動画の両端にダブルクリックするとn秒送り/戻りする機能を追加するユーザースクリプト

スマホの動画アプリなどにあるダブルタップで10秒送りなどが快適なので、PC画面やスマホのブラウザでの動画閲覧時にも出来ないかなと作成。

シークや送りボタンは繊細な操作が必要ですし、左右キーでの送りは一旦マウスで動画にフォーカスしないといけないことも多かったので、もっと大雑把にしたい。みたいな。

スマホのシークが苦手なんです。

YouTubeでの例

yotubepress.gif

(動画にadが出ると要素位置がずれるので別途切っています。要素追加位置をadより上位(兄)にすれば共存可能です)

動作検証環境

  • Firefox 64bit 66.0.2
  • Tampermonkey v4.8.5847

基本形コード

再生速度変更ボタン追加コードも混じってますが。

(function() {
  'use strict';
  // まずはメイン画面のロード完了を待つ
  const mo = new MutationObserver((data1, data2) => {
    const video = document.querySelector('video')
    if (video) {
      //addSpeedOptions()
      addSeekCurtain()
      mo.disconnect();
      return
    }
  })
  mo.observe(document.body, {
    childList: true, subtree: true
  });


  const addSpeedOptions = () => {

    const video = document.querySelector('video')
    const menu = document.querySelector('menu')
    const div = document.createElement('div')
    div.className = 'menuclass'
    div.style.display = 'block'
    div.style.marginRight = '5px'
    div.style.width = 'auto'

    const changeSpeed = (speed, state='=') => {
      return () => {
        if (state == '=') {
          video.playbackRate = speed
        } else if (state == '-') {
          video.playbackRate -= speed
        } else if (state == '+') {
          video.playbackRate += speed
        }
      }
    }

    let clone = div.cloneNode()
    clone.textContent = '=1'
    clone.addEventListener('click', changeSpeed(1))
    menu.appendChild(clone)
    clone = div.cloneNode()
    clone.textContent = '=1.25'
    clone.addEventListener('click', changeSpeed(1.25))
    menu.appendChild(clone)
    clone = div.cloneNode()
    clone.textContent = '+.25'
    clone.addEventListener('click', changeSpeed(0.25, '+'))
    menu.appendChild(clone)
    clone = div.cloneNode()
    clone.textContent = '-.25'
    clone.addEventListener('click', changeSpeed(0.25, '-'))
    menu.appendChild(clone)
    clone = div.cloneNode()
    clone.textContent = '=2'
    clone.addEventListener('click', changeSpeed(2))
    menu.appendChild(clone)
  }

  const addSeekCurtain = () => {
    // <div style="position: absolute;height: 80%;width: 20%;display: inline-block;">test left</div>
    // <div style="position: absolute;right: 0;display: inline-block;height: 80%;width: 20%;">test right</div>

    const video = document.querySelector('video')
    const videoWrapper = document.querySelector('wrapper')
    const common = document.createElement('div')
    common.style.position = 'absolute'
    common.style.height = '80%'
    common.style.width = '20%'
    common.style.display = 'inline-block'

    common.style.zIndex = '100'

    const left = common.cloneNode()
    const right = common.cloneNode()
    right.style.right = '0'


    const seek = (seconds, state='+') => {
      return (e) => {
        console.log(e)
        e.stopPropagation();
        if (state == '-') {
          video.currentTime -= seconds
        } else if (state == '+') {
          video.currentTime += seconds
        }
      }
    }

    left.addEventListener('dblclick', seek(5, '-'))
    right.addEventListener('dblclick', seek(5, '+'))

    videoWrapper.appendChild(left)
    videoWrapper.appendChild(right)

    //video.parentNode.insertBefore(left, video)
    //video.parentNode.insertBefore(right, video)

    //video.appendChild(left)
    //video.appendChild(right)

    // 通常はmouseupのクリック間隔でダブルクリック判定→フルスクリーン化しているようなので
    // シークのダブルクリックにmouseupが反応しないようにして、クリックによる再生・停止を改めてキャプチャーフェーズで定めてやる
    // ...にはやはりclick間隔でdblclickをエミュレートしないといけないので、再生・停止は機能しない簡易版にするよ
    left.addEventListener('click', e => {
      e.stopPropagation();
    })
    right.addEventListener('click', e => {
      e.stopPropagation();
    })
  }
})();

  // まずはメイン画面のロード完了を待つ
  const mo = new MutationObserver((data1, data2) => {
    const video = document.querySelector('video')
    if (video) {
      //addSpeedOptions()
      addSeekCurtain()
      mo.disconnect();
      return
    }
  })
  mo.observe(document.body, {
    childList: true, subtree: true
  });

ここは要素が現れるのを待つ個人的汎用コードですね。
イケている動画サイトではメインの動画要素が遅延読み込みされることがあるので待機する必要があります。
videoが出たらif (video)追加するコードを実行します。

    const video = document.querySelector('video')
    const videoWrapper = document.querySelector('wrapper')

操作対象のvideoと、要素の追加先や動画のコントローラーとなっているWrapperを取得しています。
動画サイトによっては追加先とコントローラーが別々の要素だったり、コントローラーがvideo要素だったりでいろいろです。
Wrapperは「動画と同じサイズ・同じ位置のdiv要素」と捕らえています。

    const common = document.createElement('div')
    common.style.position = 'absolute'
    common.style.height = '80%'
    common.style.width = '20%'
    common.style.display = 'inline-block'

    common.style.zIndex = '100'

    const left = common.cloneNode()
    const right = common.cloneNode()
    right.style.right = '0'

ダブルクリックを実装する追加要素です。動画部分にオーバーレイさせます。
z-indexはサイトによっては不要です。多分基本的には不要だと思いますが、お守りに。

Wrapperに入れれば上手く動画サイズにフィットするはずですが、サイトによっては別途調整が要るでしょう。

高さが動画の80%なのは、動画下部にメニューがオーバーレイされるので干渉避けに。幅は中央の標準クリック動作が邪魔にならない程度にお好みで。
右側の送り側はright.style.right = '0'で右端に寄せておきます。

left.jpg

right.jpg

YouTubeならもう少しheightをとってもいいですね。

ただし、右側は右下の設定のポップアップとよく干渉するので、heightを少なめにしとくといいと思います。

    const seek = (seconds, state='+') => {
      return (e) => {
        console.log(e)
        e.stopPropagation();
        if (state == '-') {
          video.currentTime -= seconds
        } else if (state == '+') {
          video.currentTime += seconds
        }
      }
    }

    left.addEventListener('dblclick', seek(5, '-'))
    right.addEventListener('dblclick', seek(5, '+'))

再生位置変更機能です。それ以上でも以下でもなく。seekは良くない命名だとおもいますけど、なんていえばよいのか。

    videoWrapper.appendChild(left)
    videoWrapper.appendChild(right)

    //video.parentNode.insertBefore(left, video)
    //video.parentNode.insertBefore(right, video)

    //video.appendChild(left)
    //video.appendChild(right)

要素の追加。上手く重なる位置を調べましょう。
コメントアウト含めてこれらとセレクターの調整で上手くいくかな?と。

    // 通常はmouseupのクリック間隔でダブルクリック判定→フルスクリーン化しているようなので
    // シークのダブルクリックにmouseupが反応しないようにして、クリックによる再生・停止を改めてキャプチャーフェーズで定めてやる
    // ...にはやはりclick間隔でdblclickをエミュレートしないといけないので、再生・停止は機能しない簡易版にするよ
    left.addEventListener('click', e => {
      e.stopPropagation();
    })
    right.addEventListener('click', e => {
      e.stopPropagation();
    })

コメントのまま。これもサイトによっては不要です。
dblclickのほうもe.stopPropagation();でバブリングを止めていますが、clickイベントでdblclick判定をしているものと同時発生してしまうので、clickイベントもバブリングしないようにします。
シングルクリックも機能しなくなりますが、このイベント内で同様にシングル・ダブルクリックを判定して、シングルなら親をクリックするような記述をすれば、もともとのシングルクリック機能を残せると思います。

Wrapperは動画サイズを持つと共に、イベントを管理していることが多いので追加要素にstopPropagationを入れていますが、場合によってはイベントは別要素の場合もあるかもしれません。

wrapper.jpg

YouTubeの場合は#movie_playerがWrapperでありイベント管理であるので、この子供として要素を追加しています。

YouTube版コード

// ==UserScript==
// @name         Youtube Video Speed
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  動画n秒送り
// @author       khsk
// @match        https://www.youtube.com/watch?*
// @grant        none
// ==/UserScript==

(function() {
  'use strict';
  // まずはメイン画面のロード完了を待つ
  const mo = new MutationObserver((data1, data2) => {
    const video = document.querySelector('.video-stream.html5-main-video')
    if (video) {
      addSeekCurtain()
      mo.disconnect();
      return
    }
  })
  mo.observe(document.body, {
    childList: true, subtree: true
  });

  const addSeekCurtain = () => {
    // <div style="position: absolute;height: 80%;width: 20%;display: inline-block;">test left</div>
    // <div style="position: absolute;right: 0;display: inline-block;height: 80%;width: 20%;">test right</div>

    const video = document.querySelector('.video-stream.html5-main-video')
    const videoWrapper = document.querySelector('#movie_player')
    const common = document.createElement('div')
    common.style.position = 'absolute'
    common.style.height = '80%'
    common.style.width = '20%'
    common.style.display = 'inline-block'

    common.style.zIndex = '100'

    const left = common.cloneNode()
    const right = common.cloneNode()
    right.style.right = '0'

    const seek = (seconds, state='+') => {
      return (e) => {
        if (state == '-') {
          video.currentTime -= seconds
        } else if (state == '+') {
          video.currentTime += seconds
        }
      }
    }

    left.addEventListener('dblclick', seek(5, '-'))
    right.addEventListener('dblclick', seek(5, '+'))

    videoWrapper.appendChild(left)
    videoWrapper.appendChild(right)
  }
})();

サイトによって不要記述も多いので調べながら削るか全部のせで気にせずか。

参考

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

Google Cloud Platform上でNode.jsとMySQLを繋げてみた

はじめに

Google Cloud Platform (GCP) には魅力的な無料枠があり、操作も比較的簡単そうだったのでGCP上に構築したNode.js+MySQLのスタックを接続してみました。

今回はGCPのApp EngineにNode.jsのアプリを構築し、Cloud SQL第二世代にMySQLを構築させました。

https://cloud.google.com/sql/docs/mysql/connect-app-engine?hl=ja
接続についてはこのリファレンスを読みましたがNode.jsが載っていなかったので書き残します。

料金について

App Engineは規模が小さい場合基本的に無料ですが、Cloud SQLの運用は課金されました。
無料枠について:https://cloud.google.com/free/?hl=ja 
Cloud SQL料金について:https://cloud.google.com/sql/pricing?hl=ja

Instanceの接続名の確認

Instanceの接続名はCloud SQLの接続に必要な項目です。project_id:region:instance_idの形式の文字列です。
GCPの「インスタンスの詳細」画面の中の「このインスタンスに接続」というボックスの中に表示されています。
これをコピーして、環境変数として保存しておきます。

.env
# プロジェクト名:hoge、インスタンス名:hoge-db、地域:東京 の場合
INSTANCE_CONNECTION_NAME="hoge:asia-northeast1:hoge-db"

MySQL関係の項目の確認

Node.jsからMySQLにアクセスするにはもちろんデータベース情報が必要なので、これも一緒に環境変数として保存しておきます。

.env
# ...
DB_USER="hogehoge"
DB_PASSWORD="fugafuga"
DB_DATABASE="piyopiyo"

Node.js側の設定

Node.jsからMySQLに接続するモジュールは色々ありますが、mysqlというクライエントを使いました。

App Engineのスタンダード環境からCloud SQLのDatabaseに接続するときには、普通にTCPでは接続できないため、Unix Domain Socketという方法で接続します。

環境変数はdotenvというパッケージを使って取り込みました。

require('dotenv').config();

const mysql = require('mysql');

const connection = mysql.createConnection({
  socketPath: `/cloudsql/${process.env.INSTANCE_CONNECTION_NAME}`,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_DATABASE 
});

App Engineスタンダード環境の場合、/cloudsql/<インスタンス接続名>のソケットが自動的に提供されるようなのでこのほかに何も設定する必要はありません。

接続プール

パフォーマンスを上げるためにプールを使う場合も、同じように接続できます。

const pool = mysql.createPool({
  user: process.env.DB_USER, 
  password: process.env.DB_PASS, 
  database: process.env.DB_NAME, 
  socketPath: `/cloudsql/${process.env.INSTANCE_CONNECTION_NAME}`
});

接続数上限

プールを使用する場合、接続数の上限も設定できます。

const pool = mysql.createPool({
  // ...
  connectionLimit: 5
});

TCPとの併用

開発環境ではローカルのMySQLにTCPで接続してほしかったので、NODE_ENVの環境変数に合わせて接続方法を変えるようにしました。

const pool = process.env.NODE_ENV === 'production'
  ? mysql.createPool({
    user: process.env.DB_USER, 
    password: process.env.DB_PASS, 
    database: process.env.DB_NAME, 
    socketPath: `/cloudsql/${process.env.INSTANCE_CONNECTION_NAME}`
  }) : mysql.createPool({
    user: process.env.DB_USER, 
    password: process.env.DB_PASS, 
    database: process.env.DB_NAME, 
    host: 'localhost'
  });

完成

gcloud app deployを実行してアクセスすると、データベースに接続できているはずです。

App EngineとCloud SQLのインスタンスが別々のプロジェクトの下に作られている場合、IAMを変更する必要があります。
App EngineのサービスアカウントにCloud SQL Admin Cloud SQL Editor Cloud SQL Clientの役割のいずれかを与えると動くそうです。

感想

GCPは比較的安価でNode.js、MySQLの環境構築をすることができるので魅力的です。リファレンスにNode.jsがなかったので少し手こずりましたが、無事接続できました。

最初の記事なので、少し間違えていたらすみませんv_v。

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

Upload image to S3 using Javascript AWS SDK

Getting started

Install aws-sdk using npm

$ npm install aws-sdk

Create a json file name config.json in the project root directory

{
    "accessKeyId": "<aws-access-key>", 
    "secretAccessKey": "<aws-secret-key>", 
    "region": "ap-northeast-1"
}

Usage

Import the aws-sdk

const AWS = require('aws-sdk')

Initialize S3 object for doing the operations

// load aws s3 configuration from json file
AWS.config.loadFromPath(path.join(__dirname, '<relative-path-to-config.json>'))

// initialize S3 object for doing operations
var S3 = new AWS.S3({
   apiVersion: '2006-03-01'
})
  • Get image from S3
// setup the params for get object operation
var params = {
  Bucket: <path-to-where-the-target-object-is-stored>
  Key: <object-name-in-s3>
}

// Async function to get object from S3 using aws-sdk
S3.getObject(params, function (err, data) {
  if (err) throw err
  console.log(data)
})
.catch(err => console.log(err))
  • Upload Image to S3
// setup the params for get object operation
var params = {
  Bucket: "bucket name with path",
  Key: "<filename>",
  Body: "<image stream>"
}

// Async function to get object from S3 using aws-sdk
S3.getObject(params, function (err, data) {
  if (err) throw err
  console.log(data)
})
.catch(err => console.log(err))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React Native 動的にUIを更新

React Native 動的にUIを更新

OverView

変数や状態によってUIを表示にしたり、非表示にしたり、したい場合があるかと思います。
その場合下記のように実装することにより実現できます。

<View style={layout(val)} />

function layout(val) {
    if (val === "no") {
        return {
        backgroundColor: #fff,
      };
    }
    return {
        backgroundColor: #000,
    };
}

動作確認を行なっていないので動作するかわかりませんが、概念的にはこんな感じです。

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

【Rails/JavaScript】Googleマップ上にある同じ座標の複数マーカーをずらす

個人開発のWebアプリまちかどルートv5.62への実装メモです。

Googleマップのマーカーが重なる

まちかどルートでは位置情報付きの投稿をすべて「ルートマップ」と名付けたGoogleマップ上にマーカー表示させています。

ちなみにgmaps4railsgeocoderというgemを使っています。

使い方についてはこちらの記事などを参考にしました。

しかしながらまったく同じ座標の投稿があると複数のマーカーが重なってしまい、とても不便です。

maxRandomDistanceを使う

handler = Gmaps.build('Google', { markers: { maxRandomDistance: 5 } });

viewに使うhandler = Gmaps.build('Google');の部分を上記のようなコードに変更すると、同じ座標にある複数のマーカーを下の写真のようにずらして表示できるようになります。

ランダムにずれるので細かな調整には不向きですが、簡単な対応策として良いのではないでしょうか。

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

AtomicDesignとVue.js(Nuxt.js)に使うと最高な開発体験できた

開発環境

Nuxt.js v2
Express v4
bootstrap v4 (bootstrap-vue)

Atomic Designとは

Atomic Design はデザインシステムを作るための1つの手段
ざっくり言うと、UI コンポーネントの粒度をカテゴリーに明確に分ける手法

http://atomicdesign.bradfrost.com/

Atomic Designの詳細については割愛しますので、下記サイトをご参照ください。

https://www.indetail.co.jp/blog/10234/

Nuxt.jsとAtomicデザインの開発が最高なポイント

routerなど面倒な設定特に意識しなくで実装とでも楽!
コンポネートの独立性が高く、さらにVuexを使うとデータの操作とビューの表示が依存性低く、仕様変更に柔軟な対応できる
デザイン変更が発生する際、一箇所を修正するだけで、全てが適応される(これが一番好きなポイント)

もちろん、それぞれのページの対応のものもありますが、そもそもデザインや機能が違うものを共通の原子にすると、実装が複雑になってくる。
設計の問題になりますが、個人的には原子の機能が簡単にするの方が使いやすいと思う

フォルダー構造

components
|
|---- atomes
|------ |---Album.vue
|------ |---BackBtn.vue
|---- molecules
|------ |---AlbumList.vue
|------ |---CommentList.vue
|---- organisms
|------ |---AlbumBook.vue
|---- page
|------ |--- AlbumBooks.vue

atomes(原子)

ボタンなどのUI上の最小単位をatomesに分ける、このUIを例とすると、中にはlinkとimgとtitleだけのもの

<template>
  <div>
    <nuxt-link to="/album/1">
      <img id="album-image" :src="album.coverUrl" />
    </nuxt-link>
    <div>
      {{ album.title }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'Album', // ここは外部をコンポネートとして呼ぶの名前になる

  props: {
    album: {
      type: Object,
      required: true,
      default: null
    }
  }
}
</script>
<style scoped>
#album-image {  /* この分子のcssのみで設定する、うっかりオーバーライドしてほかのcssに影響することも減少できる */
  height: 175px;
  width: 175px;
  object-fit: cover;
  border-radius: 10px;
  margin: 1px;
}
</style>

molecules(分子)

原子を複数持つものなど,僕の場合は原子の親となる配列やオブジェクトにする

<template>
  <b-row>
    <b-col v-for="album in albums" :key="album.id">
      <Album :album="album"></Album>  <!-- 原子の個体 -->
    </b-col>
  </b-row>
</template>

<script>
import Album from '~/components/atomes/Album.vue'  // 原子をimport

export default {
  name: 'AlbumList', // この分子の外部呼ぶ際の名前

  components: {
    Album // 原子をcomponentとして使うの宣言
  },

  props: {
    data: {
      type: Object,
      required: true,
      default: () => null
    }
  }
}
</script>

organisms(生体)

複数分子をよく組合したもの

<template>
  <section>
    <nav class="navbar navbar-light bg-light">
      <BackBtn path="/activity"></BackBtn>
    </nav>
    <div class="container-fluid">
      <AlbumList :data="albums"></AlbumList>
      <CommentList :comments="comments"></CommentList>
    </div>
  </section>
</template>

<script>
import BackBtn from '~/components/atomes/BackBtn.vue'
import CommentList from '~/components/molecules/CommentList.vue'
import AlbumList from '~/components/molecules/AlbumList.vue'

export default {
  name: 'AlbumBook', // この分子の外部呼ぶ際の名前
  components: {
    BackBtn,   // 原子も組合できる
    CommentList, // 別の分子
    AlbumList    // 複数アルバム原子を持つの分子
  }
  data() {
    comments: [
       ... // 分子が必要なデータ
    ]
  },
  computed: {
    albums() {
      return this.$store.state.albums // 分子が必要なデータ、Vuexからアクセスするとしたら、生体でまとめるか、もしくは分子で取得するか、柔軟に変更できる
    }
  },
}
</script>

最後

Page(従来のメインとなるhtmlファイル)にそれぞれのコンポネートでimportする、デザインにあわせて簡単に組合できる、再利用性高いコンテンツ実装できようになった。

難しいところは、一見沢山のなファイルを分割しないといけないし、コンポネートが利用高いものを見分けないと行けない。
多少面倒だが、一度乗れたら後ほど開発が楽になり、開発初期段階からするとおすすめです!
皆さんもぜひ一度チャレンジしてみてください!

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

AtomicDesignとVue.js(Nuxt.js)に使うと最高な開発を体験できた

開発環境

Nuxt.js v2
Express v4
bootstrap v4 (bootstrap-vue)

Atomic Designとは

Atomic Design はデザインシステムを作るための1つの手段
ざっくり言うと、UI コンポーネントの粒度をカテゴリーに明確に分ける手法

http://atomicdesign.bradfrost.com/

Atomic Designの詳細については割愛しますので、下記サイトをご参照ください。

https://www.indetail.co.jp/blog/10234/

Nuxt.jsとAtomic Designの開発が最高なポイント

Nuxt.jsの機能:
routerなど面倒な設定を特に意識しないで実装できとても楽!

生産性向上 & 一貫性:
コンポーネントの独立性が高く、さらにVuexを使うとデータの操作とビューの表示が依存性低く、仕様変更に柔軟に対応できる
デザイン変更が発生する際、一箇所を修正するだけで、全てが適用される(これが一番好きなポイント)

もちろん、それぞれのページの対応のものもありますが、そもそもデザインや機能が違うものを共通の原子にすると、実装が複雑になってくる。
設計の問題になりますが、個人的には原子の機能を簡単にする方が使いやすいと思う

フォルダー構造

components
|
|---- atomes
|------ |---Album.vue
|------ |---BackBtn.vue
|---- molecules
|------ |---AlbumList.vue
|------ |---CommentList.vue
|---- organisms
|------ |---AlbumBook.vue
|---- page
|------ |---AlbumBooks.vue

atomes(原子)

ボタンなどのUI上の最小単位をatomesに分ける
このUIを例とすると、中にはlinkとimgとtitleだけのもの

<template>
  <div>
    <nuxt-link to="/album/1">
      <img id="album-image" :src="album.coverUrl" />
    </nuxt-link>
    <div>
      {{ album.title }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'Album', // ここは外部をコンポーネントとして呼ぶ名前になる

  props: {
    album: {
      type: Object,
      required: true,
      default: null
    }
  }
}
</script>
<style scoped>
#album-image {  /* この分子のcssのみで設定する、うっかりオーバーライドしてほかのcssに影響することも減少できる */
  height: 175px;
  width: 175px;
  object-fit: cover;
  border-radius: 10px;
  margin: 1px;
}
</style>

molecules(分子)

原子を複数持つものなど
僕の場合は原子の親となる配列やオブジェクトにする

<template>
  <b-row>
    <b-col v-for="album in albums" :key="album.id">
      <Album :album="album"></Album>  <!-- 原子の個体 -->
    </b-col>
  </b-row>
</template>

<script>
import Album from '~/components/atomes/Album.vue'  // 原子をimport

export default {
  name: 'AlbumList', // この分子の外部を呼ぶ際の名前

  components: {
    Album // 原子をcomponentとして使う宣言
  },

  props: {
    data: {
      type: Object,
      required: true,
      default: () => null
    }
  }
}
</script>

organisms(生体)

複数分子をよく組み合わせたもの

<template>
  <section>
    <nav class="navbar navbar-light bg-light">
      <BackBtn path="/activity"></BackBtn>
    </nav>
    <div class="container-fluid">
      <AlbumList :data="albums"></AlbumList>
      <CommentList :comments="comments"></CommentList>
    </div>
  </section>
</template>

<script>
import BackBtn from '~/components/atomes/BackBtn.vue'
import CommentList from '~/components/molecules/CommentList.vue'
import AlbumList from '~/components/molecules/AlbumList.vue'

export default {
  name: 'AlbumBook', // この分子の外部を呼ぶ際の名前
  components: {
    BackBtn,   // 原子も組み合わせられる
    CommentList, // 別の分子
    AlbumList    // 複数アルバム原子を持つ分子
  }
  data() {
    comments: [
       ... // 分子が必要なデータ
    ]
  },
  computed: {
    albums() {
      return this.$store.state.albums // 分子が必要なデータ、Vuexからアクセスするとしたら、生体でまとめるか、もしくは分子で取得するか、柔軟に変更できる
    }
  },
}
</script>

最後

Page(従来のメインとなるhtmlファイル)にそれぞれのコンポーネントでimportする、デザインにあわせて簡単に組み合わせられる、再利用性の高いコンテンツを実装できるようになった。

難しいところは、一見沢山のファイルを分割しないといけないし、コンポーネントは再利用性の高いものを見分けないといけない。
多少面倒だが、一度乗れたら後ほど開発が楽になるので、開発初期段階からするとおすすめです!
皆さんもぜひ一度チャレンジしてみてください!

追記(AtomicDesignに関連する本)

Atomic Design ~堅牢で使いやすいUIを効率良く設計する
https://www.amazon.co.jp/dp/477419705X/ref=cm_sw_em_r_mt_dp_U_okgQCb402V52T

Vue.js入門 基礎から実践アプリケーション開発まで
https://www.amazon.co.jp/dp/4297100916/ref=cm_sw_em_r_mt_dp_U_klgQCbDR7BN3X
9章からAtomicDesignのサンプルコードの詳細説明があります。

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

jQuery 画面幅を可変した際の処理でWindowsのエアロスナップに対応する

Webページで画面いっぱいに画像や動画を表示し、尚且レスポンシブに対応する際に、
通常は.resizeを用いて処理することが多いと思いますが、
Windows7以降のエアロスナップ(画面端にウィンドウを持っていき全画面や半画面表示に出来るあの機能)
するとうまく画像や動画が全画面に表示されない場合がある。

resizeの処理はウィンドウの端をドラッグする場合に処理されるが、
エアロスナップのように一気に全画面になる場合などには処理がうまくいかないのかな??
(自分の場合は、全画面になるはずの画像や動画が画面3/1は表示され残りは表示されない不具合が生じた)

そんなこんなで、PC画面とにらめっこしていたときに頭に稲妻が走り、
実装してみたらうまくいき我ながら天才か?と思ったのでここに記します。

普段使うリサイズ処理

まず初めに普段使う可変処理をみてみましょう。

jquery.js
  $(window).resize(function(){
    ここに画面可変時の処理
  });

エアロスナップに対応した処理

ただif文でwidthを取得した時に処理を行うようにする。

jquery.js
  if $(window).width() {
    ここに画面可変時の処理
  });

こうすることによりWindowsのエアロスナップにも対応できるようになります。

ちなみに

この読み込んだ時の処理.load()もさっきのコードに置き換えることが出来ます。
.loadと.resizeで同じ処理にしているコードなどがあれば、
if $(window).width() 一文で置き換えることが出来ます。

jquery.js
  $(window).load(function(){
    ここに画面可変時の処理
  });

こっちのほうが良いよとか、あったらコメント頂ければ幸いです。

こいつ天才か?と思ったら「いいね」!

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

円周率は3.05以上であることを示す。

有名な東大入試の問題の解き方を紹介します。

紙と鉛筆でも解けますが、プログラムを組んだ方がよりスムーズに解くことができます。
なぜなら正十二角形を使うからです。
正十二角形は手書きで書くと大変なのでプログラムで書いた方が楽です。

正12角形のプログラム.png
図1:JavaScriptで描いた正十二角形

それでは早速、今回解いていく問題を確認しましょう。
問題画像.png
図2:今回扱う問題

1.円周率って何?
そもそも円周率って何でしょうか?
率という数字が示すように「何か」と「何か」の割合のことです。
例えば「勝率」という言葉は「勝ち数」÷「試合数」で求められます。
10試合して3勝している場合勝率は3÷10で0.3になります。

円周率の場合は、「円周の長さ」÷「直径」で求められます。

円周率.png
図3:円周率を求める式

ということで「円周の長さ」÷「直径」の式を活用すると良さそうです。

2.正十二角形を活用した解き方
円周と正十二角形の長さ.png
図4:円と正十二角形

余弦定理を活用して解きます。
余弦定理が分からない場合はGoogleで「余弦定理 とは」と検索しましょう。
(分からない単語が出てきたら検索する癖をつけましょう)

計算式.png

参考:Pythonによるプログラム
出展:https://qiita.com/redmeteor777/items/4b4aebd9da8db825b10d

import math
# [π > 3.05 を証明せよ]
while True:
    target_input = input("円周率がいくつより大きいことを証明しますか?")
    try: #入力値チェック
        target = float(target_input)
    except ValueError:
        print("数値を入力してください。")
    else:
        # 入力値が円周率より大きいと無限ループするため入力値をチェック
        if target <= math.pi:
            break
        else:
            print("円周率より小さい値を入力してください。")
print("円周率が{}より大きいことを証明する".format(target))
print("")
#正n角形の頂点の初期値を3にセット
n = 3
# breakするまでループさせる
while True:
    # 等辺の長さ1、頂角360/nの二等辺三角形の底辺の長さを求める
    kakudo = 360 / n
    # math関数の三角関数計算ではラジアンを用いるので度→ラジアンの変換が必要
    radian_kakudo = math.radians( kakudo )
    # 余弦定理から、底辺 x の長さは[x ^ 2 = 1 ^ 2 + 1 ^ 2 + 2 * 1 * 1 * cos(360 / n)]
    x = ( 1*1 + 1*1 - 2*1*1*math.cos( radian_kakudo ) ) ** 0.5
    # 底辺の長さ * nを円周の近似値 y とする
    y = x * n
    print("正{0}角形のとき、辺の長さの合計は{1}".format(n , y))
    if y / 2 > target: #目標値より大きくなったらブレイクして終了処理へ
        break
    # 頂点を1つ増やす
    n = n + 1

print("")
print("円周率 = 円周 / 直径")
print("")
print("{0} / 2 = {1} > {2}".format(y , y / 2 , target))
print("")
print("よって円周率は{}より大きい".format(target))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Workbox webpack Plugins の GenerateSW 仕様

最近 webpack を使ってWebアプリを作る仕事が多く、加えてPWAと話もちらほらとなってきたので情報を探していたらWorkbox webpack Pluginsというものに辿り着いた。(途中経過はかなり端折っている)
どうやって使うものなのか詳しく調べようと思ったが日本語の説明サイトでは全体像を説明しているところが見つからなかったため自分で調べることにした。

Workbox って?

公式サイト
Webアプリのオフライン処理をサポートするJavaScriptライブラリらしい。

PWAを構成する機能のひとつがServiceWorkerServiceWorkerは(ざっくり言うと)ブラウザのAjax通信をインターセプトしてキャッシュ
を返すか実体を返すかなどを分岐できる機能がある。WorkboxはそのServiceWorkerの実装を簡易化してくれるもの、と認識している。

ちなみに公式サイトには頻繁にprecacheという単語(用語?)が出てくる。precacheはServiceWorkerが機能するタイミング(install)でユーザーアクセスに関わらず事前にキャッシュするものらしい。そうじゃないキャッシュはAPI呼び出し時(fetch)の応答などになり動的キャッシュになる。
以降はそれぞれプレキャッシュランタイムキャッシュと呼ぶことにする。

Workbox webpack PluginsGenerateSWInjectManifestの2つの機能を提供している。まずはGenerateSWにどんな機能があるのかを調査する。

英訳のセンスが高くないためこの先記述する内容は最終的に公式サイトで確認することをオススメする。英訳に誤まりがある場合はご指摘大歓迎です。

以降の記載はすべてWorkbox webpack Plugins サイトをベース(というかほぼそのもの)にしている。

GenerateSW

GenerateSWwebpack assetとのパイプを持つServiceWorkerファイルを生成する。webpackでビルドする時に静的ファイルの場所は認識できるのでそれらをプレキャッシュ対象として認識してくれるということだと思う。

GenerateSW を使うケース、使わないケース

  • 使うケース
    • プレキャッシュ機能を使いたい(言うまでもないけど)
    • そんなに複雑な処理を必要としない
  • 使わないケース
    • ServiceWorker以外の機能(Web Pushなど)も使いたい
    • (生成したServiceWorkerファイルに)独自のロジックを入れたい

指定可能なオプション

webpackコンパイル時に適用されるもの

キー 必須 未指定時のデフォルト 説明
swDest string service-worker.js ビルドで生成されるServiceWorkerファイルのパスとファイル名を
webpackのoutput設定からの相対パスで指定する。
importWorkboxFrom enum: string cdn Workboxのランタイムライブラリをどこから調達するかの設定
● cdn: 可用性ある'Google Cloud Storage'からダウンロードして使う。
● local: ローカルコピーを使う。このオプションを選択する場合はローカルにライブラリを用意しておく必要がある。
● disabled: importScriptsオプションを使ってworkbox-sw.jsへのパスを自分で通せ。
※Workboxランタイムライブラリを含むwebpackモジュールのパスを指定することも許容するらしい。(ただしそれはこのオプションではなくimportScriptsで、ということだと思われる...)
chunks string[] [] プレキャッシュ対象のモジュール名(本文ではchank name)を明示的にホワイトリスト方式で指定する。デフォルト設定のままだとなんでもかんでもプレキャッシュするということだと。
excludeChunks string[] [] プレキャッシュ対象にしないモジュール名(本文ではchank name)を明示的にブラックリスト方式で指定する。デフォルトだと...以下同文。
include string[], RegExp[] [] プレキャッシュ対象のモジュールをファイル名ベース(正規表現もOK)で指定する。(多分何も指定しない場合だと思うけど)webpackのtestオプションを使用する。
exclude string[], RegExp[] [/\.map\$/, /^manifest.*\.js\$/] プレキャッシュ対象にしないモジュールをファイル名ベース(正規表現もOK)で指定する。
importsDirectory string webpackコンパイル時にWorkboxが生成するassetsの出力場所を(webpackのoutput.pathのサブディレクトリとして)指定する。
※ただしServiceWorkerファイルについてはこのオプション指定に左右されない。
precacheManifestFilename string precache-manifest.[manifestHash].js Workboxが生成するマニフェストファイル(プレキャッシュするのに必要となるURLなどを含むものらしい)のファイル名を変えたい時に指定する。ただし'[manifestHash]'は必ずファイル名に含める必要がある。
※このオプションで指定できるのはファイル名だけ、出力パスを変えたい場合はimportsDirectoryを使用する。

webpackコンパイルに影響しないもの

キー 必須 未指定時のデフォルト 説明
importWorkboxFrom string cdn (なぜここにある...?詳細は↑を参照)
skipWaiting boolean false ServiceWorkerの更新時にwait状態を無視して制御を乗っ取るかどうか。(skipWaitingの説明は別途するとしておそらく false のままでいいんじゃないか...と)
clientsClaim boolean false ServiceWorkerの新規install後にすぐに(ページのリロードとかなしで)制御できるようにするかどうか。(ServiceWorker無しでは機能しないアプリとかじゃない限り false のままでいいんじゃないか...と)
runtimeCaching object[] [] 動的なAPI応答などをランタイムキャッシュするための指定。'urlPattern'、'handler'、'options'をキーに持つオブジェクトでキャッシュ方法を指定する。(これについては元サイトの実装例を見るのが一番分かり易い)
navigateFallback string undefined なんらかの理由でキャッシュ対象にならないリソースをキャッシュするためのルート(NavigationRoute)を指定する。主にはSPAで使い回されるファイルなどをキャッシュ対象にするための設定らしい。
navigateFallbackBlacklist RegExp[] [] 'navigateFallback'設定が適用する範囲を制限するためのブラックリスト。
ブラックリストとホワイトリストが両方指定されている時はブラックリストが優先される。
navigateFallbackWhitelist RegExp[] [] 'navigateFallback'設定が適用する範囲を制限するためのホワイトリスト。
ブラックリストとホワイトリストが両方指定されている時はブラックリストが優先される。
importScripts string[] - ServiceWorkerから importScripts() を使ってインポートする必要があるJavaScriptファイルを指定する。また、インポートするJavaScriptファイルで 'self.__precacheManifest' にプレキャッシュしたいファイルのURLを指定するとプレキャッシュ対象になる。この設定でpushイベントを処理する追加コードなどをServiceWorkerに含めることができる。(ん?できるのそれ。。そして必須なのこのオプション。。)
ignoreURLParametersMatching RegExp[] [/^utm_/] キャッシュ検索のときに無視するパラメータを指定する。デフォルトだとキャンペーンパラメータはすべて無視するようになっている。
directoryIndex string index.html ウェルカムページをプレキャッシュに含めるための設定。末尾'/'でリクエストされて応答するファイル名を指定する。
cacheId string null Workboxがキャッシュ名に付けるID。主にローカルで開発時に使うもので同じlocalドメインで複数のサイトをホストしているケースで役に立つとのこと。
offlineGoogleAnalytics boolean false 'Offline Google Analytics'のON/OFFスイッチ。trueに設定すると Background Sync によるGoogleAnalyticsをうまいことやってくれる?らしい。
cleanupOutdatedCaches boolean false 時代遅れのキャッシュを削除してくれる設定。(だとしたらなぜデフォルトが false ?)
globDirectory string undefined 'globPatterns'設定が使用するベースディレクトリを指定する。これを指定する場合は'globPatterns'指定も必須。
globFollow boolean true プレキャッシュのマニフェスト生成時に symlinks を追従するかどうかを指定する。
globIgnores string[] ['node_modules/*/'] プレキャッシュのマニフェスト生成時に除外するファイルをglob指定する。
globPatterns string[] [] プレキャッシュのマニフェスト生成時に対象とするファイルをglob指定する。ただし workbox-webpack-plugin の場合は webpack の静的ファイルは自動で対象になるためほとんどの場合指定する必要はない。
globStrict boolean true プレキャッシュのマニフェスト生成時にglob指定のディレクトリの読み取りエラーが発生した場合にビルドをエラー終了させるかどうかを指定する。
templatedURLs object null プレキャッシュするファイル中で "呼び出される複数のファイルの内容" または "記述される特定の文字列" を、プレキャッシュするファイルの一意性を示すバージョンとして使用する場合に指定する。(英訳微妙?)
objectにはstring[]またはstringを指定できる。
maximumFileSizeToCacheInBytes Number 2097152 プレキャッシュする(「ひとつの」だと思うが本文には特に記述なし)ファイルの最大サイズを指定する。不注意な指定で巨大なファイルをキャッシュしてしまう動作を防止する。
dontCacheBustURLsMatching RegExp null プレキャッシュ時の一意性を判断する時のフィルターのようなものとして指定する。例えば静的ファイルに必ずハッシュ値を付与しているような場合に同じファイルを複数キャッシュしてしまわないために使用する。(おそらくここで指定した正規表現部分を削った名前で比較するという意味じゃなろうか、違うかな...?)
modifyURLPrefix object null プレキャッシュのマニフェストのエントリーに前置詞を付与(または削除)する。静的ファイル置き場がローカルとデプロイ時で異なる場合などに使用する。より柔軟な対応が必要なら 'manifestTransforms' オプションを使う。
objectにはstringのみ指定可能。
manifestTransforms ManifestTransform[] null プレキャッシュのマニフェストのエントリーに対して柔軟なカスタマイズを行う。静的ファイルのある特定のファイルだけパスを変えたり、などなど。'modifyURLPrefix' や 'dontCacheBustURLsMatching' オプションを併用している場合はそれらが先に適用される。

やや見辛いテーブルになってしまったので今後修正していきます。

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

【メモ】javascriptでおしゃれなボタンとチェックボックスを連動させる

仕様

  • ブロックが増減できる入力インターフェイスがnested_form&simple_formで実装されている。
  • 曜日のタブというかボタンをクリックするとclassが付与され、それに対応したチェックボックスにチェックが入る
  • class付与されたタブというかボタンをクリックするとclassが初期化され、それに対応したチェックボックスのチェックが外れる
  • ロード時、チェックボックスにチェックが入っているものに対応するタブというかボタンにclassが付与される

素のHTML

.daysTab
  .daysTab__label
    営業日を選んでください
    = f.link_to_remove data: { confirm: '営業時間を削除しますか?' } do
      削除
  .daysTab__buttons
    %ul{onclick: "clickToCheck(event)"}
      %li%li%li%li%li%li%li%li 祝日
      %li 祝日前
  .daysTab__checkboxes
    = f.input :monday
    = f.input :tuesday
    = f.input :wednesday
    = f.input :thursday
    = f.input :friday
    = f.input :saturday
    = f.input :sunday
    = f.input :holiday
    = f.input :before_holiday

この一式が任意で追加削除できる。

  • daysTab__checkboxesは最終的にdisplay:noneで非表示になる。
  • daysTab__buttonsの部分を好きなようにスタイリングすることでおしゃれなIFが出来上がるw

で、出来上がったJSが以下。

function clickToCheck(e) {
  var selfParentNode = e.target.parentNode;
  var selfchildrenNodes = selfParentNode.querySelectorAll("li");
  var selfIndex = Array.prototype.indexOf.call(selfchildrenNodes, e.target);
  var targetParentNode = e.target.parentNode.parentNode.nextElementSibling;
  var targetChildrenNodes = targetParentNode.querySelectorAll('input[type=checkbox]');
  (function clickToChangeClass(className){
    var classlist = e.target.classList;
    if(classlist.contains(className)){
      classlist.remove(className);
    }else{
      classlist.add(className);
    }
  }('active'));
  (function checking(){
    var targetCheckbox = targetChildrenNodes[selfIndex];
    targetCheckbox.checked = !targetCheckbox.checked;
  }());
};
function checkStatus(className){
  document.addEventListener('DOMContentLoaded', function(){
    if(document.getElementById('shopHoursFields') != null){
      var fields = document.querySelectorAll('.fields');
      fields.forEach(function(e){
        var checkboxes = e.children[0].children[2].querySelectorAll('input[type=checkbox]');
        var buttons = e.children[0].children[1].querySelectorAll('li');
        checkboxes.forEach(function(e, index){
          if(e.checked == true){
            buttons[index].classList.add(className);
          }
        });
      });
    }
  }, false);
};
checkStatus('active');

shopHoursFieldsはnested_formで増減するfieldsの親要素

とりあえず動く状態にするしか考えてないので、おそろしく長いし雑w
ブラッシュアップに時間を割けるほど余裕がないので一旦終了。
なんか不具合でたらその都度修正・更新します。

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

Vue.jsでmethodからdataの値にアクセスする時にハマった

Vue.jsで以下のchange~~メソッドを呼び出したところ・・・

App.Vue
data: () => {
    return {
        connect: {
          'connectStatus': '切断中',
        }
    }
},
methods: {
    changeConnectStatus: (status) => {
      this.$set(this.connect, 'connectStatus', status);
    },
}

コンソールに以下のエラーが出た。

TypeError: undefined is not an object (evaluating 'l.$set')

()=>ではなくfunctionにしよう

以下のようにすることで解決した。

App.Vue
changeConnectStatus: function(status) {
   this.$set(this.connect, 'connectStatus', status);
},

すごく単純なのにこれに気づくのに3時間くらいかかりました。
Javascriptの汎用性の高さは逆に難しい・・・。

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

Vue.jsでmethodからdataの値にアクセスする時にハマった

Vue.jsで以下のchange~~メソッドを呼び出したところ・・・

App.Vue
data: () => {
    return {
        connect: {
          'connectStatus': '切断中',
        }
    }
},
methods: {
    changeConnectStatus: (status) => {
      this.$set(this.connect, 'connectStatus', status);
    },
}

コンソールに以下のエラーが出た。

TypeError: undefined is not an object (evaluating 'l.$set')

()=>ではなくfunctionにしよう

以下のようにすることで解決した。

App.Vue
changeConnectStatus: function(status) {
   this.$set(this.connect, 'connectStatus', status);
},

すごく単純なのにこれに気づくのに3時間くらいかかりました。
Javascriptの汎用性の高さは逆に難しい・・・。

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

[JavaScript]ajax通信の重複を回避する方法

ajax通信の重複を回避するには

ajax()によって非同期通信をする時、イベントが発生するたびに同じ値を取得する方法を説明していきます。
まず下記のコードを見てください

ajax.js
$('html要素').on('keyup', function(){
        var input = $(this).val();

        $.ajax({
            type: 'GET',
        url: url,
        data: { keyword: input },
        dataType: 'json'
        })
        .done(function(data) {
          //処理
        })
        .fail(function() {
        //処理
        });


このようにキーが押されるたびにajax通信によって処理が行われるコードがあります。
ただしこの場合押されるたびに通信してしますので取得するデータが同じデータの場合重複して取得することになります。

それを防ぐのがjqxhrオブジェクトです。
これはajax通信をする前にjqxhrオブジェクトを判定しオブジェクトが存在する場合はajax通信を実行しません。
これによりデータの取得の重複を伏せづことができます。

ajax.js
var jqxhr; //追記部分
$('html要素').on('keyup', function(){
        var input = $(this).val(); 
        if (jqxhr){        //追記部分
            return;
        }

        jqxhr = $.ajax({  //追記部分
            type: 'GET',
            url: url,
            data: { keyword: input },
            dataType: 'json'
        })
        .done(function(data) {
          //処理
        })
        .fail(function() {
        //処理
        });


このように記述することによりキーを押した時jqxhrオブジェクトの判定が行われ、オブジェクトがあれば実行しません。

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

WebPack4 css-loader の画像相対パスで小2時間ハマった

ハマったよ。。background-imageの画像パス

Webpack4でsassをMiniCssExtractPluginを使用してコンパイルしていたら
いきなりのエラー。

Module not found: Error: Can't resolve '../images/bg_slide_sp01.jpg' in '/Users/amn-user/AMN/Alpha/app/src/scss'

なんでじゃ??

とハマったこと小2時間。

備忘として残すことにした。

原因は?

sass-loaderのエラーなの?
なんなの??
とGoogle先生に尋ねた。

困った時のQiitaと並ぶstack overflowに答えがいた!

回答は以下に。

WebPack + SASS : How to generate relative image path?

css-loaderoptionだった。

optionのurlがデフォルトではtrueになっているから絶対パスでないとエラーが出てしまう。
相対パスをしようしたかったらurl: flaseにしなくちゃならなかった!!

{
   loader: 'css-loader',
      options: {
        url: flase,
        sourceMap: true,
        importLoaders: 2
      }
}

これで、解決。

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

4/5 jsコードレシピ集 学習 classList.add textContent innerHTML

要素にクラスを追加
要素.classList.add(追加したいクラス)

要素のテキストを取得
要素.textContent

要素のテキストをXXXXXで書き換え
要素.textContent = "XXXXX"

要素のHTMLをYYYYYで書き換え
innerHTML = "YYYYY"

textContentはテキストのみ取得するが、innerHTMLはHTMLを取得出来るので、cssの操作も可能。

js
// weather要素を取得
const weatherElement = document.getElementById('weather');

// クリックしたらイベント発火
weatherElement.addEventListener('click', () =>
{
  // weather要素にnew-classというクラスを追加
  weatherElement.classList.add('new-class');

  // weather要素のテキストを書き換える
  weatherElement.textContent = "気温は<strong>66℃</strong>になる予定です"

  // アラートでweather要素のテキストを表示
  alert(weatherElement.textContent);
  // #出力結果 = 気温は<strong>66℃</strong>になる予定です

  // weather要素のHTMLを書き換え、テキストを太字にするstrongタグを追加する
  weatherElement.innerHTML = "気温は<strong>66℃</strong>になる予定です";
// #出力結果(太字、背景が黄緑) = 気温は66℃になる予定です
});
html
<p id="weather>今日は猛暑です<p>
css
.new-class {
  background-color: greenyellow;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

久しぶりにArray.Splite()を使って混乱した事

はじめに

久しぶりにArray.Splite()使ってちょっと混乱してしまいました。
思惑通りの操作は直ぐに出来たのですが、MSN等に載っている関数の説明が間違っているのではとしばらく考えてしまいました。
結果、自分の勘違いでした。
単純な事ですがメモとして残しておこうと思います。

Array.prototype.splice()の簡単な説明

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
Start :
開始位置。
負の場合、array.length - n から開始。
開始位置の要素も削除の対象になる。

deleteCount :
削除する要素の数。
省略した場合、Start以降の要素を削除する。
0または負の場合、何も削除されない。

item1, item2 : この記事では、使わないので省略。

勘違いした記述

末尾から4つ消そうと以下のように書いてしまった。

javascript
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-1, 4);
console.log(array);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]; 

この記述では、末尾の1つしか削除されません。
動作をしっかり理解すると当然なのが分かります。
末尾から開始して(右側の)4つ要素を削除するとなります。
末尾の後に続く要素は当然ありませんので、末尾1つしか削除されません。

この場合、以下のようにすると想定通りの動きになります。

javascript
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4, 4);
console.log(array);
// [1, 2, 3, 4, 5, 6];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4);
console.log(array);
// [1, 2, 3, 4, 5, 6];

削除する方向が右側固定なのが肝でしたね。

その他の動作結果

javascript
let array = [];
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(0, 1);
console.log(array);
// [2, 3, 4, 5, 6, 7, 8, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(0, 4);
console.log(array);
// [5, 6, 7, 8, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(4, 1);
console.log(array);
// [1, 2, 3, 4, 6, 7, 8, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(4, 4);
console.log(array);
// [1, 2, 3, 4, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-1, 1);
console.log(array);
// [1, 2, 3, 4, 5, 6, 7, 8, 9];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4, 1);
console.log(array);
// [1, 2, 3, 4, 5, 6, 8, 9, 0]; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4, 4);
console.log(array);
//  [1, 2, 3, 4, 5, 6]; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(0);
console.log(array);
//  []; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(4);
console.log(array);
//  [1, 2, 3, 4]; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-1);
console.log(array);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4);
console.log(array);
// [1, 2, 3, 4, 5, 6]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

久しぶりにArray.Splice()を使って混乱した事

はじめに

久しぶりにArray.splice()使ってちょっと混乱してしまいました。
思惑通りの操作は直ぐに出来たのですが、MSN等に載っている関数の説明が間違っているのではとしばらく考えてしまいました。
結果、自分の勘違いでした。
単純な事ですがメモとして残しておこうと思います。

Array.prototype.splice()の簡単な説明

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
Start :
開始位置。
負の場合、array.length - n から開始。
開始位置の要素も削除の対象になる。

deleteCount :
削除する要素の数。
省略した場合、Start以降の要素を削除する。
0または負の場合、何も削除されない。

item1, item2 : この記事では、使わないので省略。

勘違いした記述

末尾から4つ消そうと以下のように書いてしまった。

javascript
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-1, 4);
console.log(array);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]; 

この記述では、末尾の1つしか削除されません。
動作をしっかり理解すると当然なのが分かります。
末尾から開始して(右側の)4つ要素を削除するとなります。
末尾の後に続く要素は当然ありませんので、末尾1つしか削除されません。

この場合、以下のようにすると想定通りの動きになります。

javascript
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4, 4);
console.log(array);
// [1, 2, 3, 4, 5, 6];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4);
console.log(array);
// [1, 2, 3, 4, 5, 6];

削除する方向が右側固定なのが肝でしたね。

その他の動作結果

javascript
let array = [];
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(0, 1);
console.log(array);
// [2, 3, 4, 5, 6, 7, 8, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(0, 4);
console.log(array);
// [5, 6, 7, 8, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(4, 1);
console.log(array);
// [1, 2, 3, 4, 6, 7, 8, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(4, 4);
console.log(array);
// [1, 2, 3, 4, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-1, 1);
console.log(array);
// [1, 2, 3, 4, 5, 6, 7, 8, 9];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4, 1);
console.log(array);
// [1, 2, 3, 4, 5, 6, 8, 9, 0]; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4, 4);
console.log(array);
//  [1, 2, 3, 4, 5, 6]; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(0);
console.log(array);
//  []; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(4);
console.log(array);
//  [1, 2, 3, 4]; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-1);
console.log(array);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4);
console.log(array);
// [1, 2, 3, 4, 5, 6]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

久しぶりにArray.splice()を使って混乱した事

はじめに

久しぶりにArray.splice()使ってちょっと混乱してしまいました。
思惑通りの操作は直ぐに出来たのですが、MSN等に載っている関数の説明が間違っているのではとしばらく考えてしまいました。
結果、自分の勘違いでした。
単純な事ですがメモとして残しておこうと思います。

Array.prototype.splice()の簡単な説明

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
Start :
開始位置。
負の場合、array.length - n から開始。
開始位置の要素も削除の対象になる。

deleteCount :
削除する要素の数。
省略した場合、Start以降の要素を削除する。
0または負の場合、何も削除されない。

item1, item2 : この記事では、使わないので省略。

勘違いした記述

末尾から4つ消そうと以下のように書いてしまった。

javascript
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-1, 4);
console.log(array);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]; 

この記述では、末尾の1つしか削除されません。
動作をしっかり理解すると当然なのが分かります。
末尾から開始して(右側の)4つ要素を削除するとなります。
末尾の後に続く要素は当然ありませんので、末尾1つしか削除されません。

この場合、以下のようにすると想定通りの動きになります。

javascript
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4, 4);
console.log(array);
// [1, 2, 3, 4, 5, 6];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4);
console.log(array);
// [1, 2, 3, 4, 5, 6];

削除する方向が右側固定なのが肝でしたね。

その他の動作結果

javascript
let array = [];
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(0, 1);
console.log(array);
// [2, 3, 4, 5, 6, 7, 8, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(0, 4);
console.log(array);
// [5, 6, 7, 8, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(4, 1);
console.log(array);
// [1, 2, 3, 4, 6, 7, 8, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(4, 4);
console.log(array);
// [1, 2, 3, 4, 9, 0];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-1, 1);
console.log(array);
// [1, 2, 3, 4, 5, 6, 7, 8, 9];

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4, 1);
console.log(array);
// [1, 2, 3, 4, 5, 6, 8, 9, 0]; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4, 4);
console.log(array);
//  [1, 2, 3, 4, 5, 6]; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(0);
console.log(array);
//  []; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(4);
console.log(array);
//  [1, 2, 3, 4]; 

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-1);
console.log(array);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
array.splice(-4);
console.log(array);
// [1, 2, 3, 4, 5, 6]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript から C/C++ コードを呼べる, WebAssembly の概要紹介

WebAssembly の概要

  • C/C++ のコードをコンパイルしたものを Javascript から呼び出して実行することができる
  • .c をコンパイルして .wasm を作り, それを .js から読み込むことで実現する
  • あくまで Javascript ができることしか実行できないと考えてよい
    • バッチファイルの実行などを記述した .c ファイルは .wasm にコンパイルできない
    • Javascript にそもそもバッチファイルの実行機能などがないため
  • Javascript で書いた処理よりも高速に動作させることができる
  • 詳細: https://developer.mozilla.org/ja/docs/WebAssembly/C_to_wasm

WebAssembly を使ってみる

  • 前述したサイト にコンパイル用コマンド(emcc)の導入手順が書いてある
  • 準備 に書かれたものをインストールしてパスも通したら以下コマンドを実行
  • WebAssembly コンパイラのソースをダウンロードしてソースをコンパイルして...という作業に1時間はかかるので, PC を放置できるときに実行するほうがよい

インストールにはしばらく時間がかかるので、お茶でも飲んでください。

git clone https://github.com/juj/emsdk.git
cd emsdk

# on Linux or Mac OS X
./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
./emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit

# on Windows
emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit

使用例

WebAssembly を使うモチベーション

  • Javascript より高速で動作させられるので, パフォーマンス向上のため
  • Javascript という仕様が歪な言語に頼らなくて良くなるので, 保守性向上のため
  • etc.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む