ReactでMaterial-UIを使ってみる

インストール

$ yarn add @material-ui/core
$ yarn add @material-ui/icons

全体のテーマを整える

src/assets/theme.ts

import indigo from "@material-ui/core/colors/indigo";
import pink from "@material-ui/core/colors/pink";
import red from "@material-ui/core/colors/red";
import { createMuiTheme } from "@material-ui/core/styles";

const theme = createMuiTheme({
  palette: {
    primary: pink,
    secondary: indigo
  }
});

export default theme;

上書きできる設定は これ

src/index.tsx

import { MuiThemeProvider } from "@material-ui/core";
import theme from "./assets/theme";

ReactDOM.render(
  <MuiThemeProvider theme={theme}>
    <App />
  </MuiThemeProvider>,
  document.getElementById("root")
);

使ってみる

import Button from "@material-ui/core/Button";
import AccessAlarmIcon from "@material-ui/icons/AccessAlarm";
・・・
  <Button variant="contained" color="primary">
    <AccessAlarmIcon />
    Hello
  </Button>
・・・

color="primary"と指定して、青かったボタンが、

ピンクに表示される。

Vue.js と jQuery を共存させる

DOM操作、イベント処理などは Vue.js に任せるとして、
アニメーションなど jQuery で簡単に実装出来ることは jQuery でやってしまおうと思い、
Vue.js で jQuery を使う。

思想的には共存させない方が良いのかな?と思いますが一旦効率重視で。

まずはインストール。

$ npm install -D jquery
$ npm install -D @types/jquery

使う時は下記のような感じです。

import $ from "jquery";

$("html,body").animate({scrollTop: 0}, 500, "swing");

型定義が合わないのか、
$(“.xxx”).offset().top
の offset() が見つからないとかエラーが出てしまい、
// @ts-ignore
で抑制してしまったり、少しもどかしい感じです。

Vue.js(TypeScript) でグローバル変数を使う

Vue.js で開発していてアプリケーション内でデータを共有したくなりました。
いくつか方法があると思います。
・Vuex
・Cookie
・LocalStrage
・グローバル変数

Vuex とかが正しいのかもしれないですが、少し冗長な気がしたし、Cookie だとデータの保存期間の制御など要件に合わすのが大変そうだった。
アプリが起動しているときだけ保持して、且つ複数のウィンドウでアプリが起動されウィンドウごとに別のデータとして管理する想定です。
もっとも簡単そうですし要件にも合うのでグローバル変数を使う方針にしました。

今回はプラグインとして実現することにしました。
まずはプラグインと、データを保持するクラスの定義です。

import _Vue from "vue";

export default function AppDataPlugin<AppDataPluginOptions>(Vue: typeof _Vue, options?: AppDataPluginOptions): void {
    Vue.prototype.$appData = new AppData();
}

export class AppDataPluginOptions {
}

export class AppData {
    public dataAaa: string = "";
    public dataBbb: string = "";
}

VisualStudioCode などのためにコード型定義ファイルも用意。
AppDataPlugin.d.ts とかのファイル名で src 直下に保存

import AppDataPlugin, { AppData } from "./components/AppDataPlugin";
declare module 'vue/types/vue' {
  interface Vue {
    $appData: AppData
  }
}

使う側は下記のような感じです。

<script lang="ts">
import Vue from "vue";
import AppDataPlugin from "./AppDataPlugin";

Vue.use(AppDataPlugin);

export default Vue.extend({
    ・・・
    methods: {
        xxx() {
            console.log(this.$appData.dataAaa);
        }
    }
    ・・・
});

Vue.js(TypeScript)でvalidation

Vue.js(TypeScript) のプロジェクトで validation を行いたい。
表示はcss フレームワーク Bulma を拡張したUIコンポーネントの Buefy を使う。
validation には VeeValidation を使う。

パッケージのインストール

$ npm install -D buefy node-sass sass-loader vee-validate

buefy を使う

buefyのアイコンを使うので、index.htmlに下記追加。

 <link rel="stylesheet" href="//cdn.materialdesignicons.com/2.0.46/css/materialdesignicons.min.css">

VeeValidate を使う

<template>
  <div>
    <b-field label="メールアドレス"
      :type="errors.has('email') ? 'is-danger': ''"
      :message="errors.has('email') ? errors.first('email') : ''">
        <b-input
            name="email"
            v-model="email"
            v-validate="'required|email'"
            placeholder="メールアドレス">
        </b-input>
    </b-field>
  </div>
</template>
・・・
<script lang="ts">
import Vue from "vue";
import Buefy from "buefy";
import VeeValidate from "vee-validate";

Vue.use(Buefy);
Vue.use(VeeValidate);
・・・

VeeValidate を日本語化

エラーメッセージが英語なので日本語化する。
ローカライズ用のメッセージファイルの読込と、フィールド名の日本語化を行う。

・・・
        <b-input
            name="email"
            v-model="email"
            v-validate="'required'"
            data-vv-as="メールアドレス"
            placeholder="メールアドレス">
・・・
<script lang="ts">
import Vue from "vue";
import Buefy from "buefy";
import VeeValidate, { Validator } from "vee-validate";
// @ts-ignore: implicitly has an 'any' type.
import VeeValidateJa from "vee-validate/dist/locale/ja";

Vue.use(Buefy);
Validator.localize("ja", VeeValidateJa);
Vue.use(VeeValidate);
・・・

フィールド名の日本語化は、data-vv-as を追加してフィールドごとに対応。
attributesファイルを用意しても出来るようです。
https://baianat.github.io/vee-validate/guide/localization.html#aliases

メッセージファイルの読込でエラーが出たので、ts-ignoreで対応、、、

入力チェックのタイミングを変更

メールアドレスのチェックなどで入力を始めるといきなりエラーとなるので、入力チェックを行うタイミングをフォーカスが外れた時にする。

Vue.use(VeeValidate, {
  events: "blur"
});

ボタンクリックなどで入力チェック

ログイン処理など実際にはボタンクリックなどで全体の入力チェックを行うと思うので、その方法。

・・・
<a class="button is-primary is-fullwidth" @click="login()">ログイン</a>
・・・
  methods: {
    login() {
      this.$validator
        .validateAll()
        .then(result => {
          if (!result) {
            console.log(this.$validator.errors.all());
            return;
          }
        })
        .catch(() => {
          console.log(this.$validator.errors.all());
        });
    }
  }

入力チェックでエラーがあってもcatchではなくthenが呼ばれる。入力エラーがあるかはresultで判定する。

TypeScript で文字列を一文字ずつスタイルを適用する

ひとまず共通関数を定義

function decorateText(text: string, params: {[index: string]: string}[]): string {
    var result = '';
    var textArr = text.split('');
    var textLen = textArr.length;
    var paramsLen = params.length;
    for (var i = 0; i < textLen; i++) {
        var attr = '';
        let param = params[(i % paramsLen)];
        for (var key in param) {
            attr += ` ${key}="${param[key]}"`
        }
        result += `<span ${attr}>${textArr[i]}</span>`;
    }
    return result;
}

呼び出し側は

var decorateParams = [
    {"style" : "color: #000000;"},
    {"style" : "color: #ff0000;"}
];
decorateText("aaaaaaaaaa", decorateParams);

こんな感じです。

Vue.js + TypeScript で外部ライブラリを使用したいが型定義がない

型定義があるライブラリはここを参照。

ただ、そもそもない時の回避方法を考える。

  • 無視する
    該当の処理の前に、
    // @ts-ignore:

  • 型定義を作る
    ただしく定義するのは大変なので、
    declare module “{パッケージ名}” を記載した .d.ts を作成

  • declare
    declare var xxx: any;
    でany型として宣言してしまう。

Vue.js + TypeScript の最新版で動かせるようにしてみたが、、、

Webpack4で動かせるようにしてみたが、結果はうまくいかなかったので一旦あきらめる。

$ npm i -D webpack-cli
$ npm i -D ajv
$ npm i -D webpack@4.12.0

必要なモジュールをバージョン指定で手動で入れていく。

$ npm outdated

上記のコマンドで現在、最新、必要なバージョンが確認できる。
extract-text-webpack-plugin はベータ版になる。

$ npm i -D extract-text-webpack-plugin@next
$ npm i -D html-webpack-plugin@3.2.0
$ npm i -D autoprefixer@8.6.3
$ npm i -D webpack-dev-server@3.1.4
$ npm i -D vue-loader@15.2.4
$ npm i -D vue-style-loader@4.1.0
$ npm i -D url-loader@1.0.1
$ npm i -D optimize-css-assets-webpack-plugin@4.0.2
$ npm i -D ora@2.1.0
$ npm i -D shelljs@0.8.2