20210430のJavaScriptに関する記事は29件です。

WEBスクレイピングする~テレ〇限定・今日のドラマ再放送は何やるの?LineBotを作ろうと思う

前回の続きです いつも大変お世話になっているテレ朝さんの番組情報を取得したかったのですが、程よいWEBAPIは見当たらなかったのでスクレイピングで取得してみたいと思います。 ターゲットとなる情報の在処を探る テレ朝の公式ホームページにずばり「番組表」というページがありました。 ここから取得してみようと思います。 よく見ると、当日のヘッダー(ここでは4月29日(木))の色が変わっているので当日を特定しやすそうな感じです。 Chromeのデベロッパーツールを使ってソースを確認します ページのソースが表示されるので、マウス操作でソースを展開していきます。 タグを選択すると、「そのタグはページのこの部分ですよ」とハイライトを当ててくれるので、あちこち触ってみて目当ての情報を探し出します。ぐりぐり探していくと、当日の番組列に当たりました。「今日」は「today」で指定されていました。これはいけそうです。 14:47科捜研の女を発見しました! 科捜研大好き。何度見ても楽しめる。いつもありがとう! 開始時刻はclass=min 番組タイトルはbangumiDetailOpenで設定されているようです。 cheerio-httpcliを使ってスクレイピングする 前回発見したNode.js用の素敵なスクレイピングモジュール(cheerio-httpcli)をつかって再放送ゴールデンタイムの情報を取得します。 こんなコードにしてみました。 scraping.js //スーパー再放送タイムの設定 const ssstarttime = '13:46'; const ssendtime = '16:30'; let client = require('cheerio-httpcli'); client.fetch('https://www.tv-asahi.co.jp/bangumi/', {}, function (err, $, res) { //当日の番組一覧を取得して配列に入れる let tvinfo = []; let r = 0; //bangumiDetailOpenを指定して番組タイトルを取得する $('.new_table .today .new_day .prog_name .bangumiDetailOpen').each(function () { tvinfo[r] = []; tvinfo[r][0] = $(this).text(); tvinfo[r][1] = ""; r = r + 1; }); //開始時間を配列に格納する let c = 0; //minを指定して放送開始時刻を取得する $('.new_table .today .new_day .min').each(function () { let title = $(this).text(); tvinfo[c][1] = title.trim(); //空白が入っているので削除する c = c + 1; }); //スーパー再放送タイムか確認 let conststr = '2000/01/01 '; let starttime = new Date(conststr + ssstarttime); let endtime = new Date(conststr + ssendtime); let tempdatestr; let targettime; for (let t = 0; t < tvinfo.length; t++) { //判定 tempdatestr = conststr + tvinfo[t][1]; //番組表から取得した各番組の開始時刻で日付の文字列を生成 targettime = Date.parse(tempdatestr); //スーパー再放送タイムであるか判定 if (targettime > starttime && targettime < endtime) { console.log(tvinfo[t][0]); } } }); 今日は、科捜研、科捜研、相棒だったようです。いいね! PS C:\project\homework02> node scraping.js 科捜研の女13 #1 科捜研の女13 #2 相棒15 #11 個人的スーパー再放送タイムが変わってしまったり、そもそもページ構成が変わってしまったら、使いものにならなくなるのはWEBスクレイピングを使った仕掛けの仕方ないところ、、、でしょうか。。 とりあえず「テレ〇限定・今日の。。。。。LineBot」の一部ができました。 今日はここまで おつかれさまでしたー
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初心者】コピペで簡単!GASを使った体温記録管理ツール

諸事情により私のいる部署が本社から置いだされました。 まあそれは良いとして、顔認証つき体温計測記録がつかえなくなり、 出社する度に共有フォルダのEXCELファイルに記録しなくてはならなくなりました。 これがめんどくさい上に、よく忘れる。Bossも全然記入してないし… ということで、GASの勉強がてらサクッと作りました。 Index 設計 GoogleSheetの準備 GoogleFormの準備 Google App Scriptの作成 デプロイ おまけ Slackへの通知 設計 ①GoogleFormで名前を選択リストから選択、体温を入力し送信 ②GoogleSpreadSheetに記録される ③おまけとして体温を37度以上でFormを送信するとSlackへ通知 という上記3点を満たすシンプルなものを作成します。 では早速行ってみましょう。 GoogleSheetの準備 まずはGoogleSpreadSheetを作成します。 A列にIDとB列名前、一行目に日付を「MM/dd」の形式で入力します。 一枚目のシートができたら、Sheetをコピーして翌月、翌々月...と必要な分だけ作成します。 作成が完了したら、SpreadSheetIDを取得し、メモしておきましょう。 IDは、スプレッドシートのURLから確認できます。 例えば、URLが以下のようであれば、 URL(ダミー):https://docs.google.com/spreadsheets/d/1Hqp2IvxXrCGee_w9Gvbe4nXXXXXjrIMxXXXXXXX/edit#gid=597941997 d/と/editの間の「1Hqp2IvxXrCGee_w9Gvbe4nXXXXXjrIMxXXXXXXX」がスプレッドシートIDになります。 引用:【gas】googleスプレッドシートidの見方) GoogleFormの準備 続いて、GoogleFormを作成します。 今回は、SpreadSheetに記入した名前の選択リストと体温を記入するテキストボックスのみ作成します。 右側のプラスボタンから質問を追加し、それぞれ設定します。 非常に簡単に作成できて便利ですよね。 Google App Scriptの作成 さて準備が整いましたので、ここでついにGASを記述していきます。 先ほど作成したFormの右上点3つからスクリプトエディタを開きます。 Formからスクリプトエディタを開くことにより、そのFormに紐づいたスクリプトが書けます。 まずは、Formの回答を取得し、その値を次に呼び出す関数に渡してあげるコードを書いていきます。 function getFormValues(e){ FormApp.getActiveForm(); var itemResponses = e.response.getItemResponses(); var user = itemResponses[0].getResponse(); var temp = itemResponses[1].getResponse(); recordTemperature(user,temp); } 関数getFormValuesの引数である(e)にformの回答が格納されています。 Fromの質問に対し上から順に、0,1,2,3...と対応付けされています。 今回は2つ質問を用意したので、0と1を指定しています。 続いて、先ほどのrecordTemperature(user,temp)の中身を書いていきます。 その前に日付を先に用意しておきましょう。 const date = new Date(); //今月(4月なら"04") const formatMonth = Utilities.formatDate(date, "JST","MM"); //今日(4月30日なら04/30) const formatToday = Utilities.formatDate(date, "JST","MM/dd"); ここで先ほど控えていた、GoogleSheetのIDが必要になります。 コード内3行目SpreadsheetApp.openById()にて使用します。 function recordTemperature(userName,temperature){ //対象のSpreadSheet及びシートを選択 const spreadSheet = SpreadsheetApp.openById("1Hqp2IvxXrCGee_w9Gvbe4nXXXXXjrIMxXXXXXXX").getSheetByName(formatMonth); //最終列を取得 const lastRow = spreadSheet.getLastRow(); //最終行を取得 const lastCol = spreadSheet.getLastColumn(); //名前を上から順に一致するとこまでループ for(var i=2; i <= lastRow; i++){ let nameValue = spreadSheet.getRange(i,2).getValue(); if(userName == nameValue){ //名前が一致したら、今度は日付をループ for (var l = 3; l <= lastCol; l++){ let dateValue = spreadSheet.getRange(1,l).getValue(); let formatDateValue = Utilities.formatDate(dateValue,"JST","MM/dd"); if(formatToday == formatDateValue){ //日付も一致したら、その行と列の交わるセルに値を入力する spreadSheet.getRange(i,l).setValue(temperature); } } } } } デプロイ ここまで終えたら、一旦デプロイしましょう。 ①右上のデプロイボタンをクリック ②「新しいデプロイ」を選択 ③ひとまず権限は「自分のみ」のままデプロイします。 次にトリガーを選択します。 ①左側のナビゲーションからトリガー(目ざまし時計アイコン)を開きます。 ②右下の「トリガーを追加をクリック」 ③実行する関数は 「getFormValues」 実行するデプロイは「version1」 イベントのソース は「フォームから」 イベントの種類を「起動時」 ④保存をクリック 次にGoogleFormに戻り、実際に動かしてみます。 ①右上の送信をクリック ②送信方法タブの真ん中を選択 ③リンクをコピーしてアクセス ④フォームに入力して送信をクリック 最後に、スクリプトエディタに戻り、実行状況を確認しましょう。 ①左側のナビゲーションから「実行数」を開きます。 ②ステータスが「完了」になっていればOKです。 ③シートも確認しましょう。フォームから送信した内容と相違なければOKです。 おまけ Slackへの通知 ここからは少しレベルを上げて、slackへAPIを使用して、メッセージを送信します。 slackのWebAPIの使用方法については、下記の記事をご参照ください。 https://qiita.com/kshibata101/items/0e13c420080a993c5d16 今回は、体温が37度以上あった場合、Slackの任意のチャンネルへメッセージを投げる処理を追加します。 function getFormValues(e){ //前述の関数の中に下記を追記します。 //Formの名前と体温を使って文章を作成し、それを引数に関数を呼びます。 if(temp >= 37.0){ const text = "Hi, " + user + " have a fever of " + temp + " degrees!!"; alertSlack(text); }; function alertSlack(text){ var webHookUrl = "Slackの設定で取得したURL"; var jsonData = { "channel": "#チャンネル名", // 通知したいチャンネル "text" : text //通知内容 }; var payload = JSON.stringify(jsonData); var options = { "method" : "post", "contentType" : "application/json", "payload" : payload, }; // リクエスト UrlFetchApp.fetch(webHookUrl, options); }; 今回書かせていただいた内容は、人と日付の合致するセルに値をセットするという汎用性の高いであろうものです。 目的である体温管理記録表以外の用途へも応用していきたいと思います。 またAPIもこれだけ簡単に使えるのであれば、これをベースにいろいろ試していければと思います。 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

html+javascriptだけで実装したシンプルなQRコードリーダー

目的 html+javascriptだけで実装されたシンプルなQRコードリーダーのサンプル(が欲しかった) 機能 スマホのカメラやWebカメラでQRコードを値を取得する。 QRコードを認識したら、赤枠を表示する。 処理概要 <video>タグでカメラ映像を表示 タイマーでカメラ映像をイメージ化、QR認識ライブラリjsQRに引き渡す 認識すると、コードの値とQRコードがある領域の座標を取得します。 2.に戻り認識を繰り返します。 利用モジュール jsQR 使い方 下記ファイルを同一フォルダに配置して、ブラウザ(スマホの方が使いやすい)から開きます(要Webカメラ)。 index.html jsQR.js https://github.com/murasuke/js-QR-reader ※スマホの場合, httpsで開く必要があります github pagesから試せます。 index.html ローカルで試す場合 httpsが必要なため、オレオレ証明書を作成してから、http-serverを起動してください。 openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem Generating a RSA private key .................................+++++ .......................+++++ ~~略~~ npx http-server -S -C cert.pem Starting up http-server, serving ./public through https Available on: https://172.23.0.1:8080 https://127.0.0.1:8080 ソース解説 全体のソースは最後に載せてあります。 カメラ動画を表示しながら、 タイマーで画像に変換 jsQRで認識 <head>部分 QR読み取りライブラリをロードする <script src="./jsQR.js"></script> <body>部分 <div id="result" ~> QR読み取り結果を表示 <video>~</video> カメラ映像出力部分。z-indexにマイナスを指定して、オーバーレイの奥に表示します。 <div id="overlay" >~</div> QRコードを赤枠で囲うためのオーバーレイ。position:relative;で重ねています。 <div id="result" style="min-height: 20px;"></div> <div> <div style="position:relative;"> <video style="position: absolute; z-index: -100;"></video> <div id="overlay" style="position: absolute; border: 1px solid #F00;"></div> </div> </div> <script>部分 jsQRで認識したQRコードの箇所を赤枠で囲むための関数 id="overlay"をQRコードの位置へ移動します。 const drawRect = (topLeft, bottomRight) => { const { x: x1, y: y1 } = topLeft; const { x: x2, y: y2 }= bottomRight; const overlay = document.querySelector('#overlay'); overlay.style.left = `${x1}px`; overlay.style.top =`${y1}px`; overlay.style.width = `${x2 - x1}px`; overlay.style.height =`${y2 - y1}px`; }; カメラの準備(videoタグに表示) const stream = await navigator.mediaDevices.getUserMedia(constraints); const video = document.querySelector('video'); video.srcObject = stream; video.play(); canvas作成 描画負荷を軽減するためOffscreenCanvasを作成します。 QRコード認識で必要なイメージを、videoから作成するために利用します。 const { width, height } = constraints.video; const canvas = new OffscreenCanvas(width, height); const context = canvas.getContext('2d'); QRコード認識 videoからイメージデータを作成し、QR認識処理に引き渡します。 認識した場合は、コードの表示と赤枠の表示を行います。 タイマーで繰り返します。 const timer = setInterval(() => { context.drawImage(video, 0, 0, width, height); const imageData = context.getImageData(0, 0, width, height); const code = jsQR(imageData.data, imageData.width, imageData.height); if (code) { document.querySelector('#result').textContent = code.data; drawRect(code.location.topLeftCorner, code.location.bottomRightCorner); } else { document.querySelector('#result').textContent = ''; } }, 300); 全体 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>JS QR Code Reader</title> <meta name="description" content="QR Code Reader" /> <script src="./jsQR.js"></script> </head> <body> <div id="result" style="min-height: 20px;"></div> <div> <div style="position:relative;"> <video style="position: absolute; z-index: -100;"></video> <div id="overlay" style="position: absolute; border: 1px solid #F00;"></div> </div> </div> <script> const constraints = { audio: false, video: { facingMode: 'environment', width: 500, height: 500, }}; const drawRect = (topLeft, bottomRight) => { const { x: x1, y: y1 } = topLeft; const { x: x2, y: y2 }= bottomRight; const overlay = document.querySelector('#overlay'); overlay.style.left = `${x1}px`; overlay.style.top =`${y1}px`; overlay.style.width = `${x2 - x1}px`; overlay.style.height =`${y2 - y1}px`; }; (async() => { try { const stream = await navigator.mediaDevices.getUserMedia(constraints); const video = document.querySelector('video'); video.srcObject = stream; video.play(); const { width, height } = constraints.video; const canvas = new OffscreenCanvas(width, height); const context = canvas.getContext('2d'); const timer = setInterval(() => { context.drawImage(video, 0, 0, width, height); const imageData = context.getImageData(0, 0, width, height); const code = jsQR(imageData.data, imageData.width, imageData.height); if (code) { document.querySelector('#result').textContent = code.data; drawRect(code.location.topLeftCorner, code.location.bottomRightCorner); } else { document.querySelector('#result').textContent = ''; } }, 300); } catch(error) { console.log('load error', error); } })(); </script> </body> </html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

html+javascriptだけで実装されたシンプルなQRコードリーダー

目的 html+javascriptだけで実装されたシンプルなQRコードリーダーのサンプル(が欲しかった) 機能 スマホのカメラやWebカメラでQRコードを値を取得する。 QRコードを認識したら、赤枠を表示する。 処理概要 <video>タグでカメラ映像を表示 タイマーでカメラ映像をイメージ化、QR認識ライブラリjsQRに引き渡す 認識すると、コードの値とQRコードがある領域の座標を取得します。 2.に戻り認識を繰り返します。 利用モジュール jsQR 使い方 下記ファイルを同一フォルダに配置して、ブラウザ(スマホの方が使いやすい)から開きます(要Webカメラ)。 index.html jsQR.js https://github.com/murasuke/js-QR-reader ※スマホの場合, httpsで開く必要があります github pagesから試せます。 index.html ローカルで試す場合 httpsが必要なため、オレオレ証明書を作成してから、http-serverを起動してください。 openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem Generating a RSA private key .................................+++++ .......................+++++ ~~略~~ npx http-server -S -C cert.pem Starting up http-server, serving ./public through https Available on: https://172.23.0.1:8080 https://127.0.0.1:8080 ソース解説 全体のソースは最後に載せてあります。 カメラ動画を表示しながら、 タイマーで画像に変換 jsQRで認識 <head>部分 QR読み取りライブラリをロードする <script src="./jsQR.js"></script> <body>部分 <div id="result" ~> QR読み取り結果を表示 <video>~</video> カメラ映像出力部分。z-indexにマイナスを指定して、オーバーレイの奥に表示します。 <div id="overlay" >~</div> QRコードを赤枠で囲うためのオーバーレイ。position:relative;で重ねています。 <div id="result" style="min-height: 20px;"></div> <div> <div style="position:relative;"> <video style="position: absolute; z-index: -100;"></video> <div id="overlay" style="position: absolute; border: 1px solid #F00;"></div> </div> </div> <script>部分 jsQRで認識したQRコードの箇所を赤枠で囲むための関数 id="overlay"をQRコードの位置へ移動します。 const drawRect = (topLeft, bottomRight) => { const { x: x1, y: y1 } = topLeft; const { x: x2, y: y2 }= bottomRight; const overlay = document.querySelector('#overlay'); overlay.style.left = `${x1}px`; overlay.style.top =`${y1}px`; overlay.style.width = `${x2 - x1}px`; overlay.style.height =`${y2 - y1}px`; }; カメラの準備(videoタグに表示) const stream = await navigator.mediaDevices.getUserMedia(constraints); const video = document.querySelector('video'); video.srcObject = stream; video.play(); canvas作成 描画負荷を軽減するためOffscreenCanvasを作成します。 QRコード認識で必要なイメージを、videoから作成するために利用します。 const { width, height } = constraints.video; const canvas = new OffscreenCanvas(width, height); const context = canvas.getContext('2d'); QRコード認識 videoからイメージデータを作成し、QR認識処理に引き渡します。 認識した場合は、コードの表示と赤枠の表示を行います。 タイマーで繰り返します。 const timer = setInterval(() => { context.drawImage(video, 0, 0, width, height); const imageData = context.getImageData(0, 0, width, height); const code = jsQR(imageData.data, imageData.width, imageData.height); if (code) { document.querySelector('#result').textContent = code.data; drawRect(code.location.topLeftCorner, code.location.bottomRightCorner); } else { document.querySelector('#result').textContent = ''; } }, 300); 全体 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>JS QR Code Reader</title> <meta name="description" content="QR Code Reader" /> <script src="./jsQR.js"></script> </head> <body> <div id="result" style="min-height: 20px;"></div> <div> <div style="position:relative;"> <video style="position: absolute; z-index: -100;"></video> <div id="overlay" style="position: absolute; border: 1px solid #F00;"></div> </div> </div> <script> const constraints = { audio: false, video: { facingMode: 'environment', width: 500, height: 500, }}; const drawRect = (topLeft, bottomRight) => { const { x: x1, y: y1 } = topLeft; const { x: x2, y: y2 }= bottomRight; const overlay = document.querySelector('#overlay'); overlay.style.left = `${x1}px`; overlay.style.top =`${y1}px`; overlay.style.width = `${x2 - x1}px`; overlay.style.height =`${y2 - y1}px`; }; (async() => { try { const stream = await navigator.mediaDevices.getUserMedia(constraints); const video = document.querySelector('video'); video.srcObject = stream; video.play(); const { width, height } = constraints.video; const canvas = new OffscreenCanvas(width, height); const context = canvas.getContext('2d'); const timer = setInterval(() => { context.drawImage(video, 0, 0, width, height); const imageData = context.getImageData(0, 0, width, height); const code = jsQR(imageData.data, imageData.width, imageData.height); if (code) { document.querySelector('#result').textContent = code.data; drawRect(code.location.topLeftCorner, code.location.bottomRightCorner); } else { document.querySelector('#result').textContent = ''; } }, 300); } catch(error) { console.log('load error', error); } })(); </script> </body> </html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TypeScript まとめ3(モジュール化)

TypeScriptまとめ集 型について ユーティリティ型 モジュール化 インストール〜コンパイル方法 目次 クラス化 モジュール化 デコレーター 1.クラス化 ECMAScript2015以降より他言語同様クラス化が可能に。 オブジェクト思考言語によくある以下の例を設定できる。 アクセス修飾子 getter, setter コンストラクター 静的メンバー 継承 オーバーライド 抽象メソッド インターフェイス など。 アクセス修飾子 アクセス修飾子は以下の3種類 public...自由にアクセス可能、デフォルトのアクセス修飾子 protected...同じクラス、または派生クラスのメンバーからアクセス可能 private...同じクラスからのみアクセス可能 typescript(アクセス修飾子) class Sample{ public hello():string{ return `こんにちは、Qiitaさん!`; } } let s = new Sample(); s.hello(); //こんにちは、Qiitaさん! コンストラクター インスタンス化をしたと同時に実行される。 typescript(コンストラクター) class Sample{ private name:string; constructor(name:string){ this.name = name; } //コンストラクターは以下のように書くこともできる //コンストラクターの引数にアクセス修飾子を付与する constructor(private name:string){} public hello():string{ return `こんにちは、${this.name}さん!`; } } let s = new Sample('Taro'); s.hello(); //こんにちは、Taroさん! getter, setter getブロックでgetterを実装できる setブロックでsetterを実装できる typescript(getter,setter) class Sample{ private _name!:string; //getter get name():string{ return this._name; } //setter set name(value:string){ this._name = value; } } let s = new Sample(); s.name = 'Taro'; console.log(s.name); //結果:Taro 静的メンバー インスタンスを生成しなくてもメソッドを実行できる。 typescript(静的メンバー) class Sample{ //静的プロパティ public static name:string = 'Taro'; //静的メソッド public static hello(name:string):string{ return `こんにちは、${this.name}さん!`; } } let name:string = Sample.name; Sample.hello(name); 継承 元になるクラスの機能の引き継ぎ、新しい機能の追加、元の機能の一部を修正などができる。 typescript(継承) //継承元 class Sample1{ protected name:string; constructor(name:string){ this.name = name; } hello():string{ return `こんにちは、${this.name}さん!`; } } //継承先 class Sample2 extends Sample1{ //派生クラス独自のメソッドを定義 bye():string{ return `さようなら、${this.name}さん。`; } } let s = new Sample2('Taro'); s.hello(); //こんにちは、Taroさん! s.bye(); //さようなら、Taroさん。 オーバーライド 継承時、基底クラスで定義済のメソッド/コンストラクターを派生クラスで上書きできる。 typescript(オーバーライド) class Sample2 extends Sample1{ protected age:number; //コンストラクターをオーバーライド constructor(name:string, age:number){ super(name); this.age = age; } //helloメソッドをオーバーライド hello():string { return super.hello() + `年齢は${age}ですね? `; } } 抽象クラス、抽象メソッド 派生クラスで機能を上書きすること前提にする。 typescript(抽象クラス、抽象メソッド) //抽象クラスを宣言 abstract class Sample1 { abstract hello():string; } //継承先 class Sample2 extends Sample1{ hello():string{ return `こんにちは、${this.name}さん!`; } } インターフェイス すべてのメソッドが抽象メソッドであり、複数のインターフェイスを同時に継承することが可能。 typescript(インターフェイス) interface Sample1{ name:string; hello():string; } interface Sample2{ bye():string } class Sample3 implements Sample1,Sample2{ name:string; constructor(name:string){ this.name = name; } hello():string{ return `こんにちは、${this.name}さん!`; } bye():string{ return `さようなら、${this.name}さん。`; } } インターフェイスを継承して、新しいインターフェイスを宣言することもできる typescript(interfaceの継承) interface Interface1 extends Interface2{ ...} 2.モジュール化 モジュールとは? 機能ごとにファイルを分割してまとまりを持った処理を作る。 1モジュールに対して1ファイルが基本。 代表的なモジュールシステムはCommonJSとES Moduleの2種類の方式がある。 CommonJSはサーバー用、ES Moduleはブラウザ用で分けると良い。 ES ModuleはECMA Script6で追加されたため、古いブラウザだと使えない可能性があるため注意。 モジュールの定義 CommonJSでは、module.exportsで定義する。 ES Moduleでは、exportをつけて定義できる。 CommonJSの場合 typescript(CommonJSでのモジュール定義) //関数のモジュール化 module.exports= function showMessage():void { console.log(`ようこそ、Qiita!`); } //クラスのモジュール化 class Util { static getVersion():string{ return '1.0.0'; } } module.exports = Util; ES Moduleの場合 typescript(ESModuleでのモジュール定義) //これはexportがついていないため、アクセスできない const TITLE:string = 'Qiita'; //関数のモジュール化 export function showMessage():void{ console.log(`ようこそ、${TITLE}!`); } //クラスのモジュール化 export class Util { static getVersion():string{ return '1.0.0'; } } //------------------------------------------ //別の書き方も可能 class Util { ... } //そのままエクスポート export { Util }; //リネームしてエクスポート export { Util as AppInfo }; モジュールのインポート 別ファイルで定義したモジュールを使用することができる。(インポート) CommonJSでは、requireをつけて定義する。 ES Moduleでは、importをつけて定義できる。 CommonJSの場合 typescript(CommonJSでのインポート) //インポートするモジュールを選択する let a = require('Util'); let b = require('showMessage'); //インポートした関数を使用する a.showMessage(); console.log(b.Util.getVersion()); ES Moduleの場合 typescript(ESModuleでのインポート) //インポートするモジュールを選択する //from ~ は相対パスから拡張子を取り除いた形式で表す import { showMessage, Util } from './App'; //インポートした関数を使用する showMessage(); console.log(Util.getVersion()); モジュール配下のメンバーに別名を付与したい場合 typescript(モジュールのインポート(別名)) //別名を定義 import { showMessage as myMessage, Util as MyUtil } from './App'; //インポートした関数を使用する myMessage(); console.log(MyUtil.getVersion()); モジュール配下のメンバーを全てインポートしたい時 typescript(モジュールのインポート(全て)) //「*」で全てインポートできる //as区で別名を定義すること import * as aaa from './App'; //インポートした関数を使用する aaa.showMessage(); console.log(aaa.Util.getVersion()); 既定のエクスポートをインポート モジュール配下の一つのメンバーに対してdefaultキーワードを付与することで、インポート時に関数/クラスの名前を指定する必要をなくすことができる。 typescript(既定のエクスポートをインポート) export default class { static getVersion():string{ return '1.0.0'; } } //import側 import app from './App'; console.log(app.getVersion()); 任意のタイミングでモジュールをインポートする(遅延インポート、動的インポート) 今までの静的インポートと言う。 typescript(遅延インポート) //Promiseオブジェクトを生成 import('./App') .then(app => { app.showMessage(); }); //async関数 async function main(){ let app = await import('./App'); app.showMessage(); } 再エクスポート typescript(再エクスポート) //Hoge/Fooモジュール指定されたメンバーを再エクスポート export { HogeUtil } from './Hoge'; export { FooUtil } from './Foo'; //Barモジュールすべてのメンバーを再エクスポート export * from './Bar'; 名前空間 モジュールのさらに上の階層を定義して、インポート・エクスポートするモジュールをまとめる。 古い言い方だと、内部モジュールという。(外部モジュールは普通のやつ) typescript(名前空間) //namespaceを宣言する namespace MainApp{ export class Hoge { ... } export function too() { ... } } //名前空間配下のクラス・関数を呼び出し let mah = new MainApp.Hoge(); MainApp.foo(); 名前空間自体に階層儲けることも可能 typescript(階層付き名前空間) namespace Wings.MainApp{ export class Hoge{} export function foo() {} } let wmah = new Wings.MainApp.Hoge(); Wings.MainApp.foo(); //以下のような書き方も可能 namespace Wings{ export namespace MainApp{ export class Hoge{} export function foo(){} } } 3.デコレーター デコレーターとは クラスやプロパティ、メソッド、引数などに対して付与できる一種の修飾子。 例:Angularの場合 デコレーターの例 //以下の書き方で、<my-app>要素がAppComponentクラスで処理される、という意味になる @Component({ selector:'my-app', templateUrl:'./app.html', styleUrls:['./app.css] }) export class AppComponent {...} デコレーターの一般的な記法 @name(args, ...) ・name: デコレーター名 ・args: 任意の引数 複数のデコレーターを列挙することも可能 この場合myMethod2を@deco1デコレーター、@deco2デコレーターで就職していることとなる @deco1 @deco2 myMethod(){ ... } デコレーターを定義してみる 自分でデコレーターを定義してみることも可能。 下記は一例。 デコレーターの定義 //logデコレーターを宣言 function log(target: any, key: string, desc: PropertyDescriptor){ //オリジナルのメソッドを退避 let origin = desc.value; //メソッドの書き換え desc.value = function(){ //元メソッドの実行前に行う処理 console.log(`${key} start...`); let start = Date.now(); //元メソッドを実行 let result = origin.apply(this, arguments); //元メソッドの実行後に行う処理 let end = Date.now(); console.log(`${key} end...`); console.log(`Process Time ${end - start}ms`); //元のメソッドの戻り値を返す return result; } } デコレーターの利用 上記で定義した@logデコレーターを利用する場合... class MyClass{ @log test():string{ return 'TEST'; } } let c = new MyClass(); c.test(); ちなみに、デコレーターは引数付きでも定義が可能 引数付きデコレーターの利用 //定義 function log(tag: string) { ... } //利用 @log('TEST') test():string { ... }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Javscript】async/awaitを試してみたーasyncについて(No.1)

初めに 非同期処理のpromiseを学習したら、asyncとawaitというものが出てきたのでそれについて学習した内容を書いてみました。 ※内容に間違いなどがある場合はご指摘をよろしくお願いします。 前回の記事:https://qiita.com/redrabbit1104/items/02bc16cf5abd4ed10ec1 https://qiita.com/redrabbit1104/items/b8b61a72f849fa3e8881 asyncはpromiseを返す async functionは戻り値としてpromiseを返す非同期関数です。普通の関数と何が違うのかasync functionとfunctionをそれぞれconsole.logで表示してみました。 //asyncの場合 async function testAsync() { } console.log(testAsync()); //普通の関数 function test() { } console.log(test()); 結果は以下の通りです。 関数の中身が何もないので同じく「undefined」という戻り値が返ってきましたが、asyncの場合「Promise」が返ってきました。 asyncの戻り値promiseはresolveかrejectどちらか asyncの戻り値はpromiseということは分かりましたが、正常に処理ができた場合とそうでない場合にちゃんとresolve(処理成功)とreject(処理失敗)が戻ってくるのでしょうか。気になったので試してみました。 ❶async関数の処理がresolve(成功)した場合 文字列helloを戻り値にするtestAsync関数を定義して、console.logで表示してみました。 async function testAsync() { return 'hello'; } console.log(testAsync()); 戻り値"hello"とPromiseの状態が「fulfilled」と表示されました。 ❷async関数の処理がreject(失敗)した場合 処理が失敗するケースを作るために、returnの値をhelloという定義していない変数にしてみました。 async function testAsync() { return hello; } console.log(testAsync()); 処理が失敗しrejectedと出ました。予想通りです。 このようにasyncはpromiseを返し、resolve(成功)かreject(失敗)のどちらかのstateを返すことが分かりました。 promiseの代わりにasyncが使われる理由 ①asyncの中でしか呼び出すことができないawait構文を使うことで、promiseのthenで処理を繋げるより簡潔に書ける。 ②awaitで指定した関数は実行される時間を決めて呼び出すことができる。 終わりに 今回はasyncについて学習して内容を纏めてみました。次回はawaitを使ったasync関数をいろいろ試してみたいと思います。 参考サイト https://qiita.com/soarflat/items/1a9613e023200bbebcb3 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function https://ja.javascript.info/async-await
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Javascript】filterメソッド 条件に一致した要素を取り出す

Javascriptについてプラグラミングん勉強を始めた初めの頃に勉強をしたが、全くと言っていいほどなにも覚えていないため復習のためにQiitaにまとめ振り返っていこうと思う。 filterメソッド filterメソッドとは記述した条件に一致した要素のみ抽出してあらたな配列を作成するメソッド。 // charactersという配列をつくる。 const characters = [ {id: 1, name:"田中太郎", age: 56}, {id: 2, name:"小林ゴリラ", age: 1}, {id: 3, name:"森本ジョンソン", age: 31} ]; // charactersから30歳未満のキャラクターを取り出し、定数underThirtyに代入してください const underThirty = characters.filter((character) => { return character.age < 30; }); // underThirtyを出力する。 console.log(underThirty); 出力結果 [ {id: 2, name:"小林ゴリラ", age: 1} ]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TypeScript まとめ4(インストール〜コンパイル方法)

TypeScriptまとめ集 型について ユーティリティ型 モジュール化 インストール〜コンパイル方法 目次 TypeScriptのインストール〜コンパイル 外部ライブラリの使用 コンパイラオプション 以下の環境で記事を作成 エディタはVisual Studio Code Node.jsはインストール済み npmプロジェクトにて実行。 TypeScript バージョン4.2.2 1.TypeScriptのインストール〜コンパイル 1.npmプロジェクトを作成する。 以下のコマンドをターミナルにて実行する。 # npmプロジェクトを作成 $ npm init # package.jsonの設定が既定のままでもいい場合はこちら $ npm init -y 2.TypeScriptをインストールする 以下のコマンドをターミナルにて実行する。 ※個人間で設定が違うことがないように、基本はローカルインストールをすること。 # TypeScriptをインストールする $ npm install -S typescript # もしくはこちらの書き方 $ npm install --save typescript -S, --saveをつけることで、package.json内のdependenciesにパッケージ情報が記録される。 npm installを実行すると、記録したパッケージ情報に基づいて、node_modules内にパッケージがインストールされる。 3.コンパイル時の設定を記録する。 以下のコマンドをターミナルにて実行する。 # ts.configファイルを作成する $ tsc --init ※ts.configの中身は、下の方で紹介。 4.tsファイルを作成、コンパイルしてjsファイルを作成する。 コンパイルは、以下のコマンドにて実行できる。 これにより、同フォルダにてsample.jsが作成される。(sample.tsが対象) # コンパイル(sample.tsを対象) $ tsc sample.ts 複数ファイルをコンパイルしたい場合は、 # 複数ファイルをコンパイル $ tsc sample1.ts sample2.ts sample3.ts 全ファイルをコンパイルしたい場合は、 # 全ファイルをコンパイル $ tsc コンパイルオプションについては下の方で紹介。 2.外部ライブラリの使用 jQueryやChart.jsといったJavaScriptライブラリをTypeScriptでも使いたい場合。 1.型定義ファイルをインストールする。 以下のコマンドを実行する。 # 以下のコマンドで型定義ファイルとHTML内に埋め込むスクリプトファイルをインストールできる(jQueryとChart.js) $ npm install --save jquery @types/jquery $ npm install --save chart.js @types/chart.js # 型定義ファイル(@typesフォルダに格納される)だけをインストールしたい場合 $ npm install --save @types/jquery $ npm install --save @types/chart.js 上記を実行することで、@typesフォルダが作成され、中に型定義ファイルが作成される。 ファイル名は「〜.d.ts」といった形で作成される。(index.d.tsという名前が基本) インストール後のpackage.jsonは以下。 package.jsonの中 # dependenciesに記録される { "name": "sample-ts", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@types/chart.js": "^2.9.32", "@types/jquery": "^3.5.5", "chart.js": "^3.1.1", "jquery": "^3.6.0", "typescript": "^4.2.4" } } 2.外部ライブラリをインポート 外部ライブラリをtsファイル内でインポートして、各ライブラリで使用される変数を使用できるようにする。 基本的にindex.d.ts内に、インポートできるクラスやインターフェイスが定義されているため、それをインポートする。 ※jQueryはインポートしなくても使用できるようになっていた。 import { Chart } from 'chart.js'; const canvas = document.querySelector('.my-chart')! as HTMLCanvasElement; const ctx = canvas.getContext('2d')!; const data:any = {/*省略*/}; const options = {/*省略*/}; //new Chartでエラーが出なくなる const myRadarChart = new Chart(ctx, {type: 'radar',options,data,}); 3.コンパイラオプション コンパイルコマンドを入力する際に、オプションをつけることで色々できる。 -d / --declaration 宣言ソースファイル(d.ts.)を生成する。 -d/--declaration $ tsc -d sample.ts -h / --help コンパイラの使用方法を表示する。 -h/--help $ tsc -h -m / --module モジュール形式を指定する。 -m/--module # CommonJS方式の場合 tsc -m commonjs main.ts # AMD形式の場合 tsc -m amd main.ts --noImplicitAny 暗黙のany型の宣言や式を警告する。 --noImplicitAny $ tsc --noImplicitAny sample.ts --out ソースファイルを連結して単一ファイルに出力する。 --out # sample1.tsとsample2.tsを連結して、sample.jsを出力する $ tsc sample.js sample1.ts sample2.ts --outDir 出力先のディレクトリを指定する。 --outDir # resultフォルダに出力する $ tsc --outDir result --removeComments コメントを出力する。 --removeComments $ tsc --removeComments sample.ts -t / --target ECMAScriptのバージョンを指定する。 -t/--target $ tsc -t ES5 sample.ts -v / --version コンパイラのバージョン番号を表示する。 -v/--version $ tsc -v -w / --watch 入力ファイルを監視して自動コンパイルする。 -w/--watch $ tsc -w sample.ts @ ファイルからコンパイラオプションを読み込む。 @ # 以下のようなテキストファイル(build.txt)があった場合 --out result.js sample.ts # テキストファイルの内容でコンパイルする tsc @build.txt --sourcemap .mapファイルを出力する --sourceRoot デバッガが参照する.tsファイルの場所を指定する。 --mapRoot デバッガが参照する.mapファイルの場所を指定する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【新人プログラマ応援】メソッドは呼ぶ側を手前に、呼ばれる側を後ろに定義しよう

はじめに これはQiitaで開催されている「新人プログラマ応援 - みんなで新人を育てよう!」イベントの投稿記事です。 今回はメソッドの定義順に関する小ネタを書いてみようと思います。 なお、この記事はRuby版とJavaScript版の2部構成になっています。 JavaScriptを使ったコード例はRuby版のあとに載せています。 ?JavaScript版を読む おことわり この記事ではメソッドの定義順を変えてもエラーが出ないケースを議論の対象とします。 文法の制約上、特定の定義順で書かないと動かないケースは議論の対象としません。 Ruby版 メソッドの定義順は基本的に自由、だが・・・ メソッドの定義順は基本的に自由です。 class Foo def a end def b end def c end end と書いてもいいですし、 class Foo def b end def c end def a end end と書いてもエラーにはなりません。 しかし、コードを読むときは呼ぶメソッドを手前に、呼ばれるメソッドを後ろに定義した方が読みやすいです。 つまり、こういうことです。 # 呼ぶ側を手前に、呼ばれる側を後ろに定義した場合 class Foo def a b end def b c end def c end end これがバラバラになっていると、コードを読むときのリズムが崩れて読みづらくなります。 # 呼ぶ側を手前に、呼ばれる側を後ろに定義した場合 class Foo def b c end def c end def a b end end 童謡を使って考えてみる とはいえ、上のような意味のないコード例だといまいちピンとこないかもしれません。 そこで「あんたがたどこさ」という童謡の歌詞を拝借して、メソッドの定義順の良し悪しを考えてみることにします。 メソッドの定義順がバラバラの場合 最初はメソッドの定義順がバラバラになっているケースです。 以下のコードでplayer.playを実行したときの実行結果がどうなるか、ぱっとわかるでしょうか? playメソッドから順に最後までメソッド呼び出しがどのように進むか、ぜひ目で追いかけてみてください。 class MusicPlayer def play あんたがたどこさ end private def 肥後どこさ 熊本さ end def あんたがたどこさ 肥後さ end def 熊本さ puts "熊本どこさ?" end def 肥後さ 肥後どこさ end end player = MusicPlayer.new player.play どうですか?実行結果がわかりましたか? はい、そうですね、playメソッドを呼び出すと"熊本どこさ?"の文字列が出力されます。 player.play #=> 熊本どこさ? 「呼ぶ側を手前に、呼ばれる側を後ろ」のルールで定義した場合 ですが、もしメソッドの定義順が次のようになっていたらどうでしょうか? 先ほどと同じようにplayメソッドから順に最後までメソッド呼び出しがどのように進むか、目で追いかけてみてください。 class MusicPlayer def play あんたがたどこさ end private def あんたがたどこさ 肥後さ end def 肥後さ 肥後どこさ end def 肥後どこさ 熊本さ end def 熊本さ puts "熊本どこさ?" end end player = MusicPlayer.new player.play playメソッドを呼び出すと"熊本どこさ?"の文字列が出力されるのは先ほど同じですが、「呼ぶ側を手前に、呼ばれる側を後ろ」のルールで定義した方がコードが読みやすくなったのではないでしょうか? Ruby版のまとめ というわけで、この記事では「メソッドは呼ぶ側を手前に、呼ばれる側を後ろに定義しよう」という話を書いてみました。 もちろん、メソッドの定義順は絶対的な正解があるわけではないですし、読みやすさは主観によるので「ワシはメソッドの定義順なんて何でもかまわん!」という人も中にはいるでしょう。 とはいえ、僕の周りの熟練プログラマに話を聞くと、ほとんどの人が「呼ぶ側を手前に、呼ばれる側を後ろ」で書いた方がわかりやすいと答えています。 そもそもRubyだって普通はpublicメソッドを手前に、privateメソッドを後ろに定義にするので、これも「呼ぶ側を手前に、呼ばれる側を後ろ」のルールになっていますよね。 class MusicPlayer # publicメソッドはprivateメソッドを呼ぶ(手前に定義) def play あんたがたどこさ end private # privateメソッドはpublicメソッドに呼ばれる(後ろに定義) def あんたがたどこさ 肥後さ end # 以下略 end というわけで、新人プログラマの方で「メソッドってどういう順番で定義したらいいのかな〜??」と悩んでいる人はとりあえず「呼ぶ側を手前に、呼ばれる側を後ろ」の順番で定義してみることをオススメします! JavaScript版 メソッドの定義順は基本的に自由、だが・・・ メソッド(または関数)の定義順は基本的に自由です。 class Foo { a() { } b() { } c() { } } と書いてもいいですし、 class Foo { b() { } c() { } a() { } } と書いてもエラーにはなりません。 しかし、コードを読むときは呼ぶメソッドを手前に、呼ばれるメソッドを後ろに定義した方が読みやすいです。 つまり、こういうことです。 // 呼ぶ側を手前に、呼ばれる側を後ろに定義した場合 class Foo { a() { this.b() } b() { this.c() } c() { } } これがバラバラになっていると、コードを読むときのリズムが崩れて読みづらくなります。 // 呼ぶ側を手前に、呼ばれる側を後ろに定義した場合 class Foo { b() { this.c() } c() { } a() { this.b() } } 童謡を使って考えてみる とはいえ、上のような意味のないコード例だといまいちピンとこないかもしれません。 そこで「あんたがたどこさ」という童謡の歌詞を拝借して、メソッドの定義順の良し悪しを考えてみることにします。 メソッドの定義順がバラバラの場合 最初はメソッドの定義順がバラバラになっているケースです。 以下のコードでplayer.play()を実行したときの実行結果がどうなるか、ぱっとわかるでしょうか? playメソッドから順に最後までメソッド呼び出しがどのように進むか、ぜひ目で追いかけてみてください。 class MusicPlayer { play() { this.あんたがたどこさ() } 肥後どこさ() { this.熊本さ() } あんたがたどこさ() { this.肥後さ() } 熊本さ() { console.log("熊本どこさ?") } 肥後さ() { this.肥後どこさ() } } const player = new MusicPlayer() player.play() どうですか?実行結果がわかりましたか? はい、そうですね、playメソッドを呼び出すと"熊本どこさ?"の文字列が出力されます。 player.play() //=> 熊本どこさ? 「呼ぶ側を手前に、呼ばれる側を後ろ」のルールで定義した場合 ですが、もしメソッドの定義順が次のようになっていたらどうでしょうか? 先ほどと同じようにplayメソッドから順に最後までメソッド呼び出しがどのように進むか、目で追いかけてみてください。 class MusicPlayer { play() { this.あんたがたどこさ() } あんたがたどこさ() { this.肥後さ() } 肥後さ() { this.肥後どこさ() } 肥後どこさ() { this.熊本さ() } 熊本さ() { console.log("熊本どこさ?") } } const player = new MusicPlayer() player.play() playメソッドを呼び出すと"熊本どこさ?"の文字列が出力されるのは先ほど同じですが、「呼ぶ側を手前に、呼ばれる側を後ろ」のルールで定義した方がコードが読みやすくなったのではないでしょうか? JavaScript版のまとめ というわけで、この記事では「メソッドは呼ぶ側を手前に、呼ばれる側を後ろに定義しよう」という話を書いてみました。 もちろん、メソッドの定義順は絶対的な正解があるわけではないですし、読みやすさは主観によるので「ワシはメソッドの定義順なんて何でもかまわん!」という人も中にはいるでしょう。 とはいえ、僕の周りの熟練プログラマに話を聞くと、ほとんどの人が「呼ぶ側を手前に、呼ばれる側を後ろ」で書いた方がわかりやすいと答えています。 というわけで、新人プログラマの方で「メソッドってどういう順番で定義したらいいのかな〜??」と悩んでいる人はとりあえず「呼ぶ側を手前に、呼ばれる側を後ろ」の順番で定義してみることをオススメします!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails+JavaScript】残り文字を表示させる[コピペOK]

この記事の対象者 JavaScriptをRailsに組み込んでみたい方 CRUD処理は理解されている方 細かい説明が欲しい方 *最終コードは最後にに書いております。説明が必要ない方は「最終的なコード」をご覧ください。 今回作成するもの 今回作成するものは、画像のように「xxx/xxx文字」と残り文字数を伝えるものになります 今回の想定外 文字の色を変更すること 文字数を超えて入力できること CSSによる見た目の修正 準備すること フォームの作成 (サンプル) _form.html.erb <%= form_with model: @モデル名, local: true do |f| %> <%= f.text_area :content %> <% end %> *この記事では、alertで動作確認を行う記述があります。 確認できましたら、alertは削除ください。 目次 JSファイルを作成 文字数を取得する viewに表示させる 関数の作成 1.JSファイルを作成 まずは、JSファイルを作成します。名前は任意で構いません。 今回はcountLengthとします。 ターミナル touch app/javascript/packs/countLength.js app/javascript/packs/countLength.js + document.addEventListener('turbolinks:load', () => { + alert('動作確認'); //確認用です。 + }) 次に、このファイルを読み込みます application.js import "./countLength" alertが表示されればOKです!(確認後は削除してくだい。) これで、JSファイルの準備ができました! 2.文字数を取得する 次に、文字数を取得しましょう。 今回取得する必要がある文字数は、以下の3つです 最大文字数 現在入力している文字数 残り文字数 この3つを算出する必要があります。 1つずつ確認していきましょう。 1.最大文字数 「フォームで入力できる最大文字数」を取得します。 最大文字数は、自分でフォームに設定する必要があります idとmaxlength(最大文字数)を付与しましょう _form.html.erb 例 <%= f.text_area :content %> ↓ <%= f.text_area :content, id: "textarea", maxlength:"1000" %> これで、最大1000文字までしか打てないように制限がかかりました。 実際に1000文字以上打てるか確認してください。 このmaxlength: 1000をJSファイル(countLength.js)で取得していきます。 以下のコードを追加してください。 app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { + let textarea = document.getElementById('textarea'); //テキストエリアを取得 + let maxLength = textarea.maxLength; //最大の文字数を取得 + alert(maxLength); //確認用 }) maxLengthが表示されればOKです。 まずは、最大文字数を取得することができるようになりました。 2.現在入力している文字数 次に、現在入力している文字数を取得します。 先ほど定義した変数textareaを用いて、textarea.value.lengthで取得できます。 app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; + let currentLength = textarea.value.length; //テキストエリアに入力されている文字数を取得 + alert(currentLength);//確認用 }) currentLengthが表示されればOKです。(formにいくつか文字を入力しておくとわかりやすいです。) これで、現在入力している文字数を取得できました。 3.残り文字数を取得 最後に、残り何文字打てるか?を取得します。 残り文字数は、言葉にすると以下のようになります。 残り文字数 = 最大文字数 - 現在入力している文字数 これを実際にJSファイルで実行しましょう! app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; let currentLength = textarea.value.length; + remainingLength = maxLength - currentLength //残り文字 = 最大文字数 - 現在入力している文字数 + alert(remainingLength); //確認用 }) remainingLengthが表示されればOKです。 これで、必要な3つの要素をJSファイルで取得することができました。 3.viewに表示させる 最後に、取得した文字数を表示させましょう! まずは文字数を表示させるdivタグを作成し、id="message"を付与します。 _form.html.erb <%= form_with model: @モデル名, local: true do |f| %> <%= f.text_area :content, id: "textarea", maxlength:"1000" %> + <div id="message"></div> <% end %> そして、先ほど取得した最大文字数と残りの文字数を<div id="message"></div>に反映させます。 JavaScriptでinnnerHTMLメソッドというメソッドを使用することで、値をview側に渡すことができます。 - element.innerHTML app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; let currentLength = textarea.value.length; remainingLength = maxLength - currentLength; + let message = document.getElementById('message'); //メッセージを表示する要素を取得 + message.innerHTML = `${remainingLength}/${maxLength}文字`; //残りの文字/最大文字数を出力 }) これで、残り文字を出力することができます 以上で完成になりま・・・せん! これでは、ページが表示された時の情報が入るため、後から入力しても数字が変わりません。 なので、関数を作成して、入力したら文字数が反映される仕様にします。 4.関数の作成 まず、どのような条件と動作になるか言語化しておきます 言語化 「id="textarea"を持つテキストエリア」に文字を入力した時、「入力し終わった直後の残り文字を算出して、表示させる」 という風に置き換えることができます。 それでは、条件を満たす時に実行される関数を作成します。 テキストエリアに文字を入力された時に動作するイベントとして、今回'keyup'というイベントを使用します。 - Document: keyup イベント app/javascript/packs/countLength.js //テキストエリアに文字をkeyupしたときに動作する関数を作成 textarea.addEventListener('keyup', function(){   //ここに動作を書いていきます。 }) app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; let currentLength = textarea.value.length; remainingLength = maxLength - currentLength; let message = document.getElementById('message'); message.innerHTML = `${remainingLength}/${maxLength}文字`; //テキストエリアでkeyupイベントが発生した時に動作する関数を作成。 + textarea.addEventListener('keyup', function(){ + alert('動作確認'); + }) }) キーUPするたびにアラートが表示されればOKです! これで、関数が動作する条件を設定することができました。 最後に中身を作成します app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; let currentLength = textarea.value.length; remainingLength = maxLength - currentLength; let message = document.getElementById('message'); message.innerHTML = `${remainingLength}/${maxLength}文字`; textarea.addEventListener('keyup', function(){ //現在の文字数を再取得する + let currentLength = textarea.value.length //現在の文字数を再出力する + message.innerHTML = `${maxLength - currentLength }/${maxLength}文字` }) }) これで、入力(keyup)があるたびに、残り文字数を表示する関数を実装できました! 動作確認してみてください! 最終的なコード _form.html.erb <%= form_with model: @モデル名, local: true do |f| %> <%= f.text_area :content, id: "textarea", maxlength:"1000" %> <div id="message"></div> <% end %> app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { if (document.getElementById('textarea') !== null) { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; let currentLength = textarea.value.length; - remainingLength = maxLength - currentLength; //リファクタリング let message = document.getElementById('message'); + message.innerHTML = `${maxLength - currentLength}/${maxLength}文字`; //改善 textarea.addEventListener('keyup', function(){ let currentLength = textarea.value.length message.innerHTML = `${maxLength - currentLength}/${maxLength}文字` }) } }) 今後 今後、以下を実装してみたいと思っています。追加できるようになれば、この記事に追加しようと思います。 <div id = "message"></div>をJSファイルで作成する(view側で設定する必要をなくす) 残り文字数が少なくなった時、色を変化させる エラー対応 上記に説明がありませんが、document.getElementById('textarea')を取得できない場合、エラーが発生することがわかりました。 そのため、document.getElementById('textarea')で値を取得できた場合のみ、動作するように条件分岐させております。(最終的なコードに追加してあります。) app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { + if (document.getElementById('textarea') !== null) { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; let currentLength = textarea.value.length; let message = document.getElementById('message'); message.innerHTML = `${maxLength - currentLength}/${maxLength}文字`; textarea.addEventListener('keyup', function(){ let currentLength = textarea.value.length message.innerHTML = `${maxLength - currentLength}/${maxLength}文字` }) + } })
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでAzure Translatorを使って翻訳した結果のtranslationsプロパティからtext文字列だけを取得して表示する

色々なAPIを触ってお勉強中なのですが、面白そうなAPIの取得結果が英語だったりすると、「日本語に翻訳した結果をプロトタイプに使いたいなー」という場面が出てきました。無料で翻訳する方法は検索で色々出てきますが、せっかくMicrosoft Azureの従量課金サブスクリプションを使える状況にあるので、今回はAzure Cognitive ServiceのTranslatorサービスで翻訳に挑戦したいと思います。 Qiita、意外とAzureの記事は多くないのですね('ω') この記事の概要 JacaScriptでAzure Translatorサービスを使って翻訳し、翻訳結果のtext文字列のみを取り出して表示します。REST-APIでリクエストしてからレスポンスを得るまでは順調だったのですが、そもそもJSON形式のデータの扱い、変換に慣れておらずかなり時間を消費しましたので・・、ここに記録しておきます。 Azure Translatorサービスをデプロイする ますは翻訳結果をREST-APIで取得できるか試してみる 取得したJSON配列からtext文字列だけを取り出して表示したい(のに、中々できない・・) 環境は以下の通りです。 Module Version Node.js 15.13.0 npm 7.7.6 request 2.88.2 uuid 8.3.2 Azure Translatorサービスをデプロイする こちらの記事が、Azureポータルの操作画面付きで親切に紹介してくれていますので、これを参考にTranslatorサービスの作成・デプロイを行います。 【Microsoft Azure Translator Text 】Pythonで機械翻訳をしてみる(REST API) 今回はあくまでもお試し用なので、フリープランで用意しました。 APIで使用するエンドポイントとキーは、Azureポータルの以下画面で確認できます。今回は検証目的のためソースに直接記入してしまいますが、絶対に公開・漏洩しないように気をつけてください。本当はAzure Key Vaultなど使用してセキュアに使うのが推奨ですね。 ますは翻訳結果をREST-APIで取得できるか試してみる requestモジュールを使用してリクエストを実行しますので、インストールしておきます。 npm install request 作成したコードはコチラです。コーディング勉強中で見様見真似ですので、おかしな箇所がありましたら容赦なく突っ込みをお願いします('ω') get_translator_response.js //package require const request = require('request'); const uuidv4 = require('uuid/v4'); // 今回は次の英文を翻訳します const SourceText = 'When in doubt, just take the next small step.' // REST APIのPOST要求のパラメータを定義します function translateText(SourceText){ let options = { method: 'POST', baseUrl: 'https://api.cognitive.microsofttranslator.com/', url: 'translate', qs: { 'api-version': '3.0', 'from': ['en'], 'to': ['ja'] }, headers: { 'Ocp-Apim-Subscription-Key': 'YourSubscriptionKey', 'Ocp-Apim-Subscription-Region': 'YourServiceRegion', 'Content-type': 'application/json', 'X-ClientTraceId': uuidv4().toString() }, body: [{ 'text': SourceText }], json: true, }; // 応答本文(JSON配列)を受け取って表示します request(options, function(err, res, body){ // レスポンスデータを確認します(オブジェクトのまま) console.log(body); // JSON形式の文字列に変換します const jsonText = JSON.stringify(body, null, 4) console.log(jsonText); }); }; // 処理の呼び出し translateText(SourceText); さて、実行結果です。 [ { detectedLanguage: { language: 'en', score: 1 }, translations: [ [Object] ] } ] [ { "detectedLanguage": { "language": "en", "score": 1 }, "translations": [ { "text": "疑わしい場合は、次の小さな一歩を踏み出してください。", "to": "ja" } ] } ] おぉ、ちゃんと動きましたね('ω') なるほど、最初の出力がレスポンスで得られるJSON配列(入れ子オブジェクトあり)で、こう表示されるのですね。二番目の出力は、JSON.stringifyで文字列変換を掛けているので、しっかりとtranslationsプロパティ内の翻訳textまでしっかり確認できます。 取得したJSON配列からtext文字列だけを取り出して表示したい(のに、中々できない・・) 後は煮るなり焼くなりと、目的の翻訳text文字列だけ取り出して完成!となるはずが、ここから大ハマりしました。 そもそもJavaScriptのコードは今月から触り始めた初心者 よく理解していない状況で他人様のコードをコピペして動かしては喜んでいた というレベルですので、配列やオブジェクトの変換とか操作を全く分かっていませんでした。「JSON.parseとJSON.stringifyでオブジェクトと文字列を行き来すればよいのでしょ、オブジェクトでないと子プロパティ指定でデータ取れないのでしょ(分かってない)」という感じで、あーでもない、こーでもないと数時間。 あれ?おかしいな? よし!「(オブジェクト)['translations'][0]['text'] 」で行けるだろう! TypeError: Cannot read property '0' of undefined 無理('ω') その後のんびりとWeb記事でお勉強しながら、ふとコードとデータを見ていると「そもそも全体が配列で返ってきているのか・・(゚Д゚)」もしかして・・、こうか! request(options, function(err, res, body){ console.log(body[0]['translations'][0]['text']); }); 結果。 疑わしい場合は、次の小さな一歩を踏み出してください。 おぉ('ω') いったい私は何に時間を取られていたのでしょう・・。こんな不幸な初心者を増やさないよう、この記事を捧げます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails+Javascript】残り文字を表示させる【コピペ可能】

この記事の対象者 JavascriptをRailsに組み込んでみたい方 CRUD処理は理解されている方 細かい説明が欲しい方 *最終コードは最後にに書いております。説明が必要ない方は「最終的なコード」をご覧ください。 今回作成するもの 今回作成するものは、画像のように「xxx/xxx文字」と残り文字数を伝えるものになります 今回の想定外 文字の色を変更すること 文字数を超えて入力できること CSSによる見た目の修正 準備すること フォームの作成 (サンプル) _form.html.erb <%= form_with model: @モデル名, local: true do |f| %> <%= f.text_area :content %> <% end %> *この記事では、alertで動作確認を行う記述があります。 確認できましたら、alertは削除ください。 目次 JSファイルを作成 対象のフォームにidを付与する 残り文字数を表示させる 1.JSファイルを作成 まずは、JSファイルを作成します。名前は任意で構いません。 今回はcountLengthとします。 ターミナル touch app/javascript/packs/countLength.js app/javascript/packs/countLength.js + document.addEventListener('turbolinks:load', () => { + alert('動作確認'); //確認用です。 + }) 次に、このファイルを読み込みます application.js import "./countLength" alertが表示されればOKです!(確認後は削除してくだい。) これで、JSファイルの準備ができました! 2.文字数を取得する 次に、文字数を取得しましょう。 今回取得する必要がある文字数は、以下の3つです 最大文字数 現在入力している文字数 残り文字数 この3つを算出する必要があります。 1つずつ確認していきましょう。 1.最大文字数 「フォームで入力できる最大文字数」を取得します。 最大文字数は、自分でフォームに設定する必要があります idとmaxlength(最大文字数)を付与しましょう _form.html.erb 例 <%= f.text_area :content %> ↓ <%= f.text_area :content, id: "textarea", maxlength:"1000" %> これで、最大1000文字までしか打てないように制限がかかりました。 実際に1000文字以上打てるか確認してください。 このmaxlength: 1000をJSファイル(countLength.js)で取得していきます。 以下のコードを追加してください。 app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { + let textarea = document.getElementById('textarea'); //テキストエリアを取得 + let maxLength = textarea.maxLength; //最大の文字数を取得 + alert(maxLength); //確認用 }) maxLengthが表示されればOKです。 まずは、最大文字数を取得することができるようになりました。 2.現在入力している文字数 次に、現在入力している文字数を取得します。 先ほど定義した変数textareaを用いて、textarea.value.lengthで取得できます。 app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; + let currentLength = textarea.value.length; //テキストエリアに入力されている文字数を取得 + alert(currentLength);//確認用 }) currentLengthが表示されればOKです。(formにいくつか文字を入力しておくとわかりやすいです。) これで、現在入力している文字数を取得できました。 3.残り文字数を取得 最後に、残り何文字打てるか?を取得します。 残り文字数は、言葉にすると以下のようになります。 残り文字数 = 最大文字数 - 現在入力している文字数 これを実際にJSファイルで実行しましょう! app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; let currentLength = textarea.value.length; + remainingLength = maxLength - currentLength //残り文字 = 最大文字数 - 現在入力している文字数 + alert(remainingLength); //確認用 }) remainingLengthが表示されればOKです。 これで、必要な3つの要素をJSファイルで取得することができました。 3.viewに表示させる 最後に、取得した文字数を表示させましょう! まずは文字数を表示させるdivタグを作成し、id="message"を付与します。 _form.html.erb <%= form_with model: @モデル名, local: true do |f| %> <%= f.text_area :content, id: "textarea", maxlength:"1000" %> + <div id="message"></div> <% end %> そして、先ほど取得した最大文字数と残りの文字数を<div id="message"></div>に反映させます。 JavaScriptでinnnerHTMLメソッドというメソッドを使用することで、値をview側に渡すことができます。 - element.innerHTML app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; let currentLength = textarea.value.length; remainingLength = maxLength - currentLength; + let message = document.getElementById('message'); //メッセージを表示する要素を取得 + message.innerHTML = `${remainingLength}/${maxLength}`; //残りの文字/最大文字数を出力 }) これで、残り文字を出力することができます 以上で完成になりま・・・せん! これでは、ページが表示された時の情報が入るため、後から入力しても数字が変わりません。 なので、関数を作成して、入力したら文字数が反映される仕様にします。 4.関数の作成 まず、どのような条件と動作になるか言語化しておきます 言語化 「id="textarea"を持つテキストエリア」に文字を入力した時、「入力し終わった直後の残り文字を算出して、表示させる」 という風に置き換えることができます。 それでは、条件を満たす時に実行される関数を作成します。 テキストエリアに文字を入力された時に動作するイベントとして、今回'keyup'というイベントを使用します。 - Document: keyup イベント app/javascript/packs/countLength.js //テキストエリアに文字をkeyupしたときに動作する関数を作成 textarea.addEventListener('keyup', function(){   //ここに動作を書いていきます。 }) app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; let currentLength = textarea.value.length; remainingLength = maxLength - currentLength; let message = document.getElementById('message'); message.innerHTML = `${remainingLength}/${maxLength}`; //テキストエリアでkeyupイベントが発生した時に動作する関数を作成。 + textarea.addEventListener('keyup', function(){ + alert('動作確認'); + }) }) キーUPするたびにアラートが表示されればOKです! これで、関数が動作する条件を設定することができました。 最後に中身を作成します app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { let textarea = document.getElementById('textarea'); let maxLength = textarea.maxLength; let currentLength = textarea.value.length; remainingLength = maxLength - currentLength; let message = document.getElementById('message'); message.innerHTML = `${remainingLength}/${maxLength}`; textarea.addEventListener('keyup', function(){ //現在の文字数を再取得する + let currentLength = textarea.value.lengt - ここ調整すること; //現在の文字数を再出力する + remainingTextNum.innerHTML = `${remainingLength}/${maxTextNum}`; }) }) これで、入力(keyup)があるたびに、残り文字数を表示する関数を実装できました! 動作確認してみてください! 最終的なコード _form.html.erb <%= form_with model: @モデル名, local: true do |f| %> <%= f.text_area :content, id: "textarea", maxlength:"1000" %> <div id="message"></div> <% end %> app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { if (document.getElementById('textarea') !== null) { let textarea = document.getElementById('textarea'); //テキストエリアを取得 let currentTextNum = textarea.value.length; //現在の文字数を取得する let maxTextNum = textarea.maxLength; //最大の文字数を取得 let remainingTextNum = document.getElementById('remaining_message'); //メッセージを表示する要素を取得 remainingTextNum.innerHTML = `${maxTextNum - currentTextNum}/${maxTextNum}文字`; //残りの文字を出力 //残り文字を表示させる関数 textarea.addEventListener('keyup', function(){ let currentTextNum = textarea.value.length; //現在の文字数を再取得する remainingTextNum.innerHTML = `${maxTextNum - currentTextNum}/${maxTextNum}文字`; //現在の文字数を再出力する }) } }) 今後 今後、以下を実装してみたいと思っています。追加できるようになれば、この記事に追加しようと思います。 <div id = "message"></div>をJSファイルで作成する(view側で設定する必要をなくす) 残り文字数が少なくなった時、色を変化させる エラー対応 上記に説明がありませんが、document.getElementById('textarea')を取得できない場合、エラーが発生することがわかりました。 そのため、document.getElementById('textarea')で値を取得できた場合のみ、動作するように条件分岐させております。(最終的なコードに追加してあります。) app/javascript/packs/countLength.js document.addEventListener('turbolinks:load', () => { + if (document.getElementById('textarea') !== null) { let textarea = document.getElementById('textarea'); //テキストエリアを取得 let currentTextNum = textarea.value.length; //現在の文字数を取得する let maxTextNum = textarea.maxLength; //最大の文字数を取得 let remainingTextNum = document.getElementById('remaining_message'); //メッセージを表示する要素を取得 remainingTextNum.innerHTML = `${maxTextNum - currentTextNum}/${maxTextNum}文字`; //残りの文字を出力 //残り文字を表示させる関数 textarea.addEventListener('keyup', function(){ let currentTextNum = textarea.value.length; //現在の文字数を再取得する remainingTextNum.innerHTML = `${maxTextNum - currentTextNum}/${maxTextNum}文字`; //現在の文字数を再出力する }) + } })
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

条件分岐

if 条件式ifの記述は if(条件式){ 処理 } //「;」は不要 上記のように記述することで、条件式がTrueの時に処理が実行されます。if文の末尾には「;(セミコロン)」は不要です。 また、上記で条件式がFalseの時は処理は実行されません。 例 const num = 10; if (num > 5){ console.log('5より大きいです'); } 出力結果 5より大きいです else/else if elseはif文と合わせることで「もし〇〇ならば□□を行う、そうでなければ△△を行う」という処理を行うことができます。 例 const num = 10; if (num >= 15); console.log('15以上です'); //条件式がTrueの時、実行される処理 } else { console.log('15より小さいです'); //条件式がFalseの時、実行される処理 } 出力結果 15より小さいです 上記のように、条件式がFalseなので、はじめの処理は実行されずに、else後に記述された処理が実行されました。 さらに条件分岐を追加するためには「else if」を用います。 例 const num = 10; if (num > 10){ console.log('10より大きいです'); } else if (num == 10){ console.log('10です'); } else { console.log('10より小さいです'); } 出力結果 10です 上記のようにelse ifの条件式でTrueと判断されたので、elseifの処理が実行されました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React TrackedはContextだけじゃなくてReduxやZustandでも使えるんです

以前react-trackedの紹介と言う記事を書きましたが、その後少しバージョンアップしています。 v1.6.0からは、createTrackedSelectorと言うAPIが追加されReduxなどでも使えるようになりました。そもそもreact-trackedの前身はreactive-react-reduxと言うredux向けのライブラリなので技術的な目新しさはないのですが、react-trackedの位置付けとしてreact contextのためだけのライブラリではないと言うのは実は大きな変化です。 Zustandでも使えますが使い方は同じなのでReduxで説明します。ドキュメントサイトはこちら https://react-tracked.js.org/docs/tutorial-redux-01 使い方は簡単で、まずreact-reduxのuseSelectorをインポートします。 import { useSelector } from 'react-redux'; 次に、react-trackedからcreateTrackedSelectorをインポートします。 import { createTrackedSelector } from 'react-tracked'; 最後に、useTrackedSelectorを作ります。 const useTrackedSelector = createTrackedSelector(useSelector); これにより、 const foo = useSelector(state => state.foo); と書いていたところが、 const { foo } = useTrackedSelector(); と書けるようになります。ただ、これだとあまり嬉しさがわかりませんね。本領発揮するのは、reselectやequalityFnが必要になるケースです。 const selector = state => [state.foo, state.bar]; const [foo, bar] = useSelector(selector); このように書くことはお勧めされていないというか、常にrenderされてしまいます。 const selector = state => [state.foo, state.bar]; const [foo, bar] = selector(useTrackedSelector()); でも、これは大丈夫です。React Trackedのstate usage trackingによって、使われたプロパティが変更された場合だけrenderするためです。 興味がありましたら、GitHubリポジトリやドキュメントサイトを覗いてみてください。 「React Fan」というコミュニティを立ち上げていて、そのSlackでもreact-trackedに関する議論や質問ができますので、よろしければご参加ください。 詳しくは、下記のページをご参照ください。 React開発者向けオンラインサロン「React Fan」の入り口ページ Slackへの招待リンクも上記ページにあります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VueCLIコンポーネント全体にcssを適用する

全体にReboot.cssを適用する Reboot.cssとは Bootstrap 4に含まれているCSSリセットのこと。 Reboot.cssはnormalize.css 2.0に似ており、リセットの素晴らしい機能がある。 ・box-size: border-box;はデフォルトで、すべての要素に適用されます。 ・クロスブラウザに対応した一貫したリセットを提供しています。 ・要素にシンプルで自然なベーススタイルを与えます。 ・モダンなCSSを記述するためのヒントが記されています。 src/App.vue <template> <div id="app"> <!--省略--> </div> </template> <script> //省略 </script> <style> /* ファイルパスに従って@importntの後にファイルパスを書き込む */ @import "./assets/styles/bootstrap-reboot.css"; /* 省略 */ </style> ルートコンポーネントであるApp.vueのStyleタグに読み込みたい外部CSSファイルを指定する。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Azure Communication Services ことはじめ (4) : Microsoft Teams 会議にビデオ通話参加ができるまで

Azure Communication Services (以下 ACS) は、リアルタイム コミュニケーション基盤となるサービスで、テキスト | 音声 | ビデオ によるコミュニケーションのハブとなり、接続やコントロールを行うアプリやサービスを SDK などを用いて容易に開発できます。 今回は、2021 年 3 月 から ACS に追加された Microsoft Teams 会議参加ができる機能を使って、Teams 会議にビデオ通話(音声+カメラ動画)で参加できるまでの手順を追って確認し、Node.js の Web アプリを作成します。 ひとまず Teams 会議に音声で参加できるまでの手順はこちらに掲載しています: Azure Communication Services ことはじめ (3) : Microsoft Teams 会議に音声参加ができるまで 開発環境 開発環境 Windows 10 (20H2 - Build 19042) Visual Studio Code (ver 1.55.2) Node.js (12.18.4) 利用ライブラリー、フレームワークなど Azure Communication Services azure/communication-common@1.0.0-beta.5 azure/communication-calling@1.0.0-beta.10 azure/communication-identity@1.0.0 Webpack webpack@4.42.0 webpack-cli@3.3.11 webpack-dev-server@3.10.3 0. 事前準備 Azure Communication Services サービス Azure Communication Services ことはじめ (1) : チャットができるまで の 0.事前準備 と同様に、Azure Portal で ACS のサービスを作成し、接続文字列とエンドポイントを取得しておきます。 Microsoft Teams tenant interoperability (相互運用) 有効化 Azure Communication Services ことはじめ (3) : Microsoft Teams 会議に音声参加ができるまで の 0.事前準備 と同様に申請を行い、有効化しておきます。 1. ビデオ通話ができるまで (ライブラリーの使い方) Azure Communication Services ことはじめ (3) : Microsoft Teams 会議に音声参加ができるまで との差分は、動画ストリームのコントロールです。 1-0. ライブラリの追加 以下のライブラリを冒頭に追加します。動画ストリームを扱うモジュール(VideoStreamRenderer, VideoStream)が追加になります。 ライブラリ azure/communication-common ユーザーの作成、アクセストークン取得 azure/communication-identity  (同上)  azure/communication-calling 音声およびビデオ通話のコントロール import { AzureCommunicationTokenCredential } from '@azure/communication-common'; import { CommunicationIdentityClient } from "@azure/communication-identity"; import { CallClient, VideoStreamRenderer, LocalVideoStream } from "@azure/communication-calling"; 1-1. ユーザーを作成し、アクセストークンを取得する Azure Communication Services ことはじめ (3) 1-1 と全く同様です。 1-2. 通話クライアントを作成 Azure Communication Services ことはじめ (3) 1-2 と全く同様です。 1-3. Teams 会議に参加する CallAgent から、参加したい Teams 会議にアクセスします。Teams 会議 URL がそのまま引数になります。 PCカメラの画像を送る場合は、CallClient から DevideManager を呼び出し、デバイス(PC)のカメラ情報(VideoDevices)を取得します。カメラを指定して (※環境に合わせて videoDevices[x] の x 値を変更してください)、LocalVideoStream として取得し、Teams 会議情報に追加します。 client.js let call let deviceManager; let localVideoStream; deviceManager = callClient.getDeviceManager() const videoDevices = deviceManager.getCameras(); const videoDeviceInfo = videoDevices[0]; localVideoStream = new LocalVideoStream(videoDeviceInfo); call = callAgent.join( { meetingLink: "TEAMS_MEETING_URL" }, { videoOptions: { localVideoStreams: [localVideoStream] } }); Teams 会議 URL は以下のような URL をエンコードしたものになります。 https://teams.microsoft.com/l/meetup-join/19:meeting_xxx...xxx@thread.v2/0?context={"tid":"xxx...xxx","oid":"xxx...xxx"} 1-4. Teams 会議の動画をコントロールする 1-4-1. PC カメラからの動画を使用 LocalVideoStream から VideoStreamRenderer で View を作成し、HTMLElement として append すれば OKです。 let rendererLocal; rendererLocal = new VideoStreamRenderer(localVideoStream); const view = await rendererLocal.createView(); document.getElementById("myVideo").appendChild(view.target); 1-4-2. Teams 会議 (の参加者) の動画を使用 Teaams 会議の動画である RemoteVideoStream を取得したら、VideoStreamRenderer で View を生成して HTMLElement として append するという流れは同様です。 let rendererRemote; rendererRemote = new VideoStreamRenderer(remoteVideoStream); const view = await rendererRemote.createView(); document.getElementById("remoteVideo").appendChild(view.target); RemoteVideoStream は 会議情報をストアする Call から取得します。Teams会議参加者(Allay)情報から動画ストリームを取り出します。参加者の動画が切断されたら(remoteVideoStream.on('isAvailableChanged'...)、RemoteVideoStream を破棄します。 //CallAgent callAgent; let call; call = callAgent.join({ meetingLink: meetingUrlInput.value }); subscribeToRemoteParticipantInCall(call) function subscribeToRemoteParticipantInCall(call) { call.on('remoteParticipantsUpdated', e => { e.added.forEach( p => { subscribeToParticipantVideoStreams(p); }) }); call.remoteParticipants.forEach(p => { subscribeToPaticipantVideoStreams(p); }) } function subscribeToParticipantVideoStreams(remoteParticipant){ remoteParticipant.on('videoStreamsUpdated', e=> { e.added.forEach(v => { handleVideoStream(v); }) }); remoteParticipant.videoStreams.forEach(v => { handleVideoStream(v); }); } function handleVideoStream(remoteVideoStream) { remoteVideoStream.on('isAvailableChanged', async () => { if (remoteVideoStream.isAvailable) { remoteVideoView(remoteVideoStream); } else { rendererRemote.dispose(); } }); if (remoteVideoStream.isAvailable) { remoteVideoView(remoteVideoStream); } } 2. Web アプリの開発 (手順) 以上の手順を踏まえて、Visual Studio Code で Node.js Web アプリを作成します。 2-1. 新規 Node.js アプリの作成 Node.js アプリを作成するフォルダーを作成し、Visual Studio Code で開き、npm init コマンドで package.json を作成します。 npm init -y 2-2. Azure Communication Services のライブラリのインストール npm install コマンドで Azure Communication Services の必要なライブラリ (パッケージ) をインストールします。 npm install @azure/communication-common@1.0.0-beta.5 --save npm install @azure/communication-identity@1.0.0 --save npm install @azure/communication-calling@1.0.0-beta.10 --save 2-3. Webpack のインストール 今回は Webpack を利用して、JavaScript のモジュールバンドル & ローカルでの実行確認 を行います。 npm install コマンドで、webpack、webpack-cli、webpack-dev-server をインストールします。 npm install webpack@4.42.0 webpack-cli@3.3.11 webpack-dev-server@3.10.3 --save-dev 今回は Azure Communication Services ドキュメント 推奨バージョンを指定してインストールしています。 2-4. コーディング 画面 (index.html) ユーザーからの操作および音声入出力、各種情報を表示するため、index.html という名前でファイルを作成し、以下のような UI を作成します。 コードは以下になります。 ACSTeamsVideoWeb202104/index.html カメラ動画 & 音声 を使った通話機能 (client.js) client.js という名前でファイルを作成し、Teams 会話 (カメラ動画、音声) をコントロールする機能を記述します。 後ほど client.js を index.js にビルドして index.html で読み込みます。 利用ライブラリー 今回は、これらのライブラリーを利用します。 client.js import { AzureCommunicationTokenCredential } from '@azure/communication-common'; import { CommunicationIdentityClient } from "@azure/communication-identity"; import { CallClient, Features } from "@azure/communication-calling"; 接続文字列 client.js に connectionString を記載しておきます。 YOUR_CONNECTION_STRING は 事前準備で取得した 接続文字列に置き換えてください。 セキュリティの観点から別の設定ファイルなどに記載して読み出すのが一般的ですが、今回は動作を確認するのみのアプリなので本体に記載しています。 client.js let connectionString = "YOUR_CONNECTION_STRING"; UI 画面の入出力 Web 画面から Teams 会議リンク(URL) の入力を取得できるようにします。 また、Teams 会議の参加、終了のボタンのクリック、および カメラ動画のオン、オフボタンのクリックを取得できるようにします。 出力は、UserId、UserToken、動作に対するメッセージ(messageOutput)を表示するようにしておきます。 動画(自分の PC カメラ動画および Teams 会議動画) は後ほど設定します client.js // 入力 const meetingUrlInput = document.getElementById("meeting-url-input"); // Teams 会議 URL const joinMeetingButton = document.getElementById("join-meeting-button"); // Teams 会議参加ボタン const hangUpButton = document.getElementById("hang-up-button"); // Teams 会議退出ボタン const startVideoButton = document.getElementById("start-video-button"); // カメラ動画開始ボタン const stopVideoButton = document.getElementById("stop-video-button"); // カメラ動画停止ボタン // 出力 const callerIdOutput = document.getElementById("caller-id-output"); // ACS UserId const callerTokenOutput = document.getElementById("caller-token-output"); // ACS UserToken const messageOutput = document.getElementById("message-output"); // 状態メッセージ CommunicationUser の新規作成、Token の取得、CallAgent の生成 接続文字列から User を新規作成して Token を取得します。Token を利用して、Teams 会議のコントロールを行う CallAgent を生成します。CAllAgent が無事生成出来たら、joinMeetingButton (Teams会議参加ボタン) をクリック可能(disabled = false)にします。 client.js // ACS User の作成とトークンの取得 const identityClient = new CommunicationIdentityClient(connectionString); const callClient = new CallClient(); let callAgent; let call; identityClient.createUser().then(identityResponse => { callerIdOutput.value = identityResponse.communicationUserId; // ACS User Id 画面出力 identityClient.getToken(identityResponse, ["voip"]).then(tokenResponse => { const userToken = tokenResponse.token; callerTokenOutput.value = userToken; // ACS User Token 画面出力 messageOutput.innerText += "Got user token."; // 状態メッセージ画面出力 const tokenCredential = new AzureCommunicationTokenCredential(userToken); callClient.createCallAgent(tokenCredential, {displayName: 'ACS user'}).then(async agent => { callAgent = agent; deviceManager = await callClient.getDeviceManager() joinMeetingButton.disabled = false; // Teams 会議参加ボタンをクリック可能に messageOutput.innerText += "\nReady to join MSTeam's Meeting."; // 状態メッセージ画面出力 }); }); }); 動画の設定 自分の PC カメラ動画 および Teams 会議動画 の操作を設定します。 client.js let deviceManager // PCカメラを操作 let localVideoStream; // PCカメラの動画ストリーム let rendererLocal; // PCカメラの動画レンダラー let rendererRemote; // Teams 会議の動画レンダラー // 自分の PC カメラ動画を配置 async function localVideoView(){ rendererLocal = new VideoStreamRenderer(localVideoStream); const view = await rendererLocal.createView({ scalingMode: 'Crop'}); document.getElementById("myVideo").appendChild(view.target); } // Teams 会議の参加者の動画を配置 async function remoteVideoView(remoteVideoStream) { rendererRemote = new VideoStreamRenderer(remoteVideoStream); const view = await rendererRemote.createView({ scalingMode: 'Crop'}); document.getElementById("remoteVideo").appendChild(view.target); } // Teams 会議の動画有無、参加者の増減による変更をハンドリング // Teams 会議への参加者が確認出来たら動画ストリームを取得 function subscribeToRemoteParticipantInCall(callInstance) { callInstance.on('remoteParticipantsUpdated', e => { e.added.forEach( p => { subscribeToParticipantVideoStreams(p); }) }); callInstance.remoteParticipants.forEach(p => { subscribeToPaticipantVideoStreams(p); }) } function subscribeToParticipantVideoStreams(remoteParticipant){ remoteParticipant.on('videoStreamsUpdated', e=> { e.added.forEach(v => { handleVideoStream(v); }) }); remoteParticipant.videoStreams.forEach(v => { handleVideoStream(v); }); } // 取得したストリームを配置 function handleVideoStream(remoteVideoStream) { remoteVideoStream.on('isAvailableChanged', async () => { if (remoteVideoStream.isAvailable) { remoteVideoView(remoteVideoStream); } else { rendererRemote.dispose(); } }); if (remoteVideoStream.isAvailable) { remoteVideoView(remoteVideoStream); } } Teams 会議への参加 joinMeetingButton (Teams 会議参加ボタン) がクリックされたら、callAgent から Teams 会議 (meeting-url-input TextBox から取得) への参加をリクエストします。また、PC カメラを取得し、カメラ動画 と Teams 会議動画 を出力します。 call のステータスを確認して、会議参加リクエストの承認、会議参加の状態を表示します。 client.js joinMeetingButton.addEventListener("click", async () => { // PC カメラの取得 const videoDevices = await deviceManager.getCameras(); const videoDeviceInfo = videoDevices[0]; // PC カメラ動画の出力 localVideoStream = new LocalVideoStream(videoDeviceInfo); localVideoView(); // カメラ動画の開始、停止ボタンのステータス変更 startVideoButton.disabled = true; // カメラ動画開始ボタンをクリック不可に stopVideoButton.disabled = false; // カメラ動画停止ボタンをクリック可能に // Teams 会議参加リクエスト call = callAgent.join( { meetingLink: meetingUrlInput.value }, { videoOptions: { localVideoStreams: [localVideoStream] } } ); // Teams 会議動画の出力 subscribeToRemoteParticipantInCall(call); // 会議参加ステータスのチェック call.on('stateChanged', () => { messageOutput.innerText += "\nMeeting:" + call.state; }) // 各ボタンのステータス変更、状態メッセージ表示 hangUpButton.disabled = false; // Teams 会議退出ボタンをクリック可能に joinMeetingButton.disabled = true; // Teams 会議参加ボタンをクリック不可に }); Teams 会議からの退出 hangupButton (Teams 会議退出ボタン) がクリックされたら、callAgent の Teams 会議を切断します。 client.js hangUpButton.addEventListener("click", () => { // Teams 会議から退出 call.hangUp(); // 動画レンダラーの終了 rendererLocal.dispose(); // 各ボタンのステータス変更、状態メッセージ表示 hangUpButton.disabled = true; // Teams 会議退出ボタンをクリック不可に joinMeetingButton.disabled = false; // Teams 会議参加ボタンをクリック可能に stopVideoButton.disabled = true; // カメラ動画停止ボタンをクリック不可に messageOutput.innerText += "\nNow hanged up."; // 状態メッセージ画面出力 }); PCカメラ動画の開始、停止 startVideoButton(PCカメラ動画開始)、stopVideoButton(PCカメラ動画停止) がクリックされたら、カメラ動画を開始または停止します。 client.js startVideoButton.addEventListener("click", async () => { await call.startVideo(localVideoStream); localVideoView(); startVideoButton.disabled = true; // カメラ動画開始ボタンをクリック不可に stopVideoButton.disabled = false; // カメラ動画停止ボタンをクリック可能に }); stopVideoButton.addEventListener("click", async () => { await call.stopVideo(localVideoStream); rendererLocal.dispose(); startVideoButton.disabled = false; // カメラ動画開始ボタンをクリック可能に stopVideoButton.disabled = true; // カメラ動画停止ボタンをクリック不可に }); 最終的なコードはこちらになります。 ACSTeamsVideoWeb202104/client.js 3. Teams 会議へのビデオ通話参加 を試してみる 今回は Webpack を利用しているので、client.js を index.js にビルドして起動します。 npx webpack-dev-server --entry ./client.js --output index.js --debug --devtool inline-source-map 起動したら、ブラウザーから http://localhost:8080 にアクセスします。 User Id と Token が取得できると [Join Teams Meeting] のボタンがアクティブになります。 Teams 会議へのビデオ通話参加のチェック Teams 会議を作成し、参加 URL を取得します。 Teams 会議参加 URL を入力して Join Team's Meeting をクリックします。 Teams 会議(主催者側)に参加リクエストが表示されたら許可します。 会議に接続され、お互いに双方のカメラ画面が表示されます。 [Hang Up] をクリックすると会議から退出します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

if文・switch文を作って遊んでみた!【備忘録】

こんにちは! 今日は、JavaScriptのif文とswitch文を作って、遊んでみました! 初心者の備忘録ですが、誰かのためになれば、嬉しいです! if文 まずは、if文から! if文は、条件によって、処理を変化させることができます。 あらかじめ、以下のように、条件式の部分で、条件を指定しておきます。 実行時に、引数として渡された値と、条件を比較し、trueであれば、〇〇の処理を、falseであれば××の処理を...というように、処理を分けることができるのです! if (条件式) { // 条件式がtrueだったとき 処理 } else { // 条件式がfalseだったとき 処理 } 1. アトラクションの身長制限 まずは、単純に、アトラクションの身長制限です。 身長を引数として渡します。 function sample1(height) { if (height >= 102) { // trueのとき console.log(`${height}cmは、102cm以上なので、このアトラクションに乗ることができます。`); } else { // falseのとき console.log(`申し訳ございません。${height}cmは、102cm未満ですので、このアトラクションに乗ることができません。`); } } let sampleResponse1 = sample1(155.7); // 155.7cmは、102cm以上なので、このアトラクションに乗ることができます。 let sampleResponse1_2 = sample1(90.3); // 申し訳ございません。90.3cmは、102cm未満ですので、このアトラクションに乗ることができません。 2. テストの点数で成績(評価)を分ける 続いては、テストの点数によって、評価を分けてみましょう。 function sample2(score) { if (score >= 80) { // 「scoreが80以上」がtrueのとき console.log(`あなたは、${score}点だったので、成績は、Aです。`); } else if (score >= 60) { // 「scoreが60以上80未満」がtrueのとき console.log(`あなたは、${score}点だったので、成績は、Bです。`); } else if (score >= 40) { // 「scoreが40以上60未満」がtrueのとき console.log(`あなたは、${score}点だったので、成績は、Cです。補習対象です。教室の掲示板を確認してください。`); } else { // 上の条件3つ全てに対し、falseのとき = scoreが40未満のとき console.log(`あなたは、${score}点でした。コース変更対象です。講義後に事務室に来てください。`); } } let sampleResponse2 = sample2(23); // あなたは、23点でした。コース変更対象です。講義後に事務室に来てください。 let sampleResponse2_2 = sample2(55); // あなたは、55点だったので、成績は、Cです。補習対象です。教室の掲示板を確認してください。 let sampleResponse2_3 = sample2(78); // あなたは、78点だったので、成績は、Bです。 let sampleResponse2_4 = sample2(90); // あなたは、90点だったので、成績は、Aです。 なんか、学習塾とかでありそうですね(笑) switch文 ここからは、switch文です。 引数として渡された値が、どのcaseと一致するかによって、処理を変えるんです! 多くの条件を比較する場合に、使ったりします。 switch (値) { case 値1: 処理1; break; case 値2: 処理2; break; case 値3: 処理3; break; default: 処理; defaultの場合の処理は、そのほかのcase全てと一致しなかった場合に実行されます。 各処理の後に、breakを書かないと、一致したcase以降のcaseの処理も実行されてしまいます。 3. ランチの注文 それでは、switch文を使ってみましょう! とある飲食店での、ランチの注文です。 function sample3(item) { switch (item) { case 'Aセット': // 引数に渡されたitemがAセットのとき console.log('Aセットは、サラダとドリンクが付いて980円です。'); break; case 'Bセット': // 引数に渡されたitemがBセットのとき console.log('Bセットは、サラダとドリンク、デザートが付いて1050円です。'); break; case 'キッズセット': // 引数に渡されたitemがキッズセットのとき console.log('キッズセットは、お子様プレートに選べるおもちゃが付いて780円です。'); break; default: // 上の条件3つ全てに対し、どれにも当てはまらなかったとき console.log('ランチタイムは、単品ではご注文頂けません。セットプランの中からお選びください。'); } } let sampleResponse3 = sample3('Bセット'); // Bセットは、サラダとドリンク、デザートが付いて1050円です。 let sampleResponse3_2 = sample3('キッズセット'); // キッズセットは、お子様プレートに選べるおもちゃが付いて780円です。 let sampleResponse3_3 = sample3('Aセット'); // Aセットは、サラダとドリンクが付いて980円です。 let sampleResponse3_4 = sample3('煮込みハンバーグ'); // ランチタイムは、単品ではご注文頂けません。セットプランの中からお選びください。 おわりに 仕事前にサクッと、if文とswitch文で遊んでみました。 私自身、まだまだ初心者です。もし、間違っている点や補足などございましたら、コメント頂けますと、私も勉強になるので、とても助かります!! お読み頂き、ありがとうございました! 参考資料 柳井政和著 『JavaScript[完全]入門』(2021) MDN switch
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS~配列処理~

概要 プログラムの利点は、大量のデータを機械的に処理してくれます。 また、大量のデータを扱うために仕組み化が必要です。データが順番に並んだ配列、名前と値のペアでデータを管理する連想配列があります、この記事では、配列処理について触れています。 index.js const fruits = ["リンゴ", "バナナ", "イチゴ", "ブドウ"]; console.log(fruits); const fruits = [ ["リンゴ",450], ["バナナ",500], ["イチゴ",300], ["ブドウ",200] ]; 配列宣言 配列とは、0からの順番で並んだデータ構造です。 index.js const fruits = ["リンゴ", "バナナ", "イチゴ", "ブドウ"]; console.log(fruits); console.log(fruits.length); 配列のなかにある個々のデータを要素と言います。要素は0から始まります。 配列はArryオブジェクトのインスタンス化されたものです。 配列はo番始まりです。これを、index番号、もしくは添字と言います。 lengthとは配列の要素数を表します。このfruitsの中には要素数が4つはいっていることがわかります。 配列の要素数を確認する場合は lengthプロパティーで要素数を確認することができます。 (*protoはJSが内部的に作っているデータなのですが今回は触れません。) 要素へのアクセス では、fruitsのデータの要素へアクセスします。 配列名に[]の中に要素番号を入れます、これをindex番号または添字と言います。今回はinde番号で統一します。 index.js console.log(fruits[0], fruits[1], fruits[2],fruits[3],fruits[4]); //リンゴ バナナ イチゴ ブドウ undefined 上記のような結果になりました。しかし、配列の4番は存在しないのでundefinedが返ってきます。 しかし、この記述では要素数が増えたときなどに記述が増えてしまいます。 for文 1つ目の方法は、for文です。 配列のlengthプロパティを使用することで要素数の繰り返し処理を行うことができます。 index.js for(let i = 0; i < fruits.length; i++) { console.log(`${i}個: ${fruits[i]}`); } *注意:条件式i < fruit.length。こちらの記述を以下のように変えてみます。 index.js for(let i = 0; i <= fruits.length; i++) { console.log(`${i}個: ${fruits[i]}`); } //0個: リンゴ // 1個: バナナ // 2個: イチゴ // 3個: ブドウ // 4個: undefined 出力結果は4つ目がundefinedとなります。 <=これは要素数4つを含める条件式です。今回の条件式では、iは0番始まりとなります。そこで、0と要素数4を繰り返すと合計5回繰り返すことになります。しかし実質要素数は4つなので5回目の処理のときには値が無いのでundefinedとなります。 forEach 2つ目の方法は、forEachです。 index.js fruits.forEach((fruit,index) => { console.log(`${index}個:${fruit}`); count ++; }); console.log(`要素数は${fruits.length}個,繰り返し回数は${count}回`); //0個:リンゴ // 1個:バナナ // 2個:イチゴ // 3個:ブドウ // 要素数は4個,繰り返し回数は4回 forEachでは、アロー関数を使用します。 今回の処理のでは、引数が2つなのでカンマで区切ります。()ないの引数に配列要素が1つずつ渡され、処理されていきます。 *アロー関数とは、通常の関数と違い関数名やfunctionをかきません。また引数が1つの場合は()を省略することができます。 index.js fruits.forEach(fruit =>{console.log(`${fruit}`);}); 、
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

indesign スクリプト 選択された構造の要素の属性から要素を選択

構造の要素の属性名から属性を選択するスクリプトはこれで良いのかな・・・? /* 選択された構造の要素の属性から要素を選択 更新 2021/04/30 */ // アプリ指定 #target "InDesign"; // スクリプト動作指定(高速) app.doScript(function(){ // スクリプト名 var scriptName = "選択された構造の要素の属性から要素を選択"; // 選択されているオブジェクト var selectobjects = app.activeDocument.selection; // すべての選択を解除 app.activeDocument.selection = null; // 選択オブジェクトの数だけ繰り返し for(var i = 0; i < selectobjects.length; i++){ // 選択オブジェクトが属性の場合 if(selectobjects[i].constructor.name == "XMLAttribute"){ // 親の要素を選択に追加 selectobjects[i].parent.select(SelectionOptions.addTo); } } // 選択数表示 alert(app.activeDocument.selection.length + " 要素選択",scriptName); //スクリプト動作指定(高速)の続き },ScriptLanguage.JAVASCRIPT,[],UndoModes.FAST_ENTIRE_SCRIPT);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

indesign スクリプト 構造の要素の属性名から属性を選択

構造の要素の属性名から属性を選択するスクリプトはこれで良いのかな・・・? /* 構造の要素の属性名から属性を選択 更新 2021/04/30 */ // アプリ指定 #target "InDesign"; //スクリプト動作指定(高速) app.doScript(function(){ // スクリプト名 var scriptName = "構造の要素の属性名から属性を選択"; // 検索する構造の要素の属性名の入力(正規表現) var searchText = prompt("構造の要素の属性名(正規表現)","",scriptName); // キャンセルれた時の処理 if(searchText == null){exit();} // すべての選択を解除 app.activeDocument.selection = null; // 属性の要素の属性を選択する為の関数を呼び出し eraseAttribute(app.activeDocument.xmlElements,searchText); // 選択数表示 alert(app.activeDocument.selection.length +"属性選択",scriptName); // スクリプト動作指定(高速)の続き },ScriptLanguage.JAVASCRIPT,[],UndoModes.FAST_ENTIRE_SCRIPT); // 属性の要素の属性を選択する為の関数。引数(階層の要素、検索テキスト) function eraseAttribute(hierarchyElements,searchText){ // 要素の数だけ繰り返す for (var i = 0; i < hierarchyElements.length; i++) { // 要素に子要素が存在するか if(hierarchyElements[i].xmlElements.length > 0){ // 存在する場合再帰的処理 number = eraseAttribute(hierarchyElements[i].xmlElements,searchText); } // 属性の数だけ繰り返す for (var ii = 0; ii < hierarchyElements[i].xmlAttributes.length; ii++) { // 属性名を検索して引かかれば if(hierarchyElements[i].xmlAttributes[ii].name.match(searchText)){ // 選択に追加 hierarchyElements[i].xmlAttributes[ii].select(SelectionOptions.addTo); } } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Jest】名前付きインポートしたクラスとそのメソッドをそれぞれモック化する

例として@slack/webhookパッケージを使ってslackにメッセージを送るコードをテストする。 // IncomingWebhookクラスを名前付きインポートして import { IncomingWebhook } from '@slack/webhook'; const webHookUrl = 'https://hooks.slack.com/services/~' // 1. IncomingWebhookをインスタンス化して const webhook = new IncomingWebhook(webHookUrl); // 2. sendメソッドで通知を送る webhook.send({ text: 'メッセージ内容', }); 1,2をテストするために、名前付きインポートしたクラスとsendメソッドをそれぞれモック化する。 import { IncomingWebhook } from '@slack/webhook'; const mockSend = jest.fn(); jest.mock('@slack/webhook', () => ({ IncomingWebhook: jest.fn(() => ({ send: mockSend })), })); 下のようなマッチャでテストできる。 // IncomingWebhookが1回インスタンス化された expect(IncomingWebhook).toHaveBeenCalledTimes(1); // sendメソッドが1回実行された expect(mockSend).toHaveBeenCalledTimes(1); メソッドだけでいいなら sendメソッドだけモック化するなら下のようにも書ける import { IncomingWebhook } from '@slack/webhook'; const mockSend = jest .spyOn(IncomingWebhook.prototype, 'send') .mockImplementation();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Bittle(OpenCat)を動かしてみたときのメモ

はじめに クラファンでBittleをゲッツしたので、動かす際のコマンドをメモとしてまとめた。 要調査の部分はまだ試していないコマンドなので注意。 BittleとOpenCatについて Petoi社について(https://www.petoi.com/) Petoi Bittleのクラウドファンディングのページ IntroDuction(https://bittle.petoi.com/) OpenCat(https://github.com/PetoiCamp/OpenCat) 通信方法 基本はNyBoard(白いボード)にUART通信でコマンドを渡す。 TX/RXに結線し、ボードレートは115200bpsにする。(改行などは無し) コマンドの書き方 方向を伴わない動作系 k+[動作]でコマンドが決まる。 動作 コマンド 各サーボの角度をゼロにする(調整につかう) kzero おすわり ksit 挨拶 khi 見上げる klu お尻を上げる kbuttUp 腕立て伏せ(要調査) kpu 4足で立つ(バランス取り) kbalance 伏せ(サーボを緩める) krest マーキング kpee ステッピング(要調査) kvt 伸びる(要調査) kstr 見回す?(要調査) kck 方向を伴う動作系 k+[二文字コマンド]+[方向:F/B/L/R]で決まる。 動作 コマンド 歩く(walk) kwk[F/B/L/R] 駆け足(trot) ktr[F/B/L/R] 匍匐(crawl) kcr[F/B/L/R] 走る(run) krn[F/B/L/R] ジャンプ(bound)(要調査) 要調査
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue 3】コンポーネント間のデータの受渡しの基礎

1. はじめに   1-1. はじめに Vueのコンポーネント間のデータの受渡しが「親→子」「子→親」で異なり複雑です。 私の頭を整理するために、この記事を記載しています。 1-2. 説明の前に・・・ 説明で使用するプログラム ( x.html, x.js ) は、下記の.htmlファイルに記載する前提での説明です。 また、記載はVue3ですが、基本的にVue2でも同じ考え方です。 index.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://unpkg.com/vue@next"></script> <title>vue sample</title> </head> <body> <div id="app"> // ************************************** // ここにx.htmlを記載 // ************************************** </div> <script> // ************************************** // ここにx.jsを記載 // ************************************** </script> </body> </html> 2. コンポーネントの基礎 2-1. コンポーネントとは コンポーネントは「名前付きの再利用可能なインスタンス」です。 2-1.jsのようにコンポーネントを定義し、2-1.htmlで定義したコンポーネントを3つ使用しています。 コンポーネントが再利用され、3つのボタンが表示されます。 2-1.html <div id="app"> <Counter></Counter> <Counter></Counter> <Counter></Counter> </div> 2-1.js // アプリケーションの生成 const app = Vue.createApp({}) // コンポーネントを定義 (第一引数:コンポーネントの名前, 第二引数:コンポーネントオブジェクト) app.component('Counter',{ data() { return { count : 0 } }, template: ` <button v-on:click="count++"> コンポーネントだよ:{{count}} </button> ` }) // id="app" にマウント app.mount('#app') 2.2 グローバルコンポーネントとローカルコンポーネント コンポーネントには2種類あります。グローバルコンポーネントとローカルコンポーネントです。 グローバルコンポーネント アプリケーションのcomponentメソッドを利用します。 アプリケーション内のどのコンポーネントのテンプレートでも使用できます。 2-1で定義したコンポーネントもグローバルコンポーネントです。 実際はビルドの最適化を高めるために、ローカルコンポーネントで定義するほうが一般的です。    ローカルコンポーネント オブジェクトを定義して、componentsオプションで登録します。  componentsで登録したコンポーネント内でのみ使用できます。 以下の例は、ローカルコンポーネントChildをグローバルコンポーネントParentのcomponentsに登録しています。 Parentの中でのみChildが使用できるようになります。 この際、Parentを親コンポーネント(以降、親)、Childを子コンポーネント(以降、子)といいます。1 2-2.html <div id="app"> <Parent></Parent> </div> 2-2.js // アプリケーションの生成 const app = Vue.createApp({}) // ローカルコンポーネント+子コンポーネント // オブジェクトを定義 const Child = { template: ` <h2> Child ! </h2> ` } // グローバルコンポーネント+親コンポーネント app.component('Parent',{ // コンポーネントの登録をする components: { Child }, // 親コンポーネントの中で子コンポーネントは使用できる template: ` <h1> Parent ! </h1> <Child></Child> ` }) // id="app" にマウント app.mount('#app') 3. コンポーネント間のデータの受渡しの基礎 3-1. 親コンポーネントから子コンポーネントへのデータの受渡し 子にpropsオプションを定義します。親からデータを渡すときはhtmlの属性を使用するように渡すことができます。 基本的にVueでは親から子への単方向のデータフローです。 propsの定義の仕方を変えると、バリデーションも付けられます。 3-1.html <div id="app"> <Parent></Parent> </div> 3-1.js // アプリケーションの生成 const app = Vue.createApp({}) // 子コンポーネント const Child = { // 親から受け取るdataを定義 props:['parentData'], template: ` <h2> Child ! </h2> <h2> {{parentData}} </h2> ` } // 親コンポーネント app.component('Parent',{ components: { Child }, // htmlの属性のように記載してデータを渡す template: ` <h1> Parent ! </h1> <Child parentData="親コンポーネントから書き換え!"></Child> ` }) 3-2. 子コンポーネントから親コンポーネントへのデータの受渡し Vueは親から子への単方向データフローです。そのため、子から親へデータを受け渡すには少し工夫が必要です。 $emitを使用して、子から親のイベントを発火させます。 イベントで設定されたJavaScriptやメソッドを実行させ、その中で親のデータを変更します。 データの受取り方法は2種類あります。$eventを使用する方法とメソッドの第一引数で受け取る方法です。 3-2.html <div id="app"> <Parent></Parent> </div> 3-2.js const app = Vue.createApp({}) // 子コンポーネント const Child = { // $emitの第一引数はイベント名(childData)、第二引数は渡す値("親に渡すデータ")を定義 template: ` <button v-on:click='$emit("childData","親へ渡すデータ")'>親へデータ渡すボタン</button> ` } // 親コンポーネント app.component('Parent',{ data() { return { eventData: '', // $eventで渡したデータを格納 methodData: '', // メソッドで渡したデータを格納 } }, components: { Child }, // $eventを使用する方法とメソッドで渡す方法がある template: ` <h1> Parent ! </h1> <h3>1. $eventを使用する方法</h3> <Child v-on:childData="eventData = $event"></Child> eventData : {{eventData}} <h3>2. メソッドで渡す方法</h3> <Child v-on:childData="changeParentData"></Child> methodData : {{methodData}} `, methods: { // methodの第一引数としてデータが渡される changeParentData(event) { this.methodData = event } } }) // id="app" にマウント app.mount('#app') 4. おわりに 最後まで読んでいただきありがとうございました。今回の記事のポイントは以下です。 Vueは親コンポーネントから子コンポーネントへの単一方向のデータフローである。 親→子:子でpropsを用いてデータを受け取る。 子→親:子にて$emitを使用してイベントを起動。親にて$eventやメソッドでデータを受け取る。 記載の誤りや、文字の揺らぎがあるかもしれません。ご指摘がありましたらコメントいただけると幸いです。 詳細が知りたい方や、より正確な情報を知りたい方は参考URL(Vue3公式ページ)を参照してください。 参考URL 親はグローバルコンポーネント、子はローカルコンポーネントというルールはありません。componentsオプションを定義しているのが親、定義に使用されているのが子です。  ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue 3】コンポーネント間のデータの受渡し【基礎】

1. はじめに   1-1. はじめに Vueのコンポーネント間のデータの受渡しが「親→子」「子→親」で異なり複雑です。 私の頭を整理するために、この記事を記載しています。 1-2. 説明の前に・・・ 説明で使用するプログラム ( x.html, x.js ) は、下記の.htmlファイルに記載する前提での説明です。 また、記載はVue3ですが、基本的にVue2でも同じ考え方です。 index.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="https://unpkg.com/vue@next"></script> <title>vue sample</title> </head> <body> <div id="app"> // ************************************** // ここにx.htmlを記載 // ************************************** </div> <script> // ************************************** // ここにx.jsを記載 // ************************************** </script> </body> </html> 2. コンポーネントの基礎 2-1. コンポーネントとは コンポーネントは「名前付きの再利用可能なインスタンス」です。 2-1.jsのようにコンポーネントを定義し、2-1.htmlで定義したコンポーネントを3つ使用しています。 コンポーネントが再利用され、3つのボタンが表示されます。 2-1.html <div id="app"> <Counter></Counter> <Counter></Counter> <Counter></Counter> </div> 2-1.js // アプリケーションの生成 const app = Vue.createApp({}) // コンポーネントを定義 (第一引数:コンポーネントの名前, 第二引数:コンポーネントオブジェクト) app.component('Counter',{ data() { return { count : 0 } }, template: ` <button v-on:click="count++"> コンポーネントだよ:{{count}} </button> ` }) // id="app" にマウント app.mount('#app') 2.2 グローバルコンポーネントとローカルコンポーネント コンポーネントには2種類あります。グローバルコンポーネントとローカルコンポーネントです。 グローバルコンポーネント アプリケーションのcomponentメソッドを利用します。 アプリケーション内のどのコンポーネントのテンプレートでも使用できます。 2-1で定義したコンポーネントもグローバルコンポーネントです。 実際はビルドの最適化を高めるために、ローカルコンポーネントで定義するほうが一般的です。    ローカルコンポーネント オブジェクトを定義して、componentsオプションで登録します。  componentsで登録したコンポーネント内でのみ使用できます。 以下の例は、ローカルコンポーネントChildをグローバルコンポーネントParentのcomponentsに登録しています。 Parentの中でのみChildが使用できるようになります。 この際、Parentを親コンポーネント(以降、親)、Childを子コンポーネント(以降、子)といいます。1 2-2.html <div id="app"> <Parent></Parent> </div> 2-2.js // アプリケーションの生成 const app = Vue.createApp({}) // ローカルコンポーネント+子コンポーネント // オブジェクトを定義 const Child = { template: ` <h2> Child ! </h2> ` } // グローバルコンポーネント+親コンポーネント app.component('Parent',{ // コンポーネントの登録をする components: { Child }, // 親コンポーネントの中で子コンポーネントは使用できる template: ` <h1> Parent ! </h1> <Child></Child> ` }) // id="app" にマウント app.mount('#app') 3. コンポーネント間のデータの受渡しの基礎 3-1. 親コンポーネントから子コンポーネントへのデータの受渡し 子にpropsオプションを定義します。親からデータを渡すときはhtmlの属性を使用するように渡すことができます。 基本的にVueでは親から子への単方向のデータフローです。 propsの定義の仕方を変えると、バリデーションも付けられます。 3-1.html <div id="app"> <Parent></Parent> </div> 3-1.js // アプリケーションの生成 const app = Vue.createApp({}) // 子コンポーネント const Child = { // 親から受け取るdataを定義 props:['parentData'], template: ` <h2> Child ! </h2> <h2> {{parentData}} </h2> ` } // 親コンポーネント app.component('Parent',{ components: { Child }, // htmlの属性のように記載してデータを渡す template: ` <h1> Parent ! </h1> <Child parentData="親コンポーネントから書き換え!"></Child> ` }) 3-2. 子コンポーネントから親コンポーネントへのデータの受渡し Vueは親から子への単方向データフローです。そのため、子から親へデータを受け渡すには少し工夫が必要です。 $emitを使用して、子から親のイベントを発火させます。 イベントで設定されたJavaScriptやメソッドを実行させ、その中で親のデータを変更します。 データの受取り方法は2種類あります。$eventを使用する方法とメソッドの第一引数で受け取る方法です。 3-2.html <div id="app"> <Parent></Parent> </div> 3-2.js const app = Vue.createApp({}) // 子コンポーネント const Child = { // $emitの第一引数はイベント名(childData)、第二引数は渡す値("親に渡すデータ")を定義 template: ` <button v-on:click='$emit("childData","親へ渡すデータ")'>親へデータ渡すボタン</button> ` } // 親コンポーネント app.component('Parent',{ data() { return { eventData: '', // $eventで渡したデータを格納 methodData: '', // メソッドで渡したデータを格納 } }, components: { Child }, // $eventを使用する方法とメソッドで渡す方法がある template: ` <h1> Parent ! </h1> <h3>1. $eventを使用する方法</h3> <Child v-on:childData="eventData = $event"></Child> eventData : {{eventData}} <h3>2. メソッドで渡す方法</h3> <Child v-on:childData="changeParentData"></Child> methodData : {{methodData}} `, methods: { // methodの第一引数としてデータが渡される changeParentData(event) { this.methodData = event } } }) // id="app" にマウント app.mount('#app') 4. おわりに 最後まで読んでいただきありがとうございました。今回の記事のポイントは以下です。 Vueは親コンポーネントから子コンポーネントへの単一方向のデータフローである。 親→子:子でpropsを用いてデータを受け取る。 子→親:子にて$emitを使用してイベントを起動。親にて$eventやメソッドでデータを受け取る。 記載の誤りや、文字の揺らぎがあるかもしれません。ご指摘がありましたらコメントいただけると幸いです。 詳細が知りたい方や、より正確な情報を知りたい方は参考URL(Vue3公式ページ)を参照してください。 参考URL 親はグローバルコンポーネント、子はローカルコンポーネントというルールはありません。componentsオプションを定義しているのが親、定義に使用されているのが子です。  ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript: 軽量、無依存で、画面上で小窓たちを扱えるWinBox.js

WinBox.js モダンなWeb用ウィンドウマネージャ:軽量、優れたパフォーマンス、依存関係なし、完全にカスタマイズ可能、オープンソース (公式説明をDeepL翻訳) だというWinBoxというjs、まだ若いもののようだが触ってみた。 GitHub: https://github.com/nextapps-de/winbox 例えばURLセットして開くならこれだけ。 var winbox = new WinBox("Custom Color and Open URL"); winbox.setBackground("#ff005d"); winbox.setUrl("https://e99h2121.github.io/") こんな雑なこともできる。 var winbox = new WinBox("Custom Color and Open URL"); winbox.setBackground("#ff005d"); winbox.body.innerHTML = "<h1>HTMLを入れられる。</h1><h2>世の中には、</h2><h3>便利なものを作る人がいますね..</h3>"; See the Pen GRrzXoo by kachibito (@kachibito) on CodePen. See the Pen Trying Winbox by YAMADA Nobuko (@e99h2121) on CodePen. 参考記事 見栄えが超簡単に楽しくなった。 以上簡単なメモですが参考になればさいわいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React入門 - Tips1 - アロー関数

目次 概要 アローとは、英語でarrow。つまり矢印ですね。 これまでのfunctionの書き方とのメリデメについては言及しません。。 これまでの書き方は、下記の1と2みたいな感じでしょうか。 // function書き方1 function test(x) { return x + 1; } // function書き方2 const test = function(x) { return x + 1; } アロー関数での書き方 // arrow function 引数なし (かっこがいる) const test = () => 1; // 出力の式が一行の場合はreturnは不要 // arrow function 引数1つ (かっこいらない) const test = x => x + 1; // arrow function 引数2つ以上 (かっこいる) const test = (x, y) => x + y + 1; まとめ 先頭で変数を定義する(const(定数)かlet(変数)) () => {} の形で書く 引数が1つなら()も不要 (引数0なら()は必要) 出力が1行なら{}も不要 出力が1行ならreturnも不要
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「#安倍やめろ」「#〇〇に反対します」など意味のわからないTwitterトレンドを綺麗にするスクリプト

夜になると #安倍やめろ #〇〇法案に反対します #東京五輪の中止を求めます などの政治的な発言をハッシュタグに付けてトレンドに入れる遊びをしている方々がたくさんいて非常にうざい。 個人的にはわざわざTwitterのトレンドを見に行くようなことはしないが、サイドに出てくるのはどうしても目に入ってきてしまうので、こいつらを非表示にしていきます。 ハッシュタグのパターン いくつかのユーザーを調べてみた結果、 #〇〇〇〇〇〇ます ってパターンのハッシュタグを消せば8割方いけそう。 「#」から始まって、「ます」で終わる文字列を正規表現にするとこんな感じ。 /^#.+ます$/ const ngList = [ /^#.+ます$/, '#安倍やめろ', 'オリンピック', ]; 後からでも追加できるように配列形式にしました。 TwitterのDOM取得 idやclassに振られている名前はデプロイ時に生成されている系っぽく簡単に変わってしまいそうなので、 一番変更が少なそうな aria-label を使わせてもらいます。 アクセシビリティに配慮しているページはこういうときにも便利 document.querySelectorAll('[aria-label="タイムライン: トレンド"] > div > div') 目当ての要素を探しだした後、最初は element.remove(); でDOMごと削除してしまったら、モジュールの更新時にエラーになってしまったので、 element.style.display = 'none'; という感じで非表示対応にしました。 完成形 removeTrend.js (() => { const ngList = [ /^#.+ます$/, '#安倍やめろ', 'オリンピック', ]; setInterval(() => { document.querySelectorAll('[aria-label="タイムライン: トレンド"] > div > div').forEach((element) => { const tag = element.querySelector('[dir="ltr"]'); if (!tag) { return; } ngList.forEach((ng) => { if (tag.textContent.match(ng)) { element.style.display = 'none'; } }); }); }, 500); })(); ちゃんと消えた。 Chrome Extension 化 Google Chromeの機能拡張として読み込ませる。 manifest.json を作成して chrome://extensions のページから追加します。 manifest.json { "manifest_version": 2, "name": "remove trend", "version": "1.0", "description": "my extension", "icons": { "86": "images/icon.png" }, "content_scripts": [ { "matches": [ "https://twitter.com/*" ], "js": [ "removeTrend.js" ] } ] } これで twitter.com を開いたときに常にスクリプトが実行されるようになります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

react-sortablejs(v6.0.0)で MultiDrag が上手く読み込めなかった日に

Sortablejs すき Sortablejs (npm) という JS のライブラリがあります。名前の通り単純に要素を Drag/Drop でソートできるようにするものです。なんと、これ単体でも、jQuery や Vue、React といったライブラリと組み合わせてもいい感じに動いてくれます。かわいい!さらに複数の要素を選択して一気に移動させたりすることもできます。No MultiDrag, No Life な諸兄もにっこりですよね。 課題:React 用の sortablejs で複数要素を選択するサンプルが動かない 複数の要素を選択して一気に移動させる機能はすごく便利で使っていきたいのですが、React 用の Sortablejs (react-sortablejs (npm)) の現時点での最新版 6.0.0 に書かれているサンプルをそのまま書いても上手く動いてくれません。 手元で動かそうとしても MultiDrag はコンストラクタではない、と怒られている React のエラー画面が出力されます。 なんでうごかないのか 意図して export から外してました react-sortablejs の v6.0.0 に含まれている#181で export から MultiDrag と Swap が外されています。 これが原因で上述の import がそもそもできていなかったようです。そのため、import できていないコンストラクタをコンストラクタとして使おうとしたから怒られたようです。 どうして export から外したの? 変更のコミットを読む限りでは react-sortablejs ではなく Sortablejs の 1.12.x に MultiDrag に後方互換性のない変更が含まれているから、とのことです。この事情は [bug] Attempted import error: 'MultiDrag' is not exported from 'sortablejs' #179で話されており、react-sortablejs のバージョンが 5.0.5 で Sortablejs が 1.10.1 または 1.10.2 ならば問題なく動いたとのことでした。 問題が含まれる Sortablejs のバージョンについて詳細は正直わかりませんでした。正常に動いている Sortablejs 1.10.2 の次のバージョン、つまり動かなかったと目されるバージョンである 1.11.0 から 1.12.0 について GitHub からソースコードを取得することができなかったからです。npm掲載の情報によると 1.11.x および 1.12.0 は 1.10.2 にロールバックされたとのことです。 この記事を書いている時点での Sortablejs の最新版は 2021年1月8日に出た 1.13.0 となっています。しかし、1.13.0 と 1.10.2 の差分を見ると1.11.x や 1.12.0 が出た9月頃のコミットが全然なく、2020年5月24日の次のコミットが2020年12月30日と若干不自然なものになっていることからも上述のことがわかるかと思います。 どうしたら動くかな 動く組み合わせで動かす 上述の通りreact-sortablejs のバージョンが 5.0.5 で Sortablejs が 1.10.1 または 1.10.2 ならば問題なく動いたとのことなのでこのバージョンで動かすのは一案でしょう。2020年9月27日に公開された v6.0.0 の情報を見る限りは react-sortablejs のバージョンが 5.0.5 であることによって大きな問題は起こらないように見えます。 最新版を試す [bug] ReactSortable MultiDrag/Swap is not a constructor #143 で紹介されているように上述のサンプルコードの import 部分をちょっと修正すれば react-sortablejs v6.0.0 と Sortablejs 1.13.0 の組み合わせでも動かすことができます。 すなわち以下の修正をおこなう、ということです。 // Before import { ReactSortable, Sortable, MultiDrag, Swap } from "react-sortablejs"; // After import { ReactSortable } from "react-sortablejs"; import { Sortable, MultiDrag, Swap} from "sortablejs"; 実際、私の手元ではreact-sortablejs v6.0.0 と Sortablejs 1.13.0 の組み合わせと上述の修正によって動かすことができました。1.11.x および 1.12.0 で問題を起こしていた修正がどんなものなのかわかりませんが、1.13.0 と 1.10.2 の差分を見る限りはそこについて問題を引き起こすような修正には私には見えませんでした。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript基礎メモその7

コールバック関数 引数に渡される関数をコールバック関数と呼ぶ。 // 関数が引数に代入される const call = (引数名) => { //処理 }; //関数を引数に渡す call(関数名); const kayakuko = () => { // }; // 関数kayakukoが代入される const call = (callback) => { // 処理 }; call(kayakuko); // 関数kayakukoを引数に渡す const kayakuko = => { console.log("kayakuko"); }; // ② kayakukoをcallbackに代入 const call = (callback) => { console.log("コールバック関数を呼び出す"); callback(); // ③ 関数callbackを呼び出す ]; call(kayakuko); // ① 引数にkayakukoを渡し、関数callを呼び出す 結果 コールバック関数を呼び出す kayakuko コールバック関数を直接定義する 関数を直接引数の中で定義することもできる。 // ② 関数をcallbackに代入 const call = (callback) => { console.log("コールバック関数を呼び出す"); callback(); }; call(() => { console.log("kayakuko"); }); // ① 引数で関数を定義して関数callを呼び出す 結果 コールバック関数を呼び出す kayakuko コールバック関数に引数を渡す const introduce = (callback) => { callback("kayakuko"); }; introduce((name) => { console.log(name); }); 結果 kayakuko
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む