- 投稿日:2020-02-21T22:55:03+09:00
Resolved APIというnuxt.jsのプラグインを作った話
vuex疲れ
普段からnuxt.jsやvue.jsを利用している方ならご存知かと思うのですが
vuexは複雑なデータ構造を渡すと
stateが更新されない事があります。僕はそれが原因でしばらくvuex無しで
pagesのvueファイルで一枚岩に実装するなんて言う
ソースコードが腐る方法で実装していました。しかし、そんな実装ではメンテナンス性が最悪である事も
当然、自覚はありました。そろそろ、なんとかしなくてはと思うものの
やむなくvuexを利用するのはやはり違うという事で
自作でvuexに替わるプラグインを作る事にしました。Resolved APIというプラグインを作った話
Resolved API(以下、rapi)
自作プラグインというのは大袈裟で
別に単にES6をふんだんに使ってパッケージ分割しただけです。apiをcontextに流し込むメインの
index.js
とresolvers
resolvers
にはQuery、Mutation、client.js、cache.jsがあるのみです。
vuexとか、Apolloのcacheだとかは結構、複雑なアーキテクチャで構築されていますが
正直、独自にプラグインを作ると拍子抜けするほど
シンプルなアーキテクチャで作れてしまいます。rapiは、
非常にシンプルで薄く柔軟なカスタマイズが可能なように作りました。
client.jsを編集する事でGraphQLにも、REST APIにも対応できます。cacheへの読み書きは、デフォルトはjormというgormライクなcache ORMを使って行える
ようにしていますが
cacheに関しても、別にlowdbなどのapiに替える事もできます。jormというcache ORMを作った話
rapiは完全にフロントエンドに埋め込まれたサーバーというコンセプトで設計しています。
なので、参考にしたアーキテクチャはgqlgenによって生成されるGraphQLサーバーのアーキテクチャです。となると、DBであるcacheに読み書きするため
cache ORMというツールも必要になるでしょう。
という事で
gormを参考にjormというcache ORMも作りました。GraphQLにもREST APIにも対応
上述もしている通りrapiは、client.jsを書き換えるだけで
GraphQLにも、REST APIにも対応できます。
(ES6は偉大ですね。)
gqlkitはGraphQLアプリを開発するためのフレームワークなので
gqlkitのrapiのデフォルトはGraphQLです。なので、REST APIでの具体的な実装例として
resas apiを使った人口動態グラフの例も紹介しておきます。
(resas apiの認証トークンはアカウント登録して取得してください。)
https://github.com/inadati/total-population-trends-sampleまとめ
この、rapiというプラグインを使い始めてから
フロントエンドの実装が格段に楽になりました。
コンポーネント側のソースコードも全く汚染されません。
それもそのはずです。
「Resolved API」というのは
- サーバーからのデータの取得、書き込み
- キャッシュへのデータの書き込み、取得
- コンポーネント(クライアント)サイドに必要な形式へのデータの組み替え
- GraphQLの場合クエリの管理
などなど、文字通りあらゆる問題を「解決済み」としたAPIをコンポーネントに提供するわけです。
コンポーネント側では、ほとんど余計なことはしないで済むということです。ちなみに一応、nuxt.jsのプラグインと言いましたが
別にcontextに、データストアを挿入可能なフレームワークであれば利用可能かと思います。
svelteでもできるかと
reactは不明
reactはコンポーネントとデータが密結合でよく分からないです。
reactはあまり深く触れたことなくてよく分かりません。
- 投稿日:2020-02-21T19:09:37+09:00
【Nuxt.js】props実践編:inputの真偽値によるクラスの切り替え
前置き
今回はSwitchボタンです!✅
(予告と違う内容ですみません)
inputの真偽値によって
クラスバインディングを行います!前回書いた記事と違うのは
Stringを渡すだけではなく
computed関数で切り替えを行う部分です?
propsでのクラスバインディングはこちら
https://note.com/aliz/n/nc4110b1128f0構成
まずはtemplateの構成
inputをlabelで囲うとコードが
スッキリするのでこちらを採用?書き方①<label><input type="text"></label>囲わない場合は
書き方②<label for="name"></label> <input type="text" id="name">Step1: まずはlabel, inputを作成
◾️label
・文字列は親で指定したいのでprops
文字列だけなのでslotでも大丈夫です!
今回はpropsを複数使うためpropsにします。css
labelの幅を88pxにしたい!
が、labelに指定してしまうと
inputも含んだ長さのためspanを追加します。◾️input
・input type="checkbox"に
指定可能な属性checkedを使用
後でクラスバインディングを紐づけるため、
まずはcheckedされた状態から作ります✅・inputイベント(@input)で$emit
$emit基礎編はこちら
https://note.com/aliz/n/nd6e771724cd7・チェックが付けられるとイベント実行
基本イベントハンドラは
まとめてあるここが参考になります!
https://blog.capilano-fw.com/?p=2787css
まず全体をdivで囲い
そのdivにborderをつけ
●を作るdivを追加します?
●はcheckされた時の右側の配置を書きたいので
左側の分もまとめて書いちゃいましょう!✍️??ここまでのコード
scssは他のコンポーネントに影響が出ないよう、
基本的に直下セレクタ > をつけています。SwitchButton.vue<template> <label class="input switch-button"> <span class="label"> {{ label }} </span> <div class="box"> <input :checked="checked" type="checkbox" class="input" @input="$emit('switch')" > <div class="mark" /> </div> </label> </template> <script> export default { props: { label: { type: String, default: 'label' }, checked: { type: Boolean, required: true, }, }, } </script> <style lang="scss" scoped> .switch-button { display: flex; align-items: center; > .label { width: 88px; min-width: 88px; color: red; } > .box { position: relative; width: 48px; height: 24px; border: 2px solid red; border-radius: 26px; > .mark { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background-color: red; border-radius: 50%; transition: 0.12s; } > .input { display: none; &:checked ~ .mark { transform: translateX(24px); background-color: red; } } } } </style>親でpropsのlabelは
直接テキストを渡しています。
:label="変数名"でももちろんOK。
$emitに関しては現時点ではスルーでOK。index.vue<template> <div class="page"> <SwitchButton label="LABEL" :checked="checked" /> </div> </template> <script> import SwitchButton from '~/components/SwitchButton.vue' export default { components: { SwitchButton, }, data () { return { checked: true, } } } </script>Step2: クラスバインディングを追加
propsとcomputed関数を使った
クラスバインディングをしていきます。
まずはinputによる真偽値は無視しましょう。やりたいこと
チェックされたかどうかに関係なく
クラスの付け替えで全体の色を変える??
なのでこうなればOKです!
あとでチェックされていない状態
(●が左にある状態)で
この色に変わるように変更します。Point!
・labelにクラスバインディング
・computed関数で
propsをswitch関数で切り替え
・親でstatusがinactiveになれば
inactiveクラスがついてピンクになる
・inactiveクラスがついた時のcssを追加??ここまでのコード
SwitchButton.vue<template> <label :class="classes" class="input switch-button" > <span class="label"> {{ label }} </span> <div class="box"> <input :checked="checked" type="checkbox" class="input" @input="$emit('switch')" > <div class="mark" /> </div> </label> </template> <script> export default { props: { status: { type: String, default: '', required: false, validator (value) { return [ '', 'inactive', ].includes(value) }, }, label: { type: String, default: 'label' }, checked: { type: Boolean, required: true, }, }, computed: { classes() { switch (this.status) { case '': return '' case 'inactive': return 'inactive' default: return '' } }, }, } </script> <style lang="scss" scoped> .switch-button { display: flex; align-items: center; > .label { width: 69px; min-width: 69px; color: red; } > .box { position: relative; width: 48px; height: 24px; border: 2px solid red; border-radius: 26px; > .mark { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background-color: red; border-radius: 50%; transition: 0.12s; } > .input { display: none; &:checked ~ .mark { transform: translateX(24px); background-color: red; } } } &.inactive { > .label { color: pink; } > .box { border: 2px solid pink; > .mark { background-color: pink; } > .input:checked ~ .mark { background-color: pink; } } } } </style>index.vue<template> <div class="page"> <SwitchButton :checked="checked" label="LABEL" status="inactive" /> </div> </template> <script> import SwitchButton from '~/components/SwitchButton.vue' export default { components: { SwitchButton, }, data () { return { checked: true, } }, } </script>これで準備はOK✨?
Step3: 真偽値とクラスバインディングの連携
いよいよinputによるクラス付け替えです!
子ではもう全てのpropsを
書いているのでやることはありません。親で渡したpropsの
・Boolean
・String
これを変数で連携させましょう!Point!
・:checked="value"で
valueの初期値をfalseに
最初は選択されていない状態に変更
・statusに三項演算を使うので:を忘れず追加
valueがtrueなら'', falseなら'inactive'
・@switch="value = !value"で
switchイベント発火時にtrue, falseの切り替えつまり初期値チェックしてない状態の時は
inactiveクラスがついて
ピンクになって●が左にある状態?
チェックをつけるとinactiveが外れて
通常クラスの赤になって●が右にある状態???最終コード
SwitchButton.vue<template> <div class="page"> <SwitchButton :checked="value" label="LABEL" :status="value ? '' : 'inactive'" @switch="value = !value" /> </div> </template> <script> import SwitchButton from '~/components/SwitchButton.vue' export default { components: { SwitchButton, }, data () { return { value: false, } } } </script>index.vue<template> <label :class="classes" class="input switch-button" > <span class="label"> {{ label }} </span> <div class="box"> <input :checked="checked" type="checkbox" class="input" @input="$emit('switch')" > <div class="mark" /> </div> </label> </template> <script> export default { props: { status: { type: String, default: '', required: false, validator (value) { return [ '', 'inactive', ].includes(value) }, }, label: { type: String, default: 'label' }, checked: { type: Boolean, required: true, }, }, computed: { classes() { switch (this.status) { case '': return '' case 'inactive': return 'inactive' default: return '' } }, }, } </script> <style lang="scss" scoped> .switch-button { display: flex; align-items: center; > .label { width: 69px; min-width: 69px; color: red; } > .box { position: relative; width: 48px; height: 24px; border: 2px solid red; border-radius: 26px; > .mark { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background-color: red; border-radius: 50%; transition: 0.12s; } > .input { display: none; &:checked ~ .mark { transform: translateX(24px); background-color: red; } } } &.inactive { > .label { color: pink; } > .box { border: 2px solid pink; > .mark { background-color: pink; } > .input:checked ~ .mark { background-color: pink; } } } } </style>次回はVuexの続きをやります!
公開予定日は2/28(金)です。記事が公開したときにわかる様に、
note・Twitterフォローをお願いします?
https://twitter.com/aLizlab
- 投稿日:2020-02-21T19:09:37+09:00
【Nuxt.js】props実践編:switchボタンを作ろう!
前置き
今回はSwitchボタンです!✅
gifカクカクですが
実際はなめらかになります?
(予告と違う内容ですみません)
inputの真偽値によって
クラスバインディングを行います!propsを主に使います。
前回書いた記事と違うのは
Stringを渡すだけではなく
computed関数で切り替えを行う部分です?
propsでのクラスバインディングはこちら
https://note.com/aliz/n/nc4110b1128f0構成
まずはtemplateの構成
inputをlabelで囲うとコードが
スッキリするのでこちらを採用?書き方①<label><input type="text"></label>囲わない場合は
書き方②<label for="name"></label> <input type="text" id="name">Step1: まずはlabel, inputを作成
◾️label
・文字列は親で指定したいのでprops
文字列だけなのでslotでも大丈夫です!
今回はpropsを複数使うためpropsにします。css
labelの幅を88pxにしたい!
が、labelに指定してしまうと
inputも含んだ長さのためspanを追加します。◾️input
・input type="checkbox"に
指定可能な属性checkedを使用
後でクラスバインディングを紐づけるため、
まずはcheckedされた状態から作ります✅・inputイベント(@input)で$emit
$emit基礎編はこちら
https://note.com/aliz/n/nd6e771724cd7・チェックが付けられるとイベント実行
基本イベントハンドラは
まとめてあるここが参考になります!
https://blog.capilano-fw.com/?p=2787css
まず全体をdivで囲い
そのdivにborderをつけ
●を作るdivを追加します?
●はcheckされた時の右側の配置を書きたいので
左側の分もまとめて書いちゃいましょう!✍️??ここまでのコード
scssは他のコンポーネントに影響が出ないよう、
基本的に直下セレクタ > をつけています。SwitchButton.vue<template> <label class="input switch-button"> <span class="label"> {{ label }} </span> <div class="box"> <input :checked="checked" type="checkbox" class="input" @input="$emit('switch')" > <div class="mark" /> </div> </label> </template> <script> export default { props: { label: { type: String, default: 'label' }, checked: { type: Boolean, required: true, }, }, } </script> <style lang="scss" scoped> .switch-button { display: flex; align-items: center; > .label { width: 88px; min-width: 88px; color: red; } > .box { position: relative; width: 48px; height: 24px; border: 2px solid red; border-radius: 26px; > .mark { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background-color: red; border-radius: 50%; transition: 0.12s; } > .input { display: none; &:checked ~ .mark { transform: translateX(24px); background-color: red; } } } } </style>親でpropsのlabelは
直接テキストを渡しています。
:label="変数名"でももちろんOK。
$emitに関しては現時点ではスルーでOK。index.vue<template> <div class="page"> <SwitchButton label="LABEL" :checked="checked" /> </div> </template> <script> import SwitchButton from '~/components/SwitchButton.vue' export default { components: { SwitchButton, }, data () { return { checked: true, } } } </script>Step2: クラスバインディングを追加
propsとcomputed関数を使った
クラスバインディングをしていきます。
まずはinputによる真偽値は無視しましょう。やりたいこと
チェックされたかどうかに関係なく
クラスの付け替えで全体の色を変える??
なのでこうなればOKです!
あとでチェックされていない状態
(●が左にある状態)で
この色に変わるように変更します。Point!
・labelにクラスバインディング
・computed関数で
propsをswitch関数で切り替え
・親でstatusがinactiveになれば
inactiveクラスがついてピンクになる
・inactiveクラスがついた時のcssを追加??ここまでのコード
SwitchButton.vue<template> <label :class="classes" class="input switch-button" > <span class="label"> {{ label }} </span> <div class="box"> <input :checked="checked" type="checkbox" class="input" @input="$emit('switch')" > <div class="mark" /> </div> </label> </template> <script> export default { props: { status: { type: String, default: '', required: false, validator (value) { return [ '', 'inactive', ].includes(value) }, }, label: { type: String, default: 'label' }, checked: { type: Boolean, required: true, }, }, computed: { classes() { switch (this.status) { case '': return '' case 'inactive': return 'inactive' default: return '' } }, }, } </script> <style lang="scss" scoped> .switch-button { display: flex; align-items: center; > .label { width: 69px; min-width: 69px; color: red; } > .box { position: relative; width: 48px; height: 24px; border: 2px solid red; border-radius: 26px; > .mark { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background-color: red; border-radius: 50%; transition: 0.12s; } > .input { display: none; &:checked ~ .mark { transform: translateX(24px); background-color: red; } } } &.inactive { > .label { color: pink; } > .box { border: 2px solid pink; > .mark { background-color: pink; } > .input:checked ~ .mark { background-color: pink; } } } } </style>index.vue<template> <div class="page"> <SwitchButton :checked="checked" label="LABEL" status="inactive" /> </div> </template> <script> import SwitchButton from '~/components/SwitchButton.vue' export default { components: { SwitchButton, }, data () { return { checked: true, } }, } </script>これで準備はOK✨?
Step3: 真偽値とクラスバインディングの連携
いよいよinputによるクラス付け替えです!
子ではもう全てのpropsを
書いているのでやることはありません。親で渡したpropsの
・Boolean
・String
これを変数で連携させましょう!Point!
・:checked="value"で
valueの初期値をfalseに
最初は選択されていない状態に変更
・statusに三項演算を使うので:を忘れず追加
valueがtrueなら'', falseなら'inactive'
・@switch="value = !value"で
switchイベント発火時にtrue, falseの切り替えつまり初期値チェックしてない状態の時は
inactiveクラスがついて
ピンクになって●が左にある状態?
チェックをつけるとinactiveが外れて
通常クラスの赤になって●が右にある状態???最終コード
SwitchButton.vue<template> <div class="page"> <SwitchButton :checked="value" label="LABEL" :status="value ? '' : 'inactive'" @switch="value = !value" /> </div> </template> <script> import SwitchButton from '~/components/SwitchButton.vue' export default { components: { SwitchButton, }, data () { return { value: false, } } } </script>index.vue<template> <label :class="classes" class="input switch-button" > <span class="label"> {{ label }} </span> <div class="box"> <input :checked="checked" type="checkbox" class="input" @input="$emit('switch')" > <div class="mark" /> </div> </label> </template> <script> export default { props: { status: { type: String, default: '', required: false, validator (value) { return [ '', 'inactive', ].includes(value) }, }, label: { type: String, default: 'label' }, checked: { type: Boolean, required: true, }, }, computed: { classes() { switch (this.status) { case '': return '' case 'inactive': return 'inactive' default: return '' } }, }, } </script> <style lang="scss" scoped> .switch-button { display: flex; align-items: center; > .label { width: 69px; min-width: 69px; color: red; } > .box { position: relative; width: 48px; height: 24px; border: 2px solid red; border-radius: 26px; > .mark { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background-color: red; border-radius: 50%; transition: 0.12s; } > .input { display: none; &:checked ~ .mark { transform: translateX(24px); background-color: red; } } } &.inactive { > .label { color: pink; } > .box { border: 2px solid pink; > .mark { background-color: pink; } > .input:checked ~ .mark { background-color: pink; } } } } </style>次回はVuexの続きをやります!
公開予定日は2/28(金)です。記事が公開したときにわかる様に、
note・Twitterフォローをお願いします?
https://twitter.com/aLizlab
- 投稿日:2020-02-21T14:27:08+09:00
個人的GoとVueの繋げ方(CORS,FileServer)
今回はVueとGolangをつなげる際に死にかけたところを書くよ
作成時
結構前に短縮URLのバックエンドを作成してホッとしていました。
が、今度はフロントエンドの作成というわけですよ初めてフロントエンドに挑戦ということでVue.jsを使ってましたが...
まぁ、初めて触ったらなんのこっちゃで分からんがな ←なにやってんだ
直接Vueのページに見ても何書いてるか分からない
なんとなく1画面をサンプル見ながら作ってみてた
VueだとSPAとかが作れるって?
ページたくさん作らずにできるなら便利そうだな...
って思いながらrouterで接続先を設定とかカチカチ...とりあえず手探りでやって、どうにかフロントエンドのWeb画面はできました。
Golangとは違って1.5ヶ月かかりましたね...さて問題がここからだ
GolangとVueをつなごうかと思って
まずはaxiosを見つけて導入してみました。
axiosでGetメソッドやPostメソッドを作って
データの取得や新規作成などができるし、非常にわかりやすいので採用!!
エンドポイントを指定して、受け取り方を設定して動かすぜ!!て、思ってたんですよ...CORSに出会うまでは
localhostで動かそうとするとね、バックエンドとフロントエンドが噛み合わないんですよ
どうやらWebブラウザでは、Webサイトが持つ情報が別の悪意あるサイトに使われないためにSame-Origin Policyというものがあるのです。
悪意あるサイトに使われないために制限をかけているのは良いのですが、信頼しているものまで制限をかけやがるのですよ
別に私は悪意なんてないんですがね...そこで出会ったのはCORSですよ
CORSって?
CORSはあるWebサイトから別のWebサイトへのアクセスを許可するものです
これを作らないとGolangとVue.jsの間に橋がかからないのですGolang(go-chi使ってます)では
main.gofunc main() { r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(middleware.Timeout(60 * time.Second)) r.Use(Cors) } func Cors(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := appengine.NewContext(r) w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept") w.Header().Set("ExposedHeaders", "Link") w.Header().Set("Access-Control-Allow-Credentials", "true") log.Infof(ctx, "Should set headers") if r.Method == "OPTIONS" { log.Infof(ctx, "Should return for OPTIONS") return } next.ServeHTTP(w, r) }) }を書き足してあげればいけるはず
MethodやHeaderは自分で調整ということでVue.jsではconfigで調整しましょう
index.htmlproxy: { './': { target: 'http://localhost:8080', ws: true, changeOrigin: true } },これでlocalhostでつなぎました。
よっしゃ繋いだぜ、ひゃっほいで終わったら良かったのですが、
ここからが本当の地獄の始まりでしたGolangでlocalhost立ち上げると真っ白です
繋ぐことがわかったのでVue側で色んなモジュール見つけては便利にしようと色々試して「ええやん...これ」と思ってました。
vue-good-tableを使ってみたり、bootstrap-bueでデザインの良いボタンつけてみたりしてみたんですよいざそれでGolangで開くとですね...真っ白...
幻影でも見てたかのように真っ白でした。
エラーを見るとcss,jsなどなど読み取れねーよとこれを解決する方法はhttp.FileServer,http.StripPrefixが鍵となりました
これはVueで作った静的なページを返すというものです。
これを使ってjs,css,vue-good-tableなどを読んであげます
でもこれだけだと宣言しただけなのでこれを使ってあげます
http.StripPrefixで指定したパスをhttp.FileServerが捜索するURLを取り除きましょうmain.govar vueTemplate *template.Template func main() { r.Get("/", VueHandler) r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(middleware.Timeout(60 * time.Second)) r.Use(Cors) //Vue.jsで作成したの静的ページを返す //これを使用しないとGolangでVueのパッケージなどが表示されない static := http.FileServer(http.Dir("./(your-file-name)/dist/static")) table := http.FileServer(http.Dir("./(your-file-name)/node_modules/vue-good-table")) css := http.FileServer(http.Dir("./(your-file-name)/dist/static/css")) js := http.FileServer(http.Dir("./(your-file-name)/dist/static/js")) public := http.FileServer(http.Dir("./(your-file-name)/public")) src := http.FileServer(http.Dir("./(your-file-name)/src")) //http.StripPrefix()は、第1引数に指定したパスを、http.FileServer()が捜索するURLから取り除く。 http.Handle("/static/", http.StripPrefix("/static/", static)) http.Handle("/vue-good-table/", http.StripPrefix("/vue-good-table/", table)) http.Handle("/css/", http.StripPrefix("/css/", css)) http.Handle("/js/", http.StripPrefix("/js/", js)) http.Handle("/public/", http.StripPrefix("/public/", public)) http.Handle("/src/", http.StripPrefix("/src/", src)) http.Handle("/", r) appengine.Main() } //Vue.jsのindex.htmlを読み込み ブラウザで表示する処理 func VueHandler(w http.ResponseWriter, r *http.Request) { vueTemplate = template.Must(template.ParseFiles("./(your-file-name)/dist/index.html")) err := vueTemplate.ExecuteTemplate(w, "index.html", siteKey) if err != nil { log.Errorf(appengine.NewContext(r), err.Error()) w.WriteHeader(http.StatusInternalServerError) return } return }以上です
これに気づかずにずっと沼ってしまった私ですが、どうにか脱出できました。
参考程度に書きましたが、大丈夫かな?
ではでは(^^)参考URL
http://www.tohoho-web.com/ex/same-origin-policy.html Some-Origin-Policy
https://qiita.com/mochizukikotaro/items/6b72ad595db8a6b5514f GOやPHPのCORSがより詳しいです
https://www.kabanoki.net/3230/ Vue-Good-Tableの参考です
https://blog.y-yuki.net/entry/2017/05/19/163000 http.StripPrefixの参考です
- 投稿日:2020-02-21T11:45:50+09:00
Vue.jsのテンプレート構文について
⬇️HTMLっぽいこれがテンプレート構文です
<div id="app"> <p>{{message}}</p> </div>これを、Vue.jsがいろんな処理をして、最終的にHTMLとして出力し、ブラウザがレンダリングしている!
- マスタッシュタグの中に、
message
とかsayHi
とかのmain.jsのプロパティを記述しますApp.vue<div id="app"> <p>{{message}}</p> <!-- マスタッシュタグの中身はJavaScriptをそのままかける --> <p>{{number + 4 }}</p> <p>{{sayHi()}}</p> <!-- マスタッシュタグ内に プロパティを記述する --> </div>main.jsnew Vue({ //elはクラス,id,divとかも取れる el:'#app', data:{ message:'Hello Wold!', number:3 }, methods:{ sayHi:function(){ return 'Hi'; } } })methodsからdataにアクセスするには
インスタンス内のmethodsからdataにアクセスするには、以下のように書きます。
main.jsnew Vue({ //elはクラス,id,divとかも取れる el:'#app', data:{ message:'Hello Wold!', number:3 }, methods:{ sayHi:function(){ //同じインスタンス内のmessageを表示させたい時、 return this.message; } } })
this
をつけてプラパティであるmessage
書くことで、
その値のHello World!
が表示されます。
- 投稿日:2020-02-21T10:56:06+09:00
Vue.jsのカスタムディレクティブの修飾詞について
以下のコードのどれが修飾詞かというと...
ディレクティブの隣のsolidの隣の
round
です!!!!
:がついてるsolidは引数です。App.vue<template> <!-- :の後に入るのは引数 --> <!-- 引数の後に.(ドット)つけるのが修飾詞--> <p v-border:solid.round="{width:'5px',color:'red'}">Home</p> </template>jsの方では
- 修飾詞がついてる時とついてない時があるので、if文で分ける
- roundが、修飾詞として選択されているか見極めたい
- もしroundが選択されてた場合、trueそうでなければfaulse
main.js//{}内に書いたものは、bindとupdatedに適用される Vue.directive("border",function(el,binding){ //上の二つを一気に書くと、 el.style.borderWidth = binding.value.width; el.style.borderColor = binding.value.color; //arg = argument = 引数 el.style.borderStyle = binding.arg; //修飾詞がついてる時とついてない時があるので、if文で分ける //roundが、修飾詞として選択されているか見極めたい //もしroundが選択されてた場合、trueそうでなければfaulse if(binding.modifires.round){ el.style.borderRadius = "0.5rem"; } if(binding.modifires.shadow){ el.style.boxShadow = "0.2px 5px rgba(0,0,0,0.26)"; } });
- 投稿日:2020-02-21T08:13:47+09:00
Vue.jsのカスタムディレクティブについて
まずディレクティブとは
v-textとかv-modelとかv-ifとか
これ、自分で作れる!
それがカスタムディレクティブというどんな時に使うかというと?
- コードを抽象化したい
- コードを再利用したい
時に使います
再利用したいときは基本的にはコンポーネントを使いますが、もっと複雑なものを作りたい時にカスタムディレクティブを使います。
App.vue<template> <p v-border>Home</p> <!-- bindのタイミング・・・v要素が初めてpタグに結びついた時 --> </template>main.js//コンポーネントと同じように、引数は2つとる。 //1つ目は名前。border(v-●●の●●の部分) Vue.directive("border",{ //2つ目の引数はオブジェクト //5個のメソッドをとる //フック関数ともいう bind(el,binding,vnode){}, //⬆️ディレクティブが初めて対象の要素に紐づいた時(最初の一回のみ) inserted(el,binding,vnode,oldVnode){}, //⬆️実際の親DOMnodeに挿入された時 //mounted的な updated(el,binding,vnode){}, //コンポーネント(Home.vue)が更新された時 (コンポーネントのVNodeの状態で) componentUpdated(el,binding,vnode,oldVnode){}, unbind(el,binding,vnode){} });主にこんな感じで書きますが、
二つ目の引数でよく使うものは、
bind
とupdated
で基本的に同じような内容を書きます。同じような内容を書くので、省略記法があります。
カスタムディレクティブの二つ目の引数は
オブジェクトとmain.jsの方に書きましたが、オブジェクトである必要はなく、そのまま関数を書いていっちゃいます。main.js//functionの引数は、oldVnodeとかもかける //{}内に書いたものは、bindとupdatedに適用される Vue.directive("border",function(el,binding){ //elとは紐づく要素を示す(どのHTML要素とつながるか) //今回はv-borderはpタグのとこに入ってるのでpタグと繋がる el.style.border ="solid black 2px"; //el.style.borderWidth = '5px' //⬆️これを動的に渡すとすると、以下のように書く el.style.borderWidth = binding.value; });この
border
とwidth
を一緒に書く場合は、オブジェクトで書きます!App.vue<template> <!-- 二つ以上のデータを渡すときは渡すデータをオブジェクトにしちゃう --> <p v-border="{width:'5px',color:'red'}">Home</p> </template>ほんで
main.jsVue.directive("border",function(el,binding){ el.style.borderWidth = binding.value.width; el.style.borderColor = binding.value.color; });こんな感じで
引数をとる場合
カスタムディレクティブの後に引数を取り、
jsの方でargと書きます
※引数は一つしか取れないApp.vue<template> <!-- :の後に入るのは引数 --> <p v-border:dotted="{width:'5px',color:'red'}">Home</p> </template>main.jsVue.directive("border",function(el,binding){ //arg = argument = 引数 el.style.borderStyle = binding.arg; });