豚吐露@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秒









