豚吐露@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でまとめて設定できる。

  • 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される。
const vm = app.mount('#app');
※mountは他のapp methodと異なり、root component instanceを返却する。
※ここで格納している変数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:生成されて、不要となって消されるまで。

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はリアクティブな動きはしない。


  • watchEffect()

template構文

Vue.jsは、templateを仮想DOMのRender関数にcompileする。
templateの代わりにRender関数を直接書くことも可能。JSXもサポートするらしい。

Mustache構文
『{{ }}』で囲む記述を始めとする、HTMLへパラメータを埋め込む構文。
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可能

修飾子は、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として扱われる。
<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:レンダリングを行わない。
<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が出る。
<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とv-showは以下を気にして使い分ける必要がある。
v-if v-show
レンダリングcost
表示切り替えcost
ざっくり言うと、頻繁に表示/非表示を切り替えるようならv-showを使った方が良い。
初期表示に切り替える必要があるなら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エンジンの実装によって異なる場合があるので注意。

  • in-place-patch
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"が設定されていた場合...
event受信 → event.preventDefault() → doSubmit()
の順に実行される。

v-onには、@を使った省略記法が用意されている。
以下の構文は、全て同一の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内で完結する。
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する。

  • system修飾子キー
以下のように、修飾するとCtrlキーを押下しながらclickしないと、イベントリスナは呼ばれない。
<a @click.ctrl="doEvt">Ctrl押しながらで実行</a>
<a @click.ctrl.alt.shift="doEvt">Ctrl+Alt+Shift押しながら実行</a>
→ .ctrl .alt .shift .meta
 → .metaはmacのコマンドキー、WindowsのWinキーが該当する。
  → Sunに引っ張られてmetaって呼ばれてるらしい。
<input @keyup.ctrl.alt.shift.enter="doEvt" />
→ Ctrl+Alt+Shift押しながら、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

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を使う必要がある。

  • 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項目は送信される。

  • 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'

  • 値のbinding
v-modelで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>
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関数を使ってcomponentを定義。利用できる。
var app = Vue.createApp({});
app.component('hoge', { component定義 });
※通常、文字列で定義しない。SFCを利用する。

component構成
componentは、nestされたツリー構造に編成される。
component関数での登録は"グローバル"、"ローカル"の2種類ある。
→ component関数で登録:グローバルに登録。
 → グローバルなので、app内のどこからでも利用可能。
→ 登録名は小文字と'-'のみで構成。

componentのtemplateにroot要素が複数ある場合、$attrsを使って、どの要素が使用するのか定義しないと困るらしい。
→ どう動くのかは不明。全部のroot要素に付与されるのか?全く付与されないのか?
 → まぁ、root要素は1つにしとくのがえぇ気がする。

子componentへのdata受け渡し
props 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は渡される。

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)

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化後に、項目を追加するようなことは出来ない。

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'_'などを利用して実装することができる。

e.g.) mousemoveのように連続したeventが発生する場合に、mouseが止まったら実行したいというような関数を指定する。
maxWaitを指定すると、eventが来続けていても、任意の間隔で処理を実行できる。

  • Throttle
スロットル。一定時間に1回だけ実行させることができる。
Vue.JSには無い機能。Lodash'_'などを利用して実装することができる。

e.g.) mousemoveのように連続したeventが発生する場合に、任意の間隔で実行したい場合に用いる。
Debounce()にmaxWaitを指定しても同等の動作となるが、Throttleでは最初に必ず実行される。do~whileみたいな感じね。

computed
  • 算出property:算出Getter関数
templateにlogicを入れすぎるとtemplateが肥大化し、保守性が低下する。
logicを入れるよりも算出propertyを使う方法を考える。

logicを直接埋め込むのでは無く、computedに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だと常に関数を実行する。

対象が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呼び出し)を行い、その結果を処理するようなことはできない。

<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記述は共存できる。
<div class='static' :class='{ active: isActive, 'text-danger': hasError}'></div>

data() {
  return {
    isActive: true, hasError: false,
  }
}
<div class='static active'></div>
となる。
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は常に設定される。
<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にまとめて記載できる。

<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とする。

<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化可能。

トップレベルのコメントはHTMLのコメント構文を利用する。

@vue/compiler-sfc によってcompileされるっぽい。
適切な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名を指定してるトコ。
<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は、適宜読み替えてくれるらしい。
HTML JavaScript
ho-ge HoGe

tools

Vue SFC Playground を使うとどのようにbuildされたかが分かるらしい。

SFC関係のツール群は、以下を参照。
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秒

名前:
コメント:

すべてのコメントを見る
記事メニュー
ウィキ募集バナー