豚吐露@wiki
study
最終更新:
Bot(ページ名リンク)
-
view
Vue.jsお勉強
Vue.js ガイド
をbaseにVue.jsの習得を目指す。
ApplicationInstance
Vue.createApp()で生成される。Vueのbaseとなるobject(application instance)を返す。※以降app
const app = Vue.createApp({}); const vm = app.mount('#app');
appにはapp内で利用可能なcomponent、directive、pluginを登録できる。
appのほとんどのmethodはappを返すので、method chainでまとめて設定できる。
appのほとんどのmethodはappを返すので、method chainでまとめて設定できる。
- global: component
app.component('hoge', hoge);
- global: directive
app.directive('fuga', fuga);
- global: plugin
app.use(plugin_method);
RootComponent
root component instanceは、applicationをmountする際に、renderingの起点として利用される。
mount: appはDOM要素にmountしなければならない。
以下のように指定すると、id='app'のタグにmountされる。
mount: appはDOM要素にmountしなければならない。
以下のように指定すると、id='app'のタグにmountされる。
const vm = app.mount('#app');
※mountは他のapp methodと異なり、root component instanceを返却する。
※ここで格納している変数vmは、ViewModelの略。ただし、MVVM modelとは直接関係してないらしい。
※ここで格納している変数vmは、ViewModelの略。ただし、MVVM modelとは直接関係してないらしい。
ComponentInstance
data propertyはcomponent instanceを介して公開される。
ComponentOptions
template構文を用いて、createApp()に渡す。
{ data() { return { param: value, } }, mounted() { }, methods: { method_name() { console.log('process log'); } }, }
ここで渡すpropertyは、(root) component instanceを介して自由にaccessできる。
CompositionAPI
setup
インスタンス化直前に実行される。
props解決→setup()→インスタンス化
setup()内で定義された関数は、template内から直接呼び出せる。
<script setup> const msg = 'hoge' function log(){ console.log(msg) } </script> <template> <div @click="log">{{ msg }}</div> </template>
setup()内でimportされた関数は、template内から直接呼び出せる。
<script setup> import { capitalize } from './helpers' //helpers.capitalize </script> <template> <div>{{ capitalize('hoge') }}</div> </template>
methods内に定義した場合と何が異なる?
LifeCycleHook
ライフサイクルダイアグラム
ライフサイクルフック
各component instanceのlife cycleにおいて、任意のlife cycleで実行されるmethodを指定する。
life cycle:生成されて、不要となって消されるまで。
ライフサイクルフック
各component instanceのlife cycleにおいて、任意のlife cycleで実行されるmethodを指定する。
life cycle:生成されて、不要となって消されるまで。
hook method | timing | details |
---|---|---|
beforeCreate | ||
created | instance生成後 | |
beforeMount | ||
mounted | mountされた後 | |
beforeUpdate | ||
updated | ||
activated | ||
deactivated | ||
beforeUnmount | ||
unmounted | ||
errorCaptured | ||
renderTracked | ||
renderTriggered |
ここで指定する処理を、アロー関数形式で指定したらダメらしい。指定すると以下のようなerrorが出るとのこと。
- Uncaught TypeError: Cannot read property of undefined
- Uncaught TypeError: this.myMethod is not a function
ReactiveSystem
リアクティブの探究
控えめなリアクティブシステム:component instanceのpropertyを変更するとviewの値が更新される。
リアクティブ: imageはexcel関数。関数の元値を変更すると関数実行結果がlinearに変更される挙動。
一般的なjavascriptはリアクティブな動きはしない。
控えめなリアクティブシステム:component instanceのpropertyを変更するとviewの値が更新される。
リアクティブ: imageはexcel関数。関数の元値を変更すると関数実行結果がlinearに変更される挙動。
一般的なjavascriptはリアクティブな動きはしない。
- watchEffect()
template構文
Vue.jsは、templateを仮想DOMのRender関数にcompileする。
templateの代わりにRender関数を直接書くことも可能。JSXもサポートするらしい。
templateの代わりにRender関数を直接書くことも可能。JSXもサポートするらしい。
Mustache構文
『{{ }}』で囲む記述を始めとする、HTMLへパラメータを埋め込む構文。
MustacheTag内に記載した内容はJavaScriptとして扱われる。
変数や値が記載されている場合はその変数や値が、単一の式が記載されている場合は式の実行結果が対象となる。
文や、複数の式が記載されている場合、動作しない。
MustacheTag内に記載した内容はJavaScriptとして扱われる。
変数や値が記載されている場合はその変数や値が、単一の式が記載されている場合は式の実行結果が対象となる。
文や、複数の式が記載されている場合、動作しない。
Type | MustacheTag | input | details |
Variables | {{ hoge }} | ||
{{{ hoge }}} | |||
Section | {{ #hoge }} ~ {{ /hoge }} | ||
{{ #hoge }}{{ fuga }}{{ /hoge }} | {"hoge": [{"fuga": 1}, {"fuga": 2}, {"fuga": 3}, ]} | ||
{{ #hoge }}{{ . }}{{ /hoge }} | {"hoge": [1, 2, 3, ]} | ||
{{ #hoge? }} ~ { /hoge? }} | |||
InvertSection | {{ ^hoge }} ~ { /hoge }} | ||
Comment | {{ !hoge }} | ||
Partial | {{ > filename }} | ||
SetDelimiter | {{=<% %>=}} |
directive
『v-【directive】:【引数】.【修飾子】』らしい。
引数は、『[JavaScript式]』の形式でjavascriptの変数や式を指定できる動的引数が利用できる。
動的引数に指定する変数などは、全て小文字に変換されるので、大文字の利用は禁止。
動的引数には、文字列が入ることが想定されるが、nullが設定されているときレンダリングは行われない。
JavaScript式からは、『Infinity、undefined、NaN、isFinite、isNaN、parseFloat、parseInt、decodeURI、decodeURIComponent、encodeURI、encodeURIComponent、Math、Number、Date、Array、Object、Boolean、String、RegExp、Map、Set、JSON、Intl、BigInt』へのみ access可能 。
引数は、『[JavaScript式]』の形式でjavascriptの変数や式を指定できる動的引数が利用できる。
動的引数に指定する変数などは、全て小文字に変換されるので、大文字の利用は禁止。
動的引数には、文字列が入ることが想定されるが、nullが設定されているときレンダリングは行われない。
JavaScript式からは、『Infinity、undefined、NaN、isFinite、isNaN、parseFloat、parseInt、decodeURI、decodeURIComponent、encodeURI、encodeURIComponent、Math、Number、Date、Array、Object、Boolean、String、RegExp、Map、Set、JSON、Intl、BigInt』へのみ access可能 。
修飾子は、v-on、v-modelでのみ使用する?
v-once
更新不要な項目を1度だけ表示する際に用いる。
v-html
指定パラメータでHTMLを渡し、表示させることが可能。
v-bind
Mustache構文はHTML tag内部では使えないため、v-bindを用いる。
v-bind:id="hoge" のように、v-bindと一緒に属性を指定することで、その属性名のparameterを設定、bindできる。
指定parameterがnullやundefinedの場合、レンダリング自体が行われない。
disabledのように存在していたら...という属性を設定する場合、以下の用に設定する。
v-bind:disabled="isDisabled" のように記載されていた場合、isDisabledにtrueと解釈できる値が設定されている場合、属性が設定される。falseと解釈できる値の場合、設定されない。ただし、isDisabledが空文字の場合のみ、disabled="" がレンダリングされる。
v-bind:[hoge]="url"とあった場合、hogeに文字列"href"が指定されていたとすると、v-bind:href="url"と解釈される。
v-bindには省略記法が用意されている。
以下の構文は、全て同一のdirectiveとして扱われる。
指定parameterがnullやundefinedの場合、レンダリング自体が行われない。
disabledのように存在していたら...という属性を設定する場合、以下の用に設定する。
v-bind:disabled="isDisabled" のように記載されていた場合、isDisabledにtrueと解釈できる値が設定されている場合、属性が設定される。falseと解釈できる値の場合、設定されない。ただし、isDisabledが空文字の場合のみ、disabled="" がレンダリングされる。
v-bind:[hoge]="url"とあった場合、hogeに文字列"href"が指定されていたとすると、v-bind:href="url"と解釈される。
v-bindには省略記法が用意されている。
以下の構文は、全て同一のdirectiveとして扱われる。
<a v-bind:href="url">text</a> |
<a :href="url">text</a> |
<a :[ket]="url">text</a> ※ket='href'の場合。 |
<a :[KEY]="url">text</a> ※KEYはkeyに変換される。ket='href'の場合。 |
v-if / v-else / v-else-if
当該要素の表示の制御。
true:レンダリング実施、false:レンダリングを行わない。
true:レンダリング実施、false:レンダリングを行わない。
<h1 v-if="awesome">yes</h1> <h1 v-else>no</h1>
v-elseは、v-if / v-else-ifの直後にのみ配置できる。
複数要素を制御したい場合は、以下のようにtemplate tagに対してv-ifを使う。
<template v-if="ok"> <h1>title</h1> <p>p1</p> <p>p2</p> </template>
この時、template tagはレンダリングされない。
v-else-ifは複数配置も可能。
<p v-if="type === 'a'">A</p> <p v-else-if="type === 'b'">B</p> <p v-else-if="type === 'c'">C</p> <p v-else-if="type === 'd'">D</p> <p v-else-if="type === 'e'">E</p> <p v-else>other</p>
- v-ifとv-forを同時に使ってはいけない
v-ifとv-forを同時に使うのはng。
v-ifとv-forが同一要素に使われていた場合、v-ifが先に評価される。なので、以下のようなcodeはerrorが出る。
v-ifとv-forが同一要素に使われていた場合、v-ifが先に評価される。なので、以下のようなcodeはerrorが出る。
<li v-for="item in items" v-if="!item.isDisp">{{item.id}}</li>
itemsに対してならv-if可能。
<li v-for="item in items" v-if="items">{{item.id}}</li>
v-show
v-showもv-ifと同様に当該要素の表示制御。v-elseとかとは連動してくれない。
v-ifみたいにtemplate要素に使うことはできない。
v-ifと異なり、必ずレンダリングされる。v-showの条件が非表示の場合、レンダリングした結果は、CSS:displayで非表示にされる。
v-ifみたいにtemplate要素に使うことはできない。
v-ifと異なり、必ずレンダリングされる。v-showの条件が非表示の場合、レンダリングした結果は、CSS:displayで非表示にされる。
v-ifとv-showは以下を気にして使い分ける必要がある。
v-if | v-show | |
レンダリングcost | 並 | 高 |
表示切り替えcost | 高 | 低 |
ざっくり言うと、頻繁に表示/非表示を切り替えるようならv-showを使った方が良い。
初期表示に切り替える必要があるならv-ifでok。
初期表示に切り替える必要があるならv-ifでok。
v-for
list要素をdataの定義を用いて繰り返し表示させることが可能。
<ul id="array"> <li v-for="(item, i) in items" :key="item.msg">{{i + ': ' + item.msg}}</li> </ul>
const app = Vue.createApp({ data() { return { items: [ {msg: "hoge"}, {msg: "fuga"}, {msg: "piyo"}, ] } } }); const vm = app.mount('#array');
index番号は2つ目の引数を指定すれば取れる。また、
v-for="(item, i) in items"
は、
v-for="(item, i) of items"
と書いてもok。
v-forはobjectに対しても使える。
<ul id="array"> <li v-for="(val, key, i) in items">{{i}}. {{key}}: {{val}}</li> </ul>
const app = Vue.createApp({ data() { return { items: { a: "hoge", b: "fuga", c: "piyo", } } } }); const vm = app.mount('#array');
indexは第3引数を指定すれば取れる。
objectをv-forする時、同じkeyが複数あった場合、後勝ちとなる。
objectをv-forする時の並びは、Object.keys()の並びに従う。keys()の返す値は、JavaScriptエンジンの実装によって異なる場合があるので注意。
objectをv-forする時、同じkeyが複数あった場合、後勝ちとなる。
objectをv-forする時の並びは、Object.keys()の並びに従う。keys()の返す値は、JavaScriptエンジンの実装によって異なる場合があるので注意。
- in-place-patch
v-forでレンダリングされた要素を更新する際の動き。
"その場でパッチを適用する"の意。効率の良いレンダリング方法。
ただし、子componentの状態や一時的なDOMの状態に依存していない場合にのみ成り立つ。
→ 各nodeの識別情報を追跡できるよう一意なkey属性を付与することが推奨される。
→ keyに指定するのは文字列や数値のようなプリミティブ型(methodを持たない型)のみ。
→ uniqな値をしていないとどうなるん?
→ v-forに依らない他の用途 もある。
"その場でパッチを適用する"の意。効率の良いレンダリング方法。
ただし、子componentの状態や一時的なDOMの状態に依存していない場合にのみ成り立つ。
→ 各nodeの識別情報を追跡できるよう一意なkey属性を付与することが推奨される。
→ keyに指定するのは文字列や数値のようなプリミティブ型(methodを持たない型)のみ。
→ uniqな値をしていないとどうなるん?
→ v-forに依らない他の用途 もある。
- 配列の変化を検出
配列の以下のmethodをラップする。
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
- 配列の置き換え
上記以外のラップされないmethodを使う場合、常に新しい配列が作られるため、既存の配列を新しい配列で置き換える必要がある。
→ 差異のある項目だけ再レンダリングされる。
- 配列にフィルタなどを適用した結果で表示したい場合
算出propertyを使う方法。
<li v-for="n in evenNumbers" :key="n">{{n}}</li>
data() { return { numbers: [1, 2, 3, 4, 5, ] } }, computed: { evenNumbers() { return this.numbers.filter(num => num % 2 === 0); } }
methodsを使う方法。
<ul v-for="numbers in sets"> <li v-for="n in even(numbers)" :key="n">{{n}}</li> </ul>
data() { return { sets: [ [1, 2, 3, 4, 5, ], [6, 7, 8, 9, 10, ], ] } }, methods: { even(nums) { return nums.filter(num => num % 2 === 0); } }
- loop回数の整数値指定
<div id="range"> <span v-for="i in 100" :key="i">{{n}}<br></span> </div>
Vue.createApp({}).mount('#range');
- templateでもv-forが使える
複数要素のブロックをレンダリングするために、template tagにv-forを使うことも可能。
- v-ifとv-forは同時に使えない
v-ifの項目参照。
- カスタムコンポーネントとv-for
カスタムコンポーネントで直接v-forを使える。が、componentへ情報が勝手に渡される訳じゃないので、渡したい情報をbindする必要がある。
<my-component v-for="(item, i) of items" :item="item" :index="i" ></my-component>
v-on
v-on:click="doClick"のように記載されていた場合、click event listenerとevent handler"doClick"のbindを行う。
v-on:[evt]="doEvent"とあった場合、evtに文字列"click"が指定されていたとすると、v-on:click="doEvent"と解釈される。
v-on:submit.prevent="doSubmit"と修飾子"prevent"が設定されていた場合...
v-on:[evt]="doEvent"とあった場合、evtに文字列"click"が指定されていたとすると、v-on:click="doEvent"と解釈される。
v-on:submit.prevent="doSubmit"と修飾子"prevent"が設定されていた場合...
event受信 → event.preventDefault() → doSubmit()
の順に実行される。
v-onには、@を使った省略記法が用意されている。
以下の構文は、全て同一のdirectiveとして扱われる。
以下の構文は、全て同一のdirectiveとして扱われる。
<a v-on:click="doClick">text</a> |
<a @click="doClick">text</a> |
<a @[evt]="doClick">text</a> ※evt='click'の場合。 |
<a @[EVT]="doClick">text</a> ※EVTはevtに変換される。evt='click'の場合。 |
methods: { doClick(evt) { alert(evt.type); } }
- イベントハンドラ
イベントハンドラには、式、method、inline methodが書ける。
コレはViewModel内で完結する。
コレはViewModel内で完結する。
式 | cnt += 1; みたいに1行で書ける式を記載できる。 |
method | methodsに定義したmethod名を指定できる。 |
inline method | methodを実際に呼び出すように構文として記載できる。 この方法なら引数を指定したりできる。 |
ViewModelinstanceが消去されると、イベントリスナも自動で削除される。
またイベントハンドラは、『,』で区切って複数設定することも可能。
@click="hndl('1'), hndl('2'), hndl('3')"
- $event
オリジナルDOMのeventを参照したい時に、eventハンドラに$eventを渡すことで、オリジナルDOMeventを渡せる。
<div id="handler"> <button @click="warn('hogehoge', $event)">Submit</button> </div>
Vue.createApp({ methods: { warn(msg, evt) { //evt: native event if(evt) { evt.preventDefault() } alert(msg); } } }).mount('#handler')
- event修飾子
.stop | eventの伝搬が止まる。 |
.prevent | eventによってpage reloadされるのを止める。 |
.capture | キャプチャーモードでイベントリスナーを追加する。 |
.self | 対象が自身の時だけイベントハンドラが呼び出される。 |
.once | 1回だけeventが発火する。 |
.passive | https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener ※.passiveと.preventは同時に使えない。.preventは無視される。 |
※event修飾子は複数つなげる事も可能。 <a @click.once.self.capture.prevent="doEvt"></a>
- key修飾子
キーボードイベントを受け取ることも可能。
<input @keyup.enter="submit" />
enter keyが呼ばれた時にvm.submit()が呼び出される。
→ .enter .tab .delete .esc .space .up .down .left .right
→ .deleteはDelete、Backspace両方をcaptchaする。
→ .enter .tab .delete .esc .space .up .down .left .right
→ .deleteはDelete、Backspace両方をcaptchaする。
- system修飾子キー
以下のように、修飾するとCtrlキーを押下しながらclickしないと、イベントリスナは呼ばれない。
<a @click.ctrl="doEvt">Ctrl押しながらで実行</a> <a @click.ctrl.alt.shift="doEvt">Ctrl+Alt+Shift押しながら実行</a>
<input @keyup.ctrl.alt.shift.enter="doEvt" />
→ Ctrl+Alt+Shift押しながら、Enterを押して話すと実行。
→ keyupの対象はEnterキーのみ。
→ keyupの対象はEnterキーのみ。
- .exact修飾子
system修飾子をより厳密にcheckする。
<button @click.ctrl="doEvt">button</button>
→ 押されてるキーにCtrlが含まれてたらイベントハンドラ実行。
<button @click.ctrl.exact="doEvt">button</button>
→ 押されてるキーがCtrlのみの時にだけイベントハンドラ実行。
<button @click.exact="doEvt">button</button>
→ Ctrl、Alt、Shift、Metaが押されてない時にだけイベントハンドラ実行。
- マウスボタン修飾子
<button @click.right="doEvt">button</button>
→右クリック時のみイベントハンドラ実行。
→ .left .right .middle
→ .left .right .middle
v-model
formとelementの両方にbind。form入力bindingに利用する。
form type | property | event |
---|---|---|
text | value | input |
textarea | value | input |
checkbox | checked | change |
radio | checked | change |
select | value | change |
→ IMEによる入力中、v-modelは更新しない。
→ IMEによる入力でも更新させたい場合は、v-modelを使わず、inputイベントリスナとvalue propertyのbindを使う必要がある。
→ IMEによる入力でも更新させたい場合は、v-modelを使わず、inputイベントリスナとvalue propertyのbindを使う必要がある。
- text
1行
<input v-model="msg" /> <p>Msg: {{msg}}</p>
複数行
<textarea v-model="msg"></textarea> <p>Msg: {{msg}}</p>
→ <textarea>{{msg}}</textarea> て書き方はできない。
- checkbox
checkboxの状態を変数とbind。
<input type="checkbox" id="chkbox" v-model="checked" /><label for="chkbox">{{checked}}</label>
複数checkboxを配列に対してbindできる。
<div id="multiChk"> <input type="checkbox" id="A" value="AA" v-model="checkList" /><label for="A">AAA</label> <input type="checkbox" id="B" value="BB" v-model="checkList" /><label for="B">BBB</label> <input type="checkbox" id="C" value="CC" v-model="checkList" /><label for="C">CCC</label> <br> <span>List: {{checkList}}</span> </div>
Vue.createApp({ data(){ return { checkList: [] } } }).mount("#multiChk");
true-value属性、false-value属性を用いることで、check/un-check時の値を定義できる。
→ checkboxはcheckされていない項目は送信対象に含めない。
→ 含めたい場合はradioを利用すると少なくとも1項目は送信される。
→ checkboxはcheckされていない項目は送信対象に含めない。
→ 含めたい場合はradioを利用すると少なくとも1項目は送信される。
- radio
さっきのcheckboxのinput typeをradioに変えて動かす。
<div id="multiChk"> <input type="radio" id="A" value="AA" v-model="checkList" /><label for="A">AAA</label> <input type="radio" id="B" value="BB" v-model="checkList" /><label for="B">BBB</label> <input type="radio" id="C" value="CC" v-model="checkList" /><label for="C">CCC</label> <br> <span>List: {{checkList}}</span> </div>
Vue.createApp({ data(){ return { checkList: [] } } }).mount("#multiChk");
bind対象が配列でも1つしか格納されない。
- select
selectorをv-modelした例。
<div id="selector"> <select v-model="sel" multiple> <option disabled value="">Please Select</option> <option>A1</option> <option>B2</option> <option>C3</option> <span>Select: {{sel}}</span> </select> </div>
Vue.createApp({ data() { return { sel: '' } } }).mount('#selector')
select tagにmultipleを付与すると複数選択にも対応。bindするpropertyは、配列じゃ無くても大丈夫。
v-for使ってdataから生成することも可能。
<div id="selector"> <select v-model="sel"> <option v-for="o in options" :value="o.value">{{o.text}}</option> </select> <span>Select: {{sel}}</span> </div>
Vue.createApp({ sel: 'A', options: [ { text: '1', value: 'A' }, { text: '2', value: 'B' }, { text: '3', value: 'C' }, ] }).mount('#selector')
また、valueにはobjectを指定することも可能。
Vue.createApp({ sel: 'A', options: [ { text: '1', value: { name: 'A'}, }, { text: '2', value: { name: 'B'}, }, { text: '3', value: { name: 'C'}, }, ] }).mount('#selector')
→ typeof vm.sel // => Object
→ vm.sel.name //=> 'A'
→ vm.sel.name //=> 'A'
- 値のbinding
v-modelでbindされた場合、値は文字列で格納される。
→ true/falseも文字列らしい。
→ 文字列以外の値をbindしたい場合は、v-bindを使用する。
→ true/falseも文字列らしい。
→ 文字列以外の値をbindしたい場合は、v-bindを使用する。
- 修飾子
.lazy | v-modelはdefalutでは都度入力(input event)に対して動作する。 lazyを付けておくとinput eventは無視されchange eventでのみ動作するようになる。 → textboxからunforcusした時。 |
.number | 指定すると文字列から数値にparseFloat()できるか試みてくれる修飾子。parse出来なかったら元の文字列が格納される。 input type='number'の場合は、何もしなくても勝手に数値にしてくれる。 |
.trim | 入力項目からspaceをtrimしてくれる。 |
- カスタムイベントで動作するカスタム入力を作る
<input v-model="searchText" />
と
<input :value="searchText" @input="searchText = $event.target.value" />
は同じ。
→ componentで利用する時、v-modelの代わりに利用する。
<custom-input :model-val="searchText" @update:model-val="searchTex = $event"></custom-input>
と
<input :value="searchText" @input="searchText = $event.target.value" />
は同じ。
→ componentで利用する時、v-modelの代わりに利用する。
<custom-input :model-val="searchText" @update:model-val="searchTex = $event"></custom-input>
app.component('custom-input', { props: ['modelVal'], emits: ['update:modelVal'], template: `<input :value="modelVal" @input="$emit('update:modelVal', $event.target.value)" />` })
算出propertyも使える。
app.component('custom-input', { props: ['modelVal'], emits: ['update:modelVal'], template: `<input v-mode="value">`, computed: { value: { get() { return this.modelVal }, set(val) { this.$emit('update:modelVal', val) } } } })
v-slot
Component
Componentの基本。
component instance。
component instance。
component関数を使ってcomponentを定義。利用できる。
var app = Vue.createApp({}); app.component('hoge', { component定義 });
※通常、文字列で定義しない。SFCを利用する。
component構成
componentは、nestされたツリー構造に編成される。
component関数での登録は"グローバル"、"ローカル"の2種類ある。
→ component関数で登録:グローバルに登録。
→ グローバルなので、app内のどこからでも利用可能。
→ 登録名は小文字と'-'のみで構成。
component関数での登録は"グローバル"、"ローカル"の2種類ある。
→ component関数で登録:グローバルに登録。
→ グローバルなので、app内のどこからでも利用可能。
→ 登録名は小文字と'-'のみで構成。
componentのtemplateにroot要素が複数ある場合、$attrsを使って、どの要素が使用するのか定義しないと困るらしい。
→ どう動くのかは不明。全部のroot要素に付与されるのか?全く付与されないのか?
→ まぁ、root要素は1つにしとくのがえぇ気がする。
→ どう動くのかは不明。全部のroot要素に付与されるのか?全く付与されないのか?
→ まぁ、root要素は1つにしとくのがえぇ気がする。
子componentへのdata受け渡し
props propertyに配列として、渡したい情報の属性名を記載。
component利用時、component tagへ属性として渡したい情報を記載。
→ インスタンス化時に利用される。
→ propsで利用する属性をv-bindして動的にpropertyを渡せる。
component利用時、component tagへ属性として渡したい情報を記載。
→ インスタンス化時に利用される。
→ propsで利用する属性をv-bindして動的にpropertyを渡せる。
component間の通信
親componentと子component間で通信が必要となった場合。
$emit methodの利用。
→ <button @click="$emit('event_name')">hoge</button>
→ 親componentのevent発火が可能。
→ eventと一緒にparameterを渡せる。
→ <button @click="$emit('event_name', 0.1)">hoge</button>
→ イベントハンドラが式の場合、$eventでparameterにaccessできる。
→ イベントハンドラがmethodの場合、第1引数としてparameterは渡される。
$emit methodの利用。
→ <button @click="$emit('event_name')">hoge</button>
→ 親componentのevent発火が可能。
→ eventと一緒にparameterを渡せる。
→ <button @click="$emit('event_name', 0.1)">hoge</button>
→ イベントハンドラが式の場合、$eventでparameterにaccessできる。
→ イベントハンドラがmethodの場合、第1引数としてparameterは渡される。
object構文
主に:styleで便利な機能。
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data() { return { activeColor: 'red', fontSize: 30, } }
更に簡潔にこんな感じにも書ける。
<div :style="styleObj"></div>
data() { return { styleObj { color: 'red', fontSize: '13px', } } }
また、配列構文とobject構文を併用すると、object構文で定義した複数のstyleを簡潔に指定できる。
<div :style="[baseStyle, styleObj]"></div>
ベンダープレフィックス
ベンダープレフィックスが必要なCSSの場合、勝手にベンダープレフィックスを付けてくれるらしい。
また、
また、
<div :style="{display: ['-webkit-box', '-ms-flexbox', 'flex']}"></div>
って感じにdisplayに対して複数の値を配列で記載できる。
で、こう書くとどうなるかと言うと、後勝ちでブラウザがサポートしてる書き方の最後の値が有効になる。
で、こう書くとどうなるかと言うと、後勝ちでブラウザがサポートしてる書き方の最後の値が有効になる。
ちょいちょい出てくる書き方。
const { h, resolveComponent } = Vue;
これは、
const h = Vue.h; const resolveComponent = Vue.resolveComponent;
と同義らしい。左辺で指定してる名前のpropertyやmethodが右辺に無い場合、undefinedになる模様。
- $ prefix
ビルドインAPIを表す。
- _ prefix
内部propertyを表す。
- h()
VNodeを作るための関数。
h({String|Object|Function|Component} tag, {Object} props, {String|Array|Object} children)
h({String|Object|Function|Component} tag, {Object} props, {String|Array|Object} children)
data()
component instance生成時に呼ばれる関数。実行結果を$dataに格納する。
const app = Vue.createApp({ data(){ return { hoge: "hoge" } } }); const vm = app.mount("#hoge"); console.log(vm.$data.hoge); => "hoge" console.log(vm.hoge); => "hoge"; vm.hoge = "fuga"; console.log(vm.$data.hoge); => "fuga" vm.$data.hoge = "piyo"; console.log(vm.hoge); => "piyo";
createApp()で渡されたdata()から返されたObjectをget/setハンドラを持つ
Proxy
でラップする。
Proxyは、Objectをラップして、そのObjectとのやり取りを傍受できるようにしたObject。
なので、instance化後に、項目を追加するようなことは出来ない。
Proxyは、Objectをラップして、そのObjectとのやり取りを傍受できるようにしたObject。
なので、instance化後に、項目を追加するようなことは出来ない。
methods
methodsに定義した関数は、component instanceに追加される。
const app = Vue.createApp({ … data() { return { count: 4 }, }, methods: { increment() { this.count++; //この時の'this'はvm(component instance)。thisを使いたいので'=>'は使えない。 }, } … }); const vm = app.mount('#app'); //この時count=4 vm.increment(); //関数実行でcount=5
- Debounce
デバウンス。一定時間停止したら実行させることができる。
Vue.JSには無い機能。Lodash'_'などを利用して実装することができる。
Vue.JSには無い機能。Lodash'_'などを利用して実装することができる。
e.g.) mousemoveのように連続したeventが発生する場合に、mouseが止まったら実行したいというような関数を指定する。
maxWaitを指定すると、eventが来続けていても、任意の間隔で処理を実行できる。
maxWaitを指定すると、eventが来続けていても、任意の間隔で処理を実行できる。
- Throttle
スロットル。一定時間に1回だけ実行させることができる。
Vue.JSには無い機能。Lodash'_'などを利用して実装することができる。
Vue.JSには無い機能。Lodash'_'などを利用して実装することができる。
e.g.) mousemoveのように連続したeventが発生する場合に、任意の間隔で実行したい場合に用いる。
Debounce()にmaxWaitを指定しても同等の動作となるが、Throttleでは最初に必ず実行される。do~whileみたいな感じね。
Debounce()にmaxWaitを指定しても同等の動作となるが、Throttleでは最初に必ず実行される。do~whileみたいな感じね。
computed
- 算出property:算出Getter関数
templateにlogicを入れすぎるとtemplateが肥大化し、保守性が低下する。
logicを入れるよりも算出propertyを使う方法を考える。
logicを入れるよりも算出propertyを使う方法を考える。
logicを直接埋め込むのでは無く、computedにmethodを定義。
そのmethodにlogicを記載し、method名だけを埋め込む。
そのmethodにlogicを記載し、method名だけを埋め込む。
<div id='computed-basics'> <span>{{ publishedBooksMessage }}</span> </div>
Vue.createApp({ data() { return { author: { books: ['Book1', 'Book2', 'Book3'] } } }, computed: { //算出property publishedBooksMessage() { //logicを内包したmethodを定義 return this.author.books.length > 0 ? 'Yes' : 'No'; //this:mountした結果のinstance } } }).mount('#computed-basics')
computed(算出property)とmethodsの違いは?
→ 算出propertyは、reactiveな依存関係に基づいてcacheされる。
→ 上記の例だと、配列が変更されない限り、cacheされた結果が返却される。配列が変更された時は、計算結果が返却される。
→ methodだと常に関数を実行する。
→ 算出propertyは、reactiveな依存関係に基づいてcacheされる。
→ 上記の例だと、配列が変更されない限り、cacheされた結果が返却される。配列が変更された時は、計算結果が返却される。
→ methodだと常に関数を実行する。
対象がcacheすべきか否かで、computed(算出property)とmethodsを使い分ける。
- 算出property:算出Setter関数
defaultはgetterのみだが、setterも定義可能。
computed: { name: { get() { return this.first + ' ' + this.last; }, set(newName) { vals = newName.split(' '); this.first = vals[0]; this.last = vals[1]; } } }
watch
カスタムウォッチャの定義ができる。
対象のdataの変化をトリガに指定関数を実行できる。
computedとの違いは、非同期処理の実行や重い処理の実行に適してるらしい。
→算出propertyでは非同期処理(外部WebAPI呼び出し)を行い、その結果を処理するようなことはできない。
対象のdataの変化をトリガに指定関数を実行できる。
computedとの違いは、非同期処理の実行や重い処理の実行に適してるらしい。
→算出propertyでは非同期処理(外部WebAPI呼び出し)を行い、その結果を処理するようなことはできない。
<div id='watch-example'> <p><input v-model='question' /></p> <p>{{answer}}</p> </div>
const vm = Vue.createApp({ data() { return { question: '', answer: 'answer', } }, watch: { question(newVal, oldVal) { this.answer = oldVal + ' => ' + newVal; } }, }).mount('#watch-example');
Watch API
も利用可能。
基本的にwatchよりもcomputedの方がbetter。
どの機能を使うべきか吟味し、より良い選択を行うこと。
どの機能を使うべきか吟味し、より良い選択を行うこと。
classのbinding
classのbinding。
前提として、bindしたclassと通常のclass記述は共存できる。
前提として、bindしたclassと通常のclass記述は共存できる。
<div class='static' :class='{ active: isActive, 'text-danger': hasError}'></div>
data() { return { isActive: true, hasError: false, } }
↓
<div class='static active'></div>
となる。
hasErrorがtrueであれば、
hasErrorがtrueであれば、
<div class='static active text-danger'></div>
となる。
また、以下のようにも書ける。object構文とかどっかに書いてあった。
<div :class="classObject"></div>
data() { return { classObject: { active: true, 'text-danger': false } } }
で、なんでactiveにはシングルクォート付いて無くて、text-dangerには付いとるのか...理由が分からん。これハズすと動かんのか?
computed:算出propertyも使える。
<div :class="classObject"></div>
data() { return { isActive: true, error: null, } }, computed: { classObject() { return { active: this.isActive && !this.error, 'text-danger': this.error && this.error.type === 'fatal' } } }
配列構文というのもあるらしい
<div :class="[activeClass, errorClass]"></div>
data() { return { activeClass: 'active', errorClass: 'text-danger' } }
この書き方でも、
<div class='active text-danger'></div>
こうなるらしい。
また、配列内でobject構文も使えるらしい。
以下の例だとerrorClassは常に設定される。
以下の例だとerrorClassは常に設定される。
<div :class="[{active: isActive}, errorClass]"></div>
単一file component
単一ファイルコンポーネント
SFC構文仕様
SFC<script setup> Composition API setup
*.vue file、Vue SFCと呼ばれるらしい。
template(<template>)、logic(<script>)、style(<style>)を1つのfileにまとめて記載できる。
SFC構文仕様
SFC<script setup> Composition API setup
*.vue file、Vue SFCと呼ばれるらしい。
template(<template>)、logic(<script>)、style(<style>)を1つのfileにまとめて記載できる。
<script> 【JavaScript】 export default { 【defineComponent】createVueに渡すoption群 } </script> <script setup> 【SFC<script setup>】 </script> <template> 【template本文】 </template> <style> 【style定義】Vue file内に限定して指定される </style>
参照するべきStyle を参照し、準拠する必要がある。
→ file名
→ 固有prefixを付与する。
→ シングルトン:file名に"The" prefixを付与する。
→ 密結合なcomponentは、親fileの名前をprefixとする。
→ 固有prefixを付与する。
→ シングルトン:file名に"The" prefixを付与する。
→ 密結合なcomponentは、親fileの名前をprefixとする。
<script> | 標準的なJavaScript module。vue fileは1つのtoplevel<script>を含めることができる。lang属性に'ts'を指定することでTypeScriptが利用できる。 ※<script setup>を除く scriptはES moduleとして実行される。 <script setup>:事前処理されコンポーネントのsetup()関数として使用される。instance毎に実行される。 |
<template> | componentのtemplateを定義。vue fileは1つのtoplevel<template>を含めることができる。 記載した内容は、@vue/compiler-domによってJavaScriptのRender関数にプリコンパイルされる。このRender関数はexportされたcomponentのrender optionとしてattachされる。 |
<style> | componentに関係するCSSを定義。vue fileは複数の<style>を含めることができる。 lang属性に'scss'を指定することでscssが利用できる。 scoped属性、module属性を用いてカプセル化を行うことができる。 |
SFCは、file名からcomponent名を自動的に推測する。
→ 特定条件下でのみ。
→ 特定条件下でのみ。
各tagをfile分割可能。
<template src='./template.html'></template> <style src='./style.css'></style> <script src='./script.js'></script>
※相対path指定は必ず"./"で始める。
※npmの依存関係からresourceをimport可能。
※カスタムブロックも別file化可能。
※npmの依存関係からresourceをimport可能。
※カスタムブロックも別file化可能。
トップレベルのコメントはHTMLのコメント構文を利用する。
@vue/compiler-sfc によってcompileされるっぽい。
適切なfileを適切なVue project環境でbuildすれば、以下のようにimportして使える。
適切なfileを適切なVue project環境でbuildすれば、以下のようにimportして使える。
import MyComponent from './MyComponent.vue'
export default { components: { MyComponent } }
slotを用いた配置
配置したい場所にslotタグをおいて、component利用時にtagで挟んで渡すだけ。
<alert-box>Something bad hapened.</alert-box>
const app = Vue.createApp({}) app.component('alert-box', { template: ` <div class="demo-alert"> <strong>ERROR: </strong> <slot></slot> </div> ` })
動的component
動的にcomponentを変える例。
大事なのはis属性でcomponent名を指定してるトコ。
大事なのはis属性でcomponent名を指定してるトコ。
<div id="dynamic-compo"> <button v-for="tab in tabs" :key="tab" :class="['tab-button', {archive:current === tab}]" @click="current = tab"> {{tab}} </button> <component :is="currentTabComponent"> </div>
const app = Vue.createApp({ data() { return { current: 'Home', tabs: ['Home', 'Posts', 'Archive'], } }, computed: { currentTabCompo() { return 'tab-' + this.current.toLowerCase() } } }) app.component('tab-home', { template: `<div>home</div>` }) app.component('tab-posts', { template: `<div>posts</div>` }) app.component('tab-archive', { template: `<div>archive</div>` })
TemplateParse
HTMLは大文字小文字を区別しない。
なので、VueではJavaScriptでキャメルケースを使ってた場合、HTMLでケバブケースを用いる。
parserは、適宜読み替えてくれるらしい。
なので、VueではJavaScriptでキャメルケースを使ってた場合、HTMLでケバブケースを用いる。
parserは、適宜読み替えてくれるらしい。
HTML | JavaScript |
ho-ge | HoGe |
tools
Vue SFC Playground
を使うとどのようにbuildされたかが分かるらしい。
SFC関係のツール群は、以下を参照。
https://v3.ja.vuejs.org/api/sfc-tooling.html
https://v3.ja.vuejs.org/api/sfc-tooling.html
SFCを選択する理由
- HTML、CSS、JavaScriptを用いてmodule化されたcomponentを作れる
- CSSのコンポーネントスコープ<style scoped>の有効化
- <script setup>を用いた記述を使える c.f.) https://v3.ja.vuejs.org/api/sfc-script-setup.html
- IDEサポート:VSCode+Volar、WebStorm
- HMR(Hot-Module-Replacement)のサポート
InstanceProperty
組み込みproperty。全て$prefixとなっている。
- $data
- $props
- $el
- $options
- $parent
- $root
- $slots
- $refs
- $attrs
- $emit
etc...
- props down
- event up
- slot
- slot
- 名前付きslot
- スコープ付きslot
vue.config.js
更新日: 2022年10月11日 (火) 17時07分28秒