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

eslintを実行した際に発生する'module' is not definedのエラーの消し方

トラブルの内容 eslintを実行したときに'module' is not definedと表示されてしまうが、このエラーの直し方がわからない。 作業環境 Mac OS VS Code node v12.15.0 npm 6.14.8 eslint 6.14.8 トラブルの発生状況 初めてeslintを使うというレベルのユーザが対象です。 eslintをWebを見ながら設定をしていき、いざeslintを実行をします。 // eslintの実行 ./node_modules/.bin/eslint *.js すると、以下のエラーが表示されます。 /Users/[ユーザー名]/[作業ディレクトリ]/.eslintrc.js 1:1 error 'module' is not defined no-undef ✖ 1 problem (1 error, 0 warnings) これは、eslintrc.jsの1行目に書かれているmodule.exports = {の部分でエラーが発生しています。 解決方法 .eslintrc.jsのファイルを以下のように変更すれば解決します。 [-]の行を削除して、[+]の行を追加して下さい。 module.exports = { env: { browser: true, [-] es2021: true [+] es2021: true, [+] node: true, }, extends: "eslint:recommended", parserOptions: { ecmaVersion: 12, sourceType: "module", }, rules: {}, }; 再度、eslintを実行して、エラーが表示されないことを確認します。 以上です。 その他 別のコマンドでeslintを実行する方法 以下のコマンドでもeslintを実行できます。 npm run lint ただし、このコマンドでeslintを実行させるためには、packeage.jsonを以下のように編集する必要があります。 {  〜省略〜 "scripts": { [-] "test": "echo \"Error: no test specified\" && exit 1" [+] "test": "echo \"Error: no test specified\" && exit 1", [+] "lint": "eslint *.js" }, 〜省略〜 } 参考サイト https://www.webprofessional.jp/up-and-running-with-eslint-the-pluggable-javascript-linter/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Indesign スクリプト XML 構造の要素名から要素を選択する

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

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

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

Lwcでその日訪問予定の取引先をマップに表示する

営業支援ツールに関しては、標準オブジェクトでほとんど事足りるsalesforce。 さらに、その日訪問予定の顧客取得し、地図上にマッピングして... あれ、ホントにこの機能って必要なのかな。 営業したことないから分かりかねますが、 これができれば「LWCで任意の関連レコードとってきて表示させる」 という汎用的な機能のベースになると思って頑張ります。 コードについては株式会社テラスカイ様の 「TerraSkyBase ~テラスカイを支える人とテクノロジーの情報を発信する基地局~」 を参考に(ほぼ拝借して)そこに付け加える形で作成していきます。 アジェンダ 概要 ApexClassでレコードを取得 HTML JavaScript js-meta.xml 今後の課題 概要 やりたいことととしては冒頭でも触れている通り、 「今日訪問予定の顧客情報を地図へマッピングしたい」です。 ユーザ目線では、 カレンダーに予定を作成すると マップに表示されるようになります。 より具体的に説明すると、「行動(Event)オブジェクトの開始日(startDateTime)項目が“今日の日付と一致する”レコードの 関連先(What)項目に紐づいている取引先(Account)レコードの情報を取得し、地図コンポーネントを使用して googleMap上に取得した顧客の住所にピンを打つこと」が今回の目的です。 ApexClassでレコード取得 はじめにApexClassのなかでSOQLを使用し、必要なレコードを取得します。 関連レコードの取得方法を調べるといろいろ出てきますが、下記のコードを参考にしてください。 pubulic with sharing class getTodayAcc @auraEnabled(cacheable=true) public static List<Event> getAcc(){ return[ SELECT AccountId, Account.Name, Account.BillingCountry, Account.BillingState, Account.BillingCity, Account.BillingStreet, Account.Description ​//カスタム項目の場合は、下記のように項目名__cと記述してください。 //Account.Prefecture__c,Account.City__c FROM Event WHERE StartDateTime = Today and What.Type IN ('Account') ORDER BY StartDateTime ]; } } HTML 次にHTMLを記述します。 テラスカイ様のコードに加えて「zoom-level={zoomLevel}」を記述します。 タグの属性と仕様についてはこちら <template> <lightning-map map-markers={mapMarkers} selected-marker-value={selectedMarkerValue} markers-title="Today's account list" onmarkerselect={handleMarkerSelect} zoom-level={zoomLevel} list-view="auto"> </lightning-map> </template> Javascript こちらもベースのコードはテラスカイ様より拝借。 加えてHTMLに記述したzoom-levelを指定します。 今日の訪問予定が一件の場合、zoom-levelが未指定だと、マッピング時に自動的に最大ズームされてしまいます。 なので、訪問予定一件(=Eventから取得したレコードが一件)のとき、Zoom-levelを任意の値にセットします。 import { LightningElement, track, wire } from 'lwc'; // getAccounts メソッドのインポート import getAccounts from '@salesforce/apex/LightningMapExampleController.getAccounts'; export default class LightningMapExample extends LightningElement { // 表示するマーカーのリスト @track mapMarkers=[]; // 選択しているマーカーの値 @track selectedMarkerValue; // 取引先を取得して表示するマーカーを作成 @wire(getAccounts, {}) wiredAccounts({ data }) { if (data) { var markers = []; for(var i = 0; i < data.length; i++){ var acc = data[i]; markers.push({ location: { Country : acc.Account.BillingCountry, State : acc.Account.BillingState, City: acc.Account.BillingCity, Street: acc.Account.BillingStreet }, icon : "standard:account", //selectedMarkerValueへ設定される value: acc.AccountId, //マーカークリック時に表示される情報 title: acc.Account.Name, description: acc.Description }); } //取得した顧客情報レコードが一つのとき、zoom-Levelを指定します。 if(data.length == 1){ this.zoomLevel = 13; } this.mapMarkers = markers; } } ![Something went wrong]() // マーカー選択時のアクション handleMarkerSelect(event) { console.log(event.target.selectedMarkerValue); } } js-meta.xml 最後にメタデータを設定します。 isExposedはデフォルトではFalseですが、Trueにしないとカスタムコンポーネントとして使用できません。(編集画面に表示されません) Tragetで、使用するアプリケーションページを指定します。 <?xml version="1.0" encoding="UTF-8"?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>51.0</apiVersion> <isExposed>true</isExposed> <targets> <target>lightning__AppPage</target> <target>lightning__RecordPage</target> <target>lightning__HomePage</target> </targets> </LightningComponentBundle> 今後の課題 ① レンダリング  皆様お気づきかと思いますが、カレンダーへ予定を作成後、タブを切り替えただけでは  その予定に紐づく顧客が表示されません。毎回ページの再読み込みを手動で行うのは  イケていませんね!   ② 条件をいろいろ選べるようにしたい  といいますのも、きっと一週間以上訪問していない顧客や、売上が高い顧客など、  何かしら目的をもって訪問すると思いますので、そういった条件でも絞り込めると  より使いこなしてくれるのではないでしょうか。知らんけど。 ③ 自分の現在位置   これは言わずもがなですね。すぐに実装できるよう引き続き勉強します。 次回は上記の課題に対する記事を書く予定です!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TwitterのAPIでハッシュタグ作成ツールを作ってみた

【今回作ったサービス:ハシュクリ】 https://hashcre-41b10.web.app/ 【開発環境】 デプロイ先(フロントエンド):Firebase デプロイ先(バックエンド):heroku フロントエンド言語:JavaScript , nuxt.js , vuetify バックエンド言語:python 【なぜ作ったか】 エンジニアとして、自分の活動を広めるためにTwitterを始めた。 投稿でハッシュタグを選ぶときに同じようなハッシュタグが煩雑していると思い、 どれを選ぶべきなのか、どれが一番使用されているのか表示できれば、 ハッシュタグを選びやすくなるのではないかと思った。 【アプリの仕様】 ◆タグ検索について TwitterAPIで入力されたキーワードが含まれるツイートの中で 使用されているハッシュタグを検索する。 ◆ハッシュタグの使用頻度表示 yahooのリアルタイム検索をスクレイピングし、 各ハッシュタグの使用頻度取得する。 【作った感想】 スクレイピングを実施すると、処理時間が極端にかかり、使用感に影響が出る。 やはり、webサービスとしては、ボタンをクリックしてから数秒でレスポンスがないと、使用感が悪くなるため、レスポンス速度にはこだわった。 スクレイピングは、ボタンをクリックしてから実行されるのではなく、常時裏で実行し、結果をDBに登録する。 ボタンクリック時には結果のみ表示することでレスポンス速度を改善した。 また、個人開発ではサーバレンタルすると運用費が気にかかってしまうため、 無料のheroku,firebaseを使用することでサーバ代を無料にした。 リリースしたばかりだが、誰かに使ってもらえることを期待し、サービスを向上させていきたいと思う。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【備忘録】JavaScriptの変数について

let,constとvarについて データ型について 暗黙的な型変換について 暗黙的な型変換とは変数がよばれた状況によって変数の方が自動的に変換されること。 JavaScriptは動的型付け言語であり、変数宣言時の型の宣言がなく、変数を使用する状況によって、変数の型が変更される。 静的型付け言語は変数宣言時の方の宣言があり、変数を使用する状況によらず、常に同じ方を保持する。 let a = 0; let b = "1" + a;//bはString型で10になる let c = 15 - b;//cはnumber型で5になる let d = c - null;//dはnumber型で5になる let e = d - true;//eはnumber型で4になる 厳格な等価性と抽象的な等価性について a === b//型の比較も行われる a == b//型の比較は行われない
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptの基礎

JavaScriptとは JavaScriptは、Webサイトに「動き」をつけるプログラミング言語です。「JavaScript」を略して使いたいときは「js」といいましょう。 ここでは「js」と略していきたいと思います。この記事ではJavaScriptを理解するために押さえておくべき単語についてまとめていきます。 変数 jsにおける「変数」とは「箱」のようなものです。 例)私はワタルと言います。ワタルはサッカーが好きです。ワタルのポジションはフォワードです。 このような文章があったとする場合、上司からこの『ワタル』の名前を『ケンタ』に変えといてと言われたとします。 この時便利なのが変数です。変数をnameとしてこのnameに当てたい名前(ここではケンタ)を入れればいいだけです。 js上でのコメント 「コメント」はプログラムとして実行されないので、書いたコードの説明、メモに使えます。 // これで一行コメントをかけます。 複数行コメントの書き方 /* コメント コメント コメント */ データ型 データ型とは数値、文字列、配列、論理値、オブジェクトなどです。ここでは特に重要な文字列と数値について触れていきます。 文字列(string型) jsでは、文字列をダブルクォーテーション(”)またはシングルクォーテーション(’)で囲んで表現します。 そのため変数の中に文字列を入れたい場合は以下の記述をします。 let cat = "ねこ";//これはOK let cat = ねこ; //これはNG 数値(number型) 数値を入れたい場合はそのまま書いてOKです。 数値をクォーテーションでくくってしまうと、文字列として扱われてしまうので注意してください。 let num = 1; //これはOK let num = "1"; //これは文字列の1として扱われる これは文字列と数値をわかりやすくしたコードです console.log(10 + 20); console.log("15" + "25"); 10 + 20は「 30 」と表示されて “10” + “20”は「 1020 」と表示されます。 配列 簡単に言うとデータ型の複数版です。配列データを作成することで大量の値をまとめて1つのデータとして扱うことができるのです。またその値の一つ一つの要素をインデックス=住所(添字)と呼んだりします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[baserCMS]公開側をdefer属性に対応させるお手軽な手法

公開側でのdefer属性、よく見かけるようになってきたので、baserCMSの bc_sample テーマで用いた場合にどうなるのか調べてみました。 defer属性についてはこちら。 https://developer.mozilla.org/ja/docs/Web/HTML/Element/script#attr-defer 通常、HTML読込み → js読込み&実行 となるところ、defer属性を付与することで、 js読込みを非同期に行い、HTML読込み中にjsも読込み、実行自体はHTML読込み完了時に行わせる手法です。 <script src="jquery.min.js"></script>              ↓ ↓ ↓ <script src="jquery.min.js" defer="defer"></script> メリットとしては、以下の点が挙げられます。 実装が簡単 読込みが非同期となることで高速化が期待できる 読込みは非同期でも、実行順序は記述順序となる 想定している対象者 baserCMSでウェブサイトを制作をしている方 HTMLコーディングを主とするフロントエンジニア PHPer やってみた js読込み箇所は以下。 app/webroot/theme/bc_sample/Layouts/default.php のhead内。 <?php $this->BcBaser->js([ 'jquery-1.11.3.min', 'jquery-ui-1.11.4.min', 'jquery.bxslider-4.12.min', 'jquery.colorbox-1.6.1.min', 'i18n/ui.datepicker-ja', 'jquery-accessibleMegaMenu', 'startup' ], false,['defer' => 'defer']); ?> これによる影響発生を確認できたのは以下。 Chromeとかのdeveloper toolでエラーが出ていることを確認できます。 ログイン中に公開側に表示されるツールバーのメニューを開く動作が効かなくなる メールフォームで、入力後の確認画面から入力画面に戻れず送信される動作となる 環境 PHP 5.6.40 baserCMS 4.4.6 原因 defer属性が付与されているjs(この場合はjQueryが該当)の読込みは完了してますが、実行はまだです。 一方、管理ツールバーで利用されているjQuery依存のjsにはdefer属性ナシ、 また、メールフォームで利用されているjQuery依存のjsはhtml内に記述されていることで、 jQueryが未実行でも読込み後に実行されていることで正しく動作しない状態になっていることがうかがえます。 対処(※暫定策) というところで、どうやったら改善できるか試してみたのが以下です。 公開側に表示されるツールバーのメニューを開く動作 管理ツールバー用のjsにdefer属性付与。 ■ admin-second lib/Baser/View/Elements/admin/toolbar.php をオーバーライド機構を利用します。 利用中のテーマ内にファイルをコピー -> app/webroot/theme/bc_sample/Elements/admin/toolbar.php $this->BcBaser->js(['admin/vendors/outerClick', 'admin/vendors/jquery.fixedMenu', 'admin/toolbar']); $this->BcBaser->js(['admin/vendors/outerClick', 'admin/vendors/jquery.fixedMenu', 'admin/toolbar'], true, ['defer' => 'defer']); ■ admin-third app/webroot/theme/admin-third/Elements/admin/toolbar.php $this->BcBaser->js(['admin/vendors/outerClick', 'admin/vendors/jquery.fixedMenu', 'admin/toolbar']); メールフォームで、入力後の確認画面から入力画面に戻れず送信される動作となる ポイントとしては、defer属性は「DOMContentLoaded が発生する前に実行することをブラウザーに示します。」なので、 動かしたいスクリプトに対して、jQueryのdeferが完了していることを見越したタイミングにしてやれば良さ気ということです。 ■ app/webroot/theme/bc_sample/Elements/mail_form.php <script type="text/javascript"> window.addEventListener('DOMContentLoaded', function() { $(function(){ $(".form-submit").click(function(){ var mode = $(this).attr('id').replace('BtnMessage', ''); $("#MailMessageMode").val(mode); return true; }); }); }); </script> ■ lib/Baser/Plugin/Mail/View/Elements/mail_token.php をコピー   -> app/webroot/theme/bc_sample/Elements/mail_token.php <script type="text/javascript"> window.addEventListener('DOMContentLoaded', function() { $(function(){ $('input[type="submit"]').prop('disabled', true); }); }); <?php if($this->request->is('ajax')): ?> window.addEventListener('DOMContentLoaded', function() { $(function(){ <?php else: ?> window.addEventListener('DOMContentLoaded', function() { $(window).on('load', function() { <?php endif ?> let getTokenUrl = '<?php echo $this->BcBaser->getUrl('/bc_form/ajax_get_token?requestview=false') ?>'; $.ajaxSetup({cache: false}); $.get(getTokenUrl, function(result) { $('input[name="data[_Token][key]"]').val(result); $('input[type="submit"]').removeAttr('disabled'); }); }); }); </script> 手法について 暫定策なので、コア側での正式なdefer属性対応方針が定まったらそちらの手法にしましょう。 もしくはもうちょっと良い手法が出てくると良いですね。 参考記事 https://developer.mozilla.org/ja/docs/Web/HTML/Element/script#attr-defer https://developer.mozilla.org/ja/docs/Web/API/Window/DOMContentLoaded_event https://qiita.com/phanect/items/82c85ea4b8f9c373d684
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今流行りのjavascriptフレームワークのVue.jsとは

Vue.jsとは Evan You氏の個人プロジェクト 2014年にリリースされた比較的新しいフレームワーク 2015年にはPHPフレームワークのLaravelのフロントエンジンとして採用され、知名度が上がった 2016年後半にリリースされたバージョンでは仮想DOMを採用したことにより、レンダリングパフォーマンスを向上させた Adobeや任天堂、LINEやGitLabで使われている なぜVue.jsなのか 学習コストの低さ スケールの柔軟性 公式ドキュメントの充実 が多くの人々に支持されているのではないかと思われる 導入のしやすさと学習コストの低さ Vue.jsは必ずしもwebpackなどのハンドルツールやコンパイルを必要としていない ファイルを1つ読み込むだけですぐにコードを書き始めることができる スケールの柔軟性 Vue.js本体はviewに関わる面倒な処理を人間に代わって管理することが仕事 スクリプトタグで読み込むスタンドアロン版を使用してページの一部だけをインタラクティブ化するなど、小さな要件に気軽に導入できる 拡張機能や開発サポートツールも数多く提供されていてシングルページアプリケーションのような大きなプロジェクトにも対応できるフレームワークとして注目されている ドキュメントの充実 Vue.js本体のドキュメントではなく、スタイルガイドやエコシステムといった公式ドキュメントの多くが日本語に翻訳されている Vue.js日本ユーザーグループによってサポートされている 総括 普段はサーバーサイドを担当してますが、ふとしたきっかけでフロントエンドを学びたいと思って今流行りのVue.jsに手を出してみました。確かに理解しやすさと運用のしやすさは中々良いと思っています。 javascriptのフレームワークはVue.jsが初めてなので他のフレームワークとの比較はできませんが、これだけ見ると運用コストも高くないように思えます。 参考文献 改訂2版 基礎から学ぶVue.js [2.x対応! ] Vue.js: The Documentary
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript の同期処理を非同期処理にしたい

TL;DR Web Worker / Worker Threads を使え 目的 重い同期処理を非同期処理したい。 「setTimeout でもできる気がするけど、なぜダメなんだっけ?」と思ったので、サンプルコードで直感的に理解を試みる。 環境 $ sw_vers ProductName: macOS ProductVersion: 11.2.3 BuildVersion: 20D91 $ sysctl machdep.cpu.brand_string machdep.cpu.brand_string: Intel(R) Core(TM) i5-8257U CPU @ 1.40GHz $ node -v v15.14.0 setTimeout で非同期化 code 雑だが、「同期処理」と「setTimeout で非同期化した処理」を実行し、その順番を確認するコードである。 const { performance } = require("perf_hooks") /** * 同期処理のパフォーマンス計測 */ const measure = (name, func) => { const start = performance.now() func() const end = performance.now() const elapsed = end - start const elapsedStr = elapsed.toPrecision(3) console.log(`* ${name}: ${elapsedStr} [ms]`) } /** * 非同期処理のパフォーマンス計測 */ const asyncMeasure = async (name, func) => { const start = performance.now() await func() const end = performance.now() const elapsed = end - start const elapsedStr = elapsed.toPrecision(3) console.log(`* awaited ${name}: ${elapsedStr} [ms]`) } /** * とても重い同期処理 */ const heavyProc = (fromName) => () => { console.log(`heavyProc (from ${fromName}) started ...`) for (let index = 0; index < 500_000_000; index++) { Math.random() * Math.random() } console.log(`heavyProc (from ${fromName}) done`) } /** * 軽い同期処理 */ const lightProc = (fromName) => () => { console.log(`lightProc (from ${fromName}) started ...`) for (let index = 0; index < 100; index++) { Math.random() * Math.random() } console.log(`lightProc (from ${fromName}) done`) } /** * とても重い同期処理を、 setTimeout で非同期化したもの */ const asyncHeavyProc = (fromName) => () => { return new Promise((resolve) => { setTimeout(() => { heavyProc(fromName)() resolve() }, 0) }) } /** * 軽い同期処理を、 setTimeout で非同期化したもの */ const asyncLightProc = (fromName) => () => { return new Promise((resolve) => { setTimeout(() => { lightProc(fromName)() resolve() }, 0) }) } /** * 同期処理がどういう順番で実行されるか確認する */ const main = (fromName) => { const name = `main (${fromName})` console.log(`--- ${name} started ...`) measure("heavyProc", heavyProc(`${name}`)) measure("asyncHeavyProc", asyncHeavyProc(`${name} > async`)) measure("lightProc", lightProc(`${name}`)) console.log(`--- ${name} done`) } /** * とても重い非同期処理がどういう順番で実行されるか確認する */ const aMainH = async (fromName) => { const name = `aMainH (${fromName})` console.log(`--- ${name} started ...`) await asyncMeasure("asyncHeavyProc", asyncHeavyProc(`${name}`)) console.log(`--- ${name} done`) } /** * 軽い非同期処理がどういう順番で実行されるか確認する */ const aMainL = async (fromName) => { const name = `aMainL (${fromName})` console.log(`--- ${name} started ...`) await asyncMeasure("asyncLightProc", asyncLightProc(`${name}`)) console.log(`--- ${name} done`) } main(1) main(2) aMainH(1) aMainL(1) 結果 $ node sync-to-async.js --- main (1) started ... heavyProc (from main (1)) started ... heavyProc (from main (1)) done * heavyProc: 8.67e+3 [ms] * asyncHeavyProc: 0.506 [ms] lightProc (from main (1)) started ... lightProc (from main (1)) done * lightProc: 0.139 [ms] --- main (1) done --- main (2) started ... heavyProc (from main (2)) started ... heavyProc (from main (2)) done * heavyProc: 8.41e+3 [ms] * asyncHeavyProc: 0.0163 [ms] lightProc (from main (2)) started ... lightProc (from main (2)) done * lightProc: 0.0516 [ms] --- main (2) done --- aMainH (1) started ... --- aMainL (1) started ... heavyProc (from main (1) > async) started ... heavyProc (from main (1) > async) done heavyProc (from main (2) > async) started ... heavyProc (from main (2) > async) done heavyProc (from aMainH (1)) started ... heavyProc (from aMainH (1)) done * awaited asyncHeavyProc: 2.47e+4 [ms] --- aMainH (1) done lightProc (from aMainL (1)) started ... lightProc (from aMainL (1)) done * awaited asyncLightProc: 2.47e+4 [ms] --- aMainL (1) done シーケンス図 図化してわかりやすくしてみる。 注意 厳密にはタスクキューやコールスタックを書いて表現すべきだが、「実行者から見たらどういう順番で処理が行われてるか」だけを表現した雑な図である。 実行待ちの間、 YouTube でうまぴょい見てたりしたので、計測時間は目安程度。 code PlantUML src @startuml title sequence diagram autonumber actor user participant "node.js" as nodejs participant "main (1)" as main1 participant "main (2)" as main2 participant "aMainH (1)" as aMainH1 participant "aMainL (1)" as aMainL1 participant "heavyProc" as heavyProc participant "lightProc" as lightProc participant "asyncHeavyProc" as asyncHeavyProc participant "asyncLightProc" as asyncLightProc user -> nodejs++: nodejs -> main1++: main (1) started ... main1 -> heavyProc++: heavyProc -> main1--: 8.67e+3 [ms] main1 -> asyncHeavyProc: asyncHeavyProc -> main1: 0.506 [ms] main1 -> lightProc++: lightProc -> main1--: 0.139 [ms] main1 -> nodejs--: main (1) end nodejs -> main2++: main (2) started ... main2 -> heavyProc++: heavyProc -> main2--: 8.41e+3 [ms] main2 -> asyncHeavyProc: asyncHeavyProc -> main2: 0.0163 [ms] main2 -> lightProc++: lightProc -> main2--: 0.0516 [ms] main2 -> nodejs--: main (2) end nodejs -> aMainH1++: aMainH (1) started ... nodejs -> aMainL1++: aMainL (1) started ... nodejs -> asyncHeavyProc++: heavyProc (from main (1) > async) started ... asyncHeavyProc -> nodejs--: heavyProc (from main (1) > async) done nodejs -> asyncHeavyProc++: heavyProc (from main (2) > async) started ... asyncHeavyProc -> nodejs--: heavyProc (from main (2) > async) done aMainH1 -> asyncHeavyProc++: heavyProc (from aMainH (1)) started ... asyncHeavyProc -> aMainH1--: heavyProc (from aMainH (1)) done aMainH1 -> nodejs--: aMainH (1) done 2.47e+4 [ms] aMainL1 -> asyncLightProc++: lightProc (from aMainL (1)) started ... asyncLightProc -> aMainL1--: lightProc (from aMainL (1)) done aMainL1 -> nodejs--: aMainL (1) done 2.47e+4 [ms] @enduml 見どころ 5 ~ 6 や 13 ~ 14 を見るに、確かに重い処理を 後回し できている。 19, 27 ~ 29 を見るに、軽い処理の完了までに 2.47e+4 [ms] (24.7 秒) も掛かっている。 つまり? 確かに setTimeout で同期処理を 後回し できる。 しかし、後回しされた各処理は順次実行されるだけ。 軽い非同期処理として実行・先に完了して欲しかった asyncLightProc が、重い同期処理 asyncHeavyProc の完了まで待たされている。 それでも Promise.all なら・・・Promise.all ならきっと並列実行 してくれない。 実行して確認してみる。 code const { performance } = require("perf_hooks") /** * 非同期処理のパフォーマンス計測 */ const asyncMeasure = async (name, func) => { const start = performance.now() await func() const end = performance.now() const elapsed = end - start const elapsedStr = elapsed.toPrecision(3) console.log(`* awaited ${name}: ${elapsedStr} [ms]`) } /** * とても重い同期処理 */ const heavyProc = (fromName) => () => { console.log(`heavyProc (from ${fromName}) started ...`) for (let index = 0; index < 500_000_000; index++) { Math.random() * Math.random() } console.log(`heavyProc (from ${fromName}) done`) } /** * 軽い同期処理 */ const lightProc = (fromName) => () => { console.log(`lightProc (from ${fromName}) started ...`) for (let index = 0; index < 100; index++) { Math.random() * Math.random() } console.log(`lightProc (from ${fromName}) done`) } /** * とても重い同期処理を、 setTimeout で非同期化したもの */ const asyncHeavyProc = (fromName) => () => { return new Promise((resolve) => { setTimeout(() => { heavyProc(fromName)() resolve() }, 0) }) } /** * 軽い同期処理を、 setTimeout で非同期化したもの */ const asyncLightProc = (fromName) => () => { return new Promise((resolve) => { setTimeout(() => { lightProc(fromName)() resolve() }, 0) }) } /** * 軽い非同期処理がどういう順番で実行されるか確認する */ const mainPromiseAll = () => { console.log("started ...") Promise.all([ asyncMeasure("H1", asyncHeavyProc("H1")), asyncMeasure("L1", asyncLightProc("L1")), asyncMeasure("H2", asyncHeavyProc("H2")), asyncMeasure("L2", asyncLightProc("L2")), ]) console.log("done") } mainPromiseAll() 結果 $ node sync-to-async-parallel.js started ... done heavyProc (from H1) started ... heavyProc (from H1) done * awaited H1: 8.93e+3 [ms] lightProc (from L1) started ... lightProc (from L1) done * awaited L1: 8.93e+3 [ms] heavyProc (from H2) started ... heavyProc (from H2) done * awaited H2: 1.82e+4 [ms] lightProc (from L2) started ... lightProc (from L2) done * awaited L2: 1.82e+4 [ms] 見どころ どう考えても先に完了できそうな L2 が、最後に完了している。 = 直列に実行されてる。 まとめ 「setTimeout で非同期化した処理」は、「後回しされた直列処理」になるだけ。 重い同期処理を非同期化したければ、Web Worker / Worker Threads を使おう。 Worker の検証は・・・気が向いたら書く。 Ref. jquery - Is setTimeout a good solution to do async functions with javascript? - Stack Overflow
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS基礎文法~関数~

概要 関数についての記事です。 引数、仮引数、アロー関数について取り上げて行きます。 関数 関数とは様々な処理を1つの命令にまとめることができます。 index.js function show() { console.log('A'); console.log('B'); console.log('C'); } show(); 関数は、functionに名前を付けます。今回は、名前を付けます。 関数の中の処理を呼び出すためには関数名();とすることで呼び出すことができます。 index.js console.log('------'); show(); console.log('------'); show(); console.log('------'); このように関数化することで、後で内容を変更する必要があるときにメンテナンスが楽になりますね。 index.js for(let i = 0; i <= 4; i++) { show(); } ページ内であれば、呼び出すことができます。 仮引数,実引数 index.js function show(msg) {//仮引数 console.log('A'); console.log(`--${msg}--`); console.log('C'); } console.log('------'); show('hey');//実引数 console.log('------'); show('hello'); console.log('------'); また関数を呼び出す際に値を渡すことができます。これを実引数と言います。 そして元の値に仮置きする値を仮引数といいます。 return index.js function total (a,b,c) { console.log(a * b * c); } total(2,4,6); //48 total(5,3,8); //120 これを合算したいと思います。 index.js function total (a,b,c) { console.log(a * b * c); } const aaa = total(2,4,6); //48 const bbb = total(5,3,8); //120 const totalNum = aaa + bbb; console.log(totalNum); 結果はNaNでした。 これは数値を求める計算で結果が数字にならないときに現れます。 この関数では、結果を返しているからです。その場合はreturnを使います。関数を実行して返ってくる値です。 returnを使うことで、関数を式に入れて使うことができます。 index.js function total (a,b,c) { return a * b * c; } const aaa = total(2,4,6); //48 const bbb = total(5,3,8); //120 const totalNum = aaa + bbb; console.log(totalNum); 先程の計算式の結果は168でした。 index.js function name() { return } console.log(name()); undefinedが返ってきます。これは未定義という意味です。 またreturnの後に処理を記述しても実行されません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

テンプレートリテラル

テンプレートリテラル これまで文字列や変数、定数の連結には「+」を用いていましたが、それ以外の方法として「テンプレートリテラル」という連結方法があります。 記述としては「`〇〇${定数or変数}〇〇`」のように記述することで、文字列の中に定数や変数を含めることができます。 このとき、文字列全体は「 ' (シングルクォーテーション)」ではなく「 ` (バッククォーテーション)」を用いる必要があります。 例 const name = 'Abe' // 「+」を用いた場合 console.log('私の名前は' + name + 'です'); //テンプレートリテラルを用いた場合 console.log(`私の名前は${name}です`); 出力結果 私の名前はAbeです 私の名前はAbeです 上記のように、テンプレートリテラルを用いても、「+」を用いた時と同様の出力結果を出すことができました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【勉強】Next.jsで簡単な掲示板作成

はじめに 私はモダンな技術の実務経験が無いため、Javascriptを勉強しています。 この記事では以前、Next.jsを勉強した際に作成した簡易掲示板について記載しました。 なぜ掲示板か 教材に掲示板を選んだ理由は、初めての個人開発ということもあり、 CURD全ての機能が備わっている物が良かったからです。 個人的に勉強はしたいが何を題材にすればよいかわからない方におすすめです。 なぜNext.js? 数あるJavascriptのフレームワークの内、Next.jsを選んだ理由についてです。 どうしてもNode.jsを使いたかったので、それと相性がいいこととが第一条件で、 一番の決め手は知人に進められたからです。 個人開発なので使う技術は普段触れない物で良いと思うのですが、 今思えば無知な状態からNext.jsではなくReactを一通り学んだ後にNext.jsに触ればよかったです……。 実際に作った画面 機能 投稿表示 新規投稿 投稿削除 環境 名前 役割 scss デザイン全般 Next.js(React.js) フロントエンド Node.js サーバーサイド MySQL データベース GitHub https://github.com/okioka/NextBBS ※ローカルですが実際にPCで動かすこともできます。 感想 大変だったこと コンポーネント指向を理解することが難しかったです。 JavaServletでしかWebの開発をしたことがなかったことから、 今まではHTML、CSS、JavaScriptで分けて考えることが自分の中の常識としてありましたが、 コンポーネント指向では一つにして考えるので慣れるまで時間がかかりました。 モチベーションを保つ事が大変でした。 今回は小規模で終わりが見えていたのでモチベーションの維持ができましたが、 個人開発で大規模な開発をする時に、まずはどうやってモチベーションを 維持するか考えないといけないです。 やはり自分が好きなもの、本当に欲しいと思っている物を作ることが モチベーション保つ秘訣だと思いました。 学びがあったこと 今自分が触れている技術と比べて新しいので資料が少なかったです。 公式ドキュメントなどを見て調べる習慣がつきました。 調べてもわからないことは聞くべきだと思います。 仕事ではわからないことを聞くことは当たり前ですが、 個人的な勉強で聞くことをしていませんでした。 わからないことは知り合いに聞いたり技術書を読むとで解決することができました。 自分の考えだけで解決しようとするのではなく、 自分では思いつかないような考え方に日頃から触れるようにしましょう。 おわりに 最後まで読んでいただきありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

出力/変数/定数

JavaScript JavaScriptでは、コンソールに出力させるには、「console.log();」を用います。 このとき、「;(セミコロン)」を記述し忘れないようにする必要があります. コメントアウトは文頭に「//」と記述することで、その行はコメントと見なされます。 例 console.log('Good morning'); // console.logを用いて出力 出力結果 Good morning 変数の定義 変数の定義は「let 変数名 = 値;」と記述するすることで定義できます。 ここでも、末尾に「;(セミコロン)」を忘れないようにする必要があります。 例 let name = 'Abe'; console.log(name); 出力結果 Abe 変数の更新 変数は一度代入した値を変更することができます。 「変数名 = 新しい値」と記述することで値を変更できます。 このとき、文頭にletは記述する必要はありません。 例 let name = 'Abe'; console.log(name); name = 'Inoue'; console.log(name); 出力結果 Abe Inoue 定数の定義 定数の定義はletの代わりに「const」と記述することで定義できます。 なので記述としては、「const 定数名 = 値;」と記述します。 定数と変数の違いは、変数では一度代入した値を更新することができましたが、 定数では値を更新することができません。 例 const name = 'Abe'; name = 'Inoue'; //値を更新しようとするとエラーが発生します console.log(name); 定数のメリットとしては「後から値を更新できない」という点が挙げられます。 これは予期せぬ更新を防ぐことができ、より安全なコードを書くことができます。 また、第三者がコードを見たときに変更しないものだとすぐ判断できる為、可読性を上げることができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

関数を作って遊んでみた!【備忘録】

こんにちは! 今日は、タイトルの通り、JavaScriptを使って、「関数」を作って遊んでみました! 関数とは、ある処理を記述した部品です。 部品を組み合わせることで、1つのアプリケーションやWebサービスは動きます。 例えば、車。 車は、外見だけでは、動きません。エンジンや、ブレーキなどの部品が正常に動かなければ、乗り物の車としては動いてくれません。 (車に詳しい方からしたら、若干、表現がおかしいかもしれないです、すみません...) 私自身、まだまだプログラミング初心者で、JavaScriptの基礎をまだまだ固めきれていないので、テキスト片手に勉強をしています。今日の内容は、関数についてだったのですが、読んで、サンプルコードやってみて、意味はわかるんだけど、正直、「え、わかっちゃって大丈夫??自分でちゃんと作れるんかなー??」と思い、関数をいくつか自分で作ってみて、遊んでみました! ちなみに、テキストを読んでから、テキストを閉じて、遊んだので、これから紹介する関数は、全て、テキストのサンプルコードとは異なります。(似ているものはあります。) 1. 〇〇は美味い!と返す関数 引数として渡した値を〇〇の中に入れて、返します。 function sample1(drink) { return `${drink}は美味い!`; } let sampleResponse1 = sample1('芋焼酎'); console.log(sampleResponse1); // 芋焼酎は美味い! と返ってきます。 2. 年齢によって返す値が変わる関数 引数に渡された値を、if文で条件分岐させて、返ってくる値を変えます。 年齢を指定した条件で比較して、当てはまる年齢範囲の文章を返します。 function sample2(age) { if (age >= 18) { return `${age}歳は、18歳以上ですので、入場料は、1,500円です。` } else if (age >= 9) { return `${age}歳は、9歳以上17歳以下ですので、入場料は、1,000円です。` } else { return `${age}歳は、無料招待の対象です。` } } let sampleResponse2 = sample2(5); let sampleResponse2_2 = sample2(25); let sampleResponse2_3 = sample2(16); console.log(sampleResponse2); // 5歳は、無料招待の対象です。 console.log(sampleResponse2_2); // 25歳は、18歳以上ですので、入場料は、1,500円です。 console.log(sampleResponse2_3); // 16歳は、9歳以上17歳以下ですので、入場料は、1,000円です。 3. 引数にオブジェクトを渡してみた!! 今度は、引数にオブジェクトを渡してみました。 ちなみに、オブジェクトとは、名前と値を1セットにしたプロパティを持つデータ型のことです。 オブジェクトにも、プロパティの値に関数が入った場合、そのプロパティはメソッドと呼ぶ、など細かく種類が分かれていますが、今回は、通常の名前と値の1セット(プロパティ)で進めて行きます。 以下では、引数に渡したオブジェクトの中のプロパティから、名前(item)と値(price)を取り出して、それらを利用した文章を返してきます。 function sample3(itemObj) { return `${itemObj.item}は、${itemObj.price}円です。` } let aboutItem = {item: 'MacBook Pro', price: '240,000'} let sampleResponse3 = sample3(aboutItem); // ユーザー定義関数sample3の引数には、オブジェクトであるaboutItemを渡している。 console.log(sampleResponse3); // MacBook Proは、240,000円です。 4. 複数のオブジェクトを引数に渡してみた!! 1つ上の3では、オブジェクトを1つ渡しました。 今回は、いくつか渡してみましょう! 引数にいくつかのオブジェクトを渡し、それぞれのオブジェクトの中のプロパティから名前と値を取り出して、それらを利用した文章が返ってくるようにしてみましょう。 この時、1つ1つオブジェクトを変数宣言して渡すのは面倒なので、引数として渡すオブジェクトを全て配列の要素にしてしまい、その配列をスプレッド構文でささっと渡してしまいましょう! ※スプレッド構文については、こちらで解説しているので、ご覧ください! function sample4(item1, item2, item3) { return `${item1.item}は、${item1.price}円、${item2.item}は、${item2.price}円、${item3.item}は、${item3.price}円です。` } let items = [ {item: 'トマト', price: 98}, {item: 'キャベツ', price: 158}, {item: '大根', price: 190} ] let sampleResponse4 = sample4(...items); console.log(sampleResponse4); // トマトは、98円、キャベツは、158円、大根は、190円です。 おわりに 関数やオブジェクトへの理解が浅かったのですが、今回、遊んでみたおかげで少し、理解を深めることができました。 また、何を返そうか考えるのが楽しかったので、難しそうに見える関数への印象が変わり、仲良くなれそうな気がしました。 ぜひ、皆さんも、「理解が浅いな」と感じる文法で遊んでみてはいかがでしょうか?? もし、間違っている点や補足などございましたら、コメント頂けますと、助かります!! お読み頂き、ありがとうございました! 参考文献 以下のテキストで勉強しました。 柳井政和著 『JavaScript[完全]入門』(2021)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS基礎文法~繰り返し処理~

概要 プログラムでは、大量のデータを扱います。大量のデータを扱う場合は配列に格納してfor文などの繰り返し処理を行います。 繰り返し処理で使われる繰り返し処理についての記事です。 for文 指定回数の処理を行うのに使用する繰り返し処理です。 配列との組み合わせで、要素の先頭から末尾までの処理をする目的で使用されます。配列での使用については別の記事でかきます。 今回の記事ではfor文での処理の流れについて触れます。 index.js for(let i = 0;i <= 10; i++) { console.log('hello'); //hello ×10 } iは変数を表します。 let i = 0 ▶ 初期化式 最初の一回のみ実行されます。 i <= 10 ▶条件式 この条件がtrueの間処理が繰り返されます。 falseになるとfor文を抜けます。 i++ ▶ 変化式 判定用の変数を更新します。 index.js for(let i = 0;i <= 10; i++) { console.log(`${i}回hello`); } このようにテンプレート文字列を使うと何回目helloなのかわかりやすく表示することができます。iは変数カウントを表します。 break breakを使用することで、処理中に特定の条件でtrueであったときにループを抜けることができます。 今回は8のときにfor文を抜けるようにプログラムしました。 index.js for(let i = 0;i <= 10; i++) { console.log(`${i}回hello`); //hello8回まで表示 if (i === 8 ) { //iが8のときに抜ける break; } } continue continueを使うことで繰り返し処理を中断して、変化式に移動します。 ブラウザ上では、3回目のみループを抜けます。 index.js for(let i = 0;i <= 10; i++) { if (i === 3 ) { continue; } console.log(`${i}回hello`); } while文 while文は()内の条件式がtrueである間ループします。 なお、hpを減らし忘れると条件式が永遠にtrueになり無限ループになります。 今回は−20ずつhpが減少するように設計しました。 また、hpが20のときに注意喚起のメッセージをif文で追加しました。 index.js let hp = 100; while (hp > 0) { console.log(`${hp} です`); hp -= 20; if(hp === 20) { console.log(`${hp}がピンチです`); } } do while文 do while文は条件式が末尾にあります。 これにより、最低一回は処理内容が実施されます。 index.js let hp = -30; do { console.log(`${hp}です`); hp -= 20; } while(hp > 0)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

indesign スクリプト 選択しているXML要素からページアイテムを選択

indesignのJavaScriptでXML要素からページアイテムを選択したいのですが、これで良いのかな・・・? /* 選択しているXML要素からページアイテムを選択 選択出来るであろうページアイテム:テキストフレーム、画像、パスオブジェクト 更新 2021/04/29 */ // アプリ指定 #target "InDesign"; // スクリプト動作指定(高速) app.doScript(function(){ // 選択されているオブジェクト var selectobjects = app.activeDocument.selection; // すべての選択を解除 app.activeDocument.selection = null; // オブジェクトのロックを解除して選択するか var unLockFlg=confirm("オブジェクトがロックされている場合はロックを解除して選択しますか?","","選択しているXML要素からページアイテムを選択"); // 選択オブジェクトの数だけ繰り返し for(var i = 0; i < selectobjects.length; i++){ // 選択オブジェクトがXMLElementなら if(selectobjects[i].constructor.name == "XMLElement"){ // ページアイテム記憶用 var targetPageItem; // XML要素の参照(テキストコンテンツまたはページアイテム) var elementReference = selectobjects[i].xmlContent; // 参照がストーリーの場合 if(elementReference.constructor.name == "Story"){ // ストーリーの参照がテキストフレームの場合 if(elementReference.textContainers){ // トーリーの参照をページアイテム記憶用に記憶 targetPageItem = elementReference.textContainers[0]; } // 参照がimageの場合 }else if(elementReference.constructor.name == "Image"){ // imageの親(フレーム)をページアイテム記憶用に記憶 targetPageItem = elementReference.parent; // 参照が上記とテキストコンテンツ以外 }else if(elementReference.constructor.name != "Text"){ // ページアイテム記憶用に記憶 targetPageItem = elementReference; } // ページアイテムに対する処理 if(targetPageItem){ // ロックされていてオブジェクトのロックを解除して選択するかのフラグがtrueなら if(targetPageItem.locked == true && unLockFlg == true){ // ロック解除 targetPageItem.locked = false; } // 選択に追加 targetPageItem.select(SelectionOptions.addTo); } } } //function用カッコ閉 } //スクリプト動作指定(高速)の続き ,ScriptLanguage.JAVASCRIPT,[],UndoModes.FAST_ENTIRE_SCRIPT);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

indesign スクリプト 構造の選択要素からページアイテムを選択

構造の選択要素からページアイテムを選択するスクリプトはこれで良いのかな・・・? /* 構造の選択要素からページアイテムを選択 選択出来るであろうページアイテム:テキストフレーム、画像、パスオブジェクト 更新 2021/04/30 */ // アプリ指定 #target "InDesign"; // スクリプト動作指定(高速) app.doScript(function(){ // スクリプト名 var scriptName = "構造の選択要素からページアイテムを選択"; // 選択されているオブジェクト var selectobjects = app.activeDocument.selection; // すべての選択を解除 app.activeDocument.selection = null; // オブジェクトのロックを解除して選択するか入力 var unLockFlg = confirm("オブジェクトがロックされている場合はロックを解除して選択しますか?","",scriptName); // 選択オブジェクトの数だけ繰り返し for(var i = 0; i < selectobjects.length; i++){ // 選択オブジェクトがXMLElementなら if(selectobjects[i].constructor.name == "XMLElement"){ // ページアイテム記憶用 var targetPageItem; // XML要素の参照(テキストコンテンツまたはページアイテム) var elementReference = selectobjects[i].xmlContent; // 参照がストーリーの場合 if(elementReference.constructor.name == "Story"){ // ストーリーの参照がテキストフレームの場合 if(elementReference.textContainers){ // トーリーの参照をページアイテム記憶用に記憶 targetPageItem = elementReference.textContainers[0]; } // 参照がimageの場合 }else if(elementReference.constructor.name == "Image"){ // imageの親(フレーム)をページアイテム記憶用に記憶 targetPageItem = elementReference.parent; // 参照が上記とテキストコンテンツ以外 }else if(elementReference.constructor.name != "Text"){ // ページアイテム記憶用に記憶 targetPageItem = elementReference; } // ページアイテムに対する処理 if(targetPageItem){ // ロックされていてオブジェクトのロックを解除して選択するかのフラグがtrueなら if(targetPageItem.locked == true && unLockFlg == true){ // ロック解除 targetPageItem.locked = false; } // 選択に追加 targetPageItem.select(SelectionOptions.addTo); } } } // 選択数表示 alert(app.activeDocument.selection.length + " ページアイテム選択",scriptName); //スクリプト動作指定(高速)の続き },ScriptLanguage.JAVASCRIPT,[],UndoModes.FAST_ENTIRE_SCRIPT);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Quineと化した先輩

ソース yaju.js (function a(){`@@@@@@@@@@@@@@@@@@@@&*` s="";for(i=0;i<23;i++)s+=" ";`@@@@@@@@@@@@@@@@@&((, @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&*@@, &@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. /@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&&&@@@.&@@@@@@@@@@@@@@@@@@@@@@@@, @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&. @@@@@@@@@@@@@@@@@@ .@@@@@@@@@@@@@@@@@@@@@@@@,@ . %@@@@@@@@@@@@& @@@@@@@@@@@@@@@@@@@@@@@@. @@@@@@@@@@/ @@@@@@@@@@@@@@@@@@@@@@@ (@@@@@@@( @@@@@@@@@@@@@@@@@@@@@@ *@@@@@, @@@@@@@@@@@@@@@@@@@@@@& (@@@@, %@@@@@@@@@@@@@@@@@@@@@@@@@ .@@@@, .@@@@@@@@@@@@@@@@@@@@@( @@@@, (@@@@@@@@@@@@@@@@@@. ,.@@@&##(* .@@@ #@@@@@@@@@@@@@@@@@ *@@@@&(,*#&&&&@@@@@@& @@@@@@@@ @@@* *@@@@@@@@@@@@@@@@, .%@@@ #@@@/ .@@@@@@@@@@ *@( /@%. &( %@@@@@, (%&@@&@@@@@.%@@ &% (@@@@&(. ,@ %@ .@. @@@, @% &@@@% /@ @@@@@@. .@@@ ,@. @, .(&@@. #@, @@ ( /@ ,@&,@@@* . @@/ @ @@. %@.@& .@@ %#@@% ,@@ (@@ @@, &@@,#.@/* @@@@@&. @ *@ &@@@ @ #@@# /@ *@@ @ *@ @@@@*&@@@@@**(@@,#@ .,@% /@@@((@@* /@@ @@, %@@, @@. *@/ @@ .@* @@ /@, *( *&&@@@@@@@@@@&( @& .@( &@ @(,,(@@@& #@@@@ &@ @& @@ .@#, , @@ (@. #% % .@( @@ ,@@ ,@@. @@, @@. #@@@% @@ @@@ %@@@, .@( @@/ /@@@/ @@ @@/ (@@@@( @@@. .@@( ,@@@@@@@& *@@@/*@ #@@% (@@@@@@@@@@#. @ *@@ *.@. &@@@@@ @& @@@@@@@@@@@@@@@( (@ &@@@@@@@@@@@@@@@@@@@@@@@@@@&/. @@@# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* @@@& @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@% .%@@@@@@& @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@(, #%@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`;console.log(s+`(${a}())`)}()) 出力 nodeコマンドまたはChromeのコンソールで実行 (function a(){`@@@@@@@@@@@@@@@@@@@@&*` s="";for(i=0;i<23;i++)s+=" ";`@@@@@@@@@@@@@@@@@&((, @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&*@@, &@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. /@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&&&@@@.&@@@@@@@@@@@@@@@@@@@@@@@@, @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&. @@@@@@@@@@@@@@@@@@ .@@@@@@@@@@@@@@@@@@@@@@@@,@ . %@@@@@@@@@@@@& @@@@@@@@@@@@@@@@@@@@@@@@. @@@@@@@@@@/ @@@@@@@@@@@@@@@@@@@@@@@ (@@@@@@@( @@@@@@@@@@@@@@@@@@@@@@ *@@@@@, @@@@@@@@@@@@@@@@@@@@@@& (@@@@, %@@@@@@@@@@@@@@@@@@@@@@@@@ .@@@@, .@@@@@@@@@@@@@@@@@@@@@( @@@@, (@@@@@@@@@@@@@@@@@@. ,.@@@&##(* .@@@ #@@@@@@@@@@@@@@@@@ *@@@@&(,*#&&&&@@@@@@& @@@@@@@@ @@@* *@@@@@@@@@@@@@@@@, .%@@@ #@@@/ .@@@@@@@@@@ *@( /@%. &( %@@@@@, (%&@@&@@@@@.%@@ &% (@@@@&(. ,@ %@ .@. @@@, @% &@@@% /@ @@@@@@. .@@@ ,@. @, .(&@@. #@, @@ ( /@ ,@&,@@@* . @@/ @ @@. %@.@& .@@ %#@@% ,@@ (@@ @@, &@@,#.@/* @@@@@&. @ *@ &@@@ @ #@@# /@ *@@ @ *@ @@@@*&@@@@@**(@@,#@ .,@% /@@@((@@* /@@ @@, %@@, @@. *@/ @@ .@* @@ /@, *( *&&@@@@@@@@@@&( @& .@( &@ @(,,(@@@& #@@@@ &@ @& @@ .@#, , @@ (@. #% % .@( @@ ,@@ ,@@. @@, @@. #@@@% @@ @@@ %@@@, .@( @@/ /@@@/ @@ @@/ (@@@@( @@@. .@@( ,@@@@@@@& *@@@/*@ #@@% (@@@@@@@@@@#. @ *@@ *.@. &@@@@@ @& @@@@@@@@@@@@@@@( (@ &@@@@@@@@@@@@@@@@@@@@@@@@@@&/. @@@# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* @@@& @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@% .%@@@@@@& @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@(, #%@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`;console.log(s+`(${a}())`)}())
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

テレ〇限定・今日のドラマ再放送は何やるの?LineBotを作ろうと思う

先日、LineBotの作り方を学びましたので、さっそく何か作ってみたくなりました。 妄想の結果、 テレ〇限定・今日のドラマ再放送は何やるの?LineBot(自己満足型) がいいかなと。 すっかりテレワークが多くなりまして、平日の14時~17時のスーパー再放送タイム(テレ〇)がいつも気になるのです(これは大きな声で言えませんね) LineBotで実現したいこと LineBotに今日の番組は何?と聞くと、再放送ゴールデンタイムの番組ラインナップを返してくれるという簡単なものにしようと思います。 イメージはこんな 必要な機能 おそらくこんな感じになろうかと思います。 番組の情報をどうにかして取得する機能 必要な情報だけに絞り込む機能 LineBotの機能 会話になるようにやり取りする機能 番組の情報をどうにかして取得する 今回、LineBotを学ぶとともにWEBAPIの有用性についても教えてもらいましたのでTV番組の情報もWEBAPIでサクッととりたいところです。 しかしながら、自分の調査の結果においては各TV局からWEBAPIは提供されていないようでした。残念。  ちなみに、NHKはWEBAPIを提供していました。https://api-portal.nhk.or.jp/ ちょっと遠回りになりますが、スクレイピングして番組情報を取得することにしようと思います。 Node.js用のスクレイピングモジュール(cheerio-httpcli)が公開されていましたので、こちらの素敵なモジュールを利用させていただくことにします。 https://qiita.com/ktty1220/items/e9e42247ede476d04ce2 さてさて、うまく情報を引っ張ってこれるでしょうか・・・ 楽しみだなー 俺専用LineBot! 今日は方針検討と調べ物で終了です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

create-react-appでTodoアプリを作成

はじめに create-react-appはReactで簡単にアプリを作成するためのツールです。 Reactのみで簡単なTodoアプリを作成したので備忘録としてまとめたいと思います。 なお、多少の環境構築が必要なので、よろしければこの記事を参考にしてください。 また今回はJSX、props、useStateの知識を扱います。この記事では説明を省きますので ご了承ください。 挙動イメージ 1. Todoを入力したら未完了のTodoに反映される 2. 未完了のTodoは完了のTodoに移動できる or 削除できる 3. 完了のTodoは未完了のTodoに移動できる 目次 1.create-react-app 2.HTMLとCSSで構造を作成 3.Reactを意識したモックに変更 4.Todoの入力機能 5.Todoの追加機能 6.Todoの削除機能 7.Todoの完了機能 8.Todoの戻す機能 9.コンポーネント化 1. create-react-app 環境構築が終了したらターミナルでcreate-react-appを実行しましょう。 ターミナル projects $ npx create-react-app 任意のフォルダ名(今回はreact-todo) projects $ cd react-todo // サーバー立ち上げ react-todo $ npm start ブラウザが立ち上がってReactの初期画面が表示されれば成功です! 2. HTMLとCSSで構造を作成 まずは、イメージの通りに骨組みを作成します。 srcディレクトリの必要なファイルは以下通りです。 App.jsはコンポーネントと明示的にわかるようにApp.jsxと拡張子を変更しましょう。 src |-App.jsx |-index.js |-App.css 次にindex.jsを編集します。 index.js import React from 'react'; import ReactDom from 'react-dom'; import { App } from './App'; ReactDom.render(<App />, document.getElementById('root')); 上から2行はおまじないです。 3行目はApp.jsxのAppという関数をimportしますという意味です。 最後にrender関数でAppの中身をindex.htmlのidがrootのdivタグに格納しています。 準備が整ったのでメインのApp.jsxを編集します。 App.jsx import React from 'react'; // App.cssを読み込み import './App.css'; export const App = () => { return ( <> <div className="outline"> <div className="inputArea"> <input placeholder="todoを入力"/> <button>追加</button> </div> <div className="imcompleteArea"> <p className="title">未完了のtodo</p> <ul> <li className="todoList"> <p>テスト</p> <button>完了</button> <button>削除</button> </li> </ul> </div> <div className="completeArea"> <p className="title2">完了のtodo</p> <ul> <li className="todoList"> <p>テスト</p> <button>戻す</button> </li> </ul> </div> </div> </> ); }; 構成としては大きくinputArea、imcompleteArea、completeAreaに分かれます。 Todoが格納させるエリアにはリストタグで個々のtodoにボタンで操作できるようにしておきます。 ポイント return内が複数行になるときは<> </>で全体をくくる JSXでclassを付与するときはclassName記述する 次にcssですが、ここはお好みで調整可能です。 記述方法は通常のcssとかわりません。 App.css * { margin: 0; padding: 0; box-sizing: border-box; } li { list-style: none; } .outline { padding: 50px; } .inputArea { width: 300px; height: 70px; background-color: lightblue; padding: 20px; margin-bottom: 50px; border-radius: 15px; } input { border-radius: 16px; border: none; outline: none; padding: 6px 16px; margin-right: 10px; } button { border-radius: 16px; border: none; padding: 4px 16px; } button:hover { background-color: #FF7FFF; color: #FFF; cursor: pointer; } /* 未完了のタスクエリア */ .imcompleteArea { width: 800px; min-height: 300px; background-color: lightgray; padding: 20px; margin-bottom: 50px; border-radius: 15px; } .title { text-align: center; font-weight: bold; } .todoList { margin-top: 20px; display: flex; align-items: center; justify-content: space-evenly; } /* 完了のタスクエリア */ .completeArea { width: 800px; min-height: 300px; background-color: lightgreen; padding: 20px; border-radius: 15px; } .title2 { text-align: center; font-weight: bold; } 以上で骨組みはできました。 3. Reactを意識したモックに変更 現状のApp.jsx内では未完了と完了のtodoはpタグに直接書き込まれています。 しかし、本来は動的にtodoの内容は反映してほしいのでuseStateを用いて状態を管理していきたいと思います。 App.jsx // Reactの部分を{ useState }に編集 import { useState } from 'react'; import './App.css'; export const App = () => { const [incompleteTodos, setIncompleteTodos] = useState(["宿題", "洗濯"]);  return ( : : ); }; const [incompleteTodos, setIncompleteTodos] 未完了のtodoの状態を管理するための配列です。incompleteTodosが初期値。setIncompleteTodosが更新するための変数です。 useState(["宿題", "洗濯"])は初期値のincompleteTodosに宿題と洗濯という2つの値を渡しています。 次にreturn内を編集していきます。まずは未完了のtodoからです。 App.jsx return ( : : <div className="imcompleteArea"> <p className="title">未完了のtodo</p> <ul> <li className="todoList"> <p>テスト</p> <button>完了</button> <button>削除</button> </li> </ul> </div> : : ); ↓ // 変更 <div className="imcompleteArea"> <p className="title">未完了のtodo</p> <ul> {incompleteTodos.map((todo) => { return ( <li key={todo} className="todoList"> <p>{todo}</p> <button>完了</button> <button>削除</button> </li> ); })} </ul> </div> 順番に解説していきます。 まずmap関数を用いて先程定義したincompleteTodosの中身を繰り返し処理で表示させます。その際の引数はtodoとします。 key={todo}と記述したのは繰り返し処理によるレンダリングでどのtodoかを判別するためです。最後にpタグの中身は{ }でtodoを囲んで表示させます。 ポイント return内でJavascriptを扱う際は{ }で囲む 同じようにして完了のtodoもuseStateを用いて状態を管理します。 completeAreaを以下のように編集してください。 App.jsx export const App = () => { const [incompleteTodos, setIncompleteTodos] = useState(["宿題", "洗濯"]); // 追記 const [completeTodos, setCompleteTodos] = useState(["掃除"]);    return ( : : <div className="completeArea"> <p className="title2">完了のtodo</p> <ul> {completeTodos.map((todo) => { return ( <li key={todo} className="todoList"> <p>{todo}</p> <button>戻す</button> </li> ); })} </ul> </div> ); }; これで準備が整いました! それでは順番に機能を実装していきたいと思います。 4. Todoの入力機能 まずは、入力されたtodoの状態を管理するためのuseStateを用意します。 初期値は''で空にしておきましょう。 App.jsx export const App = () => {  // 追記 const [todoText, setTodoText] = useState(''); }; 入力されたtodoTextはinputタグのvalueとして設定します。 { }で変数を囲むのを忘れないでください。 <div className="inputArea"> <input placeholder="todoを入力" value={todoText} /> <button>追加</button> </div> この状態だと入力欄にテキストを打ち込んでも反応しません。それは初期値の''が常に渡されているためです。 そこでonChangeメソッドを用いてtodoTextの値を更新する関数を作成する必要があります。 inputタグを次のように編集しましょう。 <div className="inputArea"> <input placeholder="todoを入力" value={todoText} onChange={onChangeTodoText}/> <button>追加</button> </div> inputにtodoが入力されたら、onChangeメソッドでonChangeTodoTextという関数を呼び出しています。この関数の中でtodoの値を更新する処理を記述していきます。 では、onChangeTodoText関数を定義します。関数はreturnの前に定義しましょう。 export const App = () => { // 関数の定義  const onChangeTodoText = (event) => setTodoText(event.target.value); }; onChangeTodoTextは引数を取ります。今回はeventを取ります。 event.target.valueは入力されたtodoの値のことです。これをsetTodoText関数の引数として渡すことで入力された値がsetTodoTextとして更新されます。 5. Todoの追加機能 4までの内容でtodoを入力することはできました。 次に追加ボタンを押してtodoを未完了エリアに移動させる機能を実装します。 buttonタグにonClickメソッドでボタンを押したときに関数を呼び出します。 今回はonClickAddという関数名にします。 <div className="inputArea"> <input placeholder="todoを入力" value={todoText} onChange={onChangeTodoText} /> <button onClick={onClickAdd}>追加</button> </div> ではonClickAddの中身を記述しましょう。 これもreturnの前に記述します。 const onClickAdd = () => { if (todoText === '') return; const newTodos = [...incompleteTodos, todoText]; setIncompleteTodos(newTodos); setTodoText(''); } 2行目のifは空の入力は無効にするという意味です。 3行目の[...incompleteTodos, todoText]は配列のコピーをしています。 [...変数名]と記述するとその変数の値をコピーできます。すでにある未完了のtodoに新しく入力したtodoTextを加えて、新しくnewTodosという変数に格納しています。 4行目は未完了のtodoのstateを更新したいのでnewTodosをsetIncompleteTodos関数の引数に渡して値を更新します。 5行目は追加ボタンを押した際に入力欄をリセットしたいのでsetTodoText関数を空にします。 6. Todoの削除機能 未完了エリアのtodoを削除する機能を実装します。方針は次の通りです。 1. 削除ボタンにonClickメソッドを設定して関数を呼び出す 2. 削除ボタンを押したら未完了エリアから選んだtodoが削除される 削除ボタンにonClickメソッドを設定 todoを削除する関数をonClickDeleteとします。 <div className="imcompleteArea"> <p className="title">未完了のtodo</p> <ul> {incompleteTodos.map((todo, index) => { return ( <li key={todo} className="todoList"> <p>{todo}</p> <button }>完了</button> <button onClick={() => onClickDelete(index)>削除</button> </li> ); })} </ul> </div> ポイントとしてはmap関数に新しくindexを引数に設定しています。 これはtodoを削除する際に何番目のtodoかを判別する際に必要です。関数の中でもindexは必要なのでonClickDeleteの引数にもindexを渡します。 関数の定義 例によってreturnの前に記述しましょう。 const onClickDelete = (index) => { const newTodos = [...incompleteTodos]; // newTodosから指定のindex番号を1つ削除する newTodos.splice(index, 1); setIncompleteTodos(newTodos); }; 2行目で現在の未完了のtodoをnewTodosという変数に格納します。 3行目でspliceメソッドを使用しています。spliceは配列の要素を操作できるメソッドで要素の追加や削除することができます。第一引数に削除対象のindexを渡して第二引数は指定したindexから何番目までの要素を操作するかを設定します。(今回は1なのでつまり、指定したtodoのみを削除します。) 4行目で削除し終えた未完了のtodoの状態を更新するためにsetIncompleteTodos関数にnewTodosを渡して値を更新します。 7. Todoの完了機能 未完了のtodoを完了エリアに移動させます。方針は以下の通りです。 1. 完了ボタンにonClickメソッドを設定して関数を呼び出す 2. 完了ボタンを押したら未完了エリアからtodoが削除される 3. 完了ボタンを押したら削除されたtodoが完了エリアに追加される 完了ボタンにonClickメソッドを設定 関数名はonClickCompleteとします。 <div className="imcompleteArea"> <p className="title">未完了のtodo</p> <ul> {incompleteTodos.map((todo, index) => { return ( <li key={todo} className="todoList"> <p>{todo}</p> <button onClick={() => onClickComplete(index)}>完了</button> <button onClick={() => onClickDelete(index)}>削除</button> </li> ); })} </ul> </div> onClickCompleteにも、どのtodoを完了にするか判別するために引数としてindexを渡しましょう。 関数を定義 const onClickComplete = (index) => { const newIncompleteTodos = [...incompleteTodos]; // newTodosから指定のindex番号を1つ削除する newIncompleteTodos.splice(index, 1); const newCompleteTodos = [...completeTodos, incompleteTodos[index]]; setIncompleteTodos(newIncompleteTodos); setCompleteTodos(newCompleteTodos); }; 2~4行目で未完了エリアから選んだtodoを削除しています。[...incompleteTodos]で現在の未完了のtodoをコピーして、変数newIncompleteTodosに格納します。次にspliceメソッドでtodoを削除します。 6~8行目で選んだ未完了エリアと完了エリアにtodoを更新してます。 [...completeTodos, incompleteTodos[index]]で完了エリアに現在の完了のtodoであるcompleteTodosをコピーし、選んだ未完了のtodoであるincompleteTodos[index]を追加し 変数newCompleteTodosに格納します。 最後に未完了エリアのtodoの値と完了エリアのtodoの値をuseStateで更新しています。 8. Todoの戻す機能 機能としてはこれで最後です。方針は以下の通りです。 1. 戻すボタンにonClickメソッドを設定し関数を呼び出す 2. 戻すボタンを押したら完了エリアから選んだtodoを削除する 3. 戻すボタンを押したら未完了エリアに選んだtodoを追加する 完了機能の逆ですね 戻すボタンにonClickメソッドを設定 関数名はonClickBackとします。 <div className="completeArea"> <p className="title2">完了のtodo</p> <ul> {completeTodos.map((todo, index) => { return ( <li key={todo} className="todoList"> <p>{todo}</p> <button onClick={() => onClickBack(index)}>戻す</button> </li> ); })} </ul> </div> 例によってmap関数とonClickBack関数にindexを引数として渡します。 関数を定義 const onClickBack = (index) => { const newCompleteTodos = [...completeTodos]; newCompleteTodos.splice(index, 1); const newIncompleteTodos = [...incompleteTodos, completeTodos[index]]; setCompleteTodos(newCompleteTodos); setIncompleteTodos(newIncompleteTodos); }; 2~3行目で完了エリアから選んだtodoを削除します。 5~7行目は完了機能の逆なので説明は割愛します。 これで一応機能は実装しました。最終的なコードはこんな感じです。 App.jsx import { useState } from 'react'; import './App.css'; export const App = () => { const [todoText, setTodoText] = useState(''); const [incompleteTodos, setIncompleteTodos] = useState([]); const [completeTodos, setCompleteTodos] = useState([]); const onChangeTodoText = (event) => setTodoText(event.target.value); const onClickAdd = () => { if (todoText === '') return; const newTodos = [...incompleteTodos, todoText]; setIncompleteTodos(newTodos); setTodoText(''); } // タスクを削除する const onClickDelete = (index) => { const newTodos = [...incompleteTodos]; // newTodosから指定のindex番号を1つ削除する newTodos.splice(index, 1); setIncompleteTodos(newTodos); }; // 未完了のタスクを完了タスクへ const onClickComplete = (index) => { const newIncompleteTodos = [...incompleteTodos]; // newTodosから指定のindex番号を1つ削除する newIncompleteTodos.splice(index, 1); const newCompleteTodos = [...completeTodos, incompleteTodos[index]]; setIncompleteTodos(newIncompleteTodos); setCompleteTodos(newCompleteTodos); }; // 完了のタスクを未完了のタスクへ const onClickBack = (index) => { const newCompleteTodos = [...completeTodos]; newCompleteTodos.splice(index, 1); const newIncompleteTodos = [...incompleteTodos, completeTodos[index]]; setCompleteTodos(newCompleteTodos); setIncompleteTodos(newIncompleteTodos); }; return ( <> <div className="outline"> <div className="inputArea"> <input placeholder="todoを入力" value={todoText} onChange={onChangeTodoText} /> <button onClick={onClickAdd}>追加</button> </div> <div className="imcompleteArea"> <p className="title">未完了のtodo</p> <ul> {incompleteTodos.map((todo, index) => { return ( <li key={todo} className="todoList"> <p>{todo}</p> <button onClick={() => onClickComplete(index)}>完了</button> <button onClick={() => onClickDelete(index)}>削除</button> </li> ); })} </ul> </div> <div className="completeArea"> <p className="title2">完了のtodo</p> <ul> {completeTodos.map((todo, index) => { return ( <li key={todo} className="todoList"> <p>{todo}</p> <button onClick={() => onClickBack(index)}>戻す</button> </li> ); })} </ul> </div> </div> </> ); }; それでは、ここからコンポーネント化をしてコードをスッキリさせたいと思います。 9. コンポーネント化 今回はインプットエリア、未完了エリア、完了エリアの3つにコンポーネント化していきます。 まずはインプットエリアから始めます。src配下にcomponentsディレクトリを作成し、InputTodo.jsxというファイルを作成します。 src |-components |-InputTodo.jsx |-index.js |-App.jsx |-App.css inputAreaのコンポーネント化 それではInputTodo.jsxに必要な記述をしていきます。 App.jsxのreturn内のinputAreaの中身をInputTodo.jsxのreturn内に切り抜きします。 また、App.jsxでこのファイルを使用できるようにexportします。 InputTodo.jsx import React from 'react'; export const InputTodo = () => { return ( <div className="inputArea"> <input placeholder="todoを入力" value={todoText} onChange={onChangeTodoText} /> <button onClick={onClickAdd}>追加</button> </div> ); }; 次にApp.jsxを編集します。 InputTodo.jsxをimportします。 App.jsx import { useState } from 'react'; import './App.css'; // 追記 import { InputTodo } from './components/InputTodo'; : : return ( <div className="outline"> <InputTodo /> <div className="imcompleteArea"> : : ); このままではInputTodo.jsx内にtodoTextやonChangeTodoTextなどの変数や関数が設定されてないのでエラーが起きてしまいます。なのでpropsを用いてInputTodo.jsxに必要な要素を渡します。 App.jsx : : return ( : : <InputTodo todoText={todoText} onChange={onChangeTodoText} onClick={onClickAdd} /> ); InputTodoに3つのpropsを設定します。 それぞれtodoText、onChange、onClickとします。 InputTodo.jsx import React from 'react'; export const InputTodo = (props) => { const { todoText, onChange, onClick } = props; return ( <div className="inputArea"> <input placeholder="todoを入力" value={todoText} onChange={onChange} /> <button onClick={onClick}>追加</button> </div> ); }; propsを引数に取り、それぞれの値として渡します。const { todoText, onChange, onClick } = props;は分割代入といってメソッドを書くときに簡略化することができます。例えば本来ならprops.todoTextやprops.onChangeと書かないといけないところをtodoTextやonChangeと省略できます。 これでインプットエリアのコンポーネント化は完了です。 imcompleteAreaのコンポーネント化 コンポーネント用のファイルを作成します。components配下にIncompleteTodos.jsxを作成します。 src |-components |-InputTodo.jsx |-IncompleteTodos.jsx |-index.js |-App.jsx |-App.css 同じようにincompleteAreaの中身を切り取ります。 IncompleteTodos.jsx import React from 'react'; export const IncompleteTodos = () => { return ( <div className="imcompleteArea"> <p className="title">未完了のtodo</p> <ul> {incompleteTodos.map((todo, index) => { return ( <li key={todo} className="todoList"> <p>{todo}</p> <button onClick={() => onClickComplete(index)}>完了</button> <button onClick={() => onClickDelete(index)}>削除</button> </li> ); })} </ul> </div> ); }; 次にApp.jsxを編集します。 App.jsx import { useState } from 'react'; import './App.css'; import { InputTodo } from './components/InputTodo'; // 追記 import { IncompleteTodos } from './components/IncompleteTodos'; : : rerun ( : : <IncompleteTodos /> : ); それでは必要なpropsを設定します。 App.jsx : : return ( : <IncompleteTodos todos={incompleteTodos} onClickComplete={onClickComplete} onClickDelete={onClickDelete} /> : ); IncompleteTodos.jsx内で使用する変数と関数をそれぞれ渡します。 IncompleteTodos.jsx import React from 'react'; export const IncompleteTodos = (props) => { const { todos, onClickComplete, onClickDelete } = props; return ( <div className="imcompleteArea"> <p className="title">未完了のtodo</p> <ul>      // incompleteTodosをtodosに変更 {todos.map((todo, index) => { return ( <li key={todo} className="todoList"> <p>{todo}</p> <button onClick={() => onClickComplete(index)}>完了</button> <button onClick={() => onClickDelete(index)}>削除</button> </li> ); })} </ul> </div> ); }; 先程と同じように分割代入でpropsを渡します。 それでは最後に完了エリアのコンポーネント化をしていきます。 completeAreaのコンポーネント化 コンポーネント用のファイルを作成します。components配下にCompleteTodos.jsxを作成します。 src |-components |-InputTodo.jsx |-IncompleteTodos.jsx |-CompleteTodos.jsx |-index.js |-App.jsx |-App.css ここも同様にcompleteAreaの中身を切り取ります。 CompleteTodos.jsx import React from 'react'; export const CompleteTodos = () => { return ( <div className="completeArea"> <p className="title2">完了のtodo</p> <ul> {completeTodos.map((todo, index) => { return ( <li key={todo} className="todoList"> <p>{todo}</p> <button onClick={() => onClickBack(index)}>戻す</button> </li> ); })} </ul> </div> ); }; 次にApp.jsxを編集します。 App.jsx import { useState } from 'react'; import './App.css'; import { InputTodo } from './components/InputTodo'; import { IncompleteTodos } from './components/IncompleteTodos'; // 追記 import { CompleteTodos } from './components/CompleteTodos'; : return ( : : <CompleteTodos /> : ); それでは必要なpropsを設定します。 App.jsx : : return ( : <CompleteTodos todos={completeTodos} onClickBack={onClickBack} /> ); それではpropsを渡しましょう。 CompleteTodos.jsx import React from 'react'; export const CompleteTodos = (props) => { const { todos, onClickBack} = props; return ( <div className="completeArea"> <p className="title2">完了のtodo</p> <ul> {todos.map((todo, index) => { return ( <li key={todo} className="todoList"> <p>{todo}</p> <button onClick={() => onClickBack(index)}>戻す</button> </li> ); })} </ul> </div> ); }; 以上でコンポーネント化完了です! 終わりに 記事が長くなってしまいましたが、最後まで読んでいただきありがとうございました! React学習の助けになれば幸いです。。。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails でJavaScriptを使う

商品出品機能をつくる際に、販売手数料や利益を計算させるためにJavaScriptを使ったので まとめておこうと思います。 手順 -手順1 必要なJSファイルを作成する -手順2 必要な要素を取得する -手順3 入力するたびにイベントを発火できるようにする -手順4 必要なvalue属性を取得できるようにする -手順5 HTMLをJavaScriptで作成し、ブラウザ上に描画できるようにする ファイルを作成して読み込もう まずは、app/javascriptディレクトリにファイル名.jsを作成しましょう。 そして、application.jsにrequire("作成したJSファイルのパス");を記述して、作成したJSファイルを読み込めるようにしましょう。このとき、作成したJSファイルが存在するディレクトリに注意して記述してください。 【例】application.js require("../item_price"); 作成したJSファイルがブラウザで読み込まれるか確認するため、JSファイルにconsole.logを記述します。 【例】item_price.js window.addEventListener('load', () => { console.log("OK"); }); loadというイベントは、ページが全て読み込まれた後に発火します。JSファイルの読み込みが正しく出来ていればコンソール上に"OK"という文字列が表示されるはずです。 記述ができたら、ブラウザをリロードし、コンソールを開いて確認しましょう。 ブラウザのコンソールは、command + option + Jで開くことができます。 もし"OK"という文字列がコンソール上で確認できない場合は、以下の項目を確認しましょう。 -application.jsファイルで、作成したJSファイルを読み込むための記述が誤っていないか(ファイル名やディレクトリ構造に注意する) -application.html.erbファイルで、application.jsを読み込むためのscriptタグの挿入を忘れていないか 手順2 必要な要素を取得する 次に、取得すべき要素を確認します。 手順2で実装したいことは、「金額を入力したら、その金額の販売手数料と販売利益を表示すること」です。 金額を入力したときに画面上に動きがあった要素を示すセレクタは以下の3つです。 -金額を入力する場所のidセレクタ -販売手数料を表示する場所のidセレクタ -販売利益を表示する場所のidセレクタ idセレクタを確認するときは、検証ツールで探すと分かりやすい。 idセレクタを取得する場合はdocument.getElementById("id名")を使用します。 document.getElementById("id名")は、id名を指定してHTMLの要素を取得するメソッドです。 【例】item_price.js // 金額を入力した数値をpriceInputという変数に格納する const priceInput = document.getElementById("金額を入力する場所のid"); console.logを記述して、定義した変数にinput要素が格納されているか確認をします。 【例】item_price.js const priceInput = document.getElementById("金額を入力する場所のid"); console.log(priceInput); もしコンソール上に何も表示されないもしくはエラーが出る場合は、以下の項目を確認しましょう。 -取得すべきidセレクタの場所に間違いがないか 手順3 入力するたびにイベントを発火できるようにする 金額を入力するたびに、イベント発火するようにaddEventListenerを使用します。 addEventListenerは、イベント発火の際に実行する関数を定義するためのメソッドです。 今回は、入力があるたびにイベント発火を起こしたいため、以下のようにinputというイベントを使用します。そして console.logを記述して、入力するたびにイベント発火されるか確認をします。 【例】item_price.js const priceInput = document.getElementById("金額を入力する場所のid"); priceInput.addEventListener("input", () => { console.log("イベント発火"); }) 商品出品ページで金額を入力し、コンソール上に"イベント発火"と表示されるか確認をします。 もし"イベント発火"という文字列がコンソール上に表示されない場合は、以下の項目を確認しましょう。 -そもそもJSファイルが読み込めているか -turbolinksの記述が残っていないか -JSファイルのコードの記述に間違いがないか 手順4 必要なvalue属性を取得できるようにする 入力した金額の値を取得したい場合は、以下のようにvalue属性を指定する必要があります。 console.logを記述して、入力した金額の取得ができるか確認します。 【例】item_price.js const priceInput = document.getElementById("金額を入力する場所のid"); priceInput.addEventListener("input", () => { const inputValue = priceInput.value; console.log(inputValue); }) 続いて、商品出品ページで金額を入力し、コンソール上に金額が表示されるか確認をします。 もし金額の値がコンソール上に表示されない、もしくはエラーが出る場合は、以下の項目を確認しましょう。 -取得すべきidセレクタの場所に間違いがないか 手順5 HTMLをJavaScriptで作成し、ブラウザ上に描画できるようにする innerHTMLを使用して、販売手数料や利益計算結果を表示できる ようにしましょう。 innerHTMLは、HTML要素の書き換えを行うことができます。 【例】item_price.js const addTaxDom = document.getElementById("販売手数料を表示する場所のid"); addTaxDom.innerHTML = "入力した金額をもとに販売手数料を計算する処理" innerHTMLを実装することで、計算した販売手数料の金額に書き換え、表示することができます。 販売手数料や利益計算の処理は、Math.floorメソッドを用いて実装してみましょう。 もし、表示されているHTMLが崩れたり表示できない場合は、以下の項目を確認しましょう。 -console.logを使用して取得すべきidの場所に間違いがないか 今回はこんな感じ const priceInput = document.getElementById("item-price"); priceInput.addEventListener("input", () => { const inputValue = priceInput.value; const addTaxDom = document.getElementById("add-tax-price"); addTaxDom.innerHTML = (Math.floor(inputValue * 0.1)); const profitNumber = document.getElementById("profit") const value_result = inputValue * 0.1 profitNumber.innerHTML = (Math.floor(inputValue - value_result)); }) 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS基礎文法~if文~

概要 if文での条件分岐についての記事です。 if文とは、入力の値によって処理を変えて適切な結果を表示します。 プログラムでは、条件分岐の構文を使って処理の流れを変えます。 if文 index.js let score = 50; const num = 80; if (score > num) { console.log("すごい!"); }else{ console.log("頑張りましょう"); } 基本的なif文は以下のようになります。 定数numの80よりもscoreがtrueの処理とfalseの処理を記述します。 index.js score > num ? console.log("すごい!") : console.log("頑張りましょう"); 短縮すると上記のようになります。 index.js let score = 10; if (score < 60) { console.log("頑張りましょう"); }else if(score > 60 ){ console.log("さすが"); }else { console.log("前進あるのみ"); } 上記のプログラムだと数字以外が変数に代入された場合に前進あるのみと処理されます。 論理演算子 index.js let name = "あ"; const job = "医者" if(name === "なお" && job === "医者" ) { console.log("ご本人です"); } else { console.log("他人です"); } A && B ▶両方がtrueであればtrue A || B ▶どちらか一方がtrueであればtrue
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS基礎③

概要 プログラミングで使われる変数と定数についての記事です。 JSでは変数をlet,定数をconstで宣言します。 変数は、宣言してから再代入可能です。それに対して、定数は再代入ができません。 index.js let 変数名 = 〇〇; const 定数名 = 〇〇; 定数 定数は、代入した後に再代入することはできません。値を変えたくないときなどに使用します。 またもし値が変わった場合、代入の値を変えるだけで済むのでメンテナンスが楽になります。 定数は宣言したときに値を必ず代入しなくてはなりません。変数のように宣言後に再代入することはできません。 では以下のようなコードを修正していきます。 index.js console.log(800 + 600); console.log(800 + 500); index.js const price = 800; console.log(price + 600); //1400 console.log(price + 500); //300 変数 変数とは値をいれて使用する箱のような役割を果たします。 下記の例では、最初に変数priceに800を代入。この時点でpriceという箱に800が保存されています。 こうすることで、値を再代入することで処理を使い回すことができます。 index.js let price = 800; console.log(price + 600); //1400 console.log(price + 500); //300 price = 500; console.log(price); console.log(price + 600); //1100 console.log(price + 500); //1000 更に変数は再代入することができます。 price = 500;とあります。これは、priceに500を再代入しています。ここで、consoleで確認します。コンソールで500と確認することができました。 変数名定数名ともに、$マークや大小の大文字小文字、アンダースコアなどが使えます。しかし、JSの予約語は使えません。 ブロックスコープ index.js let fruit = "りんご"; if (fruit === "りんご") { let food = "ケーキ"; //ケーキ console.log(food); if (fruit === "りんご") {     console.log(fruit); //りんご console.log(food); //ケーキ } console.log(food); //ケーキ } console.log(fruit); //りんご console.log(food); //定義されていませせん 変数フルーツはグローバル変数といいます。同じページ内からであれば呼び出すことができます。 if文で宣言されたfoodには、ケーキが保存されています。変数foodはローカル変数といいます。 変数foodはif文のスコープ内であれば呼び出すことができます。 ただし、スコープの外では無効になります。 *スコープとは、{処理}の範囲になります。 再宣言 変数は再宣言することができますが、同じスコープ内では再宣言することはできません。 index.js if (fruit === "りんご") { let food; console.log(food); let food; } index.js let fruit = "りんご"; if (fruit === "りんご") { let food = "ケーキ"; console.log(food); if (fruit === "りんご") { let food = "カレー"; console.log(fruit); console.log(food); //カレー let food = "シチュー"; //error } console.log(food); } console.log(fruit); console.log(food); 関数スコープ 変数foodのりんごは関数名フルーツ内でのみ呼び出すことができます。 index.js function fruit () { let food = "りんご"; console.log(food); } function buy () { console.log(food); } fruit(); //りんご buy(); //error
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GoogleMapsAPI を使って地点検索/経路検索/コワーキングスペース検索ができるアプリを作った

表題の通り、GoogleMapAPIを用いた地点検索/経路検索/コワーキングスペース検索が出来る簡易Webアプリを作ったので記録します。 目的 ・JavaScriptの練習 ・地図表示/マーカー表示の練習 ・社内MBO(目標達成するとボーナス上がるやつ)に設定したので← 成果物 Webサイト ※テストデータの都合上、コワーキングスペース検索では新宿あたりのコワーキングスペースしか出ません。 ※簡単にレスポンシブ対応もしてます なお、例えばですが、作りこむと下記のようなサービスになることを想定して作ってます。(ドトールの店舗検索サービス) https://shop.doutor.co.jp/?_gl=1*1r4f95x*_ga*ODU2NTg5OTY3LjE2MTc0MzMwNDc.*_ga_XY2GKX2DP6*MTYxOTY1NTI1Ni4xMS4wLjE2MTk2NTUyNTYuMA.. ソースはこちら アプリ本体(.NET Core + JavaScript) コワーキングスペース検索で呼んでるAPI(.NET Core) GoogleMapAPI導入方法 GCPのコンソールからAPIKeyを取得して、scriptタグをHTMLに追加しないといけなかったりします。こちらを参照してください。 機能1 地点検索 検索欄に地名を入力し「Get Map」ボタンを押すと、入力した地点を中心とした地図が表示され、中心にマーカーが表示されます。 GoogleMapAPIの、地名と緯度経度の変換をしてくれる機能(Geocoding)が結構優秀なので、かなりマイナーな地名や、逆にざっくりしすぎた地名を入力しても検索してくれます。 実装 ボタンのidを"getMap"とし、クリック時にjs記載の処理が走るようにしています。 index.html <div class="heading font-weight-bold">地点検索</div> <input class="width-full" id="address" type="text" placeholder="地点を入力してください" /> <button id="getMap" class="btn">Get Map</button> initMap.js // 地点検索 地点⇔座標変換 $('#getMap').click(function () { // 画面入力値を取得 const address = document.getElementById("address") .value; // mapインスタンスを作る const map = new google.maps.Map(document.getElementById("map"), { zoom: 15 }); // GeocodingAPI使用 地点名(address)を緯度経度(results)に変換 const geocoder = new google.maps.Geocoder(); geocoder.geocode({ address: address }, function (results, status) { if (status === google.maps.GeocoderStatus.OK) { // 変換に成功したら // あらかじめ作ったmapインスタンスの中心緯度経度を設定 map.setCenter(results[0].geometry.location); // 中心にマーカーを設定 new google.maps.Marker({ map: map, position: results[0].geometry.location, }); } else { //変換に失敗したらアラート alert("Geocode was not successful for the following reason: " + status); } }); }) 機能2 経路検索  始点、終点を入力し、移動方法を選択したうえで「Get Route」ボタンを押すと、始点をA、終点をBとした移動経路が記載されます。 経路検索にはGoogleMapAPIの機能の内の一つ「Direction API」を使ってます。 実装 index.html   <div class="heading font-weight-bold">経路検索</div> <div> <input class="width-full" id="start" type="text" placeholder="始点を入力してください" /> </div> <div> <input class="width-full" id="end" type="text" placeholder="終点を入力してください" /> </div> <div> 移動方法 <select id="travelmode"> <option value="DRIVING">車</option> <option value="WALKING">徒歩</option> <option value="BICYCLING">自転車</option> <option value="TRANSIT">電車</option> </select> </div> <button id="getRoute" class="btn" value="Get Route">Get Route</button> initMap.js // 経路検索 ('#getRoute').click(function () { //Direction用インスタンス生成 const directionsService = new google.maps.DirectionsService(); const directionsRenderer = new google.maps.DirectionsRenderer(); //mapインスタンス生成 const map = new google.maps.Map(document.getElementById("map"), { zoom: 15 }); //画面入力値(始点・終点・モード)取得 const start = document.getElementById("start").value; const end = document.getElementById("end").value; const travelMode = document.getElementById("travelmode").value; //経路表示線(polyline)の色を紫に変える directionsRenderer.setOptions({ polylineOptions: { strokeColor: '#6F51A1' } }); //画面入力値をdirectionServiceに教える directionsService.route({ origin: start, destination: end, travelMode: google.maps.TravelMode[travelMode] }, function (response, status) { if (status === google.maps.DirectionsStatus.OK) { //成功したらmapに表示 directionsRenderer.setMap(map); directionsRenderer.setDirections(response); } else { //失敗したらアラート window.alert("Directions request failed due to " + status); } }); }) 機能3 コワーキングスペース検索 「コワーキングスペース表示」ボタンを押すと、別途作った自作APIを呼び、呼び出し結果を加工して地図にマーカー表示する。 また、呼び出し結果のうち最初の3件を画面右側に詳細表示する。 実装 別途作ったコワーキングスペース検索API(get通信叩くとDBからコワーキングスペース情報をJSONで返す)をたたいて、ajaxで地図表示しています。 index.html <div class="heading font-weight-bold">近隣コワーキングスペース検索</div> <div class="form-check"> <input class="form-check-input" type="checkbox" id="currentpositionflg"> <label class="form-check-label" for="currentpositionflg">現在地周辺を検索</label> </div> <button id="getCW" class="btn">コワーキングスペース表示</button> getCoworkingspace.js $(function () { $('#getCW').click( function () { $.ajax({ //自作 コワーキングスペースAPI url: 'https://coworkingspaceapi.azurewebsites.net/Coworkingspace', //通信方法 type: 'GET', //データ形式を指定 dataType: 'json', //通信に成功した場合の処理 }).done(function (data) { // データを地図外に表示 displayHtml(data); const useCurrentPosition = document.getElementById("currentpositionflg"); if (useCurrentPosition.checked) { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( function (position) { const currentLatLng = new google.maps.LatLng( position.coords.latitude, position.coords.longitude); displayMapByCurrentPosition(data, currentLatLng); }, function (error) { switch (error.code) { case 1: // PERMISSION_DENIED alert("位置情報の利用が許可されていません"); break; case 2: // POSITION_UNAVAILABLE alert("現在位置が取得できませんでした"); break; case 3: // TIMEOUT alert("タイムアウトになりました"); break; default: alert("その他のエラー(エラーコード:" + error.code + ")"); break; } } ) } else { alert("この端末では位置情報が取得できません"); } } else { displayMap(data); } //通信エラーになった場合の処理 }).fail(function (data) { alert("失敗しましたm(__)m"); }); }); }); function displayMap(data) { const map = new google.maps.Map(document.getElementById("map"), { zoom: 15, // 仮の値(東京都庁) center: { lat: 35.6896385, lng: 139.689912 } }); //現在地表示 const center = map.getCenter(); makeCurrentPos(map, center.lat(), center.lng()); //データを距離によって選択 var arrayPlace = []; var arrayName = []; for (let i = 0; i < data.length; i++) { const place = new google.maps.LatLng(data[i].lat, data[i].lon); const distance = google.maps.geometry.spherical.computeDistanceBetween(center, place); if (distance < 2400) { arrayPlace.push(place); arrayName.push(data[i].name); } } // 地図範囲調整 // 検索結果によっては地図が見づらくなることがあるので... map.fitBounds(new google.maps.LatLngBounds( // sw { lat: Math.min(...arrayPlace.map(d => d.lat())), lng: Math.min(...arrayPlace.map(d => d.lng())) }, // ne { lat: Math.max(...arrayPlace.map(d => d.lat())), lng: Math.max(...arrayPlace.map(d => d.lng())) } )); const markers = Array(arrayPlace.length); const infoWindows = Array(arrayPlace.length); for (let i = 0; i < arrayPlace.length; i++) { const cwLat = arrayPlace[i].lat(); const cwLng = arrayPlace[i].lng(); markers[i] = new google.maps.Marker({ map: map, position: { lat: cwLat, lng: cwLng } }); // 吹き出しの追加 infoWindows[i] = new google.maps.InfoWindow({ content: '<div class="map">' + arrayName[i] + '</div>' }); // マーカークリック時の吹き出し表示 markers[i].addListener('click', function () { infoWindows[i].open(map, markers[i]); }); } } function displayMapByCurrentPosition(data, currentLatLng) { var map = new google.maps.Map(document.getElementById("map"), { zoom: 15, // 現在地 center: currentLatLng }); //現在地表示 const center = map.getCenter(); makeCurrentPos(map, center.lat(), center.lng()); //データを距離によって選択 var arrayPlace = []; var arrayName = []; for (let i = 0; i < data.length; i++) { const place = new google.maps.LatLng(data[i].lat, data[i].lon); const distance = google.maps.geometry.spherical.computeDistanceBetween(center, place); if (distance < 2400) { arrayPlace.push(place); arrayName.push(data[i].name); } } // 地図範囲調整 map.fitBounds(new google.maps.LatLngBounds( // sw { lat: Math.min(...arrayPlace.map(d => d.lat())), lng: Math.min(...arrayPlace.map(d => d.lng())) }, // ne { lat: Math.max(...arrayPlace.map(d => d.lat())), lng: Math.max(...arrayPlace.map(d => d.lng())) } )); const markers = Array(arrayPlace.length); const infoWindows = Array(arrayPlace.length); for (let i = 0; i < arrayPlace.length; i++) { const cwLat = arrayPlace[i].lat(); const cwLng = arrayPlace[i].lng(); markers[i] = new google.maps.Marker({ map: map, position: { lat: cwLat, lng: cwLng } }); // 吹き出しの追加 infoWindows[i] = new google.maps.InfoWindow({ content: '<div class="map">' + arrayName[i] + '</div>' }); // マーカークリック時の吹き出し表示 markers[i].addListener('click', function () { infoWindows[i].open(map, markers[i]); }); } } // 現在地マーカー作成 function makeCurrentPos(map, currentLat, currentLon) { const currentMarker = new google.maps.Marker({ map: map, position: { lat: currentLat, lng: currentLon }, icon: { url: 'https://maps.google.com/mapfiles/ms/icons/purple-dot.png', scaledSize: new google.maps.Size(40, 40) } }) const currentMarkerWindow = new google.maps.InfoWindow({ content: '<div class="map">現在地</div>' }); // マーカークリック時の吹き出し表示 currentMarker.addListener('click', function () { currentMarkerWindow.open(map, currentMarker); }); }; //APIの戻り値最初の3件をHTML表示 function displayHtml(data) { $('#cw1_name').html(data[0].name); $('#cw1_description').html(data[0].description); $('#cw1_link').html("公式サイト"); var target1 = document.getElementById("cw1_link"); target1.href = data[0].url; $('#cw2_name').html(data[1].name); $('#cw2_description').html(data[1].description); $('#cw2_link').html("公式サイト"); var target2 = document.getElementById("cw2_link"); target2.href = data[1].url; $('#cw3_name').html(data[2].name); $('#cw3_description').html(data[2].description); $('#cw3_link').html("公式サイト"); var target3 = document.getElementById("cw3_link"); target3.href = data[2].url; } (参考)APIの戻り値 [ { "cw_id": 1, "name": "HAKADORU 新宿三丁目店", "lon": 139.70319, "lat": 35.690205, "url": "https://haka-doru.jp/", "description": "〒160-0022 東京都新宿区新宿3丁目1−24 京王新宿三丁目ビル 1F", "area_id": 1, "station_id": 1, "has_FreeDrink": true, "is_RecentCreated": false, "created": "2021-02-03T00:00:00", "updated": "2021-02-03T00:00:00" }, { "cw_id": 2, "name": "Workmedi", "lon": 139.6952, "lat": 35.697464, "url": "https://www.workmedi.jp/", "description": "〒160-0023 東京都新宿区西新宿7丁目7−26 ワコーレ新宿第一ビル 2階", "area_id": 1, "station_id": 1, "has_FreeDrink": true, "is_RecentCreated": false, "created": "2021-02-03T00:00:00", "updated": "2021-02-03T00:00:00" }, { "cw_id": 3, "name": "INBOUND LEAGUE", "lon": 139.69907, "lat": 35.692673, "url": "https://inbound-league.jp/", "description": "〒160-0022 東京都新宿区新宿5丁目15−14", "area_id": 1, "station_id": 1, "has_FreeDrink": true, "is_RecentCreated": false, "created": "2021-02-03T00:00:00", "updated": "2021-02-04T00:00:00" }, { "cw_id": 4, "name": "勉強カフェ", "lon": 139.69453, "lat": 35.68686, "url": "https://www.benkyo-cafe.net/studio/shinjuku/", "description": "〒151-0053 東京都渋谷区代々木2丁目14−1 新宿松本ビル6F", "area_id": 1, "station_id": 1, "has_FreeDrink": true, "is_RecentCreated": false, "created": "2021-02-03T00:00:00", "updated": "2021-02-04T00:00:00" }, { "cw_id": 5, "name": "クロスオフィス新宿", "lon": 139.69681, "lat": 35.694733, "url": "https://www.crossoffice.jp/office/shinjuku/", "description": "〒160-0023 東京都新宿区西新宿7丁目1−12", "area_id": 1, "station_id": 1, "has_FreeDrink": true, "is_RecentCreated": false, "created": "2021-02-03T00:00:00", "updated": "2021-02-04T00:00:00" }, { "cw_id": 7, "name": "TSUTAYA BOOK APARTMENT", "lon": 139.70016, "lat": 35.69179, "url": "http://tsutaya.tsite.jp/feature/store/tba_shinjuku/", "description": "〒160-0022 東京都新宿区新宿3-26-14 新宿ミニムビルⅠ4F ~6F、新宿ミニムビルⅡ5F~6F", "area_id": 1, "station_id": 1, "has_FreeDrink": true, "is_RecentCreated": false, "created": "2021-02-01T00:00:00", "updated": "2021-02-01T00:00:00" }, { "cw_id": 10, "name": "moboff SHINJUKU i-LAND", "lon": 139.69095, "lat": 35.69313, "url": "http://www.moboff-shinjuku.jp/", "description": "〒163-1320 東京都新宿区西新宿6丁目5−1 新宿アイランドタワ 20階", "area_id": 1, "station_id": 1, "has_FreeDrink": true, "is_RecentCreated": false, "created": "2021-02-01T00:00:00", "updated": "2021-02-01T00:00:00" }, { "cw_id": 11, "name": "BIZcomfort(ビズコンフォート)田町", "lon": 139.74352, "lat": 35.64858, "url": "https://bizcomfort.jp/", "description": "〒105-0014 東京都港区芝5丁目16−14 三田ノックスビル", "area_id": 1, "station_id": 1, "has_FreeDrink": true, "is_RecentCreated": false, "created": "2021-02-11T00:00:00", "updated": "2021-02-11T00:00:00" }, { "cw_id": 12, "name": "BASE POINT", "lon": 139.69307, "lat": 35.69512, "url": "http://office-bp.jp/", "description": "〒160-0023 東京都新宿区西新宿7丁目22−3 BP ビル ANNEX", "area_id": 1, "station_id": 1, "has_FreeDrink": true, "is_RecentCreated": false, "created": "2021-02-11T00:00:00", "updated": "2021-02-11T00:00:00" }, { "cw_id": 14, "name": "HAPON SHINJUKU", "lon": 139.69641, "lat": 35.696007, "url": "https://hapon.asia/shinjuku/", "description": "〒160-0023 東京都新宿区西新宿7丁目4−4", "area_id": 1, "station_id": 1, "has_FreeDrink": true, "is_RecentCreated": false, "created": "2021-02-11T00:00:00", "updated": "2021-02-11T00:00:00" } ] 【補足】イケてないところ、改善点 ・地図表示画面が小さい。本家GoogleMapみたいに地図表示の割合を大きくして、その上に検索欄を作るなどしたい ・コワーキングスペース検索で、地図上の検索結果と右側に出る詳細情報が紐づいてなくて見づらい 長文ですが、長くなってしまいましたね。 機能ごとに分けて記事を詳細化するかもしれません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】未経験独学エンジニアのポートフォリオ【概要・気づき編】

概要・気づき編 ポートフォリオ Log: https://portfolio-studyapp.web.app/ アプリ概要 用途 自分が取り組んだことを記録して視覚化 使い方 取り組み時間、場所、集中力、内容を記録 記録した内容をユーザーごとに管理 カレンダーとデータを同期 場所ごとにグラフを用いて集中力を視覚化 特徴 SPA(シングルページアプリケーション) Firebase(BaaS)を使用したフロントエンドのみの実装 ニューモーフィズムを取り入れた最新のデザイン 作成理由と意図 理由 ポートフォリオ VueとFirebaseを使ったバックエンドレスなフロントエンド開発 ユーザー毎のデータ管理の実装 意図 作成決定までのフロー 作りたいものがない→何を基準に作りたいものを決定するべきか→自分の一番身近なものに目を向けよう→プログラミングの勉強→解決すべき課題は?→計画を立てるのが苦手でいつも挫折している→勉強した後に記録をするようにして見える化を図り逆説的に計画が立てれるようにならないか 意識したこと 新しい知識はほどほどにして学んだ内容をフルに活用する Vueの機能を網羅的に使いwebアプリケーションの最低限の機能を備える 作ってみて感じたこと 教材をやるより楽しい 非同期処理の理解が深まる 次作るものへの意欲が湧く 成功体験を得ることができる 追加機能を付けてみたくなる CSSのbox-shadowは結構コピペ VueのCSS設計について学ぶことができる 教材を使って勉強するより圧倒的に身に付く Vueのライフサイクルについて深く勉強できる 実体験を通じたGitの勉強をすることができる 一つのコードを書く上でも計画を立てることの重要さを知る Array型はかなり便利だと知る(頼り過ぎていいものか模索中) vuetifyの一部導入は結構めんどくさい(やるなら全てマテリアルデザインにしたほうがいい) 抜粋 追加機能を付けてみたくなる アプリケーションとは最低限の機能を実装した上で、プラスアルファによって進化していくものだと感じた。完成形を先に決める必要はなく、今後どのように展開させていくのか考えることこそが重要で、作ってみないとこの考えには至らなかったと痛感している。今後追加してみたい機能は後述する。 実体験を通じたGitの勉強をすることができる 今までなんとなくGitを使用していたが重要さについては理解できていなかった。教材をやるときは流れが全て決まっているため履歴を管理する必要がなかったからだ。今回全ての工程を自分で管理してみて履歴管理とブランチを作ることの重要さを痛感した。 例えばDBとの通信をaxiosからFirebaseのメソッドに変える時、色々なコンポーネントやファイルを書き換える必要があったため挙動がうまくいかない可能性がある。その時ブランチを切ることでリスクを回避することができた。 VueのCSS設計について 教材でやるときはあらかじめクラスが振られているため考える必要がなかったが、今回自分でコンポーネントの管理をする必要があったためCSS設計について初めて疑問を持つことができた。親コンポーネントにscopedが振られてない時の挙動や子コンポーネントでのクラスの付け方、レスポンシブ対応の時にどのようにファイルを分けるのか考えるきっかけになった。 次回 技術選択編
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascript 配列のループ処理 勉強用

配列のループ処理の種類 forEach / filter / mapの3種類がある forEachで配列要素を繰り返し処理する forEachは、配列データに対してのみ実行することが可能で、各要素1つずつに任意の処理を実行させることがでる。 let items = [ 'バナナ', 'リンゴ', 'メロン', 'ブドウ' ]; items.forEach(function( value ) { console.log( value ); }); 実行結果 バナナ //配列要素を1つずつコンソールに出力 リンゴ メロン ブドウ filterで配列要素を抽出する let items = [5,2,7,8,3,1,6,8,4]; let result = items.filter( function( value ) { //5よりも小さい数値だけを抽出 return value < 5; }) console.log( result ); 実行結果 [2, 3, 1, 4] //5よりも小さい数値だけを抽出 mapで処理した要素を新しい配列で作成する let items = [1,2,3,4,5]; let result = items.map(function( value ) { //配列の各要素を2倍にする return value * 2; }); console.log( result ); 実行結果 [2, 4, 6, 8, 10] //1*2,2*2,2*3,2*4,2*5の結果を新しい配列として作成する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascript 配列の連結、結合、分割方法 勉強用

配列を連結・結合する方法 (join()) join()は、配列の各要素を連結・結合して「文字列(String)」として出力することができる。 let items = [2018, 1, 10]; let result = items.join('/'); console.log( result ); 実行結果 2018/1/10 //要素ごとに/が追加され文字列として出力される。 join()の引数を何も指定しない場合 let items = ['バナナ', 'イチゴ', 'リンゴ', 'メロン']; let result = items.join(); console.log( result ); 実行結果 バナナ,イチゴ,リンゴ,メロン //カンマ区切り」の文字列を取得 配列を分割する方法 (slice) slice()は、指定した配列のインデックス番号を境目に分割して 新しい配列データを取得することができる。 let items = ['バナナ', 'イチゴ', 'リンゴ', 'メロン']; let result = items.slice( 2 ); console.log( result ); 実行結果 ["リンゴ", "メロン"] //配列の2番目のインデックス番号にある要素から末尾までを分割 slice()は「開始位置」「終了位置」の2つの値を引数に取ることもできる。 let items = ['バナナ', 'イチゴ', 'リンゴ', 'メロン']; let result = items.slice( 1, 3 ); console.log( result ); 実行結果 ["イチゴ", "リンゴ"] //配列の1番目のインデックス番号から3番目のインデックスの手前までの要素を分割
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascript 配列の参照、追加、削除方法 勉強用

配列の参照 let firstName = ['kato','sato','suzuki','tanaka','hayama']; //1番目の要素 console.log('firstName[0]:' + firstName[0]); //4番目の要素 console.log('firstName[3]:' + firstName[3]); //6番目の要素(空っぽ) console.log('firstName[5]:' + firstName[5]); 実行結果 firstName[0]:kato //firstName[0] katoの要素が取得される。 firstName[3]:tanaka //firstName[3] tanakaの要素が取得される。 firstName[5]:undefined //firstName[5] 要素がないのでundefinedが返ってくる。 配列の要素を追加する方法 追加したい配列の現在の一番後ろの要素番号を指定して追加する方法と pushメソッドを使い要素を追加する方法 let firstName = ['kato','sato','suzuki','tanaka','hayama']; console.log('追加前:' + firstName); // 要素を追加 firstName[5] = 'maeda'; console.log('追加後:' + firstName); // pushメソッドを使い要素を追加 firstName.push('yamada'); console.log('追加:' + firstName); 実行結果 追加前:kato,sato,suzuki,tanaka,hayama //追加前の要素 追加後:kato,sato,suzuki,tanaka,hayama,maeda //指定した要素番号に追加 追加:kato,sato,suzuki,tanaka,hayama,maeda,yamada //一番最後の要素の後ろに追加 配列の要素を削除する方法 let firstName = ['kato','sato','suzuki','tanaka','hayama']; // ‘sato’君が転校することになった delete firstName[1]; console.log(firstName); 実行結果 [ 'kato', , 'suzuki', 'tanaka', 'hayama' ]//指定したfirstName[1] satoが削除される。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascript 配列の宣言方法 勉強用

配列の宣言方法 配列の宣言には2種類の方法がある。 1つ目は配列コンストラクタ「Array」を使う方法で、2つ目は配列リテラル「[ ]」を使う方法。 一般的には配列リテラル[ ]を使う。 //①配列コンストラクタの例 let array1 = new Array('リンゴ', 'バナナ', 'イチゴ'); //②配列リテラルの例 let array2 = ['リンゴ', 'バナナ', 'イチゴ']; console.log( array1 ); console.log( array2 ); 実行結果 ["リンゴ", "バナナ", "イチゴ"] //配列の[0][1][2]の全要素が取得される。 ["リンゴ", "バナナ", "イチゴ"] //配列の[0][1][2]の全要素が取得される。 結果が異なる配列 let array1 = new Array(5); let array2 = [5]; console.log( array1 ); console.log( array2 ); 実行結果 [empty × 5] //5つ分の配列要素を用意する [5] //5という数値を配列に格納する 配列の初期化 すでに作成した配列データを初期化する方法 配列データの中身を空っぽにする let array = []; console.log( array ); 実行結果 [] //空の要素が取得される
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む