ルーターコンポーネント
Router Componentは、component
またはcomponentUrl
プロパティを使用してルートコンテンツを指定したときにRouterによって読み込まれることができる、特別なタイプのコンテンツです。
これは、アプリケーションをより良く構成し、物事を適切な場所に保持し、多くのことをより速く、より明確で快適な方法で行うのに役立ちます。
コンポーネント機能
コンポーネントは、props
とcontext
を受け取り、レンダリング関数を返す関数です。
コンポーネントのレンダリング関数は、コンポーネントのHTMLコンテンツを含むタグ付きのテンプレートリテラルを返す必要があります。
例:
const MyComponent = (props, context) => {
// いくつかのコンポーネントロジック
let value = 'foo';
// レンダリング関数を返す
return () => context.$h`
<div class="page">
<p>Value is ${value}</p>
</div>
`;
}
コンポーネントのテンプレート
前述のとおり、コンポーネントのレンダリング関数は、コンポーネントのHTMLコンテンツを含むタグ付きテンプレートリテラルを返す必要があります。これには注意すべき点がいくつかあります。
すべての自閉式タグは閉じなければなりません!。<br>
, <img src="">
, <input ...>
のような自己完結型のタグを閉じていない場合、コンパイラはエラーを出します。
すべての空要素は自己閉鎖することができます。
<div class="my-div"></div>
<!-- としても有効です。 -->
<div class="my-div" />
コンポーネントの小道具
コンポーネント関数を受け取る最初の引数は props
です。このオブジェクトには、navigateメソッドに渡すすべてのpropsと、すべてのルートパラメータが含まれます。
例えば、以下のようなルートがあるとします。
{
path: '/blog/:id',
component: MyComponent
}
そして、/blog/34/
というURLでルートに移動すると、props.id
が'34'
になります。
また、次のようにAPIを使ってコンポーネントに移動した場合も同様です。
router.navigate('/blog/34/', {
props: {
foo: 'bar'
}
})
すると、props
は次のようなオブジェクトになります: { id: '34', foo: 'bar' }
。
また、propsにはカスタムコンポーネントに属性として渡されるプロパティが含まれます。カスタムコンポーネントがそのような属性を持っている場合
<my-component foo="bar" id="25" user=${{name: 'John'}} number=${30}></my-component>
とすると、$props
は次のようになります。
{
foo: 'bar',
id: '25',
user: {
name: 'John'
},
number: 30
}
コンポーネントコンテクスト
context
オブジェクトには、たくさんの便利なヘルパーが含まれています。
Property | Description |
---|---|
$h | 特別な タグ付きテンプレートリテラル コンポーネントのレンダリング関数の結果と、その中のすべての HTML エントリをラップするために使用しなければなりません。
|
$el | .value` プロパティがコンポーネント HTML 要素を持つ Dom7 インスタンスを含むオブジェクトです。
|
$ | Dom7ライブラリです。
|
$f7 | Framework7 アプリのインスタンス
|
$store | ストアのインスタンスです。詳細や例は Store documentation をご覧ください。 |
$f7route | 現在のルート。ルートの query , hash , params , path , url を持つオブジェクトが含まれています。 |
$f7router | 関連するルーターインスタンス
|
$theme | 現在のテーマを示す
|
$update(callback) | このメソッドは、このコンポーネントとその子供たちが、更新された状態で再レンダリングされる必要があることを示します。
DOMの変更がすぐに適用されることは保証されていないので、DOMに依存している場合(例えば、状態が変更された後にHTMLコンテンツや属性の値を取得する必要がある場合)は、 |
$tick(callback) | また、DOMに依存していて、 渡されたコールバックは、DOMの更新時に実行されます。 このメソッドは、DOMの更新時に解決されるPromiseを返します。 そのため、このように使用することができます。
|
$f7ready(callback) | このメソッドは、メインアプリコンポーネントを使用して、アプリの初期化時にFramework7のAPIを確実に呼び出す場合にのみ使用する必要があります。
|
Events | |
$on | コンポーネントのルート要素にDOMイベントハンドラーをアタッチする機能
このようなイベントハンドラは、コンポーネントが破壊されると自動的に切り離されます。 |
$once | DOMイベントハンドラーをコンポーネントのルート要素にアタッチする関数です。on`と同じですが、このようなハンドラは一度だけ実行されます。 |
$emit(event, data) | 再利用可能なカスタムコンポーネントで、カスタムDOMイベントを発行する関数です。
そして、他の親コンポーネントでも。
|
Lifecycle Hooks | |
$onBeforeMount | コンポーネントがDOMに追加される直前に呼び出されます。 |
$onMounted | コンポーネントがDOMに追加された直後に呼び出されます。
|
$onBeforeUpdate | VDOMの前のコンポーネントがパッチ/アップデートされた直後に呼び出される。 |
$onUpdated | コンポーネントVDOMがパッチ/アップデートされた直後に呼び出される。 |
$onBeforeUnmount | コンポーネントがアンマウントされる(DOMから切り離される)直前にコールされる。 |
$onUnmounted | コンポーネントがアンマウントされ、破壊されたときに呼び出される |
つまり、ページコンポーネントを使ったルートの例は次のようになります。
routes = [
// ...
{
path: '/some-page/',
// コンポーネント
component: (props, { $h, $f7, $on }) => {
const title = 'Component Page';
const names = ['John', 'Vladimir', 'Timo'];
const openAlert = () => {
$f7.dialog.alert('Hello world!');
}
$on('pageInit', (e, page) => {
// ページ開始時に何かをする
});
$on('pageAfterOut', (e, page) => {
// ページがビューから離れた
});
return () => $h`
<div class="page">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="title">${title}</div>
</div>
</div>
<div class="page-content">
<a @click=${openAlert} class="red-link">Open Alert</a>
<div class="list simple-list">
<ul>
${names.map((name) => $h`
<li>${name}</li>
`)}
</ul>
</div>
</div>
</div>
`;
},
},
// ...
]
コンポーネントのページイベント
コンポーネントのページイベントハンドラは、$on
コンポーネントイベントハンドラで渡すことができます。これらは通常のDOMイベントであるページイベントです。これらはDOMイベントなので、第一引数に event
を、第二引数に ページデータ を受け取ります。通常のDOMイベントとの唯一の違いは、イベントハンドラ名がキャメルケース形式で指定されなければならないことです(page:init
-> pageInit
)。
const MyComponent = (props, { $on }) => {
$on('pageMounted', (e, page) => {
console.log('page mounted');
});
$on('pageInit', (e, page) => {
console.log('page init');
});
$on('pageBeforeIn', (e, page) => {
console.log('page before in');
});
$on('pageAfterIn', (e, page) => {
console.log('page after in');
});
$on('pageBeforeOut', (e, page) => {
console.log('page before out');
});
$on('pageAfterOut', (e, page) => {
console.log('page after out');
});
$on('pageBeforeUnmount', (e, page) => {
console.log('page before unmount');
});
$on('pageBeforeRemove', (e, page) => {
console.log('page before remove');
});
}
DOM イベントの処理
コンポーネントのテンプレートには、追加の @
属性があることに注意してください。これは、指定された要素にイベントリスナーを割り当てるための、省略可能な方法です。指定されたイベントハンドラは、コンポーネントのスコープ内で検索されます。
このイベントハンドラ属性の値は関数でなければなりません。
const MyComponent = (props, { $h, $update }) => {
let value = 10;
const addValue = (number) => {
value += number;
$update();
}
const onClick = () => {
console.log('click');
}
return () => $h`
<div class="page">
<!-- アトリビュートに関数を渡す -->
<button @click=${onClick}>Button</button>
<!-- も動作します。 -->
<button @click=${() => onClick()}>Button</button>
<!-- 属性値 "onClick "が単なる文字列の場合は動作しません。 -->
<button @click="onClick">Button</button>
<!-- 動的なデータを渡すと期待通りに動作します。 -->
<button @click=${() => addValue(15)}>Button</button>
</div>
`
}
イベントハンドラは、最初のレンダリング時、またはVDOMでパッチされた要素に対してのみ処理されます。そのような要素を手動でDOMに追加しても動作しません!。
const MyComponent = (props, { $h, $on }) => {
const onClick = () => {
console.log('click');
}
$on('pageInit', (e, page) => {
// これは動作しません
page.$el.append('<a @click="onClick">Link</a>');
});
return () => $h`
<div class="page">
</div>
`
}
コンポーネントのルート要素
コンポーネントのテンプレートやレンダリング関数は、1つのHTML要素のみを返す必要があります。そしてそれは、ルーターでサポートされている要素でなければなりません。
ルーターコンポーネントとしてページを読み込む場合、ルーターコンポーネントはPage要素を返さなければなりません。
<template> <div class="page"> ... </div> </template>
モーダル(Routable Modals)をルーターコンポーネントとして読み込む場合、ルーターコンポーネントはそのモーダル要素を返さなければなりません。
<template> <div class="popup"> ... </div> </template>
パネル(Routable Panels)をルーターコンポーネントとしてロードした場合、ルーターコンポーネントはPanel要素を返さなければなりません。
<template> <div class="panel panel-left panel-cover"> ... </div> </template>
タブコンテンツ(Routable Tabs)をルーターコンポーネントとして読み込んだ場合、ルーターコンポーネントは、ルーティング可能なタブの内側に挿入されるタブの子要素を返さなければなりません。
<template> <div class="some-element"> ... </div> </template>
シングルファイルコンポーネント
すべてのコンポーネントのルートを同じルート配列で指定するのは、特にルートがたくさんある場合には、あまり快適ではありません。そこで、componentUrl
を使用して、コンポーネントを1つのファイルにまとめることができます。
routes = [
...
{
path: '/some-page/',
componentUrl: './some-page.f7',
},
..
];
そして、some-page.f7
に入れます。
<!-- コンポーネントテンプレートでは、同じタグ付きテンプレートリテラルを使用しています。 -->
<template>
<div class="page">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="title">${title}</div>
</div>
</div>
<div class="page-content">
<a @click=${openAlert}>Open Alert</a>
<div class="list simple-list">
<ul>
${names.map((name) => $h`
<li>${name}</li>
`)}
</ul>
</div>
</div>
</div>
</template>
<!-- コンポーネントのスタイル -->
<style>
.red-link {
color: red;
}
</style>
<!-- コンポーネントロジックの残りの部分 -->
<script>
// スクリプトはコンポーネント関数を返す/エクスポートしなければならない
export default (props, { $f7, $on }) => {
const title = 'Component Page';
const names = ['John', 'Vladimir', 'Timo'];
const openAlert = () => {
$f7.dialog.alert('Hello world!');
}
$on('pageInit', () => {
// ページの初期化で何かをする
});
$on('pageAfterOut', () => {
// ページがビューから離れた
});
// コンポーネント関数はレンダリング関数を返さなければならない
return $render;
}
</script>
さて、これでだいぶすっきりしましたね。と