- 投稿日:2020-06-02T23:53:35+09:00
お絵かきできるSNSを作りたい!9
お絵かきできるSNSを作りたい後半戦、下のメニューを作っていきます。
まずはPNGで保存機能。
function saveCanvas(){ var src1_img = new Image(); var src2_img = new Image(); src1_img.src = $("#canvas")[0].toDataURL(); src1_img.addEventListener('load', function() { src2_img.src = $("#canvas2")[0].toDataURL(); src2_img.addEventListener('load', function() { var dst_canvas = document.createElement('canvas'); dst_canvas.width = 800; dst_canvas.height = 600; dst_canvas.getContext("2d").drawImage(src1_img, 0, 0, 800, 600); dst_canvas.getContext("2d").drawImage(src2_img, 0, 0, 800, 600); var imageType = "image/png"; var fileName = "download.png"; // base64エンコードされたデータを取得 「data:image/png;base64,iVBORw0k~」 var base64 = dst_canvas.toDataURL(imageType); // base64データをblobに変換 var blob = Base64toBlob(base64); // blobデータをa要素を使ってダウンロード saveBlob(blob, fileName); }, false); }, false); } // Base64データをBlobデータに変換 function Base64toBlob(base64){ // カンマで分割して以下のようにデータを分ける // tmp[0] : データ形式(data:image/png;base64) // tmp[1] : base64データ(iVBORw0k~) var tmp = base64.split(','); // base64データの文字列をデコード var data = atob(tmp[1]); // tmp[0]の文字列(data:image/png;base64)からコンテンツタイプ(image/png)部分を取得 var mime = tmp[0].split(':')[1].split(';')[0]; // 1文字ごとにUTF-16コードを表す 0から65535 の整数を取得 var buf = new Uint8Array(data.length); for (var i = 0; i < data.length; i++) { buf[i] = data.charCodeAt(i); } // blobデータを作成 var blob = new Blob([buf], { type: mime }); return blob; } // 画像のダウンロード function saveBlob(blob, fileName){ var url = (window.URL || window.webkitURL); // ダウンロード用のURL作成 var dataUrl = url.createObjectURL(blob); // イベント作成 var event = document.createEvent("MouseEvents"); event.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); // a要素を作成 var a = document.createElementNS("http://www.w3.org/1999/xhtml", "a"); // ダウンロード用のURLセット a.href = dataUrl; // ファイル名セット a.download = fileName; // イベントの発火 a.dispatchEvent(event); }無駄に関数が増えました。
レイヤーが2枚あるので1枚にがっちゃんこしてます。
・[github]修正内容はこちら次はフルスクリーンボタンの実装です。
var blFullscreen = true; function doFullscreen(){ var elem = document.getElementById("screen"); if (blFullscreen){ if (elem.requestFullscreen) { elem.requestFullscreen(); } else if (elem.webkitRequestFullScreen) { elem.webkitRequestFullScreen(); } else if (elem.mozRequestFullScreen) { elem.mozRequestFullScreen(); } else if (elem.msRequestFullscreen) { elem.msRequestFullscreen(); } blFullscreen = false; } else { if (document.webkitCancelFullScreen) { document.webkitCancelFullScreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } else if(document.cancelFullScreen) { document.cancelFullScreen(); } else if(document.exitFullscreen) { document.exitFullscreen(); } blFullscreen = true; } }フルスクリーン状態の判定をJSで行おうとするとブラウザによって挙動が怪しくなり悩むくらいならとグローバルおじさんになりました。
あと細かい修正もしたので詳しくは↓こちらを。
・[github]修正内容はこちらそして、左右反転。
これがちょっと手間で、左右反転するとレイヤー1とレイヤー2のX座標も反転させています。
メインの関数は↓こちら。var blReflect = true; function doReflect(){ if (blReflect){ $("#canvas").css('transform', 'scale(-1, 1)'); $("#canvas2").css('transform', 'scale(-1, 1)'); blReflect = false; } else { $("#canvas").css('transform', 'scale(1, 1)'); $("#canvas2").css('transform', 'scale(1, 1)'); blReflect = true; } }あとは、押したとき、動かしている時、離したときに左右反転状態かを判定してX座標を左右逆になるようにしました。
if (blReflect) { ox=event.clientX-event.target.getBoundingClientRect().left; } else { ox=$("#canvas").width() + (parseInt($("body").css('padding-left')) * 2) - event.clientX-event.target.getBoundingClientRect().left; }今回最後は最初から書き直すの実装です。
これはページリロードでいいんじゃ・・?とも思いましたが、折角なのでちゃんと実装しました。function doClear(){ if(confirm('本当にいいんですね?')){ ct.clearRect(0, 0, $("#canvas").width(), $("#canvas").height()); ct2.clearRect(0, 0, $("#canvas2").width(), $("#canvas2").height()); } }ちゃんとアラートで消すことを確認する新設設計。
レイヤー1とレイヤー2をクリアしています。次回、Ctrl+Zをしたい。お楽しみに。
- 投稿日:2020-06-02T22:38:31+09:00
非同期通信の手順書②
前提条件
以下のブログを読んでから本記事をお読みください。
非同期通信の手始めにcreateアクションに何を記入するか
何をjsonで返して、何をHTMLで返すか…
それはrespond_toで決めるのでした。以下、コードです。def create @comment = Comment.create(comment_params) respond_to do |format| format.html { redirect_to tweet_path(params[:tweet_id]) } format.json end end気付く人は気付きますがrender json 〇〇がありません。
これはこの後にjbuilderを用いるためです。
次はjbuilderについて記述します。
- 投稿日:2020-06-02T22:17:52+09:00
とりあえずVue.jsのComposition APIで書くためのまとめ
自分含め、これまで Vue.js 2.x でコードを書いていた人に向けて書きます。
あまり深いところや細かいところまでは掘らずに、Vue.js 2.x で書いてきた基本的な記述をComposition APIで書くために、と言う視点で書いてみました。目次
- Composition API
- Vue.js 2.xで慣れ親しんだ書き方からの移行
- ロジックの抽出と再利用
Composition API
これまでのVue.jsでは
data
computed
methods
などのoptionごとにリアクティブなデータや関数などを書いてきたが(Options API
というらしい)、大きなコンポーネントになってくると必要な機能ごとにコードをまとめた方がいい。そのための関数ベースのAPI群。Vue.jsのv3から利用可能予定。
v2でもプラグインとして利用可能。現在はRFCとして仕様を揉んでいるところなのでここに記載の内容は変更される可能性があります。
https://vue-composition-api-rfc.netlify.app/メリット
- 自由なコードの構成
- ロジックの抽出と再利用
- 型推論の強化
これまでのVue.jsのOptions APIを上書きするのものではなく、上記のメリットを受けられるような大規模なプロジェクトで使うのが良い。
Options APIはそれ自体がコードの規約となるので小・中規模なプロジェクトでとても有用と思う。setup()
setup
は新しいOptionで、コンポーネント内でComposition API を使うときのエントリーポイントになります。
setup
関数内にリアクティブなデータや算出プロパティ、メソッドなどを定義していきます。<template> ... </template> <script> import { computed, ref, reactive } from 'vue' // 必要なAPIはimportが必要 export default { setup() { // } } </script> <style> ... </style>
setup
関数内で使うcomputed
,ref
,reactive
などの関数(後述)はimportしておく必要があります。import { computed, ref, reactive } from 'vue'templateで使うものは return { } が必要
template
で使う値や関数はsetup
関数の最後でreturn
しておく必要がある。
下の例でいうとreturnされたcount
などは、いままでのOptions APIで言うところのthis.count
のような形でぶら下ります。
いちいちこれを書く手間がある一方、template
でどの値/関数が使われているかがわかりやすいというメリットもあります。<template> <div> {{ count }} * 2 = {{ double }} <button @click="increment">+</button> </div> </template> <script> import { computed, ref, reactive } from 'vue' export default { setup() { const count = ref(0) const double = computed(() => { return count.value * 2 } const increment = () { count.value++ } // template で出力するデータはここで渡す必要がある return { count, double, increment } } } </script>Options APIからCompositio APIへの移行
これまで慣れ親しんだOptions APIでの書き方をComposition APIで書くときのまとめです。
data
やcomputed
などoptionごとに書いてます。data
ref()
、またはreactive()
でリアクティブなデータを扱うことができます。ref()
ref
関数は数値や文字列、booleanなどのプリミティブ値を引数にとり、リアクティブなrefオブジェクトを返す
setup
関数内でリアクティブな値を使う場合は.value
プロパティを参照します。<template> <div> {{ count }} </div> </template> <script> import { ref } from 'vue' export default { setup() { const count = ref(0) // リアクティブな値をもつオブジェクトを返す console.log(count.value) // 0 count.value++ console.log(count.value) // 1 const increment = () => { count.value++ } return { count } // return する場合はリアクティブなrefオブジェクトごと返す。 .value は不要 } } </script>reactive()
オブジェクトを引数にとり、リアクティブプロキシーを返します。Vue.js 2.x系の
Vue.observable()
と等しいようです。
(参考:Proxy - MDN web docs)The reactive conversion is "deep": it affects all nested properties. In the ES2015 Proxy based implementation, the returned proxy is not equal to the original object. It is recommended to work exclusively with the reactive proxy and avoid relying on the original object.
<template> <div> {{ state.count }} {{ state.code }} </div> </template> <script> import { reactive } from 'vue' export default { setup() { const state = reactive({ count: 1, code: 'ready' } state.count++ // 2 refオブジェクトと違い.valueを参照しない return { state } } } </script>computed
算出プロパティは
computed
関数を使います。
引数にgetter関数をとり、イミュータブルなref
オブジェクトを返します。
templateで使う場合はもちろんreturn
する必要があります。import { ref, computed } from 'vue' export default { setup() { const count = ref(2) count.value++ // 3 const double = computed(() => { return count.value * 2 }) console.log(double.value) // 6 double.value++ // error return { double } } }methods
Composition APIのなかで
methods
は単純なJavaScriptの関数として宣言します。
template
内で利用する場合はリアクティブな値と同様、setup
関数の最後にreturn
してあげる必要があります。<template> <div> Count is {{ count }} <button @click="increment">+</button> </div> </template> <script> import { ref } from 'vue' export default { const count = ref(1) // 単純なJSの関数として宣言する const increment = () => { count.value++ } return { count, increment } } </script>props
これまで同様、
setup
関数の外で指定。setup(props)
のように引数に指定し使う。setupに渡されたpropsオブジェクトはリアクティブであり、export default { props: { id: string }, setup(props) { // props.id } }ただし
props
オブジェクトからプロパティだけを取り出すとリアクティビティは失われます。export default { props: { id: Number }, setup({ id }) { watchEffect(() => { console.log(`id is: ` + id) // リアクティブではなくなる。 }) } }created(), mounted(), updated()
RFCのリファレンスには以下のような対応表があります。
https://vue-composition-api-rfc.netlify.app/api.html#lifecycle-hooks
beforeCreate
->setup()
を使うcreated
->setup()
を使うbeforeMount
->onBeforeMount
mounted
->onMounted
beforeUpdate
->onBeforeUpdate
updated
->onUpdated
beforeDestroy
->onBeforeUnmount
destroyed
->onUnmounted
errorCaptured
->onErrorCaptured
created()
setup
関数はpropの初期値が解決された後、beforeCreated
フックとcreated
フックの前に呼ばれます。
そのためsetup
自体をbeforeCreated
,created
として扱うのがいいようです。なお、
setup
はいままでのcreated
よりも前に解決されるため、
- setup関数内からはこれまでの data() のプロパティやmethodsの関数にアクセスできない
- 逆に
setup
でreturn された値/関数はcreated() やmethodsの中でthis.xxx
の表記でアクセスできる。となります。
mounted(), updated()
created
,beforeCreated
以外のライフサイクルフック、例えばmounted
,updated
なんかは
onXxxx
の形でimportした上でsetup
関数内でonMounted()
onUpdated()
のように使います。import { onMounted, onUpdated } from 'vue' export default { setup() { onMounted(() => { console.log('mounted.') } onUpdated(() => { console.log('updated.') }) } }そのほかのライフサイクルフック
beforeMount()
,beforeUpdate()
,beforeDestroy()
,destroyed()
,errorCaptured()
などのそのほかのLife Cycle Hookも同様に関数をimportしてsetup
内で使います。import { onBeforeMount, onBeforeUpdate, onBeforeUnmount, onUnmounted, onErrorCaptured } from 'vue' export default { setup() { onBeforeMount(() => { ... }) // = beforeMount() onBeforeUpdate(() => { ... }) // = beforeUpdate() onBeforeUnmount(() => { ... }) // = beforeDestroy() onUnmounted(() => { ... }) // = destroyed() onErrorCaptured(() => { ... }) // = errorCaptured() } }emit, attrs, slots
emit
,attrs
,slots
は、setup
関数の第二引数に渡されるcontext
オブジェクトを通してアクセス可能です。export default { setup(props, context) { context.attrs context.slots context.emit } }ロジックの抽出と再利用
Composition APIを使うメリットの一つにロジックの抽出とその再利用があります。
いくつかのコンポーネント間で利用されるような機能のロジックや、膨大で複雑なコードの機能を切り出して再利用することができ、見通しがよく効率的なコードが書けます。
ロジックを抽出して再利用する際にも、Composition APIのコード構成に対する非常に高い柔軟性が活きてきます。以下の例はクリックで増えるカウントに対する機能を抽出しています。
// count.vue import { ref, computed, onMounted } from 'vue' export function count() { const count = ref(0) const update = (e) => { count.value++ } const displayCount = computed(() => { return status.value = count.value >= 10 ? '10+' : count.value }) onMounted(() => { window.addEventListener('click', update) }) return { cont, displayCount } }抽出した
count
関数を利用しますimport { count } from './count' export default { setup() { const { count, displayCount } = count() return { count, displayCount } } }終わりに
Compositio APIの基本的な書き方、そしてこれまでのVue.jsに慣れ親しんだ人からの目線での書き方をまとめてみました。
Composition APIにはここで紹介していないAPIがまだあります。
冒頭のメリットでも触れたように、自由なコード構成、型サポートの強化、ロジックの抽出など、特に大規模なプロジェクトでは非常に可能性を感じさせる新機能となることでしょう。一方、RFCである現在(2020/06)はAPIの追加や破壊的変更がされる可能性があります。
そのため業務での利用はまだ難しいですが、
来るべきVue.js 3.0の正式リリースに備え今から概要を掴んでいくのは良いかなと思います。
- 投稿日:2020-06-02T19:32:37+09:00
Nightwatch で E2E テストをしたいので Bing 検索のテストを書いてみた
Vue CLI で e2e テストを有効にすると入ってくる Nightwatch ですが、こんな感じで使うよ~というメモです。
公式サイト
こちらです。よくまとまったドキュメントもあります。
Bing で検索するテストを書いてみよう
サンプルとしては、ecosia のサイトの検索とか Google の検索とかがあります。
プレーンな API を使った例としては Nightwatch の公式を開いた時点でコード例が上がってます。ただ、実際に画面系のテストをするときは Page Object Pattern を少なくとも使わないとテストコード内にページの内部実装に依存したコードが散らばって大変なことになります。なので、Page Object の機能を使って Bing で Microsoft と検索して、検索結果のページのテキストボックスに Microsoft という文字列がちゃんと入っているか確認するというテストを書いてみようと思います。
とりあえず必要最低限だけだと以下のドキュメントを見るといいかも。
Chai の expect とかも使えるみたいなので、興味があったらこっちのドキュメントも見ておくといいかもです。
Chai の expect って可読性のための Chain が
- to
- be
- been
- is
- that
- which
- and
- has
- have
- with
- at
- of
- same
- but
- does
- still
とあって、個人的には英語圏の人じゃないとフルの恩恵って難しいような気がするんだけどどうだろう?(英語弱者の意見
というわけで Nightwatch で Bing 検索してみようと思います。
プロジェクトの作成
以下のコマンドでプロジェクトの作成と必要な依存関係をインストールします。
$ npm init -y $ npm install --save-dev nightwatch chromedrivernightwatch.conf.js を以下のような内容で作ります。chrome を使うということと、テスト用のソースコードは tests/e2e フォルダーだということを設定しています。その他にもカスタムコマンド(今回は使わないのでコメントアウト)、カスタムアサーション(今回は使わないのでコメントアウト)、ページオブジェクトのパスを指定しています。
nightwatch.conf.jsconst chrome = require('chromedriver') module.exports = { src_folders: ['tests/e2e'], //custom_assertions_path: ['tests/custom-assertings'], //custom_commands_path: ['tests/custom-commands'], page_objects_path: ['tests/page-objects'], webdriver: { start_process: true, server_path: chrome.path, port: 9515, }, test_settings: { default: { desiredCapabilities: { browserName: 'chrome', }, }, }, }では、tests/page-objects/bingTop.js に Bing のトップページのページオブジェクトを作っていきましょう。
ページオブジェクトではセクションというものを使って、いい感じにページを領域単位に区切って管理することが出来ます。例えばヘッダーやメニューや入力フォームやレポート出力領域のような感じです。セクションを使わずにべたっとエレメントを定義することも出来ますが、小さな画面じゃない限りはセクション区切った方が可読性的にはいいと思います。セクションの使い方を示すために、今回の Bing のトップページはセクションいらないくらいシンプルなのですが、あえてセクションを定義しています。
tests/page-objects/bingTop.jsmodule.exports = { url: 'https://bing.com?cc=jp', sections: { search: { selector: '', elements: { input: { selector: '', }, submit: { selector: '', }, }, }, }, };とりあえず操作項目としては、検索入力エリアと検索ボタンがあればいいので、それを定義しました。selector を指定していないので、Chrome か Chronium Edge で bing を開いて開発者ツールを開いて要素のツリーでセレクターがゲットしたいエレメントで右クリックしてコピー→セレクターでセレクターをゲットします。
セレクターを入れるとこんな感じです。
tests/page-objects/bingTop.jsmodule.exports = { url: 'https://bing.com?cc=jp', sections: { search: { selector: 'body > div.hp_body > div.hp_cont', elements: { input: { selector: '#sb_form_q', }, submit: { selector: '#sb_form > label', }, }, }, }, };これでテストコードからは、セレクターを指定せずにセクション名やエレメント名でアクセスできます。ページの構造が変わってもページの仕様が大きく変わらなければページオブジェクトの修正だけで対応できます。
後は、コマンドも定義できて例えば今回の例だと検索ボタンを押すとかいうのを以下のようにコマンドで定義できます。
tests/page-objects/bingTop.jsconst bingCommands = { wait: function() { this.section.search.waitForElementVisible('@input'); }, submit: function() { this.section.search.waitForElementVisible('@submit') .click('@submit') .waitForElementNotPresent('@submit'); }, }; module.exports = { commands: [bingCommands], url: 'https://bing.com?cc=jp', sections: { search: { selector: 'body > div.hp_body > div.hp_cont', elements: { input: { selector: '#sb_form_q', }, submit: { selector: '#sb_form > label', }, }, }, }, };同じ要領で検索結果のページのページオブジェクトも
tests/page-objects/bingSearchResult.js
に以下のように定義しました。tests/page-objects/bingSearchResult.jsmodule.exports = { sections: { header: { selector: '#b_header', elements: { input: { selector: '#sb_form_q', }, }, }, }, };ページが出来たのでテストを書いていきます。
tests/bingtest.js
に以下のように書きました。これで、
npx nightwatch
というコマンドを叩くとブラウザーが起動して画面に文字をうって操作してアサートしてくれます。後は、ものによっては Nightwatch のページオブジェクトのエレメントとかは、日本語にしてもいいかもですね。以下のように。tests/page-objects/bingSearchResult.jsconst bingSearchResultCommands = { wait: function() { this.section.header.waitForElementVisible('@検索欄'); } }; module.exports = { commands: [bingSearchResultCommands], sections: { header: { selector: '#b_header', elements: { '検索欄': { selector: '#sb_form_q', }, }, }, }, };tests/page-objects/bingTop.jsconst bingCommands = { wait: function() { this.section.search.waitForElementVisible('@検索欄'); }, submit: function() { this.section.search.waitForElementVisible('@submit') .click('@submit') .waitForElementNotPresent('@submit'); }, }; module.exports = { commands: [bingCommands], url: 'https://bing.com?cc=jp', sections: { search: { selector: 'body > div.hp_body > div.hp_cont', elements: { '検索欄': { selector: '#sb_form_q', }, submit: { selector: '#sb_form > label', }, }, }, }, };こうすると、テストコードは以下のようになります。チームでのルール決めですが日本オンリーならありかも。
tests/e2e/bingtest.jsmodule.exports = { beforeEach: function(browser) { browser.page.bingTop() .navigate() .wait(); }, '検索語を入力して検索結果の画面に遷移': function(browser) { const bingTop = browser.page.bingTop(); bingTop.section.search.setValue('@検索欄', 'Microsoft'); bingTop.submit(); const bingSearchResult = browser.page.bingSearchResult(); bingSearchResult.wait(); bingSearchResult.section.header.assert.value('@検索欄', 'Microsoft'); browser.end(); }, '検索語を入力して検索結果の画面に遷移(日本語版)': function(browser) { const bingTop = browser.page.bingTop(); bingTop.section.search.setValue('@検索欄', 'マイクロソフト'); bingTop.submit(); const bingSearchResult = browser.page.bingSearchResult(); bingSearchResult.wait(); bingSearchResult.section.header.assert.value('@検索欄', 'マイクロソフト'); browser.end(); }, };動かしてみた結果は以下のような感じです。
まとめ
Nightwatch を使うと割とさくっと簡単に E2E テストが出来そうですね。
GitHub Actions の Windows マシンに入ってるブラウザーのリストにも Chrome がいるので、GitHub Actions でも気軽に走らせることが出来るかも。
- 投稿日:2020-06-02T18:39:02+09:00
【Nuxt.js】Nuxt文法編:v-for
前置き
文法シリーズ第二弾
今回は定番のv-forです!文法は覚えましょう?
ある程度の構文・単語は
覚える必要があります?
英文法・英単語を覚えないと
文が作れないのと同じです??❓どんな時に使うか
配列やオブジェクトを
listで描写させる時に使います。
https://note.com/aliz/n/nda7438249ca8v-for
https://qrunch.net/@rokujiro/entries/ylmWdFAZsaAtMTpq?ref=qrunch
【解説】
・v-for="i in 6"
forといえば繰り返しですね。
数字の6までの1つ1つをiとし
それを繰り返しています。
・:key
ここだと分かりにくいので
後半に解説します。index.vue<template> <div class="page"> <ul> <li v-for="i in 6" :key="i" > {{ i }} </li> </ul> </div> </template>配列の繰り返し
【解説】
・v-for="item in items"
配列のitemsにある
1つ1つのオブジェクトをitemと名付けます。
in の代わりに of も使用できます?
・:key (v-bind: key)
プロパティ= key
1つ1つの要素がitemなので
item.messageになります?
(itemの中のmessageプロパティ)
⏬左がプロパティ: 右が値です!
message: 'Foo',
message: 'Bar',
v-forには基本的に一意のkeyを指定します。
要素を効率よく追跡し、
パフォーマンス向上のためです。
一意については
オブジェクトのv-forで解説しています?
?keyによる再利用可能な要素の制御
https://note.com/aliz/n/n76280a0e3a02/edit
・{{ item.message }}
itemsの1つ1つの要素をitemとしたので
itemのmessageプロパティの値を表示
index.vue<template> <div class="page"> <ul> <li<img width="665" alt="スクリーンショット 2020-06-01 10.48.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/3923d8d8-bbcd-4d8e-309d-5673130b1fea.png"> v-for="item in items" :key="item.message" > {{ item.message }} </li> </ul> </div> </template> <script> export default { data () { return { items: [ { message: 'Foo' }, { message: 'Bar' }, ] } }, } </script>配列番号のサポート
v-forは配列[ ]のインデックス(配列番号)を
第二引数としてサポートしています?
配列番号は0からスタートします!index.vue<template> <div class="page"> <ul> <li v-for="(item, index) in items" :key="item.message" > {{ parentMessage }} - {{ index }} - {{ item.message }} </li> </ul> </div> </template> <script> export default { data () { return { parentMessage: 'Parent', items: [ { message: 'Foo' }, { message: 'Bar' }, ] } }, } </script>【解説】
v-forで繰り返すのはitem.messageのみ
そのため配列0,1の2つが表示されます。オブジェクトのv-for
配列だけでなくオブジェクトにも使えます?
index.vue<template> <div class="page"> <ul> <li v-for="value in object"> {{ value }} </li> </ul> </div> </template> <script> export default { data () { return { object: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } } }, } </script>【表示】
?オブジェクトでも配列と同様に
keyと配列番号が使用できます!【index.vue: keyを使用】
バラバラのプロパティ名ですが、
これらのkeyをnameと名付けて使用しています?index.vue<template> <div class="page"> <ul> <li v-for="(value, name) in object" :key="name" > {{ name }} : {{ value }} </li> </ul> </div> </template> <script> export default { data () { return { object: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } } }, } </script>【index.vue: 配列番号indexを使用】
index.vue<template> <div class="page"> <ul> <li v-for="(value, name, index) in object" :key="name" > {{ index }}. {{ name }} : {{ value }} </li> </ul> </div> </template> <script> export default { data () { return { object: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } } }, } </script>:keyに使う値
❌非プリミティブ値
オブジェクトや配列
⭕️プリミティブ値
文字列や数字【解説】
・:key="index"
indexは配列番号のため非プリミティブ値
配列は追加したり削除したりで
対の値がズレることがあるので
予期せぬ挙動になることがあります?【❌index.vue: NG例】
index.vue<template> <div class="page"> <ul> <li v-for="(todo, index) in todos" :key="index" @click="deleteTodo(index)" > {{ todo.value }} </li> </ul> </div> </template> <script> import Vue from 'vue' export default { data () { return { todos: [ { id: 1, value: '記事を書く' }, { id: 2, value: '投稿する' }, { id: 3, value: 'ツイートする' }, ] } }, methods: { deleteTodo (index) { this.$delete(this.todos, index) }, }, } </script>【解説】
・:key="todo.id"
idは文字列のためプリミティブ値
todos配列の中のオブジェクト1つ1つがtodo
そのtodoにあるプロパティidと
valueを含めてidと名付けています?【補足】
・$delete
VueのグローバルAPI
Vue.deleteを使用しています!
そのためvueのimportが必要です?
Nuxtで使う際には$deleteと書きます✍️【⭕️index.vue: OK例】
index.vue<template> <div class="page"> <ul> <li v-for="(todo, index) in todos" :key="todo.id" @click="deleteTodo(index)" > {{ todo.value }} </li> </ul> </div> </template> <script> import Vue from 'vue' export default { data () { return { todos: [ { id: 1, value: '記事を書く' }, { id: 2, value: '投稿する' }, { id: 3, value: 'ツイートする' }, ] } }, methods: { deleteTodo (index) { this.$delete(this.todos, index) }, }, } </script>記事が公開したときにわかる様、
フォローをお願いします??
https://twitter.com/aLizlab
- 投稿日:2020-06-02T18:15:30+09:00
【Nuxt.js】Nuxt文法編:v-if, v-else, v-else-if
前置き
今までの記事で
何度も使ってきたv-if!
記事ごとに解説はしていましたが
v-if自体の記事はない??
ということが、ちらほら。。。
そこで文法の記事を投稿していきます??
今後v-forやv-modelなどを
更新していくのでお楽しみに♪❓どんな時に使うか
表示/非表示の切り替えに使います!
buttonをclickしてモーダルなどの
表示/非表示を切り替えたりします。
https://note.com/aliz/n/n2f0bc857defbv-if
ディレクティブの式が
真の時のみブロックが描写されます!
単一の要素にv-ifをつけます。index.vue<template> <div class="page"> // h1タグの描写をtitleの真偽値で切り替え <h1 v-if="title"> titleがtrueの時のみ表示 </h1> </div> </template> <script> export default { data () { return { // trueなので描写 title: true, } }, } </script>【表示】
?false?
title: falseにした場合
h1タグが描写されません。
? ! を使うと…
真偽値を逆にすることができます!index.vue<template> <div class="page"> // titleがfalseですが!で逆にするのでtrueになり描写されます <h1 v-if="!title"> titleがtrueの時のみ表示 </h1> </div> </template> <script> export default { data () { return { title: false, } }, } </script>?複数の要素を
切り替えたい場合
→親要素にv-ifをつけてあげます?index.vue<template> <div class="page"> <p>親要素ごと描写が切り替わる</p> <div v-if="titles"> <h1> Hello Nuxt.js! </h1> <h2> Hello Nuxt.js! </h2> <h3> Hello Nuxt.js! </h3> </div> </div> </template> <script> export default { data () { return { titles: false, } }, } </script>v-else
v-if="true":v-ifのみ描写
v-if="false":v-elseのみ描写v-ifとセットで使います!
v-elseはv-ifもしくはv-else-ifの
直後に書きましょう!
それ以外は認識されません??index.vue<template> <div class="page"> <h1 v-if="title"> Hello Nuxt.js! </h1> // titleがfalseのためv-elseが描写 <h1 v-else> v-ifがfalseの場合に表示 </h1> </div> </template> <script> export default { data () { return { title: false, } }, } </script>?v-ifに直接関数を入れてみましょう
Math.random()で
0〜1の数字をランダムで作り
0.5より上ならv-ifがtrueとなります。
より、なので0.5は含みません。
数字は確認したいので
Mustache構文(二重中括弧)で
表示させておきます?index.vue<template> <div class="page"> {{ Math.random() }} <h1 v-if="Math.random() > 0.5"> Hello Nuxt.js! </h1> <h1 v-else> v-ifがfalseの場合に表示 </h1> </div> </template> <script> export default { } </script>【表示】
v-else-if
複数の条件を指定したい時に使います?
こちらもv-ifもしくはv-else-ifの
直後に書きましょう!index.vue<template> <div class="page"> <h1 v-if="type === 'A'"> A </h1> <h1 v-else-if="type === 'B'"> B </h1> <h1 v-else-if="type === 'C'"> C </h1> <p v-else> ABCどれにも当てはまりません </p> </div> </template> <script> export default { data () { return { type: 'E' } }, } </script>keyによる再利用可能な要素の制御
効率的に描写するために
要素を再利用することがよくあります。
例えばこちらのコード。
v-ifとv-elseでinputを分けています?
toggleボタンでinputを切り替えます?index.vue<template> <div class="page"> <label v-if="loginType === 'username'"> Username <input placeholder="Enter your username"> </label> <label v-else> Email <input placeholder="Enter your email address"> </label> <button @click="toggle" > toggle </button> </div> </template> <script> export default { data () { return { loginType: 'username' } }, methods: { toggle () { if (this.loginType === 'username') { this.loginType = 'email' } else { this.loginType = 'username' } }, }, } </script>【表示】
toggleを押しても
inputに入力したものが残ってます。
切り替えができていません。
placeholderは変わっていますが、
input自体が再利用されています?
この場合の再利用は
望ましくありません?
【key属性】
そこでkey属性の出番!
Vueで使える特別な属性のことです?
これを追加することで
「別物だよ!再利用しないでね!」
と伝えることができます?index.vue<template> <div class="page"> <label v-if="loginType === 'username'" >Username <input placeholder="Enter your username" // inputにkey属性を追加 key="username-input" > </label> <label v-else>Email <input placeholder="Enter your email address" // inputにkey属性を追加 key="email-input" > </label> <button @click="toggle" > toggle </button> </div> </template> <script> export default { data () { return { loginType: 'username' } }, methods: { toggle () { if (this.loginType === 'username') { this.loginType = 'email' } else { this.loginType = 'username' } }, }, } </script>inputが最初から
描写されていますね✨?
※ inputはkey属性を持ちますが
labelにはないため
labelは再描写されています!記事が公開したときにわかる様、
フォローをお願いします??
https://twitter.com/aLizlab
- 投稿日:2020-06-02T16:46:17+09:00
jQuery Dragg&Drop テンパズル
- 投稿日:2020-06-02T15:46:17+09:00
VSCode の Prettier でファイル毎にフォーマットを変える
プロジェクトのルートに .prettierrc を作成して、下記のように記述
下記の場合は、プロジェクト内の SCSS ファイルはシングルクォートを使って、 JS ファイルはダブルクォートを使いたい場合。{ "overrides": [ { "files": "*.scss", "options": { "singleQuote": true } }, { "files": "*.js", "options": { "singleQuote": false } } ] }.prettierrc
- 投稿日:2020-06-02T15:13:53+09:00
JSのお勉強 その1
自分用に、、結構調べ直したりが多いので 汗
JSの記法
記法名 主な用途 使用例 キャメルケース 変数/関数名 lastName Pascal記法 クラス・コンストラクター名 LastName アンダースコア 定数名 LAST_NAME , last_name マジックナンバー
意味を持たない数字(ぱっと見なんの値かわからないやつ)
消費税計算の 1.1 とかがいきなりコード内に記述されてても、
読み解かないとなんの値かわからない、こういう数字。テンプレート文字
`こんにちは、${name}さん。`これで変数を + を使わずに文字列に入れられる。
オブジェクトリテラル記法
let obj = { x:1 , y:2 , z:3 }; obj.x //結果は1 obj['x']; //結果は1obj.x、の x は識別子の命名規則(頭に数字使えない)に沿ってるので数字の指定はNG
演算子
演算子 意味 使用例 + 数値の加算 1 + 1 //2
- 数値の減算 1 - 2 //1
* 数値の乗算 2 * 2 //4
/ 数値の除算 10 / 5 //2
% 除算したあまり 10 % 4 //2
++ *前置加算 a = 3; b = ++a //bは4になる
++ *後置加算 a = 3; b = a++ //bは3になる
-- *前置減算 a = 3; b = --a //bは2になる
-- *後置減算 a = 3; b = a-- //bは3になる
*前置加算では a に 1 を加算してからbに代入、後置加算では a を b に代入してから a に +1 してるので結果が異なる。
後置加算の a と b の結果は a が 4 で b が 3 になる。代入演算子
演算子 意味 使用例 = 変数へ値を代入 x = 1
+= 加算したものを代入 x = 1; x += 2 //3
-= 減算したものを代入 x = 3; x -= 1 //2
*= 乗算したものを代入 x = 2; x *= 2 //4
/= 除算したものを代入 x = 6; x /= 3 //2
%= 除算したあまりを代入 x = 7; x %= 3 //1
**= べき算を代入 x = 7; x **= 3 //xは7の3乗なので、 343 になる
&= ※論理積演算した結果を代入 a = 3; b = a++ //bは 3 になる
|= ※論理和演算した結果を代入 a = 3; b = --a //bは 2 になる
^= ※排他的論理和演算した結果を代入 a = 3; b = a-- //bは 3 になる
<<= ※左の値を右の値だけ左シフトした結果を代入 a = 3; b = a-- //bは 3 になる
>>= ※左の値を右の値だけ右シフトした結果を代入 a = 3; b = a-- //bは 3 になる
>>>= ※左の値を右の値だけ右シフトした結果を代入 a = 3; b = a-- //bは 3 になる
※この辺りはちょっとまだ理解できてない、、難しい。。
定数の再代入
//NG例1 const hoge = 100; hoge = 200; //NG例2 const hoge = [100,200,300]; hoge = [500,600,700]; //OK例 const hoge = [100,200,300]; hoge[0] = 500;イメージとして、const hoge = この右側はhogeがみてる参照先
NG例1はhogeの参照先がかわるのでダメ、
NG例2もhogeの参照先がかわってるのでダメ、OK例では参照先が変わらず、
参照先の値だけを変更してるので、OK。
まー基本的には定数は変更しない。分割代入
配列/オブジェクトを分解して配下の要素/プロパティ値を個々の変数に分解するための構文。
むつかしい・・・とりあえず下記で。。配列
今までの配列の値の取り方
var hoge = [10 , 20 , 30 , 40 , 50 , 60 , 70]; var x0 = hoge[0]; var x1 = hoge[1]; var x2 = hoge[2];分割代入での値の取り方
let hoge = [10 , 20 , 30 , 40 , 50 , 60 , 70]; let [x0 , x1 , x2 , x3 , x4 , x5 , x6] = hoge console.log(x0) //この結果は 10 になる分割代入での値の取り方(応用)
let hoge = [10 , 20 , 30 , 40 , 50 , 60 , 70]; let [x0 , x1 , x2 , x3 , ...other] = hoge console.log(x0) //この結果は 10 になる console.log(x1) //この結果は 20 になる console.log(x2) //この結果は 30 になる console.log(x3) //この結果は [40 , 50 , 60 , 70] になるオブジェクト
分割代入での値の取り方
let hoge = {name: '名前' , age: '年齢' , address: '住所'}; let {age , name} = hoge console.log(age) //この結果は 年齢 になる配列と違って、プロパティ名で紐づけるので、順番が変わっても大丈夫。
また、分割代入で、[name: '名前' , age: '年齢' , address: '住所']
に対して、
let [age , name] = hoge
とすると、address は無視される。分割代入での値の取り方(入れ子)
let hoge = {name: '名前' , age: '年齢' , address: '住所' ,other: {children: '2人' , dependents: 'いる'}}; let {age , name , other:{children}} = hoge console.log(other) //この結果は {children: '2人' , dependents: 'いる'} になる console.log(children) //この結果は 2人 になる分割代入での値の取り方(変数名を別名に)
let hoge = {name: '名前' , age: '年齢' , address: '住所'}; let {age: nenrei , name: namae} = hoge console.log(nenrei) //この結果は 年齢 になる console.log(namae) //この結果は 名前 になるデフォルト値を設定
let hoge = {name: '名前' , age: '年齢' , address: '住所'}; let {age , name , tel = 000} = hoge console.log(tel) //この結果は 000 になる
- 投稿日:2020-06-02T14:44:35+09:00
jQueryを自分なりにまとめた
初めに
備忘録です。
jQueryの概要
冒頭
Webアプリなど作っている人には有名な「jQuery」、私は名前しか知らなかったです。。。。
jQueryはWebサイトやWebサービスを作成する上で便利便利な物で、デザインのスキルを向上させたいという人は習得するのがマストだそうです。jQueryの大きな特徴
ブラウザの違いを意識せずに済む
HTMLのDOM操作(HTMLの部品を、DOMと呼びます。)が簡単にできる
Ajax処理が簡単に記述できるAjax処理ってなんぞや
Ajaxとは、Asynchronous JavaScript And XML の略です。直訳すると、「非同期(で動作する)JavaScript と XML」です。
jQueryを使う
HTMLファイルとリンクさせる
jQueryを使えるようにします。
Test.html<script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js"></script>HTMLファイルのDOMとリンクさせる(例:テキストボックス)
Test.htmlテキストボックス <input type="text" id="tBox" class="font-main" />main.js// DOMのidをキーにする場合 $("#tBox);Buttonとリンクさせる
ボタンを押下するとアラート表示されます
html:Test.html
テキストボックス
<button type="button" id="btn1">表示</button>
main.js// DOMのidをキーにする場合 $(function(){ // 指定ボタンを押下すると処理を開始する $("#btn1").on("click", function() { alert('アラートのメッセージ'); }); });最後に
jQueryを習得することで、HTMLのDOM操作を簡単に実現できそうです。
- 投稿日:2020-06-02T13:17:34+09:00
Javascript 初めてのGSAPアニメーションの使い方 その8 Timeline制御と開始位置制御
前回の記事はこちら
Javascript 初めてのGSAPアニメーションの使い方 その7 TimelineMaxのラベルと同期処理
今回はtimelineの制御について説明します。
以下のhtmlを準備します。※配置と色はCSSで調整しています。
<div class="row row1"> <div class="column col1"> <p>パネル 1 (.circle)</p> <div class="circle shape"></div> </div> <div class="column col2"> <p>パネル 2 (.square)</p> <div class="square shape"></div> </div> <div class="column col3"> <p>パネル 3 (.rectangle)</p> <div class="rectangle shape"></div> </div> </div> <!--row1 --> <div class="row row2"> <div class="column col4"> <p>パネル 4 (.triangle)</p> <div class="triangleContainer"> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> </div> <!--triangle container --> </div> <div class="column col5"> <p>パネル 5 (.oval)</p> <div class="oval shape"></div> </div> <div class="column col6"> <p>パネル 6 (.pacman)</p> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> </div> </div> <!--row1 --> <div class="playback_controls_row"> <a href="#0" class="playbackButton playButton">Play</a> <a href="#0" class="playbackButton pauseButton">Pause</a> <a href="#0" class="playbackButton resumeButton">Resume</a> <a href="#0" class="playbackButton reverseButton">Reverse</a> <a href="#0" class="playbackButton slowButton">Slow</a> <a href="#0" class="playbackButton fastButton">Fast</a> <a href="#0" class="playbackButton seekButton">Seek</a> <a href="#0" class="playbackButton progressButton">Progress</a> </div>timeline制御
まずはtimelineを作成してstaggerFromで連続したアニメーションにします。
x軸方向50px、y軸方向50pxの位置、opacity0の状態から
0.2秒の時間差で.shapeクラスのついた要素をアニメーションします。要素の取得はJqueryで記述します。
const tlShapes = new TimelineMax(); tlShapes.staggerFrom('.shape', 0.5, {x: 50, y:50, opacity:0},0.2);下のボタンにそれぞれtimeline制御の操作を設定します。
play/pause
$('.playButton').click(function(){ tlShapes.play(); }); $('.pauseButton').click(function(){ tlShapes.pause(); });pauseボタンで一時停止、playボタンで再開の制御を設定できました。
resume/reverse
$('.resumeButton').click(function(){ tlShapes.resume(); }) $('.reverseButton').click(function(){ tlShapes.reverse(); })reverseボタンでアニメーションの逆再生、resumeボタンで再生方向の再生を設定しました。
playの場合はアニメーションは順方向に必ず再生されますが
resumeでは進行中のアニメーションの方向に再生ができます。reverse再生したものを止めて再びreverse方向に再生したい時に使いましょう。
timeScale
$('.slowButton').click(function(){ tlShapes.timeScale(0.5); }) $('.fastButton').click(function(){ tlShapes.timeScale(1.5);timeScaleを使うとスピードの速さを比率で制御できます。
slowボタンには0.5倍速、fastボタンには1,5倍速を設定しました。seek/progress
$('.seekButton').click(function(){ tlShapes.seek(0.2); }) $('.progressButton').click(function(){ tlShapes.progress(0.8); })seekは指定した秒の箇所からアニメーションを再生します。
上記では全体の0.2秒後から再生progressは指定したパーセンテージの箇所からアニメーションを再生します。
上記では全体の80%の位置から再生開始位置制御
シンプルなTweenMaxではアニメーションの開始位置は
htmlとCSSで書かれた場所になります。下記では円を左右中央揃えしたポジションが0の位置です。
以下のコードでは上記を起点にしてx軸方向にアニメーションは動きます。
TweenMax.to ('.circle', 1, {x:100});以下のようにfromToを使用すると第3引数と第4引数で開始位置と終了位置を指定できます。
TweenMax.fromTo('.circle', 1, { x: -100, scale:0}, {x:100, scale:1.5});開始位置を-100px,終了位置を100pxの方向にアニメーションさせています。
位置以外のプロパティ(scaleなど)も一緒に指定することができます。staggerにstaggerFromToとすることで開始と終了位置を指定できます。
以下はx軸y軸方向に起点と終点を設定しています。TweenMax.staggerFromTo('.triangle', 1, { y:200, x:200},{ y:-50, x:-50},0.2)アニメーション
少しわかりにくいですが起点が右下に200pxずれて終点は左上に50pxずれています。
- 投稿日:2020-06-02T13:17:34+09:00
Javascript 初めてのGSAPアニメーションの使い方 その7 Timeline制御と開始位置制御
前回の記事はこちら
Javascript 初めてのGSAPアニメーションの使い方 その7 TimelineMaxのラベルと同期処理
今回はtimelineの制御について説明します。
以下のhtmlを準備します。※配置と色はCSSで調整しています。
<div class="row row1"> <div class="column col1"> <p>パネル 1 (.circle)</p> <div class="circle shape"></div> </div> <div class="column col2"> <p>パネル 2 (.square)</p> <div class="square shape"></div> </div> <div class="column col3"> <p>パネル 3 (.rectangle)</p> <div class="rectangle shape"></div> </div> </div> <!--row1 --> <div class="row row2"> <div class="column col4"> <p>パネル 4 (.triangle)</p> <div class="triangleContainer"> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> </div> <!--triangle container --> </div> <div class="column col5"> <p>パネル 5 (.oval)</p> <div class="oval shape"></div> </div> <div class="column col6"> <p>パネル 6 (.pacman)</p> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> <div class="pacman shape"></div> </div> </div> <!--row1 --> <div class="playback_controls_row"> <a href="#0" class="playbackButton playButton">Play</a> <a href="#0" class="playbackButton pauseButton">Pause</a> <a href="#0" class="playbackButton resumeButton">Resume</a> <a href="#0" class="playbackButton reverseButton">Reverse</a> <a href="#0" class="playbackButton slowButton">Slow</a> <a href="#0" class="playbackButton fastButton">Fast</a> <a href="#0" class="playbackButton seekButton">Seek</a> <a href="#0" class="playbackButton progressButton">Progress</a> </div>timeline制御
まずはtimelineを作成してstaggerFromで連続したアニメーションにします。
x軸方向50px、y軸方向50pxの位置、opacity0の状態から
0.2秒の時間差で.shapeクラスのついた要素をアニメーションします。要素の取得はJqueryで記述します。
const tlShapes = new TimelineMax(); tlShapes.staggerFrom('.shape', 0.5, {x: 50, y:50, opacity:0},0.2);下のボタンにそれぞれtimeline制御の操作を設定します。
play/pause
$('.playButton').click(function(){ tlShapes.play(); }); $('.pauseButton').click(function(){ tlShapes.pause(); });pauseボタンで一時停止、playボタンで再開の制御を設定できました。
resume/reverse
$('.resumeButton').click(function(){ tlShapes.resume(); }) $('.reverseButton').click(function(){ tlShapes.reverse(); })reverseボタンでアニメーションの逆再生、resumeボタンで再生方向の再生を設定しました。
playの場合はアニメーションは順方向に必ず再生されますが
resumeでは進行中のアニメーションの方向に再生ができます。reverse再生したものを止めて再びreverse方向に再生したい時に使いましょう。
timeScale
$('.slowButton').click(function(){ tlShapes.timeScale(0.5); }) $('.fastButton').click(function(){ tlShapes.timeScale(1.5);timeScaleを使うとスピードの速さを比率で制御できます。
slowボタンには0.5倍速、fastボタンには1,5倍速を設定しました。seek/progress
$('.seekButton').click(function(){ tlShapes.seek(0.2); }) $('.progressButton').click(function(){ tlShapes.progress(0.8); })seekは指定した秒の箇所からアニメーションを再生します。
上記では全体の0.2秒後から再生progressは指定したパーセンテージの箇所からアニメーションを再生します。
上記では全体の80%の位置から再生開始位置制御
シンプルなTweenMaxではアニメーションの開始位置は
htmlとCSSで書かれた場所になります。下記では円を左右中央揃えしたポジションが0の位置です。
以下のコードでは上記を起点にしてx軸方向にアニメーションは動きます。
TweenMax.to ('.circle', 1, {x:100});以下のようにfromToを使用すると第3引数と第4引数で開始位置と終了位置を指定できます。
TweenMax.fromTo('.circle', 1, { x: -100, scale:0}, {x:100, scale:1.5});開始位置を-100px,終了位置を100pxの方向にアニメーションさせています。
位置以外のプロパティ(scaleなど)も一緒に指定することができます。staggerにstaggerFromToとすることで開始と終了位置を指定できます。
以下はx軸y軸方向に起点と終点を設定しています。TweenMax.staggerFromTo('.triangle', 1, { y:200, x:200},{ y:-50, x:-50},0.2)アニメーション
少しわかりにくいですが起点が右下に200pxずれて終点は左上に50pxずれています。
- 投稿日:2020-06-02T09:57:20+09:00
QRコードベースのオンライン入退室管理システム
Introduction
今回の騒動で,研究室内の入室人数を非接触で可視化するシステムが必要になったため,
Googleアカウントを持っていれば誰でもwebアプリが無料で作れちゃう,Google Apps Script(GAS)を使って簡単なwebアプリケーションを作成しましたサンプルはこちらをクリックして確認してください
特徴
- QRコードを読み込むだけで,入退室処理が可能
- 部屋内の人数をオンラインで管理することができる
プログラミング言語
フロント;HTML, CSS, JavaScript … CSSはBootstrapを使用しています
バック;JavaScript
データベース;Google Spread Sheetソースコード
非エンジニアの方にとりあえず作って貰う,という状況を念頭に置いて本エントリを作成いたしました.そのため,大まかな作成方法の流れのみ説明しソースコードやアルゴリズムはここで触れません.
本体はGithubで配布しています.MITライセンスなので,こちらからソースコードをコピペして自由に利用してください.
Main
目次
フォルダ構成
ちなみに,最終的には以下のようなフォルダ構成になります.
なんとなく,把握しておいてもらえるとありがたいです.sample //project名 ├ main.gs //JavaScriptでバックの関数を定義 ├ index.html //人数を動的に表示 ├ in.html //入室処理を行います ├ out.html //退室処理を行います └ error.htmlそれでは,さっそくwebアプリを作っていきましょう!!
(1)Google Spread Sheetを作成する
資料進行の都合上,先にデータベースを使うGoogle Spread Sheetを作成し,URLを取得します
今回のGASでは,Google Spread Sheetを疑似的なデータベースとして使用します.
まず,Google Driveを開き,「新規作成」をクリックします
新規作成から,「Google スプレッドシート」を選択し名前を「sample_DB」(名前はなんでもよいです)に変更してください.続いて,下記のようなSpreadSheetのURLにおける ×××××××× の部分をコピペで取得し,どこかにメモしておいてください. URLは図の赤字の線で引いてある部分に記載されています.
https://docs.google.com/spreadsheets/d/××××××××/edit続いて,"A1セル"に「現在の入室人数」,”B1セル”に「条件設定用」と入力してください
そして,"A2セル"に以下の関数を入力し、"B2セル"に"0"を入力してください
=IF(B2<=0,0,B2)(少しエンジニア寄りの話になりますので,飛ばしてもらって構いません)
今回のwebアプリケーションではソースコードを見て貰えれば分かるように,A2セルの数値をGETしてindex.htmlに動的に数値を表示し,また入退室処理時にはA2セルからGETした数値に対して演算処理した値をB2セルに格納します.同時に,A2セルを上記のIF関数でB2セルが負になっても「0以上」になるような設定にしてあげることで,「人数」が「負」になることを回避しています.(おそらくもっと賢いやり方があるかと思いますが,ご容赦ください…笑)
(2)GASでwebアプリを作成し公開する
(1)と同様にGoogle Driveを開き,新規作成をクリック
新規作成から,「その他 → Google Apps Scripts」を選択.もし,まだGoogle DriveにGASがインストールされていなかった場合は,こちらを参考にして追加してください
早速,プロジェクトの名前を変更してみましょう.「無題のプロジェクト」をクリックして,名前を「sample」に変更してください(名前はhogeやfoo等,なんでもよいです).変更が終われば,「OK」をクリックしてください
続いて,プロジェクトに必要なフォルダを作成します.「ファイル → New → HTMLファイル」の順でクリックして…
「index.html」をダイアログに入力して,作成してみてください,次のような画面に移れば,成功です.
今回のフォルダ構成は以下の通りなので,同様に,「in.html」,「out.html」,「error.html」を作成してください.上手くいけば,次のような画面になります.
sample //project名 ├ main.gs //JavaScriptでバックの関数を定義 ├ index.html //人数を動的に表示 ├ in.html //入室処理を行います ├ out.html //退室処理を行います └ error.htmlこれで,必要なファイルの構築は完了しました,続いて,Githubにあげたソースコード(こちら)をそれぞれのファイルにコピペしてください.
(✳︎)ペーストする時には、もともとsampleプロジェクトの「.gs」や「.html」にあったカードは全部消してから、新しく貼り付けてください
まずはじめに,「main.gs」ファイルをコピペします.
(1) Google Spread Sheetを作成するでスプレッドシートのURLから抽出した番号を,ソースコードの5, 14, 23行目にある以下のコードの「××××××××××××」部分にペーストしてくださいSpreadsheetApp.openById('××××××××××××')続いて,「index.html」「in.html」「out.html」「error.html」ファイルをコピペしてください
コピペしたhtmlのソースコードには,以下のようなソースコードがあると思いますhref="https://script.google.com/××××××××××××/exec?p=○○" //○○にはindexやin,out,errorなどが記載されていますhtmlファイル内にある「××××××××」は,GASで作成したwebアプリの公開URLです
すなわち,webアプリを公開しURLを取得する必要があります.webアプリを公開していきましょう.
まず,「公開 → ウェブアプリケーションとして導入…」をクリックします
すると,ダイアログが出てくると思いますが,「Who has access to the app:」を「Anyone, even anonymous」に変更し「更新」してください.ここを,「Only myself」にすれば自分だけがアクセス可能なwebアプリになります.他の設定項目はこちらを参照してください.
webアプリの公開が成功すれば,以下のようなダイアログが出てきます.
(✳︎)もし、「承認が〜ウンタラカンタラ」のようなダイアログがでてきましたら、こちらを参考に承認してください生成されたURLをコピペして,先ほど説明したように以下のソースコード「××××××××」に該当する文字列を切り出し、貼り付けてください.
href="https://script.google.com/××××××××××××/exec?p=○○" //○○にはindexやin,out,errorなどが記載されていますこれで完成です!!!
(3)編集したwebアプリを更新する
適時,HTMLを編集して,各研究室の名前にあわせてください
たとえば,「index.html」の25行目
<div class="text-center"><h6>@○棟△号室</h6></div>の「@〇棟△号室」を適当な名前(例;山田研@28棟283号室)等に変えれば,各々の部屋で管理することができます.
そして,編集した後の注意点ですが,「公開 → ウェブアプリケーションとして導入…」をクリックしてダイアログを開いたら,Project versionを必ず「New」に変更してから「更新」をクリックしてください
ここが,GASのよく分からないところなのですが,「New」にしないと修正点は反映されません…(4)作成したURLを元に,QRコードを生成する
QRコードは各種無料ツールを使用して,作成してみてください.
QRコードを生み出したデンソー公式の「クルクルManager」がお勧めです
生成するURLは以下の通りです
- 入口に貼るQRコードのURL
https://script.google.com/××××××××/exec?p=in //「××××××××」は,GASで作成したwebアプリの公開URL
- 出口に貼るQRコードのURL
https://script.google.com/××××××××/exec?p=out //「××××××××」は,GASで作成したwebアプリの公開URLあとがき
今回がQiita初投稿でした.見にくいところがあれば,ぜひご指摘ください.
GASも初めて触れてみましたが,意外と疑似的には簡単なwebアプリができるのですね
ちょっと感動しました
- 投稿日:2020-06-02T09:41:52+09:00
30分刻みの時刻を動的生成
追記
コメントにカッコイイ書き方乗っていますので、ぜひ
もっとカッコよくかけないものかね
array = Array.prototype.concat.apply( [], [...Array(24).keys()].map(v => { return [ String(v).padStart(2, '0') + ':' + '00', String(v).padStart(2, '0') + ':' + '30' ]; }) ); console.log(array);実行結果[ '00:00', '00:30', '01:00', '01:30', '02:00', '02:30', '03:00', '03:30', '04:00', '04:30', '05:00', '05:30', '06:00', '06:30', '07:00', '07:30', '08:00', '08:30', '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30' ]
- 投稿日:2020-06-02T09:17:59+09:00
jQuery1系をWebpackerで流用した話
背景
新規開発プロジェクトにてデザインの一部を他アプリから流用したいリクエストがありました。
そのアプリはjquery1系で動いていたため、そのまま流用しても後述の環境では動かず・・・。
Chromeの開発者ツールによるデバッグで「$ is not defined」が頻発したりとだいぶハマったので備忘録として残します。局所的にjqueryを利用するため、アプリ内におけるグローバル化は実施しておりません。
参考
以下の回答が大変参考になりました!
環境
Rails: 6.0.2
Webpacker: 4.2.2
jQuery: 3.5.1
パッケージマネージャ: yarn流用したコード(抜粋)
test.js
'use strict'; (function($){ // 各処理 var hoge = (function () { var $fuga = $('viewのclassまたはid属性') return{ piyo: function () { // 取得したclass,id属性に対してjqueryで実現したい処理 } } })(); $(window).on('load', function(){ // ページが読み込まれた時に実行するモジュール化された関数たち hoge.piyo(); }); })(jQuery);CDNによるjquery読み込み
test.html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>修正したコード(抜粋)
test.js
'use strict'; import $ from 'jquery'; $(function(){ // 各処理 var hoge = (function () { var $fuga = $('viewのclassまたはid属性') return{ piyo: function () { // 取得したclass,id属性に対してjqueryで実現したい処理 } } })(); $(window).on('load', function(){ // ページが読み込まれた時に実行するモジュール化された関数たち hoge.piyo(); }); });webpackerによるjavascript読み込み
[webpacker管理対象ディレクトリ]/packs/app.js
import '../[任意のディレクトリ]/test.js';test.html.slim(要件に従いslimを採用しております)
= javascript_pack_tag 'app'
- 投稿日:2020-06-02T08:45:51+09:00
new Promise(function(onFulfilled, onRejected)) のonFullfilledとonRejectedってなにもの??
JSの勉強会をしていたときに
new Promise(function(onFulfilled, onRejected)) のonFullfilledとonRejectedってなにもの??
となったので自分なりにまとめてみることにしたまず、なにが疑問なのか
Promiseのインスタンス生成のとき
非同期処理の内容を記述した関数を引数に指定する
こんな感じnew Promise( function(onFulfilled, onRejected) { /* 非同期の処理を記述 */ } )これの
onFulfilled
,onRejected
が何なのか・どういう関数なのかという話onFulfilledとonRejected
onFulfilledとonRejectedの説明書きはされていて、以下のように書かれている
onFulfilled
処理が正常に終了し結果が得られた場合に実行させるもの
これが実行される時はプロミスはfulfilled(成功)の状態
onRejected
処理の結果エラーが起こった場合に実行させるもの
これが実行される時はプロミスはrejected(失敗)の状態ふむふむ、そうね、成功のときはonFulfilled、失敗のときはonRejectedという認識でした
この説明はわかっていそうひとまず、Promiseについて書かれているコレを読んでみた
JavaScript Promiseの本Promiseのリファレンスも読んでみて、なんだかわかったような、さらに深みにハマっているような、、、そんな気持ちになってしまった。。。
Promiseの処理の例を書いてみた
function dispSmile(str) { return new Promise( function(onFulfilled, onRejected) { if(str != 'OK') { onRejected(new Error()); // 失敗の状態を返す } else onFulfilled(console.log(☺︎)); // 成功の状態を返す // onFulfilledまたはonRejectedのどちらかを返さなければこのPromiseは終了しない } ) }引数の値が'OK'のときは
Fulfilled
の状態を返し、onFulfilled()の引数の値は次の処理に渡す値になってる
引数の値が'OK'以外はRejected
の状態を返し、onRejected()でエラーを返すようになっている
なので結果はこんな感じ// 実行結果 dispSmile('OK'); // ☺︎ dispSmile('No'); // Error例えば以下のようなPromiseを返すと、状態は呼び出されてもPending(初期状態)のままになる
function dispSmile(str) { return new Promise(function(onFulfilled, onRejected) {}) }onFulfilledとonRejectedは、関数で、状態によって実行される処理、ということかな・・・
うーん、まだスッキリという感じではないけれど
Promiseの状態の持ち方は以前より理解できた気がするのはよかったもう少し勉強してみて理解を深めていきたい
- 投稿日:2020-06-02T08:33:17+09:00
JavaScriptの文字列操作(サンプルでマスター)
はじめに
JavaScriptの基本的な文字列操作をまとめました。
テンプレートリテラル
基本は文字列を
`テキスト`
のように、バッククオートで囲むだけです。
エスケープ無しの改行や変数埋め込みができます。テンプレートリテラルで改行var a = `Java Script`; console.log(a); // -> Java // -> Scriptテンプレートリテラル内に変数埋め込みvar num = 10; var str = `りんごを${num}個とみかんを${num - 5}個ください`; // ${}内に計算式をいれてもOK console.log(str); // -> りんごを10個とみかんを5個くださいエスケープはシングルクオートやダブルクオートのように、
\
でOKです。テンプレートリテラル内のエスケープvar a = `Java\\Script`; console.log(a); // -> Java\Script連結(結合)
+
演算子で連結+演算子で連結var a = 'Java'; var b = 'Script'; var result = a + b ; console.log(result); // -> JavaScript
`文字列`
テンプレートリテラルで連結テンプレートリテラルで文字列を連結var a = '6'; var b = '2'; var c = '火'; var result = `今日は${a}月${b}日、${c}曜日です`; console.log(result); // -> 今日は6月2日、火曜日です
対象の配列.join('つなぎ目の文字列');
.joinで配列の文字列を連結var a = ['Hello', 'World']; var result = a.join(''); console.log(result); // -> HelloWorld
対象の配列.join('');
.joinでつなぎ目の文字列を指定// つなぎ目の文字列を指定 -> 「--」 var a = ['Hello', 'World']; var result = a.join('--'); console.log(result); // -> Hello--World
文字列と数値を連結すると、文字列
になります。切り出し
対象の文字列.slice( 開始位置, 終了位置 );
.slicevar str = '本日も、よろしくお願いします!'; var result = str.slice(0, 3); console.log(result); // -> 本日も // 開始位置を後ろから数えて切り出し -> 開始位置:後ろから7文字目, 文字数:文字列の最後まで var result2 = str.slice(-7); console.log(result2); // -> お願いします!
対象の文字列.substr( 開始位置, 切り出す文字数 );
.substrvar str = '本日も、よろしくお願いします!'; var result1 = str.substr(0, 3); console.log(result1); // -> 本日も // 開始位置を後ろから数えて切り出し -> 開始位置:後ろから7文字目, 切り出す文字数:3文字(省略すると文字列の最後まで) var result2 = str.substr(-7, 3); console.log(result2); // -> お願い
対象の文字列.substring( 開始位置, 終了位置 );
.substringvar str = '本日も、よろしくお願いします!'; var result1 = str.substring(0, 3); console.log(result1); // -> 本日も // 開始位置 > 終了位置 のとき -> 開始位置:8文字目, 終了位置:4文字目 // 終了位置と開始位置は逆になる var result2 = str.substring(8, 4); console.log(result2); // -> よろしく // 開始位置から文字列の先頭まで -> 開始位置:8文字目, 終了位置:文字列の先頭 var result3 = str.substring(8, -1); console.log(result3); // -> 本日も、よろしく分割
対象の文字列.split( 区切り文字 );
.splitvar str = '2018, 2019, 2020'; var result = str.split(','); // 「,」 カンマ区切りで分割して配列に格納 console.log(result); // -> ["2018", " 2019", " 2020"]置換・削除
対象の文字列.replace( 置換前の文字列, 置換後の文字列 );
.replaceで置換var str = '夕食はラーメンとカレーです'; var result = str.replace('カレー', '餃子'); console.log(result); // -> 夕食はラーメンと餃子です
対象の文字列.replace( 削除したい文字列, '' );
.replaceで削除var str = '夕食はラーメンとカレーです'; var result = str.replace('とカレー', ''); console.log(result); // -> 夕食はラーメンです検索
対象の文字列を含むかどうかのチェック。
対象の文字列.indexOf( 検索したい文字列 );
.indexOfで検索(前方一致)var str = 'おはようございまーす'; var result1 = str.indexOf('ございまー'); var result2 = str.indexOf('!'); console.log(result1); // -> 4 console.log(result2); // -> -1検索したい文字列を含む :インデックスを返す(0文字目から数えて何文字目か?)
検索したい文字列を含まない:「-1」を返すを利用して、次のように条件分岐できます。
.indexOfの戻り値を利用した条件分岐if (str.indexOf('おはよう') != -1) { //strに「おはよう」を含む場合の処理 }
対象の文字列.lastIndexOf( 検索したい文字列 );
.lastIndexOfで検索(後方一致)var str = 'おはようございまーす'; var result1 = str.lastIndexOf('ございまー'); var result2 = str.lastIndexOf('!'); console.log(result1); // -> 4 console.log(result2); // -> -1検索したい文字列を含む :インデックスを返す(0文字目から数えて何文字目か?)
検索したい文字列を含まない:「-1」を返す※ 対象の文字列の最後から検索しますが、
インデックスは文字列の先頭から数えた値
です。トリム
対象の文字列の前後にある空白を削除する
対象の文字列.trim();
.trimvar str = ' おはようございまーす '; var result = str.trim(); console.log(result); // -> おはようございまーす大文字・小文字に変換
対象の文字列.toUpperCase();
.toUpperCasevar str = 'Chrome'; var result = str.toUpperCase(); console.log(result); // -> CHROME
対象の文字列.toUpperCase();
.toLowerCasevar str = 'MSIE'; var result = str.toLowerCase(); console.log(result); // -> msie文字列を数値にする
Number( 文字列 );
Numbervar str = '123'; var result = Number(str); console.log(result); // -> 123 // typeofで型判定 console.log(typeof result) // -> number数値を文字列にする
String( 数値 );
Stringvar num = 123; var result = String(num); console.log(result); // -> 123 // typeofで型判定 console.log(typeof result) // -> string文字数をカウント
対象の文字列.length;
.lengthvar str = 'あいうえお'; var result = str.length; console.log(result); // -> 5参考
https://qiita.com/kura07/items/c9fa858870ad56dfec12
http://catprogram.hatenablog.com/entry/2013/05/13/231457おわりに
よく使うものをまとめてみました。(たぶん追記します。。)
正規表現をマスターすると.match
や.search
も便利に使えます。(長くなるので別の機会にまとめます)
- 投稿日:2020-06-02T08:33:17+09:00
JavaScriptの文字列操作(サンプル集でマスター)
はじめに
JavaScriptの基本的な文字列操作をまとめました。
テンプレートリテラル
基本は文字列を
`テキスト`
のように、バッククオートで囲むだけです。
エスケープ無しの改行や変数埋め込みができます。テンプレートリテラルで改行var a = `Java Script`; console.log(a); // -> Java // -> Scriptテンプレートリテラル内に変数埋め込みvar num = 10; var str = `りんごを${num}個とみかんを${num - 5}個ください`; // ${}内に計算式をいれてもOK console.log(str); // -> りんごを10個とみかんを5個くださいエスケープはシングルクオートやダブルクオートのように、
\
でOKです。テンプレートリテラル内のエスケープvar a = `Java\\Script`; console.log(a); // -> Java\Script連結(結合)
+
演算子で連結+演算子で連結var a = 'Java'; var b = 'Script'; var result = a + b ; console.log(result); // -> JavaScript
`文字列`
テンプレートリテラルで連結テンプレートリテラルで文字列を連結var a = '6'; var b = '2'; var c = '火'; var result = `今日は${a}月${b}日、${c}曜日です`; console.log(result); // -> 今日は6月2日、火曜日です
対象の配列.join('つなぎ目の文字列');
.joinで配列の文字列を連結var a = ['Hello', 'World']; var result = a.join(''); console.log(result); // -> HelloWorld
対象の配列.join('');
.joinでつなぎ目の文字列を指定// つなぎ目の文字列を指定 -> 「--」 var a = ['Hello', 'World']; var result = a.join('--'); console.log(result); // -> Hello--World
文字列と数値を連結すると、文字列
になります。切り出し
対象の文字列.slice( 開始位置, 終了位置 );
.slicevar str = '本日も、よろしくお願いします!'; var result = str.slice(0, 3); console.log(result); // -> 本日も // 開始位置を後ろから数えて切り出し -> 開始位置:後ろから7文字目, 文字数:文字列の最後まで var result2 = str.slice(-7); console.log(result2); // -> お願いします!
対象の文字列.substr( 開始位置, 切り出す文字数 );
.substrvar str = '本日も、よろしくお願いします!'; var result1 = str.substr(0, 3); console.log(result1); // -> 本日も // 開始位置を後ろから数えて切り出し -> 開始位置:後ろから7文字目, 切り出す文字数:3文字(省略すると文字列の最後まで) var result2 = str.substr(-7, 3); console.log(result2); // -> お願い
対象の文字列.substring( 開始位置, 終了位置 );
.substringvar str = '本日も、よろしくお願いします!'; var result1 = str.substring(0, 3); console.log(result1); // -> 本日も // 開始位置 > 終了位置 のとき -> 開始位置:8文字目, 終了位置:4文字目 // 終了位置と開始位置は逆になる var result2 = str.substring(8, 4); console.log(result2); // -> よろしく // 開始位置から文字列の先頭まで -> 開始位置:8文字目, 終了位置:文字列の先頭 var result3 = str.substring(8, -1); console.log(result3); // -> 本日も、よろしく分割
対象の文字列.split( 区切り文字 );
.splitvar str = '2018, 2019, 2020'; var result = str.split(','); // 「,」 カンマ区切りで分割して配列に格納 console.log(result); // -> ["2018", " 2019", " 2020"]置換・削除
対象の文字列.replace( 置換前の文字列, 置換後の文字列 );
.replaceで置換var str = '夕食はラーメンとカレーです'; var result = str.replace('カレー', '餃子'); console.log(result); // -> 夕食はラーメンと餃子です
対象の文字列.replace( 削除したい文字列, '' );
.replaceで削除var str = '夕食はラーメンとカレーです'; var result = str.replace('とカレー', ''); console.log(result); // -> 夕食はラーメンです検索
対象の文字列を含むかどうかのチェック。
対象の文字列.indexOf( 検索したい文字列 );
.indexOfで検索(前方一致)var str = 'おはようございまーす'; var result1 = str.indexOf('ございまー'); var result2 = str.indexOf('!'); console.log(result1); // -> 4 console.log(result2); // -> -1検索したい文字列を含む :インデックスを返す(0文字目から数えて何文字目か?)
検索したい文字列を含まない:「-1」を返すを利用して、次のように条件分岐できます。
.indexOfの戻り値を利用した条件分岐if (str.indexOf('おはよう') != -1) { //strに「おはよう」を含む場合の処理 }
対象の文字列.lastIndexOf( 検索したい文字列 );
.lastIndexOfで検索(後方一致)var str = 'おはようございまーす'; var result1 = str.lastIndexOf('ございまー'); var result2 = str.lastIndexOf('!'); console.log(result1); // -> 4 console.log(result2); // -> -1検索したい文字列を含む :インデックスを返す(0文字目から数えて何文字目か?)
検索したい文字列を含まない:「-1」を返す※ 対象の文字列の最後から検索しますが、
インデックスは文字列の先頭から数えた値
です。トリム
対象の文字列の前後にある空白を削除する
対象の文字列.trim();
.trimvar str = ' おはようございまーす '; var result = str.trim(); console.log(result); // -> おはようございまーす大文字・小文字に変換
対象の文字列.toUpperCase();
.toUpperCasevar str = 'Chrome'; var result = str.toUpperCase(); console.log(result); // -> CHROME
対象の文字列.toUpperCase();
.toLowerCasevar str = 'MSIE'; var result = str.toLowerCase(); console.log(result); // -> msie文字列を数値にする
Number( 文字列 );
Numbervar str = '123'; var result = Number(str); console.log(result); // -> 123 // typeofで型判定 console.log(typeof result) // -> number数値を文字列にする
String( 数値 );
Stringvar num = 123; var result = String(num); console.log(result); // -> 123 // typeofで型判定 console.log(typeof result) // -> string文字数をカウント
対象の文字列.length;
.lengthvar str = 'あいうえお'; var result = str.length; console.log(result); // -> 5参考
https://qiita.com/kura07/items/c9fa858870ad56dfec12
http://catprogram.hatenablog.com/entry/2013/05/13/231457おわりに
よく使うものをまとめてみました。(たぶん追記します。。)
正規表現をマスターすると.match
や.search
も便利に使えます。(長くなるので別の機会にまとめます)
- 投稿日:2020-06-02T04:25:35+09:00
Javascript 初めてのGSAPアニメーションの使い方 その7 TimelineMaxのラベルと同期処理
前回の記事はこちら
Javascript 初めてのGSAPアニメーションの使い方 その6 TweenMax.setとTimelineMaxプロパティ
今回はTimelineMaxのラベルと同期処理について説明します。
htmlは以下です。CSSで配置と色は調整しています。
<div class="row row1"> <div class="column col1"> <p>パネル 1 (.circle)</p> <div class="circle shape"></div> </div> <div class="column col2"> <p>パネル 2 (.square)</p> <div class="square shape"></div> </div> <div class="column col3"> <p>パネル 3 (.rectangle)</p> <div class="rectangle shape"></div> </div> </div>丸(.circle)→正方形(.square)→長方形(.rectangle)の順にアニメーションを設定します。
それぞれx軸方向へ100px動かします。const tlshapes = new TimelineMax(); tlshapes.to('.circle', 1, { x: 100 }) .to('.square', 1, { x: 100}) .to('.rectangle', 1, { x: 100});このとき個々の要素の動く順番やタイミングをコントロールするために
任意の名前でラベルが設定できます。circleRectangleラベルで、丸が動くタイミングで長方形を一緒に動かします。
const tlshapes = new TimelineMax(); tlshapes.to('.circle', 1, { x: 100 }, 'circleRectangle') .to('.square', 1, { x: 100}) .to('.rectangle', 1, { x: 100},'circleRectangle');次にsquareRectangleラベルで正方形と長方形を一緒に動かします。
const tlshapes = new TimelineMax(); tlshapes.to('.circle', 1, { x: 100 }) .to('.square', 1, { x: 100},'squareRectangle') .to('.rectangle', 1, { x: 100},'squareRectangle');ラベルの中に秒数を設定すると同期処理の中で時間差をつけることができます。
const tlshapes = new TimelineMax(); tlshapes.to('.circle', 1, { x: 100 }) .to('.square', 1, { x: 100},'squareRectangle') .to('.rectangle', 1, { x: 100},'squareRectangle+=0.25');正方形の動き出しから0.25秒後に長方形が動き出します。
マイナス数値を入れることで動き出しを早めることもできます。
const tlshapes = new TimelineMax(); tlshapes.to('.circle', 1, { x: 100 }) .to('.square', 1, { x: 100},'squareRectangle') .to('.rectangle', 1, { x: 100},'squareRectangle-=0.25');長方形は正方形と同期していますが0.25秒早く動き出します。
ラベルはつけずに秒数のみ調整することも可能です。
const tlshapes = new TimelineMax(); tlshapes.to('.circle', 1, { x: 100 }) .to('.square', 1, { x: 100}, '-=0.5') .to('.rectangle', 1, { x: 100}, '-=0.5');正方形と長方形の動き出しを-0.5秒することで滑らかに動かしています。
数値のみを指定するとアニメーションの中で絶対値の秒数を指定できます。
const tlshapes = new TimelineMax(); tlshapes.to('.circle', 1, { x: 100 }) .to('.square', 1, { x: 100},3) .to('.rectangle', 1, { x: 100},3);アニメーション開始から3秒経過後に正方形と長方形が動き出します。
次回はTimeline制御と開始位置制御です
- 投稿日:2020-06-02T03:06:43+09:00
Javascript 初めてのGSAPアニメーションの使い方 その6 TweenMax.setとTimelineMaxプロパティ
前回の記事はこちら
Javascript 初めてのGSAPアニメーションの使い方 その5 staggerTo/staggerFrom今回はTweenMax.setとTimelineMaxのプロパティーを
組み合わせたアニメーションについて説明します。TweenMax.set
今回使用するhtmlは以下です。
※CSSで配置調整と色付けしています。<div class="column col5"> <p>パネル 5 (.oval)</p> <div class="oval shape"></div> </div>jsシートに以下を記述します
TweenMax.set('.oval', { x: -100});TweenMax.setを使用することによってアニメーションの初期位置をずらすことができます。
※この段階ではアニメーションはしません。
CSSのtransform: translate();と同じ意味です。TimelineMaxのプロパティ
ここからTimelineMaxを使用してアニメーションを設定しています。
まずは繰り返しを3回にしてみます。TweenMax.set('.oval', { x: -100}); const tlAnimation = new TimelineMax({ repeat:3 }); //繰り返しを3回に設定 tlAnimation.to('.oval', 0.5, { x: 100 }) .to('.oval', 0.5, { x: -100});タイムラインでx軸方向に100px,動かしてから-100px方向に動かす処理を入れています。
ここで気をつけるのは基準位置は.setで取得したx:-100にはならず
htmlで設定した位置になるという点です。そのため見た目には最初の動き幅は200px動きますが実際に指定するのは左右100pxです。
回数制限なく繰り返す場合は数値に-1を入れます。なんとなくrepeat:trueにしたくなりますが
それでは無制限にならないので注意しましょう。TweenMax.set('.oval', { x: -100}); const tlAnimation = new TimelineMax({ repeat:-1 }); tlAnimation.to('.oval', .5, { x: 100 }) .to('.oval', .5, { x: -100});プロパティにrepeatDelayを入れるとリピート間隔の指定(秒)になります。
TweenMax.set('.oval', { x: -100}); const tlAnimation = new TimelineMax({ repeat:-1, repeatDelay:2 }); //2秒の間隔を開けて繰り返し(無制限) tlAnimation.to('.oval', .5, { x: 100 }) .to('.oval', .5, { x: -100});プロパティにyoyo:trueを入れると名前の通りヨーヨーの動きになります。
TweenMax.set('.oval', { x: -100}); const tlAnimation = new TimelineMax({ repeat:-1, yoyo: true }); tlAnimation.to('.oval', 1, { x: 100 })
- 投稿日:2020-06-02T02:52:20+09:00
PlayCanvasでTypeScriptを使うためのメモ(Webpack編)
概要
前回の記事でwebpackを使わず、無理やりコードを追加することでモジュール問題を解消しましたが、
今回は、そもそもああいったモジュール問題を解決するためにあるWebpackを利用したgulpタスクを作ります。Webpackの設定
ポイントとしては、PlayCanvasライブラリは実行時に別の形で(たぶんScriptタグで)読み込まれるため、externalで生成されるJavaScriptコードに組み込まないように設定しておく必要があります(そうしないと競合するのでたぶん動かない)
webpack.config.jsconst path = require("path"); const glob = require("glob"); module.exports = { mode: "development", //mode: 'production', devtool: "", entry: glob.sync("./src/*.ts"), output: { filename: "output.js", path: path.resolve(__dirname, "dist/"), }, externals: [ { playcanvas: 'pc' } ], module: { rules: [ { test: /\.ts$/, exclude: /node_modules/, loader: "ts-loader" }, ] }, resolve: { extensions: [".ts", ".js"] }, };gulpfile.js
WebPack未使用版との違いは、TypeScriptのトランスパイルをWebpack経由にしていることです。その関係で前回はgulpfile.js上で直接TypeScriptのオプションを設定していましたが、今回はtsconfig.jsonで設定をしておく必要があります。
gulpfile.jsconst gulp = require("gulp"); const playcanvas = require("gulp-playcanvas"); const pcOptions = require("./playcanvas.json"); const webpackStream = require('webpack-stream'); const webpack = require('webpack'); const webpackConfig = require('./webpack.config.js'); gulp.task("ts", () => { return webpackStream(webpackConfig, webpack) .pipe(gulp.dest('./dist/')) .pipe(playcanvas(pcOptions)); }); gulp.task("js", () => { return gulp .src(["src/**/*.js", "!src/**/_*.js", "!./node_modules/**"]) .pipe(gulp.dest("dist/")) .pipe(playcanvas(pcOptions)); }); gulp.task("watch", function() { gulp.watch(["src/**/*.ts", "!src/**/_*.ts", "!./node_modules/**"], gulp.task("ts")); gulp.watch(["src/**/*.js", "!src/**/_*.js", "!./node_modules/**"], gulp.task("js")); }); gulp.task("default", gulp.parallel("watch"));感想
これで、トランスパイルに成功するとoutput.jsという単一のJavascriptファイルが生成され、PlayCanvasにアップロードされます。
眺めるとそこそこの量のコードがWebpackによって追加されるので、小規模なものだと気になるかもしれませんね…
規模によって使い分けるといいのではないでしょうか。
- 投稿日:2020-06-02T02:29:47+09:00
PlayCanvasでTypeScriptを使うためのメモ(Webpack未使用編)
概要
前回の記事(準備編)でアセットをアップロードするための設定までやりましたが、今回はgulpを使ってトランスパイルからアップロードまで一括で行えるようにgulpタスクを作ります。
なぜgulpを使うのかというと、前回の記事にも書いた通り、PlayCanvas用のgulpタスクが公開されているからです。
gulpfile.js
後述の問題のため、through2というgulp用のプラグインを使い、トランスパイル後のコードの先頭に2行ほどコードを書き加えるという泥臭い処理を行っています…(´・ω・`)
gulpfile.jsconst gulp = require("gulp"); const playcanvas = require("gulp-playcanvas"); const pcOptions = require("./playcanvas.json"); const typescript = require("gulp-typescript"); const through2 = require('through2'); gulp.task("ts", () => { return gulp .src(["src/**/*.ts", "!src/**/_*.ts", "!./node_modules/**"]) .pipe(typescript({target: "ES5", module: "commonjs"})) //ES5 //.pipe(typescript({target: "ES2015", module: "commonjs"})) //ES2015(ES6) .pipe(through2.obj((file, enc, callback) => { if (file.isBuffer()) { let contents = String(file.contents); contents = "var exports = {};\nvar require = function(mod){};\n" + contents; //contents = "/*jshint esversion: 6, asi: true, laxbreak: true*/\n" + contents; //ES2015(ES6) file.contents = Buffer.from(contents); } callback(null, file); })) .pipe(gulp.dest("dist/")) .pipe(playcanvas(pcOptions)); }); gulp.task("js", () => { return gulp .src(["src/**/*.js", "!src/**/_*.js"]) .pipe(gulp.dest("dist/")) .pipe(playcanvas(pcOptions)); }); gulp.task("watch", function() { gulp.watch(["src/**/*.ts", "!src/**/_*.ts"], gulp.task("ts")); gulp.watch(["src/**/*.js", "!src/**/_*.js"], gulp.task("js")); }); gulp.task("default", gulp.parallel("watch"));モジュール問題
トランスパイルしたコードの先頭に付け足す理由はモジュール機構の問題になります、ざっくり挙げると
- トランスパイルしただけのJavascriptコードそのままではモジュール機構の関係でPlayCanvas上ではエラーになります。
- ブラウザ環境ではES2015(ES6)形式のモジュールしかサポートされていません(IEの場合はモジュール自体対応していません)
- ES2015形式でimportすると、Playcanvasの実行時にエラーが出ます(importはトップレベルに記載する必要があるのですがランタイム上でスクリプトは下位へ移動されるから?)
- AMDやUMDはブラウザ上でも動くモジュール形式だそうですが、非同期だからなのかPlayCanvasエディタでアトリビュートを読み込めないので意味がありません
これをいろいろどうにかする方法を探りましたが、最も簡単で無難だったのが、commonjs形式でトランスパイルした上で
var exports = {}; var require = function(mod){};という何もしないモジュール関係の変数と関数を定義するコードを付け足すことでした。
もっといい方法があればだれか教えてください…そのためのWebpack
そもそもこういったモジュール機構の問題を解決するためにWebpackがあるので、
次回はWebpackを使ってあんなことをしなくてもPlaycanvasで使えるコードを生成するためのタスクを作ります。
- 投稿日:2020-06-02T02:01:04+09:00
Javascript 初めてのGSAPアニメーションの使い方 その5 staggerTo/staggerFrom
前回の記事はこちら
Javascript 初めてのGSAPアニメーションの使い方 その4 easing設定今回はstaggerFrom/staggerToについて説明します。
staggerは繰り返す複数の要素に対して連続したアニメーションを設定できます。
staggerFrom
htmlは以下のように三角形を連続して表示させています。
<div class="column col4"> <p>パネル 4 (.triangle)</p> <div class="triangleContainer"> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> <div class="triangle shape"></div> </div> <!--triangle container --> </div>ここにstaggerを使用してアニメーションを設定します。
TweenMax.staggerFrom('.triangle', 1, { x: 200, y:200, opacity:0 }, 0.1)三角形(.triangle)に対して
・各要素のアニメーションの時間は1秒
・x方向へ200px,y方向へ200pxから
・透明度0から徐々に
・各要素のずれは0.1秒ずつ
という設定にします。staggerTo
続いてstaggerToの動きを見てみましょう
TweenMax.staggerTo('.triangle', 1, { x: 200, y:200 }, 0.1)三角形(.triangle)に対して
・各要素のアニメーションの時間は1秒
・x方向へ200px,y方向へ200px
・透明度0から徐々に
・各要素のずれは0.1秒ずつ
という設定にします。このように初期位置から指定位置へ向かっていく動きとなります。
プロパティとしてeasingを設定することもできます。
easingの記事はこちらTweenMax.staggerFrom('.triangle', 1, { x: 200, y:200, ease:Back.easeOut }, 0.1)次回はTweenMax.setとTimelineMax プロパティです。
Javascript 初めてのGSAPアニメーションの使い方 その6 TweenMax.setとTimelineMaxプロパティ
- 投稿日:2020-06-02T02:00:07+09:00
React Redux基礎の基礎/小さなカウンターアプリを作る流れ
この記事で書くこと
UdemyのReact、Redux講座の基礎編を学んでおり、本当にReduxがややこしいので一旦基礎の基礎をまとめました。
環境構築のあたりや細かい用語の説明や調査は省き、ミニマムにコードの流れをまとめただけの記事です。
ほぼ頭の整理のためなのでいろいろ認識違ってるかもしれないです。。w。最低限わかっておくべきprops、stateについてはこちらが分かりやすかったです。
+と-ボタンで数字が増える、減るというだけの処理を書いてます。流れ
【1】まず、アクションのタイプを書く。incrementかdecrementか。これをReducerへ渡す。
action/index.js//あとでレデューサーでも使うので、constしておく。 export const INCREMENT = 'INCREMENT' export const DECREMENT = 'DECREMENT' //それぞれをアクションクリエイターとよぶよ export const increment = () => ({ type:INCREMENT }) export const decrement = () => ({ type:DECREMENT })【2】アクションからReducerへINCREMENT、DECREMENTを渡し、typeによりstateを返す。
reducers/count.jsimport { INCREMENT,DECREMENT } from '../actions' //初期状態のオブジェクトを入れる変数名をinitialStateとする。 const initialState = { value:0 }//初期のカウント //関数として定義。引数はstate、acitonとして2つ持つ export default(state =initialState, action) => { //actionのtype(INCREMENTかDECREMENTか)はaction.typeという処理で拾える switch(action.type){ case INCREMENT://INCREMENTを拾った場合は値をプラス1する。 return { value:state.value + 1} case DECREMENT://同様に、DECREMENTの場合はマイナス。 return { value:state.value - 1} default: //初期状態は0のまま return state } }【3】count.jsを同じReducerの中のindex.jsに渡し、combineReducersでまとめる(今回は1つだが、複数のreducersをまとめるのに良い)
reducers/index.js//すべてのreducsersをここでまとめてしまうcombineReducers を取り込む。 import { combineReducers } from 'redux' //count.jsから取得 import count from './count' //storeで使うので、Reducerで決めた数値をエクスポートする。 export default combineReducers({ count }) //なお、今回は受け渡す値は「count」一つだが //いろいろな状態を管理したい場合は //export default combineReducers({ foo,bar,baz }) みたいな感じ【4】ReducserからComponent/App.jsへ。ここでconnect関数を使い、
component/App.jsimport React, { Component } from 'react'; //コネクト関数を追加 import { connect } from 'react-redux' import { increment, decrement } from '../actions' class App extends Component { //counterには、レデューサーのカウンター内のオブジェクトの値の値を渡す。propsで受け取ってる。 render(){ const props = this.props return( <React.Fragment> <div>counter:{props.value}</div> <button onClick={props.increment}> +1</button> <button onClick={props.decrement}> -1</button> </React.Fragment> ) } } //mapStateToPropsは、stateの情報から、componentに必要な情報を受け渡す const mapStateToProps = state => ({ value:state.count.value}) //アクションが実行された時に、該当のアクションを渡し、状態遷移をさせるのがディスパッチ const mapDispatchToProps = dispatch => ({ increment: () => dispatch(increment()), decrement: () => dispatch(decrement()) }) //connect関数でstoreと描写側がつながるらしい。 export default connect(mapStateToProps,mapDispatchToProps)(App)【5】これらをまとめるトップにあるファイルがこれ。
index.jsimport React from "react"; import ReactDOM from 'react-dom'; //createStoreはstoreを利用するためのもの import { createStore } from 'redux' //Providerはすべての環境でstoreを使うためのもの import { Provider } from 'react-redux' import './index.css'; import reducer from './reducers'; import App from './components/App'; import registerServiceWorker from './registerServiceWorker'; //ここで作られるstoreはアプリ内の唯一のものになる const store = createStore(reducer) //既存のコンポーネントを、providerコンポートネントで囲み、store属性に、 //上のconstしたstoreを当てはめる。これで、バケツリレーをせずにproviderが使える //この中の<App />が【4】でrenderされてるもの。 ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ); registerServiceWorker();//?実際の表示。※【4】でrenderされてるコンテンツのみ!
+1と-1をクリックすると数字が増えるよ。
むずい
書き始めたときは流れに沿って書けば整理できそう!と思ったけど、まとめてみると全然1つの流れ、というわけではない。し、あまりよくわかってないです。。w
とにかく、
action、action creatorでアクションを作り
ビュー側のクリックとかでそのアクションをディスパッチする。
レデューサーでそのアクションを元に実際にstate(値)を変える。
したらビュー側が変わる、というくらいは分かりました!ほんまにわかってるんかこれ!qiitaでも色々あったので、もう少し整理するためにいろんな記事読んでみようと思います。。
外部サイトですがこれも図になってて分かりやすかった。ちなみに
これやってます!まだ基礎編を学んだだけなのでこっからしんどそう!
「フロントエンドエンジニアのためのReact・Redux実践入門」
https://www.udemy.com/course/react-application-development/learn/
ちなみに、gitもpushとclone、commitくらいしかしてなかった(しかもSource tree)のでめっちゃ練習になってます、、、w
- 投稿日:2020-06-02T01:59:03+09:00
PlayCanvasでTypeScriptを使うためのメモ(コーディング編)
概要
せっかくTypeScriptでPlayCanvasをコーディングできるようになっても、
従来のPlayCanvasサンプルによくみられるプロトタイプベースのコーディングをしていたのでは意味がないので
(最近まで古いJavaScriptしかサポートしていなかったので致し方ないのですが…)サンプルとして同じコードをクラスベースに書き換えたものを載せておきます。
TypeScriptではなく、ES2015(ES6)で作る際の参考にもなるかもしれません。コードは新規登録したときに作成された「My First Project」のfollow.jsというコードをクラスベースに書き換えてみます。
プロトタイプベース
var Follow = pc.createScript('follow'); Follow.attributes.add('target', { type: 'entity', title: 'Target', description: 'The Entity to follow' }); Follow.attributes.add('distance', { type: 'number', default: 4, title: 'Distance', description: 'How far from the Entity should the follower be' }); // initialize code called once per entity Follow.prototype.initialize = function() { this.vec = new pc.Vec3(); }; // update code called every frame Follow.prototype.update = function(dt) { if (!this.target) return; // get the position of the target entity var pos = this.target.getPosition(); // calculate the desired position for this entity pos.x += 0.75 * this.distance; pos.y += 1.0 * this.distance; pos.z += 0.75 * this.distance; // smoothly interpolate towards the target position this.vec.lerp(this.vec, pos, 0.1); // set the position for this entity this.entity.setPosition(this.vec); };クラスベース
上記のプロトタイプベースのコードをクラスベースに書き換えるとこうなります。
コメントで書き換えるポイントを載せてあります。import 'playcanvas'; //PlayCanvasライブラリ //クラスベースの場合はpc.ScriptTypeを継承する。 class Follow extends pc.ScriptType { public vec!: pc.Vec3; //TypeScript上ではアトリビュートは下記のattributes.addとは別に、フィールドとして別途設定しておく必要があります。 //DRY原則に反していて面倒ですが、typeとクラス名を合わせれば正しくコード補完が効くので便利です。 //(PlayCanvadのwebエディタではアトリビュートのコード補完は未対応のようです) //トランスパイル後にはこのフィールドは消える模様 public target!: pc.Entity; public distance!: number; // update等の各種メソッドはprototype.メソッド名に関数を代入するのではなく、pc.ScriptTypeクラスのメソッドをオーバーライドする。 // initialize code called once per entity public initialize() { this.vec = new pc.Vec3(); } // update code called every frame public update(dt: number) { //updateメソッドの引数であるdtはnumber型です。 // called each tick if (!this.target) { return; } // get the position of the target entity var pos = this.target.getPosition(); // calculate the desired position for this entity pos.x += 0.75 * this.distance; pos.y += 1.0 * this.distance; pos.z += 0.75 * this.distance; // smoothly interpolate towards the target position this.vec.lerp(this.vec, pos, 0.1); // set the position for this entity this.entity.setPosition(this.vec); } } //クラスベースで作る場合はpc.createScriptではなく、pc.registerScriptを使う。 //またコードの先頭ではなく、クラス定義の後に呼び出す。 pc.registerScript(Follow, "follow"); //アトリビュートはクラス定義かつpc.registerScriptの後に追加する Follow.attributes.add('target', { type: 'entity', title: 'Target', description: 'The Entity to follow' }); Follow.attributes.add('distance', { type: 'number', default: 4, title: 'Distance', description: 'How far from the Entity should the follower be' });
- 投稿日:2020-06-02T01:16:43+09:00
[JavaScript] 正規表現の Firefox 限定問題の回避方法 (flags s)
概要
- JavaScript の正規表現で flags の一部にブラウザ依存があり、それの回避方法を説明します。
Firefox で生じる問題
- 以下のコードは Google Chrome と Safari では動作しますが、Firefox では動作しません。
const str = `aaa bbb ccc` str.match(/.{11}/s)
- 正規表現の説明。
- 正規表現中の
.
は、ディフォルトでは「改行以外の任意の一文字」にマッチします。/.{11}/
は「11文字の長さの文字列」にマッチします。/.{11}/s
の最後のs
は正規表現の flags で、「正規表現中の.
を、改行文字にもマッチさせる」と云う指定です。aaa ... ccc
は、アルファベット9文字とaaa
とbbb
の後ろの改行を含めて11文字あります。原因
flags の
s
は比較的新しい仕様で、Firefox (v76.0.1) が未対応のため。
(2020/06/01 現在)Firefox の例外
const str = `aaa bbb ccc` str.match(/.{11}/s) // SyntaxError: invalid regular expression flag s回避策
- flags に
m
を指定する。(複数行指定).
の代わりに[^]
を使う。const str = `aaa bbb ccc` str.match(/[^]{11}/m)
Q.E.D.
[^]
の意味が知りたい方は、最寄りの StewEucen までお尋ね下さいな。
- 投稿日:2020-06-02T01:09:22+09:00
Javascript 初めてのGSAPアニメーションの使い方 その4
前回の記事はこちら
Javascript 初めてのGSAPアニメーションの使い方 その3
easingの設定
今回はeasingのプロパティを設定していきます。
htmlは前回と同じです(CSSにて色付けしています)<div class="row row1"> <div class="column col1"> <p>パネル 1 (.circle)</p> <div class="circle shape"></div> </div> <div class="column col2"> <p>パネル 2 (.square)</p> <div class="square shape"></div> </div> <div class="column col3"> <p>パネル 3 (.rectangle)</p> <div class="rectangle shape"></div> </div> </div>前回のjsシートで作成したTimelineMaxにeasingを設定していきます。
Liniar.ease
まずはLinear.easeNoneを動かしてみます。
const tlAnimation = new TimelineMax(); tlAnimation.to('.circle', 1, { x: 100, ease: Linear.easeNone }) .to('.square', 1, { x:100, ease: Linear.easeNone }) .to('.rectangle', 1, { x:100, ease: Linear.easeNone });Linear.easeNoneは名前の通り無機質な一定の動きでeasingします。
Power2.easeOut
次はPower2.easeOutの動きです。
tlAnimation.to('.circle', 1, { x: 100, ease: Power2.easeOut }) .to('.square', 1, { x:100, ease: Power2.easeOut }) .to('.rectangle', 1, { x:100, ease: Power2.easeOut });easeOutは動き出しが早く終了に向けてゆっくりに変化します。
power2の数字を大きくすると全体のスピードが変わります。Power2.easeIn
tlAnimation.to('.circle', 1, { x: 100, ease: Power2.easeIn }) .to('.square', 1, { x:100, ease: Power2.easeIn }) .to('.rectangle', 1, { x:100, ease: Power2.easeIn });easeInは動き出しが遅く終了に向けて加速します
Power4.easeOut
Powerの数字を最大の4に変えてみます。
(0〜4)で設定可能です。tlAnimation.to('.circle', 1, { x: 100, ease: Power4.easeOut }) .to('.square', 1, { x:100, ease: Power4.easeOut }) .to('.rectangle', 1, { x:100, ease: Power4.easeOut });easeOutの動きは同じですが全体のスピードが早くなりました。
Back.easeOut
tlAnimation.to('.circle', 1, { x: 100, ease: Back.easeOut }) .to('.square', 1, { x:100, ease: Back.easeOut }) .to('.rectangle', 1, { x:100, ease: Back.easeOut });Backを指定するとアニメーションは少しオーバーしてから戻る動きになります。
Elastic.easeOut
tlAnimation.to('.circle', 1, { x: 100, ease: Elastic.easeOut }) .to('.square', 1, { x:100, ease: Elastic.easeOut }) .to('.rectangle', 1, { x:100, ease: Elastic.easeOut });Elasticはガタッと落ちてきたようなアニメーションを加えることができます
Bounce.easeOut
tlAnimation.to('.circle', 1, { x: 100, ease: Bounce.easeOut }) .to('.square', 1, { x:100, ease: Bounce.easeOut }) .to('.rectangle', 1, { x:100, ease: Bounce.easeOut });Bounceを設定すると名前の通り重力のあるバウンドのような動きをします。
- 投稿日:2020-06-02T01:09:22+09:00
Javascript 初めてのGSAPアニメーションの使い方 その4 easing設定
前回の記事はこちら
Javascript 初めてのGSAPアニメーションの使い方 その3 Timelinemax
easingの設定
今回はeasingのプロパティを設定していきます。
htmlは前回と同じです(CSSにて色付けしています)<div class="row row1"> <div class="column col1"> <p>パネル 1 (.circle)</p> <div class="circle shape"></div> </div> <div class="column col2"> <p>パネル 2 (.square)</p> <div class="square shape"></div> </div> <div class="column col3"> <p>パネル 3 (.rectangle)</p> <div class="rectangle shape"></div> </div> </div>前回のjsシートで作成したTimelineMaxにeasingを設定していきます。
Liniar.ease
まずはLinear.easeNoneを動かしてみます。
const tlAnimation = new TimelineMax(); tlAnimation.to('.circle', 1, { x: 100, ease: Linear.easeNone }) .to('.square', 1, { x:100, ease: Linear.easeNone }) .to('.rectangle', 1, { x:100, ease: Linear.easeNone });Linear.easeNoneは名前の通り無機質な一定の動きでeasingします。
Power2.easeOut
次はPower2.easeOutの動きです。
tlAnimation.to('.circle', 1, { x: 100, ease: Power2.easeOut }) .to('.square', 1, { x:100, ease: Power2.easeOut }) .to('.rectangle', 1, { x:100, ease: Power2.easeOut });easeOutは動き出しが早く終了に向けてゆっくりに変化します。
power2の数字を大きくすると全体のスピードが変わります。Power2.easeIn
tlAnimation.to('.circle', 1, { x: 100, ease: Power2.easeIn }) .to('.square', 1, { x:100, ease: Power2.easeIn }) .to('.rectangle', 1, { x:100, ease: Power2.easeIn });easeInは動き出しが遅く終了に向けて加速します
Power4.easeOut
Powerの数字を最大の4に変えてみます。
(0〜4)で設定可能です。tlAnimation.to('.circle', 1, { x: 100, ease: Power4.easeOut }) .to('.square', 1, { x:100, ease: Power4.easeOut }) .to('.rectangle', 1, { x:100, ease: Power4.easeOut });easeOutの動きは同じですが全体のスピードが早くなりました。
Back.easeOut
tlAnimation.to('.circle', 1, { x: 100, ease: Back.easeOut }) .to('.square', 1, { x:100, ease: Back.easeOut }) .to('.rectangle', 1, { x:100, ease: Back.easeOut });Backを指定するとアニメーションは少しオーバーしてから戻る動きになります。
Elastic.easeOut
tlAnimation.to('.circle', 1, { x: 100, ease: Elastic.easeOut }) .to('.square', 1, { x:100, ease: Elastic.easeOut }) .to('.rectangle', 1, { x:100, ease: Elastic.easeOut });Elasticはガタッと落ちてきたようなアニメーションを加えることができます
Bounce.easeOut
tlAnimation.to('.circle', 1, { x: 100, ease: Bounce.easeOut }) .to('.square', 1, { x:100, ease: Bounce.easeOut }) .to('.rectangle', 1, { x:100, ease: Bounce.easeOut });Bounceを設定すると名前の通り重力のあるバウンドのような動きをします。
次回はstaggerTo/staggerFromです。
- 投稿日:2020-06-02T00:25:26+09:00
Javascript 初めてのGSAPアニメーションの使い方 その3
前回の記事はこちら
Javascript 初めてのGSAPアニメーションの使い方 その2
Timelinemax
<div class="row row1"> <div class="column col1"> <p>パネル 1 (.circle)</p> <div class="circle shape"></div> </div> <div class="column col2"> <p>パネル 2 (.square)</p> <div class="square shape"></div> </div> <div class="column col3"> <p>パネル 3 (.rectangle)</p> <div class="rectangle shape"></div> </div> </div>上記のようなhtmlをTweenMax.toで動かしてみます。
TweenMax.to('.circle', 1, {x: 100}); TweenMax.to('.square', 1, {x: 100, delay: 1}); TweenMax.to('.rectangle', 1, {x: 100, delay: 2});パネル1→3に向かってアニメーションをコントロールしていますが
秒数指定では要素が増えるほど記述が煩雑になります。そこでTimelineMaxを使用してアニメーションの順番をコントロールします。
const tlAnimation = new TimelineMax(); //tlAnimationというタイムラインを作成 tlAnimation.to('.circle', 2, { x: 100 }) .to('.square', 0.5, { x:100 }) .to('.rectangle', 1, { x:100 });上記のようにタイムラインを作成して取得した要素を.チェーンでつなぐことによってdelayの指定をすることなくアニメーションの順番を指定できます。
順番を指定しているのでアニメーションの時間にも影響を受けません。
次回はeasingの設定です。
- 投稿日:2020-06-02T00:25:26+09:00
Javascript 初めてのGSAPアニメーションの使い方 その3 Timelinemax
前回の記事はこちら
Javascript 初めてのGSAPアニメーションの使い方 その2 Tween.from/Jqueryとの併用
Timelinemax
<div class="row row1"> <div class="column col1"> <p>パネル 1 (.circle)</p> <div class="circle shape"></div> </div> <div class="column col2"> <p>パネル 2 (.square)</p> <div class="square shape"></div> </div> <div class="column col3"> <p>パネル 3 (.rectangle)</p> <div class="rectangle shape"></div> </div> </div>上記のようなhtmlをTweenMax.toで動かしてみます。
TweenMax.to('.circle', 1, {x: 100}); TweenMax.to('.square', 1, {x: 100, delay: 1}); TweenMax.to('.rectangle', 1, {x: 100, delay: 2});パネル1→3に向かってアニメーションをコントロールしていますが
秒数指定では要素が増えるほど記述が煩雑になります。そこでTimelineMaxを使用してアニメーションの順番をコントロールします。
const tlAnimation = new TimelineMax(); //tlAnimationというタイムラインを作成 tlAnimation.to('.circle', 2, { x: 100 }) .to('.square', 0.5, { x:100 }) .to('.rectangle', 1, { x:100 });上記のようにタイムラインを作成して取得した要素を.チェーンでつなぐことによってdelayの指定をすることなくアニメーションの順番を指定できます。
順番を指定しているのでアニメーションの時間にも影響を受けません。
次回はeasingの設定です。