- 投稿日:2019-07-16T19:18:44+09:00
<初心者>Vue.jsとviz.jsでgraphvizのオンラインエディタを作ってみた。<Vue.js練習>
Vue.jsの公式にはマークダウンエディタの例がある。これのgraphviz版を作ってみる。
公式のマークダウンエディタ作ったもの
Viz.jsにはサンプルがあるので、この記事で作っているのは車輪の再発明(バージョンダウン)です。
Vue.jsもViz.jsもcdnから読み込むため、htmlファイル1つで完結します。Viz.jsとGraphvizについてはそれぞれの公式参照。
Viz.js-公式
Viz.j-github
Graphviz-公式サンプルだけ引用します。
Graphvizを使用してDOT言語でこのように書くとdigraph G { subgraph cluster_0 { style=filled; color=lightgrey; node [style=filled,color=white]; a0 -> a1 -> a2 -> a3; label = "process #1"; } subgraph cluster_1 { node [style=filled]; b0 -> b1 -> b2 -> b3; label = "process #2"; color=blue } start -> a0; start -> b0; a1 -> b3; b2 -> a3; a3 -> a0; a3 -> end; b3 -> end; start [shape=Mdiamond]; end [shape=Msquare]; }中身
最低限、下記をhtml形式で保存するだけで動きます。
CSSとpng保存用のmethodが付いた全文はgithubで公開しています。<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>Vue.js-Viz.js</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> <script type="text/javascript" src="https://unpkg.com/viz.js@1.8.0"></script> <style> </style> </head> <body> <div class="container"> <div id="graph"> <div class="write"> <h2>入力</h2> <textarea v-model="input"></textarea> </div> <div class="out"> <h2>結果</h2> <div class="graph" v-html="svg"></div> </div> </div> </div> </body> <script> new Vue({ el: '#graph', data: { input: `digraph x { graph [ charset = "UTF-8", rankdir = LR, ]; start -> a0; start -> b0; a1 -> b3; b2 -> a3; a3 -> a0; a3 -> end; b3 -> end; } `, }, computed: { svg: function() { return Viz(this.input, { format: 'svg' }); }, }, }); </script> </html>vue.jsで初めて作ったwebサービスが外部サーバーを挟んでもっさりしており、なにかリアルタイムで書き換わるものを作ってみたかったので作りました。
まだまだ勉強を始めたばかりです。突っ込みどころがあるかもしれません。お気づきの点ありましたら、コメントなどいただけますと大変ありがたいです。
- 投稿日:2019-07-16T18:25:43+09:00
[Vue]v-ifに特定のメソッドを連動させたい場合、v-onがとても手軽な件
いきなりサンプル
See the Pen [Vue]v-ifのメソッドを連動させる by riotam (@riotam4) on CodePen.
サンプルの使い方
入力欄に「b」「y」「r」のいずれかを入力したら、下の文字が非同期的に変わります。
「r」を入力した場合だけ、メソッドが発火してalertがでます。ポイント
当初は、dataのstateをwatchフックで監視して、変更のたびにif分岐させる必要があるかと考えていました。
しかし、サンプルの通り、v-ifのあるタグ内にそのままv-on="メソッド名"
とすれば、v-ifがtrueのときに勝手に発火してくれます。最後に
v-ifとv-onの使い方として、あまりいい方法ではないのかもしれませんが、とりあえず方法との1つとして共有させて頂きます。
何かご意見等ありましたら、ご連絡いただけると嬉しいです。最後まで、ありがとうございました。
- 投稿日:2019-07-16T16:39:23+09:00
Vue.jsを勉強する Session�8
イベントハンドラ
イベントの購読(サブスクライブ)
v-onディレクティブを使うことで、DOMイベントの購読、イベント発火時のjavascriptの実行
<div id="example"> <p>ボタンを押すとカウントが増えます</p> <p>カウント: {{ counter }}</p> <button @click="counter += 1">カウントアップ!</button> </div>let app = new Vue({ el: '#example', data: { counter: 0 } })ブラウザ上ではボタンを押すたびにカウントが増えていきます。
メソッドイベントハンドラ
イベントハンドラのロジックは複雑になっていくので、v-on属性の値に式を記述し続けるのはアンチパターンです。
そのためv-onは呼び出したいメソッド名を記述する事ができます。<div id="example"> <p>ボタンを押すとカウントが増えます</p> <p>カウント: {{ counter }}</p> <button @click="countUp">カウントアップ!</button> </div>let app = new Vue({ el: '#example', data: { counter: 0 }, methods: { countUp:function(){ this.counter += 1 } } })インラインメソッドハンドラ
メソッド名を直接指定する代わりに、インラインメソッドを指定することもできます。
<div id="example"> <p>{{ message }}</p> <button @click="say('こんちわ')">こんにちは</button> <button @click="say('こんばんわ')">こんばんわ</button> </div>let app = new Vue({ el: '#example', data: { message: '挨拶' }, methods: { say:function(message){ this.message = message } } })インラインステートメントハンドラでオリジナルのDOMイベントを参照する方法があります。
特別な $event変数を使うことでメソッドにDOMイベントを渡すことができます。<div id="example"> <p>{{ message }}</p> <button @click="say('こんちわ', $event)">こんにちは</button> </div>let app = new Vue({ el: '#example', data: { message: '挨拶' }, methods: { say:function(message, event){ console.log(event) this.message = message } } })console.log()でボタンが押された時にDOMイベントを出力しています。
気になる人は実装してみてください。イベント修飾子
イベントハンドラ内でのevent.preventDefault( )、またはevent.stopPropagation( )の呼び出しは、様々な場面で必要になります。
DMOの込み入った処理をおこなうよりも、単純なデータロジックだけになっていた方が扱いすいです。
Vue.jsはこの問題を解決するためにv-onのためにイベント修飾子(event modifiers)がサポートされています。.stop
通常、同じイベントをハンドルしたDOMがネストされている場合、親要素に向かってイベントが連鎖する。
下記の例ではdiv(親要素)の中にbutton(子要素)があり、両方とも同じイベントをハンドルしています。
.stopを使用することでhandler(子要素)は実行されるが、handler(親要素)は実行されない。<div id="example"> <p>.stopなし</p> <div @click="handler('親要素')"> <button @click="handler('子要素')"> イベント実行ボタン </button> </div> <p>.stopあり</p> <div @click="handler('親要素')"> <button @click.stop="handler('子要素')"> イベント実行ボタン </button> </div> </div>let app = new Vue({ el: '#example', methods: { handler:function(element){ alert(element + 'のイベント実行') } } }).prevent
Event.preventDefault()を呼ぶ。v
下記の例ではイベント(handler())は実行されるが画面遷移は行われない<div id="example"> <p>.preventなし</p> <a href="https://qiita.com/Sthudent_Camilo/items/58b8c21af0db5bea2340" @click="handler('Vue.js を勉強する Session1に遷移する')"> Vue.js を勉強する Session1に遷移 </a> <p>.preventあり</p> <a href="https://qiita.com/Sthudent_Camilo/items/58b8c21af0db5bea2340" @click.prevent="handler('Vue.js を勉強する Session1に遷移しない')"> Vue.js を勉強する Session1に遷移しない </a> </div>let app = new Vue({ el: '#example', methods: { handler:function(element){ alert(element) } } }).capture
キャプチャーモードでDOMイベントをハンドルする。
ルート要素から順番にイベントが実行される。<div id="example"> <div @click.capture="handler('親要素')"> <button @click="handler('子要素')">イベントを実行</button> </div> </div>let app = new Vue({ el: '#example', methods: { handler:function(element){ alert(element + 'が実行されました') } } })handler('親要素') -> handler('子要素')の順番で実行されます。
通常、イベントが発生すると、キャプチャーフェーズでルート要素から要素を探し、ターゲットフェーズで発生要素を検出、パブリングフェーズでルートまで要素をさかのぼりますが、キャプチャーモードにするとキャプチャーフェーズでイベントが発生します。
.self
実行した要素のみが処理を行われ、他の要素のイベントは実行されない。
<div id="example"> <div @click.self="handler('親要素')"> <button @click="handler('子要素1')">イベントを実行</button> <button @click="handler('子要素2')">イベントを実行</button> </div> </div>let app = new Vue({ el: '#example', methods: { handler:function(element){ alert(element + 'が実行されました') } } }).native
コンポーネントのルート要素上のネイティブイベントをハンドルする
※コンポーネントについて勉強不足なため今回はこんな感じだよ程度に記載<!-- コンポーネントをクリックするとhandlerが呼び出される --> <my-component @click.native="handler"></my-component> <!-- コンポーネントをクリックしてもhandlerが呼び出されない --> <my-component @click="handler"></my-component>.once
1回だけイベントが実行される。
<div id="example"> <button @click.once="handler('初回イベント実行')">イベントを実行</button> </div>let app = new Vue({ el: '#example', methods: { handler:function(element){ alert(element + 'が実行されました') } } }).passive
event.preventDefault()を呼び出さない事を明示する。
(.preventとの併用不可)修飾子は繋げることができる
<div id="example"> <div @click="handler('親要素')"> <button @click.stop.once="handler('子要素')"> イベント実行ボタン </button> </div> </div>let app = new Vue({ el: '#example', methods: { handler:function(element){ alert(element + 'が実行されました') } } })イベント修飾子は繋げて書くことができ、上記の例では子要素だけ実行されるイベントが1回だけ行われ、そのあとは親要素のイベントだけ呼ばれるようになります。
キー修飾子
キーボードイベントを検出するにあたって、特定のキーチェックが必要になった時にVue.jsではv-onに対してキー修飾子を追加することができます
- .entser
- .tab
- .delete (windowsだとbackspace)
- .esc
- .space
- .up
- .down
- .left
- .right
上記のキー修飾子から .enter を利用して例を作ります。
下記の例ではbuttonは左クリックでは実行されず、Enterキーで実行されます。<div id="example"> <button @keyup.enter="handler('イベント実行')"> Enterで実行ボタン </button> </div>let app = new Vue({ el: '#example', methods: { handler:function(element){ alert(element + 'が実行されました') } } })KeyboardEvent.keyで公開されているキャメルケースのキー名は、ケバブケースに変換することで修飾子として直接使用できます。
キーコード
【注意】
keyCodeイベントの使用は非推奨で、新しいブラウザではサポートされない可能性があります。
Vue.jsで使用することはできますが、今回は説明しません。システム修飾子
下記の修飾子を使用すると、対応するキーが押された時にのみキーボードのイベントリスナを実行できます。
- .ctrl
- .alt
- .shift
- .meta
【注意】
Macintosh キーボードの場合、meta はコマンドキー(⌘)です
Windows のキーボードでは、meta はウィンドウキー(⊞)です
Sun Microsystems のキーボードでは、メタは実線のダイヤモンド(◆)とマークされています。
特定のキーボードでは、特に MIT や Lisp マシンのキーボードと Knight キーボード、space-cadet キーボード、メタのような後継機には “META” と表示されます。 Symbolics のキーボードでは、 “META” または “Meta” というラベルが付いています。<div id="example"> <button @keyup.enter.ctrl="handler('イベント実行')"> Enterで実行ボタン </button> </div>let app = new Vue({ el: '#example', methods: { handler:function(element){ alert(element + 'が実行されました') } } })【注意】
修飾子キーは通常のキーとは異なり、keyup イベントで使用する場合、イベント発生時に押されていなければならない。
言い換えると、keyup.ctrl は ctrl を押しながら何かのキーを離したときにのみ、実行されます。
ctrl キーだけを離しても、トリガされません。
トリガされることを望むなら、ctrl ではなく keyup.17 のように keyCode を使用します。.exact 修飾子
イベントを実行するために必要なシステム修飾子の正確な組み合わせを制御する。
<div id="example"> <!-- これは Ctrl に加えて Alt や Shift キーが押されていても発行されます --> <button @click.ctrl="handler('イベント実行')">@click.ctrl</button> <!-- これは Ctrl キーが押され、他のキーが押されてないときだけ発行されます --> <button @click.ctrl.exact="handler('イベント実行')">@click.ctrl.exact</button> <!-- これは システム修飾子が押されてないときだけ発行されます --> <button @click.exact="handler('イベント実行')">@click.exact</button> </div>let app = new Vue({ el: '#example', methods: { handler:function(element){ alert(element + 'が実行されました') } } })マウスボタンの修飾子
イベント実行のハンドリングを特定のマウスのボタンのみに制限します。
使用方法は上記の修飾子と同様です。なぜHTMLにイベントリスナを記述するのか
v-onを利用することでいくつかの利点があるからです。
HTML テンプレートを眺めることで、JS コード内のハンドラ関数を探すことを容易にします
JS内のイベントリスナーを手作業で加える必要がないので、ViewModelをDOM依存のない純粋な処理にできます。これはテスタビリティも向上します。
ViewModel が消去されるときに、すべてのイベントリスナーは自動で削除されます。手動でそれらの消去をおこなうことを気にする必要がない。
あとがき
今回の記事ではhtmlとjsのコードにタグを付けずに掲載することにしました。
Qiita独特の機能らしくmdをエディタでプレビューするときに上手く反映されず、変更を加えるのが手間だったためです。参考資料
- 投稿日:2019-07-16T16:22:13+09:00
脱jQueryしてみて、憧れのVue.jsでLPコーディングしたとき必要だった知識たち
こんちは、森高千里の「17才」を聴きながらサーモン春巻き食べてます。
Perfumeがカバーしたら素敵になると思ってます。先日、
LPを禁jQueryで、ピュアJsでコーディングしてみました。
(ちなみに私はjQuerもLoveです。)
トキメキ不足だったのでとても楽しかったです!皆さん試したいのではないでしょか!その時のTips私的メモです。
欲しい情報が、公式やいろんなブログに散らばってたので改良してまとめました。(ps.世間を知るたび無力な自分の記事投稿って怖いですよね)
ひとまずVue.jsのハローワールドを初体験しました。
vue.html<div id="app"> {{ message }} </div> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> //el:にはVue.jsであれこれしたい部分のIDを new Vue({ el: '#app', data: { message: '憧れのVue,js なんかオシャレ' } }) </script>これでHTMLの{{ message }}にjs側のmessageのテキストが表示されました!
お次は、クリック検知。死ぬほど使うonclickです。
click.js$("#target").on("click",function(){ $(this).text("へロー"); });jQuery だとこうですよね。
click.html<div id="app"> <button v-on:click="changeBg">背景変更</button> </div> <script> // v-on:click="ここ" で関数名を登録するようです。 // methods:内に内容を記述 new Vue({ el: '#app', data: { message: 'ハロー Vue.js!' }, methods: { changeBg: function () { document.body.style.backgroundColor = 'red'; } } }) </script>el: '#app'の中に入ってなきゃダメみたいです。
v-on:click="ここ" で関数名を登録するようです。
methods:の中にどんどん関数を登録してくわけですね! おっけー!toggleClassの検知 これがきっと味噌や!
onclickしたらtoggleClassをvue.jsでやります!!
click.js$("#target").on("click",function(){ $(".target").toggleClass("active"); });jQuery だとこうですよね。
sample:vue.html <div id="app"> <p class="target" v-bind:class='{active:isActive}'>表示されるエリア</p> <button v-on:click='isActive=!isActive'>クラスtoggleボタン</button> </div> <style> .target{ transition:3s all; opacity:0; } .active{ opacity:1.0; } </style> <script> data: { message: '憧れのVue,js なんかオシャレ', isActive: false, } </script>簡単なので落ち着いて解説読んでください
v-on:click='isActive=!isActive'の指定で、
クリックするたびに
isActiveがtrueかfalseに切り替わり(toggle)
.activeがついたり消えたりする仕組みです!
vueの方はisActive: false,のフラグを書いてあげるだけですスクロールイベント,リサイズイベントの検知 これもめっちゃ使いますよね!
click.js// スクロール $(window).on("scroll",function() { console.log($(this).scrollTop()); }); // リサイズ var w = 0; $(window).on('load resize',function(){ w = $(window).width(); if(w < 768){ // スマホごにょごにょ } });jQuery だとこうですよね。
そして肝心のvueバージョン!
これはもうシンプルに、これでいいのかな。。vue.html<div id="app"> <p style="height:4000px;"></p> </div> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> //el:にはVue.jsであれこれしたい部分のIDを new Vue({ el: '#app', data: { scrollY: 0, windowWidth: 0, loadWidth:0, }, //mounted DOMにアクセスできるようになった状況 mounted: function(){ window.addEventListener('scroll', this.handleScroll); window.addEventListener('resize', this.handleResize); window.addEventListener('load', this.handleLoadSize); }, methods: { handleResize: function(){ this.windowWidth = window.innerWidth; console.log(this.windowWidth); }, handleScroll: function() { this.scrollY = window.scrollY; console.log(this.scrollY); }, handleLoadSize: function(){ this.loadWidth = window.innerWidth; console.log(this.loadWidth); } } }) </script>感想は、超絶楽しかったけど、なんかもう途中で何やってんだ間でてきて、普通のシンプルなLPはjQueryとCSSで綺麗に書いて作ればいいと思いました。笑
使い方が甘いのかな!毎回データ取ってきて値が変わったりするインタラクティブなやつは向いてるんだなと思いましたが、どうなんでしょかね。フレームワークだしな、、。泣
あんまフレームワークやらんから、、泣しかし記事にしてアウトプットすると整理されて理解が深まります。
以上、ご静聴有難うごいました。
お前こっちのが楽だぞとか、ここ違うぞとかあれば教えてください。
(プラグインとか調べて、使いこなせばもっと楽なんだろなとこっそり気づいてます笑)最後になりましたが、僕はjQuery好きです。
- 投稿日:2019-07-16T13:12:38+09:00
Vue + AWS Amplifyでシンプルな画像共有アプリを作成する (作成〜デプロイ) #2
前 → Vue + AWS Amplifyでシンプルな画像共有アプリを作成する (概要) #1
〜この記事でやること〜
- VueProjectの作成
- Amplifyの導入
- Auth ( Cognito )
- Storage ( S3 )
- 作成したprojectをAmplifyConsoleからBuild & Deploy
VueProjectの作成
まずはProjectを作成します。
■ 前提条件
- Node.js
- npm
がインストールされていること
■ 参考
Node.js / npm をインストール (Mac環境)
Node.js / npmをインストールする(for Windows)
とりあえず Ubuntu で新しい Node.js, npm をインストールVueCLIのinstall
$ npm install -g @vue/cliVueProjectの作成
今回は全部盛りにしていますが各自好きなように選択してください。
※この記事は
class-style
ではなくobject-style
で書きます$ vue create <your-project-name> Vue CLI v3.9.2 ? Please pick a preset: Manually select features ? Check the features needed for your project: Babel, TS, PWA, Router, Vuex, CSS Pr e-processors, Linter, Unit, E2E ? Use class-style component syntax? No ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfill s, transpiling JSX)? Yes ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with node-sass) ? Pick a linter / formatter config: Standard ? Pick additional lint features: Lint on save, Lint and fix on commit ? Pick a unit testing solution: Jest ? Pick a E2E testing solution: Cypress ? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In package. json ? Save this as a preset for future projects? No起動してみる
$ yarn serve
このように表示されればOK
GitHubへpush
Remoteリポジトリの追加
$ git remote add origin <your-remote-repository>
Push
$ git add . $ git commit -m "first commit" $ git push origin masterAmplifyの導入
Amplifyを導入するにあたって
develop
ブランチを作成しておきます。developブランチの作成
$ git checkout -b developAmplify-CLIのinstall
$ npm install -g @aws-amplify/cli $ amplify -v 1.8.1次に、AWSアカウントを紐付けます。以下のコマンドを打つとAmplifyで使用するユーザーを新規作成することが出来ます。
詳しくはAWS Amplify クイックスタートを参考にしてください。$ amplify configure
もし既にAWSのユーザーがあり、そちらを使う場合はこの作業は必要ありません。
AWS Backendの設定
Amplify-CLIのプロジェクトの設定を選択することが出来ます。
amplifyの環境名はdev
にしています。$ amplify init ? Enter a name for the project <project name> ? Enter a name for the environment dev ? Choose your default editor: Visual Studio Code ? Choose the type of app that you're building typescript Please tell us about your project ? What javascript framework are you using vue ? Source Directory Path: src ? Distribution Directory Path: dist ? Build Command: yarn build ? Start Command: yarn serve設定が終わるとしばらく動いた後にS3にbucketが作成されます。
これはDeploy用のCloudFormationTemplateを配置するbucketになります。
Amazon Cognitoの追加
ユーザー管理・認証をしたいのでAmazonCognitoを使えるようにします。
commandで簡単に作成出来ます。$ amplify auth add // Manualを選択 Do you want to use the default authentication and security configuration? Manual configuration // IAM controlをするかどうか Select the authentication/authorization services that you want to use: User Sign-Up, Sign-In, connected with AWS IAM controls (Enables per-user Storage features fo r images or other content, Analytics, and more) Please provide a friendly name for your resource that will be used to label this category in the project: <label-name> Please enter a name for your identity pool. <identity-pool-name> Allow unauthenticated logins? (Provides scoped down permissions that you can cont rol via AWS IAM) No // GoogleアカウントやTwitterアカウントでのサインアップ(今回はなし) Do you want to enable 3rd party authentication providers in your identity pool? No Please provide a name for your user pool: <user-pool-name> // サインイン時に使える属性(今回はユーザー名) Warning: you will not be able to edit these selections. How do you want users to be able to sign in? Username // 多要素認証 Multifactor authentication (MFA) user login options: OFF // Emailを使って登録変更する Email based user registration/forgot password: Enabled (Requires per-user email e ntry at registration) // アカウント認証コード送付用の文面 Please specify an email verification subject: Your verification code Please specify an email verification message: Your verification code is {####} // パスワードポリシー(デフォルト使用) Do you want to override the default password policy for this User Pool? No // 登録時に必要な属性の選択(今回はEmailのみ) Warning: you will not be able to edit these selections. What attributes are required for signing up? (Press <space> to select, <a> to tog gle all, <i> to invert selection)Email Specify the app's refresh token expiration period (in days): 30 Do you want to specify the user attributes this app can read and write? No // OAuth(今回はなし) Do you want to enable any of the following capabilities? (Press <space> to select , <a> to toggle all, <i> to invert selection) Do you want to use an OAuth flow? No // Lambdaトリガー(今回はなし) ? Do you want to configure Lambda Triggers for Cognito? No Successfully added resource <project-name> locallyこれでOKです。
S3 Storageの追加
今回は画像共有アプリなので画像を保存するbucketを用意します。
$ amplify storage add // Imageが含まれている方を選択 ? Please select from one of the below mentioned services Content (Images, audio, v ideo, etc.) ? Please provide a friendly name for your resource that will be used to label this category in the project: <label-name> ? Please provide bucket name: <bucket-name> // 認証済みユーザーのみがアクセスできる ? Who should have access: Auth users only // どこまでの権限を与えるか ? What kind of access do you want for Authenticated users? create/update, read, de lete // Lambdaトリガー(今回はなし) ? Do you want to add a Lambda Trigger for your S3 Bucket? No Successfully added resource <label-name> locallyリソースの作成
amplifyの状態を確認します。
$ amplify status Current Environment: dev | Category | Resource name | Operation | Provider plugin | | -------- | ------------- | --------- | ----------------- | | Auth | resourcename | Create | awscloudformation | | Storage | resourcename | Create | awscloudformation |AuthとStorageがCreateの状態になっていますが、あくまでLocalの設定が追加されただけでリソースは作成されません。
実際にリソースを作成するには$ amplify push
を実行します。色々走った後に、
✔️ All resources are updated in the cloud
となればOKです。
Cloud上にS3 bucketとCognitoのUserpoolが作成されているのが確認できます。変更をGitHubにpush
$ git add . $ git commit -m "Add amplify ~" $ git push origin developAmplify Consoleを使ってDeploy
いよいよdeployです。
まずはAmazon Amplify Consoleを開きましょう。アプリの作成をクリックするとGitプロバイダーを選択する項目があるのでGitHubを選択してcontinueをクリック
対象のリポジトリとブランチを選択して次へをクリック
バックエンドの設定の画面が表示されます。
Amplifyの環境名を選択し、AmplifyConsole用のロールを選択します。無い場合はCreate new role
を選択「アプリの作成」を押すと早速ビルドが始まります。
ビルドが終わり、プロビジョンから検証までオールグリーンであればDeploy成功です!
ドメインのところに書かれているURLを開いて以下のように表示されればOK!Basic認証を追加
このままだと誰でもアクセス出来てしまうので簡単な認証を追加することでそれを防ぎます。
Amplify Console左メニュの「アクセスコントロール」をクリック
「アクセスの管理」をクリック
Apply a global password
を ON にしてusername
とpassword
を設定してSave
をクリック
キャッシュをクリアしてからURLを開いて以下のように表示されればOKです!
終わりに
VueProjectの作成からリソースの生成、ビルド&デプロイまで行いました。
次回はUIデザインを詰めていこうと思います。
ありがとうございました!前 → Vue + AWS Amplifyでシンプルな画像共有アプリを作成する (概要) #1
次 → Vue + AWS Amplifyでシンプルな画像共有アプリを作成する (UIデザイン) #3
- 投稿日:2019-07-16T08:53:14+09:00
Vue.jsで簡単デバッグ
最近、Vue.jsを触る機会が多くなりました。
APIから受け取ったデータをなんやかんやと確認したいときに「created」に「console.log」を記述してデバッグしています。
dataに登録したデータは「this」で参照できるのですが、急いでいると忘れて怒られたり...σ(^_^;)アセアセ...)<script> export default { name: 'App', data: function () { return { test: 'hogehoge' } }, created: function () { console.log(this.test) } } </script>「this」をつけてと・・・出ました。
公式ガイドによると、「created」フック(処理を割り込ませる仕組み)はインスタンスが生成された後にコードを実行したいときに使われます。
Vue.jsのライフサイクルフックの1つ。
下の図を見ると結構早い段階で呼ばれることがわかります。今回は備忘録として簡単デバッグの方法を記載させていただきました。
また機会があればVue.jsに関して記載したいと思います。
- 投稿日:2019-07-16T05:26:33+09:00
Vue.jsと<input type=range>でSoundCloudみたいなシークバーを作る
挨拶
こんにちはkaijiです。
最初に、初投稿かつ今までWebをほとんどやったことのない人なので、色々と間違っていたり不足している部分があるかと思います。もしそういった点があった時はコメントで優しく教えてもらえると嬉しいです。経緯・注意
個人で開発しているサイトでオーディオを再生するためシークバーを実装しようとして色々調べてたのですが、HTML5のAudioタグで作っていたり、inputの標準のUIで作っているものだったり、オリジナルの見た目で作っていてもプログレスバーまで作っているものはほとんど見当たらなかったので、Vue.js上でJavascriptのWeb Audio APIとinputタグを使って自分で作ってみました。
ここでは、シークバーを作ることをメインにしているので、再生、停止、ボリューム調整等の基本的な動作に関しては他のサイトとかを参考にしてください。全体的な流れ
- シークバーの見た目を作る
- 実際にシークさせてみる
- 現在の再生時間と、全体の再生時間を表示させる(分:秒表示)
- 再生済み用のプログレスバーを作り、元のinputタグに重ねる
といった感じです。
シークバーの見た目を作る
シークバーの見た目に関しては、基本好きなように作ってねっていう感じなんですが、いくつか注意点があるので、それについて書きます。
まずinputタグにはデフォルトで見た目が設定されています。(Mac版Chromeの場合はこんな感じ↓)
ですが、これだとブラウザごとに見た目が変わってしまったり、サイトによってはデザイン的に浮いてしまうことがあるため(ちなみにこれはHTML5のオーディオタグにも言える)今回は自分でCSSを書いて見た目を作っていくのですが、その前にこのデフォルトの見た目を表示させないように<style>
内に以下のCSSを書いてみましょう。input[type=range] { -webkit-appearance: none; } input[type=range]::-webkit-slider-thumb { } input[type=range]::-ms-tooltip { display:none; } input[type=range]::-moz-range-track { } input[type=range]::-moz-range-thumb { }ここでは
input[type=range]
の見た目を表示させないでくださいと各ブラウザ用に書いています。
こうすることで、真っさらなinput[type=range]
ができたので、ここからは実際に見た目を作っていきます。
なぜ-ms
だけthumbの設定がないのかや、-moz
には何も書いていないのか等は以下のページにわかりやすく書かれていたので、そちらを参考にしてみてください。input type=range タグをカスタマイズするために
実際にシークさせてみる
次は実際にシークをさせてみましょう。
ここではWeb Audio API上でオーディオファイルが再生できる状態になっていることを前提に話をするので、まだ実装できてない人は他の投稿やリファレンス等をみて実装してからもう一度来てください。今回はVue.jsを使っているので双方向データバインディングのできるv-modelを現在の再生時間、v-bindを全体の再生時間を表示させるために使っていきます。
まず
<script>
内でオーディオのcurrentTime(現在の再生時間)とdurationTime(全体の再生時間)を取得します。const audio = new Audio export default { data() { return { currentTime: 0, durationTime: 0 } }, mehods:{ play() { audio.src = //オーディオのURLとか audio.addEventListener("loadedmetadata", function () { return { durationTime: audio.duration.toFixed(0) } }); audio.addEventListener("timeupdate", function () { return { currentTime: audio.currentTime.toFixed(0) } }); audio.addEventListener("ended", function () { return { currentTime: 0, durationTime: 0 } }); audio.play(); }, seek() { audio.currentTime = this.currentTime; } } }ここでやっていることは
audio.src
で取得したオーディオデータからaddEventListener
を使ってメタデータを抽出できたタイミングでaudio.durationTime
を取得し、その値を返させています。
それと同じように再生中にaudio.currrentTime
を取得しその値を返させています。
また再生が終了したら両方の値を0(初期値)にしています。そして下に書かれている
seek()
というメソッドではv-modelの特性である双方向データバインディングを使ってthumbを移動させるたびにその位置(時間)まで実際に再生されている音源のaudio.currentTime
を移動させています。また
audio.durationTime
やaudio.currrentTime
を取得するときtoFixed(0)
と書いていますが、これは取得してきた値を整数に変換しています。
なぜこんなことをするのかというと、標準で取得してくる再生時間はミリ秒(1/1000秒)で表されているため、今回作るようなプレイヤーの場合あまり適している形とは言えません。
そのため今回は整数で表すようにしていますが、もし作るプレイヤーがミリ秒まで表示できるものであって欲しいならtoFixed(n)
を書く必要はありませんし、toFixed(n)
はnの値を変えることによって0.1秒単位(その場合nは1になる)などもっと細かい値にすることも可能なので、自分の用途に合わせて調整してみてください。
詳細は下記のURLから見てくださいでは次に
<template>
内に記述していきます。
<a v-on:click=play>再生</a>
<input type="range" v-model="currentTime" v-on:input="seek" v-bind:max="durationTime"/>最初のaタグやinputの
type="range"
は単に処理を呼び出したり、inputのタイプを指定しているだけなので気にしないでください。まずv-modelを使ってcurrentTimeを取得しています。なんども言っていますが、v-modelは双方向データバインディングが可能なため、値が変化する度にリロード等の処理をせず、直接表示される値を変化させることが可能です。
そしてv-on:input="seek"
はシークバーに触れる(thumbが動く)度に先ほど記述したseek()メソッドが呼び出されます。
最後にv-bind:max="durationTime"
はシークの最大値をdurationTimeにしています。そのほか最小値やステップは記述していないためデフォルトの値が使われますので、これも必要に応じて設定してみてください。現在の再生時間と、全体の再生時間を表示させる(分:秒表示)
v-modelを使ったcurrentTime(現在の再生時間)、v-bindを使ったdurationTime(全体の再生時間)を反映させる処理を見てきた皆さんであれば、おそらくinputに値を反映させたように、文字にも同じように反映させればいいとすぐにわかったと思いますが、今回は少し発展して分:秒(mm:ss)で時間を表示していきたいと思います。
const audio = new Audio export default { data() { return { currentTime: 0, durationTime: 0, convertedDurationMin: "00", convertedDurationSec: "00", convertedCurrentMin: "00", convertedCurrentSec: "00" } }, mehods:{ play() { audio.src = //オーディオのURLとか audio.addEventListener("loadedmetadata", function () { const durationMin = Math.floor(audio.duration.toFixed(0) / 60); const durationSec = audio.duration.toFixed(0) % 60; return { durationTime: audio.duration.toFixed(0), convertedDurationMin: ("00" + durationMin).slice(-2), convertedDurationSec: ("00" + durationSec).slice(-2) } }); audio.addEventListener("timeupdate", function () { const currentMin = Math.floor(audio.currentTime.toFixed(0) / 60); const currentSec = audio.currentTime.toFixed(0) % 60; if ((currentMin > this.convertedCurrentMin && audio.currentTime !== 0) || (currentMin < this.convertedCurrentMin)) { return { currentTime: audio.currentTime.toFixed(0), convertedCurrentMin: ("00" + currentMin).slice(-2), convertedCurrentSec: ("00" + currentSec).slice(-2) } } else { return { convertedCurrentSec: ("00" + currentSec).slice(-2) } } }); audio.addEventListener("ended", function () { return { currentTime: 0, durationTime: 0, convertedDurationMin: "00", convertedDurationSec: "00", convertedCurrentMin: "00", convertedCurrentSec: "00" } }); audio.play(); } } }オーディオから取得したdurationTimeを整数に変換し、その値を60で割った数を
durationMin
、60で割った数の余りをdurationSec
とします。
covertedDurationMin
へは"00"にdurationMin
を加算した要素から最後の2つを取り出して返し、
covertedDurationSec
へは"00"にdurationSec
を加算した要素から最後の2つを取り出して返しています。わかっている人もいると思いますが、"00は"文字列のため、それに
durationMin
を加算すると9分以下なら3桁(Ex.009)、10分以上なら4桁(Ex.0010)となってしまいmm表記にはなりませんが、最後の二つの要素のみを取り出せば、9分以下の時は10の位が0になり、10分以上の時はdurationMin
と同じ値になるので、mm表記にすることができます。
covertedDurationSec
にも同じことが言えるので、これでdurationTimeをmm:ss表記にすることができました。currentTimeにも同じことが言えますが、currentTimeは値がどんどん変わっていくため、それも考慮してコードを書くと上記のようなコードになります。
currentMin
がconvertedCurrentMin
より大きく、かつaudio.currentTime
が0でない場合というのはcurrentMin
が加算されるタイミング(currentSec
が0になるタイミングとも言える)の時呼び出されるものです。
thumbを移動させないシークであればこれで問題ありませんが、今回はthumbを移動するため、それに加えてcurrentMin
がconvertedCurrentMin
より大きいときという条件を加えました。こうすることにより1分以上戻った時でも正常に表示できるようになりました。次に
<template>
内に記述していきます。
<span v-text="convertedCurrentMin + ':' + convertedCurrentSec"></span>
<span v-text="convertedDurationMin + ':' + convertedDurationSec"></span>正直そのまますぎて説明することがないので注釈を一つ。ここではspanタグを使っていますが、もちろん別のタグを使っても構いません。
例えばSoundCloudではdurationTimeはaタグになっていて、一度クリックすると残り時間の表示になり、もう一度クリックすると従来通り全体の再生時間を表示することができます。再生済み用のプログレスバーを作り、元のinputタグに重ねる
まず↓のようなinputと同じサイズのプログレスバーを作ります。
<span class="progress" id="progress"></span>
もちろんタグはdiv等でも構いません。次に
style
を書いていきます。span.progress { width: /*width*/ background: linear-gradient(/*YourFavoriteColor*/, /*YourFavoriteColor*/) no-repeat; background-size: 0; position: absolute; pointer-events: none; }まずプログレスバーに
position: absolute
を加える等をして、inputの上に重ねます。
background: linear-gradient(/*YourFavoriteColor*/, /*YourFavoriteColor*/) no-repeat;
でプログレスバーの色をグラデーションで指定し、backgroud-size
を使ってプログレスの度合いを表しています。
また最後のpointer-events: none;
はプログレスバーの操作を無効化して、その下に配置されているシークバーの操作をできるようにしています。これを指定することにより、プログレスバーが真上に重なっても操作ができるようになりました。ちなみにプログレスを表示する項目が1つであれば、spanを足さずに直接inputに書くこともできます。
しかしこういったWebサービスではストリーミング再生、つまり再生済みだけでなく読み込み済みのプログレスも作る必要があることが多いため、今回は別のタグにして複数のプログレスを重ねられるようにしました。次に
<script>
のtimeUpdate内に記述していきます。const percent = audio.currentTime.toFixed(0) / audio.duration.toFixed(0) * 100; document.getElementById("progress").style.backgroundSize = percent + "%";currentTimeをdurationTimeで割った数に100を掛けた数を定数
percent
とします。
定数percent
の範囲は0 <= percent <= 100なので、background-sizeの値をwidthに対しての百分率とすることができます。そして、span.progress
のbackground-size
に定数parcent
に"%"を足した値を反映させます。そうするとthumbに従ってプログレスバーが動いているように見えるかと思います。最後に
長々と書いてきましたが、これで終わりです。初めてな上に眠気と戦いながら書いたので、ミスや分かりづらいところがあったかもしれないですが、少しでも読んでくださった方の参考になれば幸いです。
- 投稿日:2019-07-16T03:11:30+09:00
ASAP Vue SPA入門:コンポーネント
Vue CLI3 で作成した SPA(Single Page Application)プロジェクト上で、段階的に Vue.js を学んで行きましょう。
今回はコンポーネント編です。
TodoList を作りながらコンポーネントの使い方を学びます。前提事項
ASAP Vue SPA入門:Vue の基本 が完了していること。
ページの追加
新規に Todo List ページを作成します。
- TodoList.vue を作成
- router.js を修正
- App.vue にナビゲーションを追加
やり方を忘れてしまった人は「ページの追加」を振り返ってください。
src/views/TodoList.vue<template> <div class="todolist"> <h1>Todo</h1> <ul v-if="todos.length"> <li v-for="todo in todos" :key="todo.id" >{{ todo.text }}</li> </ul> <p v-else> TODO 一覧はありません </p> </div> </template> <script> export default { data() { return { todos: [ { id: 1, text: "Learn Vue" }, { id: 2, text: "Learn about single file components" }, { id: 3, text: "Learn about conponents" } ] }; } }; </script> <style> h1 { text-align: center; } .todolist { max-width: 400px; margin: 0 auto; text-align: left; } </style>コンポーネントの作成とプロパティによる値渡し
Todo List から Todo List Item を別コンポーネントに切り出します。
TodoListItem.vue コンポーネントを作成します。
src/components/TodoListItem.vue<template> <!-- todo プロパティのテキストを表示 --> <li>{{ todo.text }}</li> </template> <script> export default { // 親コンポーネントから todo プロパティを受け取る props: ["todo"] }; </script>親コンポーネントから子コンポーネントに値を渡すにはプロパティを使用します。
上記ではtodo
プロパティを受け取れるよう宣言しています。TodoList.vue を下記の様に修正します。
TodoList.vue<template> <div class="todolist"> <h1>Todo</h1> <ul v-if="todos.length"> <!-- TodoListItem コンポーネントを使います --> <!-- v-bind を使って動的に todo プロパティを渡します --> <TodoListItem v-for="todo in todos" :key="todo.id" :todo="todo" /> </ul> <p v-else> TODO 一覧はありません </p> </div> </template> <script> // TodoListItem コンポーネントを import します import TodoListItem from "../components/TodoListItem"; export default { // 使用するコンポーネントを Vue に伝えます components: { TodoListItem }, data() { // ... } }; </script> <style> /* ... */ </style>JavaScript のところで先程作成した
TodoListItem.vue
をインポートして、Vue オブジェクトのcomponents
属性に設定しています。こうすることで、HTML のところで、TodoListItem
タグが使用できるようになります。HTML のところでは
li
タグの代わりにTodoListItem
タグを使用するように変更しました。子コンポーネントに値を渡すためにtodo
プロパティにtodo
オブジェクトをバインドしています。プロパティのバリデーション
プロパティは以下のように記述することでバリデーションチェックをすることができます。
export default { props: { // 基本的な型の検査 (`null` と `undefined` は全てのバリデーションにパスします) propA: Number, // 複数の型の許容 propB: [String, Number], // 文字列型を必須で要求する propC: { type: String, required: true }, // デフォルト値つきの数値型 propD: { type: Number, default: 100 }, // デフォルト値つきのオブジェクト型 propE: { type: Object, // オブジェクトもしくは配列のデフォルト値は // 必ずそれを生み出すための関数を返す必要があります。 default: function () { return { message: 'hello' } } }, // カスタマイズしたバリデーション関数 propF: { validator: function (value) { // プロパティの値は、必ずいずれかの文字列でなければならない return ['success', 'warning', 'danger'].indexOf(value) !== -1 } } } }
TodoListItem.vue
もバリデーションチェックをするよう修正します。TodoListItem.vueprops: { todo: { type: Object, // オブジェクト型であること required: true // 必須項目 } }イベント
親コンポーネントから子コンポーネントへはプロパティを使って値を渡すことができますが、子コンポーネントから親コンポーネントへ値を渡すことは出来ません。その代わりにイベントを使って通信することができます。
イベントの発火
TodoListItem.vue
に削除ボタンを設け、remove
イベントを発火するよう修正します。TodoListItem.vue<li> {{ todo.text }} <button @click="$emit('remove', todo.id)">x</button> </li>
botton
がクリックされると$emit('イベント名', ペイロード)
でイベントを発火します。イベントハンドリング
TodoList.vue
でremove
イベントをハンドリングして Todo を削除します。TodoList.vue<!-- remove イベントをハンドリングして removeTodo メソッドをコールします --> <TodoListItem v-for="todo in todos" :key="todo.id" :todo="todo" @remove="removeTodo" />TodoList.vuemethods: { removeTodo(idToRemove) { this.todos = this.todos.filter(todo => { return todo.id !== idToRemove; }); } }
removeTod
メソッドにはremove
イベントが発火された時のペイロードが引数として渡されます(この場合は todo の id です)。演習
TodoInputText.vue
コンポーネントを作成して、TodoList.vue
でそれを使って TODO を追加できるようにしてください。次回
Coming Soon...