基本ガイド

ichigo.js の中核となる、アプリの作り方とリアクティビティを解説します。ディレクティブの文法は「ディレクティブ・リファレンス」、コンポーネントは「コンポーネント」を参照してください。

アプリを作る

VDOM.createApp(options) でアプリを生成し、mount(selector) でマウントします。

import { VDOM } from '@mintjamsinc/ichigojs';

VDOM.createApp({
  data() {
    return { message: 'Hello ichigo.js!', count: 0 };
  },
  methods: {
    increment() { this.count++; }
  }
}).mount('#app');

オプション

オプション 役割
data() 初期データを返す関数。this$ctx{ $markRaw }
computed 算出プロパティ。getter 関数、または { get, set }
methods メソッド群
watch プロパティパスごとのウォッチャ
emits 発火予定のイベント名(任意。検証用)
logLevel ログレベル('debug' / 'info' / 'warn' / 'error'

インスタンスでは $markRaw / $nextTick / $emit / $refs / $ctx などのヘルパーが使えます。

リアクティビティ

data

data() が返す値は自動的にリアクティブになります。プロパティの代入、ネストしたオブジェクトの変更、配列のミューテーション(push / splice など)はすべて検知され、DOM 更新が自動でスケジュールされます。

data() {
  return { count: 0, user: { name: 'Alice' }, items: [1, 2, 3] };
},
methods: {
  update() {
    this.count++;            // 反映される
    this.user.name = 'Bob';  // ネストも反映される
    this.items.push(4);      // 配列ミューテーションも反映される
  }
}

computed

算出プロパティは依存を自動追跡し、結果をキャッシュします。評価はプル型(遅延評価)で、依存が変わると「stale(再計算が必要)」と印が付き、次に読み取られたときに再計算されます。そのため、依存を変更した直後に同期的に読み取っても最新値が得られます。

this.cartItems.push(item);
console.log(this.subtotal); // すでに新しい item を反映している

DOM 更新はマイクロタスクでバッチ処理されるため、同期的な複数変更でも描画は 1 回です。各 computed は更新サイクルごとに最大 1 回だけ再計算され、再計算しても値が変わらなければ DOM 更新やウォッチャは発火しません。computed → computed の連鎖も宣言順に依存せず自動的に解決されます。

{ get, set } の形で書き込み可能な computed も定義できます。v-model の対象にしたり、直接代入したりできます。

computed: {
  fullName: {
    get() { return `${this.firstName} ${this.lastName}`; },
    set(v) { const [f, l] = v.split(' '); this.firstName = f; this.lastName = l; }
  }
}
<!-- 代入は computed の setter を通る -->
<input v-model="fullName">

watch

watch オプションで、プロパティが変化したときにコールバックを実行します。キーはプロパティパス("count""user.name" など)で、コールバックは新旧の値を受け取ります。

watch: {
  // 省略形: コールバック関数
  count(newValue, oldValue) {
    console.log(`count: ${oldValue} → ${newValue}`);
  },

  // ネストしたパス
  'user.name'(newValue, oldValue) { /* ... */ },

  // フル形式: deep / immediate つきオプション
  user: {
    handler(newValue, oldValue) { /* ... */ },
    deep: true,      // ネストした変更も監視
    immediate: true  // 登録時に一度すぐ実行
  }
}
オプション 既定 説明
handler 値が変わったときに呼ばれるコールバック
deep false ネストしたオブジェクト/配列の変更も監視
immediate false 登録時に現在値で一度実行

$markRaw

$markRaw() を使うと、オブジェクトがリアクティブプロキシで包まれるのを防げます。Chart.js などサードパーティのインスタンスや、リアクティビティが不要な大きなデータの保持に向きます。

data() {
  return { chart: null };
},
methods: {
  initChart($ctx) {
    const instance = new Chart(canvas, { /* ... */ });
    this.chart = this.$markRaw(instance); // 非リアクティブに保持
  }
}

$markRaw() したオブジェクトは変更しても更新を起こしません。更新が必要なときは、別のリアクティブなプロパティを変更してトリガーします。なお、ライフサイクルフックでは $ctx.userData(Proxy を介さない Map)も同じ目的で使えます(「ディレクティブ・リファレンス」参照)。

メソッド

methods 内では this から data / computed / 他のメソッド/ヘルパーにアクセスできます。

methods: {
  increment() { this.count++; },
  reset() { this.count = 0; }
}

イベントハンドラは第 1 引数にイベント、第 2 引数に $ctx を受け取ります(「ディレクティブ・リファレンス › v-on」参照)。

$nextTick

更新はマイクロタスクでバッチ処理されます。DOM への反映後に処理したいときは $nextTick を使います。

methods: {
  async addAndScroll() {
    this.messages.push(msg);
    this.$nextTick(() => {
      // ここでは DOM が更新済み
      this.$refs.list.scrollTop = this.$refs.list.scrollHeight;
    });
  }
}

テンプレート参照($refs

ref 属性を付けると、その DOM 要素(またはコンポーネントのホスト要素)への参照を取得できます。参照は $refs オブジェクトに集約され、メソッドやテンプレート式から使えます。

<input ref="search">
<button @click="focusSearch">フォーカス</button>
methods: {
  focusSearch() { this.$refs.search.focus(); }
}
  • 利用できるタイミングref はマウント時に登録され、アンマウント時に解除されます。@mounted 時にはすでに参照可能です。v-if / v-for で新たに描画された要素は、$nextTick を待ってから読み取ります。
  • コンポーネント — コンポーネントに付けた ref はホストのカスタム要素を指します。
  • v-for の中v-for(内部)で使うと、同名の参照は配列に集約されます。
  • 動的・関数 ref(:ref:ref で式から算出できます。文字列なら参照名、関数なら mount 時に要素・unmount 時に null で呼ばれます(関数 ref)。
<li v-for="item in items" :key="item.id" ref="rows">{{ item.name }}</li>
this.$refs.rows; // [<li>, <li>, ...] 描画された行ごとに 1 件

注意: $refs はリアクティブではありません。参照の登録・解除では再描画は起きず、リアクティブな出力の駆動には使えません。イベントハンドラやライフサイクルフックから読み取ってください(Vue と同じ挙動)。

ヒント

  • 更新はマイクロタスクでバッチ処理されます。複数の同期変更も 1 回の描画にまとまります。
  • DOM 反映後の処理は $nextTick で。
  • 外部ライブラリのインスタンスは $markRaw$ctx.userData で非リアクティブに保持します。
  • v-componentVComponentRegistry は非推奨です。defineComponent を使ってください。

次のステップ