カテゴリーアーカイブ JavaScript

村上 著者:村上

【React】Material-UIのListsコンポーネントのrightIconButtonについて

ちょっとハマったので、対応方法をまとめ。
今回は、React のプロジェクトでマテリアルデザインを導入するために利用している「Material-UI」というフレームワークについてです。
このフレームワークで用意されている Lists コンポーネントを使ってリストを作成しているのですが、リストアイテムの右端にアイコンボタンを設置したとき、ボタンを押すとリストアイテムまで反応してしまうという現象が発生していました。

バージョンが古いのも問題なのでしょうが…依存関係の問題もあり、まだアップデートができていません。
時間を見つけて行いたいと思います。

 

サンプルのコードはこちら。

const rightButton = (
    <IconButton onClick={this.clickButton}>
        <MoreVertIcon color={grey400} />
    </IconButton>
);

<ListItem
    onClick={this.listClick}
    primaryText={[タイトル]}
    secondaryText={[サブタイトル]}
    leftAvatar={<img src={[画像URL]} height="40" width="40" style={style.image} />}
    rightIconButton={rightButton}/>

上記のように、右端に表示したいアイコンボタンを rightIconButton を使って定義したのですが、このボタンをクリックすると、ListItem で指定した onClick も発火してしまいます。
ドキュメントによると、rightIconButton を使って定義したボタンをクリックした時は、ListItem のクリックイベントは発火しないと書かれているのですが…。

で、正直面倒くさくなってしまったため、力業で解決することにしました。
それが下記のコードです。



<div className="listItem">
    <ListItem
        onClick={this.listClick}
        primaryText={[タイトル]}
        secondaryText={[サブタイトル]}
        leftAvatar={<img src={[画像URL]} height="40" width="40" style={style.image} />}
        rightIconButton={rightButton}/>
    <IconButton onClick={this.clickButton} className="rightButton">
        <MoreVertIcon color={grey400} />
    </IconButton>
</div>


ListItem から IconButton を外に出してしまい、CSS で位置を調整しました。
なお、CSS は下記のとおりです。

.listItem {
    position: relative;
}
.rightButton {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
}

恐らく上記の CSS であれば、ListItem の高さが変わってもボタンの位置は上下中央揃えになるはずです。
なお、CSS はデザインに応じて適宜変更してください。

 

以上、Material-UI のLists コンポーネントの rightIconButton が思った通りの動作をしなかった時の対処法でした。
正式な方法ではありませんが、少なくとも私の環境では問題なく動作しておりますので、お急ぎの時はこの方法を検討してみてはいかがでしょうか。

  • この記事いいね! (0)
村上 著者:村上

【Cordova】端末のプラットフォームやバージョン情報を取得できるプラグイン「cordova-plugin-device」

Cordova アプリを開発中に、Android と iOS で処理を分けるなど、端末の情報を取得する必要があるときに便利なプラグイン「cordova-plugin-device」についてのご紹介です。
主に、プラグインによっては、Android でしか動作しないものがあったり、逆に iOS でのみ動作するものもあったりするのでそれの処理をかき分けたい時などに使っています。

GitHub のページはこちらから。

GitHub – apache/cordova-plugin-device: Apache Cordova Plugin device
https://github.com/apache/cordova-plugin-device

 

インストールは下記のコマンドで行います。

cordova plugin add cordova-plugin-device --save

準備は以上で完了です。
あとは、任意の場所でプラットフォームの種類などのデバイス情報を取得できます。

私が主に使うのは下記のコードです。

const device = window.device.platform;

switch (device) {
    case 'Android':
        // 端末が Android だった時の処理
        break;
    case 'iOS':
        // 端末が iOS だった時の処理
        break;
    default:
        // その他の処理
}

上記では、アプリを実行している端末が Android なのか iOS なのか、それ以外のものなのかを判定して、それぞれの処理を実行できます。

他にも、UUID を取得したり、バージョン情報を取得したりすることもできます。
取得できる情報は下記のとおりです。

  • device.model
  • device.platform
  • device.uuid
  • device.version
  • device.manufacturer
  • device.isVirtual
  • device.serial

また、端末の製造元や、現在の実行環境が実機なのかシュミレータなのかを判断することもできます。
使い方は下記のとおりです。

// 製造元を取得
const manufacturer = window.device.manufacturer;
// シュミレータかどうかを取得
const isSimulator = window.device.isVirtual;

なお、シュミレータかどうかの判定については、OS Xブラウザの場合は常に false を返すようです。

 

以上、アプリを実行している端末の情報を取得できるプラグイン「cordova-plugin-device」のご紹介でした。
プラットフォームの取得以外はまだ使ったことはありませんが、それだけでもかなり使えますので、是非ご活用ください。

  • この記事いいね! (0)
村上 著者:村上

【Cordova】写真からExif情報を取得するプラグイン「cordova-exif」

今回は、写真から Exif 情報を取得するためのプラグイン「cordova-exif」について。
以前は JavaScript を使って取得していたのですが、色々修正することになったので併せてこちらも修正しました。

GitHub のページはこちらから。

GitHub – guilhermefarias/cordova-exif: This plugin, is the simplest way to get exif data of images at Cordova platform (Phonegap)
https://github.com/guilhermefarias/cordova-exif

 

実装方法ですが、まず下記のコードを実行します。

cordova plugin add https://github.com/domax/cordova-exif.git --save

なお、このプラグインを使うには cordova-plugin-cameracordova-plugin-file が必要です。
インストールされてない場合は、自動でこれらのプラグインもインストールされます。

ただし、プラグインのバージョンによっては競合が起こる事もあり、私の環境ではカメラプラグインのバージョンが新しすぎたようでエラーになりました。
そのため、最新のカメラプラグインやファイルプラグインを既にインストール済みの場合は、問題がなければ一度削除してから cordova-exif をインストールすることをおすすめします。

インストールが完了したら、あとは下記のコードで Exif 情報を取得できます。

CordovaExif.readData(imageURI, function(exifObject) {
  console.log(exifObject);
});

取得できるデータ一覧は上の GitHub のページに記載されているので、分からなくなった場合はご確認ください。

なお、カメラプラグインと合わせて使う場合は下記のように書きます。

function onSuccess(imageURI) {
  CordovaExif.readData(imageURI, function(exifObject) {
    console.log(exifObject);
  });
}
function onFail(message) {
  alert('Failed because: ' + message);
}
var options = {
  sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
  quality: 50,
  encodingType: Camera.EncodingType.JPEG,
  destinationType: Camera.DestinationType.FILE_URI
}
navigator.camera.getPicture(onSuccess, onFail, options);

なお、上記のプログラムでは、フォトアルバムから写真を選択するようにしています。

気を付けたい点としては、カメラプラグインのオプションで correctOrientationtrue に設定し、画像を正しい向きに直す処理を追加すると、取得できる Exif 情報が減りました。
私は写真から緯度経度を取得したかったので、上記の理由から correctOrientation を追加するのをやめました…。
なお、写真の向きは取得できたので、そちらで正しい向きに直す処理を追加することはできます。

 

以上、写真から Exif 情報を取得するためのプラグイン「cordova-exif」についてのご紹介でした。
インストール時に若干手間取りましたが、便利なプラグインですので是非ご活用ください。

  • この記事いいね! (0)
asaba 著者:asaba

【react-material-Ui】ListとDialogを組み合わせて動的に削除するコンポーネント

window.confirmは簡単な実装でOK/キャンセルの処理を作ることが出来ます。しかしその汎用性に反し対応していないosが多く

ちゃんと発動するか不明な点が多いことと、ESLintで引っかかることもありストア向けのアプリには不向きです。

最初見つけた時はこれめっちゃ便利じゃん他のアプリにも入れたろと考えましたが

reactではandroidやiosでwebviewを介してみるので爆弾扱いされているみたいですね。

てな訳で素直にdialogを使いましょうということにしました。

material-uiではスタイリッシュなコンポーネントがずらりと揃っていますが今開発しているアプリでも

使われているmaterial-uiのdialogコンポーネントを使うことにしました。(こっちのほうがずっとかっこいいです)

 

</pre>
choice(i){
this.setState({index: i});
this.setState({deleteMessage : "削除しますか?"})
this.setState({deleteOpen: true});
}
delete() {
const i = this.state.index;
this.state.count.splice(i,1);
this.setState({count: this.state.count});
this.DialogClose();
}
deleteDialogClose() {
this.setState({deleteOpen: false});
}

render() {
const i = this.state.count;
const reText = i;
const deleteActions = [
<FlatButton
label="削除する"
primary={true}
onTouchTap={this.delete}
/>,
<FlatButton
label="キャンセル"
primary={true}
onTouchTap={this.deleteDialogClose}
/>,
];
return (
<Dialog
actions={deleteActions}
modal={true}
open={this.state.deleteOpen} >
{this.state.deleteMessage}
</Dialog>
)
}
<pre>

 

render内でダイアログのオプションを設定してreturn内でそのオプションを取り込んで実際にトリガーが発火

した時にダイアログの処理内容を引数に合わせて変えていくイメージで作りました。

最初はどこで発火するんだ?と迷子状態ですが、this.setState({Open: true});でon状態になるとダイアログが

起動することが分かったので一安心。

 

とりあえずthis.setState({Open: true});で発火することを覚えておけば適当な関数にこれを設置して

さきほど切り分けた処理を実際に試すことができるみたいですね、覚えておきます。

ちなみにメッセージはthis.setState({Message : “hoge!!”})で変えられますのでそちらもお見知りおきを・・・。

 

使ってみた感想:良かったです。従来のjsのダイアログより優しい・安心のmaterial-uiブランドなので視覚的に優しいと

優しい尽くしでした。とくに凝ったデザインにしないならば第一におすすめします。

  • この記事いいね! (0)
asaba 著者:asaba

【react】mapで新しく配列を作る際に気を付けること

javascriptではリストとして表示したい時・リスト別に値を持たせたいときにはmapがよく使われますが、mapで

新しく配列を作る際にん?と思ったことがありました。

まず、動的にリストを作りたい場合はコンストラクタ生成時に配列を定義するのが普通ですが

ここで{}を定義するとmap is not definedで跳ね返されます。

 

なぜこうなるかというと、{}はオブジェクトを新しく作る時、連想配列を作る時、スコープに用いるといった

役割があり、通常の新しい配列を作ることに向いたmapにはカッコを変換する機能が備わっておらず

ここで不適合とみなされるためです。

なのでmapで新しくカッコを作りたい時はコンストラクタに[]を定義しておきましょう。


this.state = {

//<strong>{}</strong>ではなく<strong>[]</strong>であること
count : [],
}

render() {

{ hallo.map((hallo, index) => {

//処理

})}

}

 

普通の配列を使いたい時はmap、連想配列でmapを使いたい場合は

const map = new Map([’a’,’January’],[’b’,’February’])と書き方が変わってきます。

 

こちらはあまり実用性がないので使ったことがないですね・・・。

  • この記事いいね! (0)
asaba 著者:asaba

【react】onClick内の関数に引数を付けるのに少しコツがほしかった

タイトルの通りですが、いつも使っているためかonClickに正しく引数を付ける方法を全く知らずにここまで来てしまいました。

今回は普通にこんな感じで

 


<span class="p"><</span><span class="nt">button</span> <span class="na">onClick=</span><span class="si">{</span><span class="k">this</span><span class="p">.buttonClick</span><span class="p">(</span><span class="mi">member.count</span><span class="p">)</span><span class="si">}</span><span class="p">></span><span class="p">

 

この書き方だとonClickの機能を果たさずにrenderした瞬間に処理をして後にクリックしても無反応になってしまいます。

とりあえず公式に沿ってbindをした後に引数をつけてあげると期待した動きをしてくれるようになりました。

こんな感じ↓


onClick={this.buttonClick.bind(this, member.count)}>

 

あんまり変わっていないですね・・・。でもこれさえできれば動的に値を操作できるので応用が利きやすいのも強みですね、

onClickで引数とりたいなと思っている方には一番おすすめの方法です。

 

ちなみに公式ページがこれ(^.^)/~~~

https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers

 

  • この記事いいね! (0)
asaba 著者:asaba

【react】ListItemSecondaryActionが参照できない

material-uiを使ってリストビューみたいなのを作ろうと思ったら読み出し先が違うらしいエラーが出ました。

以下のような英文です。

 

invariant.js:38 Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined

 

多分、material-uiにはアイコンとかを収納している箱みたいのがあって本来その箱には存在しないuiを取ってこようとしている

ので怒っているんだと思います。いやいや公式ですけど!!!(# ゚Д゚)

 

 

例えば、

import { List, ListItem, ListItemSecondaryAction, ListItemText } from “material-ui/List”;
この中のListItemSecondaryActionも確かListItemとかと同じカテゴリで参照先は同じはず・・・。なのに
実装しようとしたら無いとか言われる始末。あかんこれどれ信用していいかわかったもんじゃありません。
バージョンアップとかが必要になったら書き換えとかどちゃくそめんどくさそうなので手を出さずに自前でcssで作った方が
早いかもしれません。(他に方法があるのでしょうがバージョンアップとかして仕様が変わっているのが怖いので手を出しません。)
他にも試してみると、アイコン系は全部このエラーが出てしまいました・・・。解決策はなんとかしてuiの参照先を
見つけるしかないみたいですね。
ちなみに公式で書いてあるimport IconButton from ‘@material-ui/core/IconButton’;みたいな書き方だと100%エラーになります。
インチキ参照もいいかげんにしろといいたいですけど上手くできないのは今の自分の技術不足ということでのんでおきます。
※追記 無事参照出来ました。
import ListItemSecondaryAction from “material-ui/List”;で単独でインポートして解決。
  • この記事いいね! (0)
村上 著者:村上

【JavaScript】Ajaxを使わない非同期通信処理「XMLHttpRequest」の書き方

自分のための備忘録としてまとめ。
Ajax のかわりに XMLHttpRequest を使って非同期通信の処理を行う方法です。
普段、Ajax に頼りきりで、書き方をすっかり忘れていたので、今後のためにまとめておきます。

今回参考にさせていただいた記事はこちらから。

XMLHttpRequestによるPOSTメソッド|JavaScript プログラミング解説
https://so-zou.jp/web-app/tech/programming/javascript/ajax/post.htm

JavaScript によるフォームの送信 – Web 開発を学ぶ|MDN
https://developer.mozilla.org/ja/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript

 

早速ですが、サンプルコードは下記のとおりです。
なお、サンプルは POST の場合の書き方です。

// POSTメソッドで送信するデータ
var data = { param1: 'abc', param2: 100 }; 
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest .addEventListener('load', function(event) {
    // データが正常に送信された場合の処理
});
xmlHttpRequest .addEventListener('error', function(event) {
    // エラーが発生した場合の処理
});
xmlHttpRequest.open('POST', '[送信先URL]');
// サーバに対して解析方法を指定する
xmlHttpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// データをリクエスト ボディに含めて送信する
xmlHttpRequest.send(EncodeHTMLForm(data));

一緒に送信したいデータは、変数 data に代入し、14行目で送付しています。
ただし、送信するデータは HTML フォームの送信に使用される形式に変換する必要がありますので、下記の関数でエンコードする必要があるとのことでした。

function EncodeHTMLForm(data) {
    var params = [];
    for(var name in data) {
        var value = data[ name ];
        var param = encodeURIComponent(name) + '=' + encodeURIComponent(value);
        params.push(param);
    }
    return params.join('&').replace(/%20/g, '+');
}

うっかりこの処理を抜いて実行したところ、当然ながら正しく値が渡せていなかったため、ご注意ください。

送信完了時の処理と、エラーが発生した時の処理は、それぞれ 4行目と 7行目の関数内で定義します。
ステータスコードなどで判断する方法もありましたが、こちらの方がコードがすっきりとしていて好みなので、こちらの書き方を採用しました。

 

以上、Ajax を使わずに非同期通信処理を行う方法でした。
ご参考になれば幸いです。

  • この記事いいね! (0)
asaba 著者:asaba

【react】react-tagcloudの使用感について

snsでバズっているワードをタグクラウドで出したくてjqueryとかで色々探していたのですがjqueryプラグイン

同士の競り合いを起こしたり古いバージョンのjqueryが必要だったりとやたらと面倒だったのでnpmの

react-tagcloudというプラグインの力を少しお借りしました。

名前の通りreact向けにタグクラウドを生成してくれるnpmのパッケージで、規約(決まったコード)が少ない

ので比較的自由度が高く少しのアレンジでタグクラウドをカスタマイズすることができます。

 

</pre>
--------render------

const values = ["like vegetable", "like meet", "like fish"];
const data = [];
for(i=0; i < values.length; i++){
data[i] = { value: values[i], count: 5 };
};

--------return-------

<TagCloud minSize={5}
maxSize={35}
tags={data}
onClick={tag => this.tagClick(`'${tag.value}'`)} />
<pre>

 

これは配列に格納した値を順にTagCloudのプロパティに設定するだけのコードです。

(自作ですがconosle.logで最終的に値を取れたので載せておきます)

render内でdata[i] = { value: values[i], count: 5 };と二つのオプションがありますが、valueは

タグにしたい文字列、countはタグの大きさを指定しています。20でもかなり大きいので10前後にして

おいたほうが見栄えがいいかもです。

 

次にTagCloud内の説明になりますが、tags={data}で上でぶん回した配列の値を指定しています。

onClickの書き方がちょっと特殊で処理内に`’${tag.value}’`と書いてありますが

これは格納してあったタグの値つまり”like vegetable”, “like meet”, “like fish”を指定しており、処理も

値別に分けることができます。

 

簡単な説明ですが以上になります。

このコード量でタグクラウドの基本的な動きを抑えられるので、ブラウザで化けなければ採用できるかもです。

タグクラウドのプラグインの中でも一番わかりやすくて余計なことが書いていないので、同じような

機能を探している人におすすめのプラグインです。

 

  • この記事いいね! (0)
著者:杉浦

【Vue】改行とv-htmlとXSS対策

 Vue.js上で文字列を展開したい時があります。例えばそれは誰かが投稿したコメントをコンポーネント上に表示する時です。こういった時コメントの改行が反映されていない場合、見栄えが悪くなります。改行を行う必要があります。
 HTML上の改行と言えばbrタグです。PHPにはnl2brという改行コードを改行タグに変換する組み込み関数があるぐらいです。
PHP: nl2br – Manual
 改行の実現でありがちで危険なアンチパターンはこのnl2br関数を用いたコメントをそのまま表示しようと考えるものです。Vue.jsにはv-htmlというディレクティブがあり、これを用いると普段かかっている安全装置のHTMLエスケープを外し、HTMLとしてパース、実行します。brタグとv-htmlを用いることで改行コードを改行タグに変換して表示できます。
 v-htmlはXSSをまあまあ容易に招く危険性を持ちます。まあまあ危険というのは単純な

<script>alert('XSS')</script>

ぐらいならVueの仕組み上実行されず済むからです。とはいえ

<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>

の様な多少の変化球(scriptタグをbase64形式でエンコード、埋め込んだコード中でデコードして実行)であっさり破られるのでやはり危険です。

XSS 脆弱性を容易に引き起こすので、ウェブサイトで動的に任意のHTMLを描画することは、非常に危険です。信頼できるコンテンツにだけ HTML 展開を利用してください。ユーザーから提供されたコンテンツに対しては決して使用してはいけません。

テンプレート構文 — Vue.js

 これの対策は実現したい機能に関しての実装を生のHTMLに頼るのでなく個々の別手法を用いるのが一番でしょう。
 例えば改行に関してはCSSのwhite-space実現できます。white-spaceは要素内のホワイトスペースをどう扱うか決定するスタイルであり、ホワイトスペースの一種(少なくとも正規表現の\sグループでまとめられる)である改行文字の制御もこれでできます
white-space – CSS: カスケーディングスタイルシート | MDN
 上記リンクから引用した次の表の’改行を残す’スタイルを用いれば
と生のHTML実行を用いるまでもありません。

  改行 空白とタブ文字 テキストの折り返し 行末の空白
normal まとめる まとめる 折り返す 除去
nowrap まとめる まとめる 折り返さない 除去
pre 残す 残す 折り返さない 残す
pre-wrap 残す 残す 折り返す ぶら下げ
pre-line 残す まとめる 折り返す 除去
break-spaces 残す まとめる 折り返す 折り返す
  • この記事いいね! (0)