Skip to content

docs #26 Reusability & Composition > Custom Directives の翻訳 #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 26, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 45 additions & 45 deletions src/guide/custom-directive.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Custom Directives
# カスタムディレクティブ

## Intro
## 基本

In addition to the default set of directives shipped in core (like `v-model` or `v-show`), Vue also allows you to register your own custom directives. Note that in Vue, the primary form of code reuse and abstraction is components - however, there may be cases where you need some low-level DOM access on plain elements, and this is where custom directives would still be useful. An example would be focusing on an input element, like this one:
Vue.js 本体で提供されているデフォルトのディレクティブ (`v-model` `v-show`) に加えて、独自のカスタムディレクティブ (custom directives) を登録することも可能です。Vue ではコードの再利用や抽象化の基本形はコンポーネントです。しかしながら、単純な要素への低レベルな DOM のアクセスが必要なケースがあるかもしれません。こういったケースにカスタムディレクティブが役に立つことでしょう。以下のような input 要素へのフォーカスが1つの例として挙げられます:

<p class="codepen" data-height="300" data-theme-id="39028" data-default-tab="result" data-user="Vue" data-slug-hash="JjdxaJW" data-editable="true" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Custom directives: basic example">
<span>See the Pen <a href="https://codepen.io/team/Vue/pen/JjdxaJW">
Expand All @@ -11,68 +11,68 @@ In addition to the default set of directives shipped in core (like `v-model` or
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

When the page loads, that element gains focus (note: `autofocus` doesn't work on mobile Safari). In fact, if you haven't clicked on anything else since visiting this page, the input above should be focused now. Also, you can click on the `Rerun` button and input will be focused.
ページを読み込むと、この要素にフォーカスが当たります (注意:`autofucus` はモバイルの Safari で動きません)。実際、このページに訪れてから他に何もクリックしなければ、上記の input 要素にフォーカスが当たります。また、`Rerun` ボタンをクリックしても、input 要素はフォーカスされます。

Now let's build the directive that accomplishes this:
ここからこれを実現するディレクティブを実装しましょう:

```js
const app = Vue.createApp({})
// Register a global custom directive called `v-focus`
// `v-focus` と呼ばれるグローバルカスタムディレクティブを登録します
app.directive('focus', {
// When the bound element is mounted into the DOM...
// 束縛されている要素が DOM にマウントされると...
mounted(el) {
// Focus the element
// その要素にフォーカスを当てる
el.focus()
}
})
```

If you want to register a directive locally instead, components also accept a `directives` option:
ディレクティブを代わりにローカルに登録したい場合、コンポーネントの `directives` オプションで登録できます:

```js
directives: {
focus: {
// directive definition
// ディレクティブの定義
mounted(el) {
el.focus()
}
}
}
```

Then in a template, you can use the new `v-focus` attribute on any element, like this:
そしてテンプレートでは、新規登録した `v-focus` 属性をどの要素に対しても以下のように利用できます:

```html
<input v-focus />
```

## Hook Functions
## フック関数

A directive definition object can provide several hook functions (all optional):
ディレクティブの定義オブジェクトは、いくつかのフック関数を提供しています (全てオプション):

- `beforeMount`: called when the directive is first bound to the element and before parent component is mounted. This is where you can do one-time setup work.
- `beforeMount`: ディレクティブが初めて要素に束縛された時、そして親コンポーネントがマウントされる前に呼ばれます。ここは1度だけ実行するセットアップ処理を行える場所です。

- `mounted`: called when the bound element's parent component is mounted.
- `mounted`: 束縛された要素の親コンポーネントがマウントされた時に呼ばれます。

- `beforeUpdate`: called before the containing component's VNode is updated
- `beforeUpdate`: 束縛された要素を含むコンポーネントの VNode が更新される前に呼ばれます。

:::tip Note
We'll cover VNodes in more detail [later](render-function.html#the-virtual-dom-tree), when we discuss render functions.
VNodes は[後で](render-function.html#the-virtual-dom-tree)詳細に扱います。描画関数を説明する時です。
:::

- `updated`: called after the containing component's VNode **and the VNodes of its children** have updated.
- `updated`: 束縛された要素を含むコンポーネントの VNode **とその子コンポーネントの VNode** が更新された後に呼ばれます。

- `beforeUnmount`: called before the bound element's parent component is unmounted
- `beforeUnmount`: 束縛された要素の親コンポーネントがアンマウントされる前に呼ばれます。

- `unmounted`: called only once, when the directive is unbound from the element and the parent component is unmounted.
- `unmounted`: ディレクティブが要素から束縛を解かれた時、また親コンポーネントがアンマウントされた時に1度だけ呼ばれます。

You can check the arguments passed into these hooks (i.e. `el`, `binding`, `vnode`, and `prevVnode`) in [Custom Directive API](../api/application-api.html#directive)
これらのフック関数に渡される引数 (すなわち、`el`, `binding`, `vnode`, `prevVnode`) は、[カスタムディレクティブ API](../api/application-api.html#directive) にて確認できます。

### Dynamic Directive Arguments
### 動的なディレクティブ引数

Directive arguments can be dynamic. For example, in `v-mydirective:[argument]="value"`, the `argument` can be updated based on data properties in our component instance! This makes our custom directives flexible for use throughout our application.
ディレクティブの引数は動的にできます。例えば、`v-mydirective:[argument]="value"` において、`argument` はコンポーネントインスタンスの data プロパティに基づいて更新されます! これにより、私たちのアプリケーション全体を通した利用に対して、カスタムディレクティブは柔軟になります。

Let's say you want to make a custom directive that allows you to pin elements to your page using fixed positioning. We could create a custom directive where the value updates the vertical positioning in pixels, like this:
ページの固定位置に要素をピン留めするカスタムディレクティブを考えてみましょう。引数の値が縦方向のピクセル位置を更新するカスタムディレクティブを以下のように作成することができます:

```vue-html
<div id="dynamic-arguments-example" class="demo">
Expand All @@ -87,15 +87,15 @@ const app = Vue.createApp({})
app.directive('pin', {
mounted(el, binding) {
el.style.position = 'fixed'
// binding.value is the value we pass to directive - in this case, it's 200
// binding.value はディレクティブに渡した値です - このケースの場合、200 です
el.style.top = binding.value + 'px'
}
})

app.mount('#dynamic-arguments-example')
```

This would pin the element 200px from the top of the page. But what happens if we run into a scenario when we need to pin the element from the left, instead of the top? Here's where a dynamic argument that can be updated per component instance comes in very handy:
これにより、ページの上端から 200px の位置に要素を固定できます。しかし、上端からではなく左端から要素をピン留めする必要があるシナリオが出てきたらどうでしょうか?ここでコンポーネントインスタンスごとに更新できる動的引数がとても便利です:

```vue-html
<div id="dynamicexample">
Expand All @@ -116,7 +116,7 @@ const app = Vue.createApp({
app.directive('pin', {
mounted(el, binding) {
el.style.position = 'fixed'
// binding.arg is an argument we pass to directive
// binding.arg がディレクティブに渡した引数です
const s = binding.arg || 'top'
el.style[s] = binding.value + 'px'
}
Expand All @@ -125,7 +125,7 @@ app.directive('pin', {
app.mount('#dynamic-arguments-example')
```

Result:
結果:

<p class="codepen" data-height="300" data-theme-id="39028" data-default-tab="result" data-user="Vue" data-slug-hash="YzXgGmv" data-editable="true" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Custom directives: dynamic arguments">
<span>See the Pen <a href="https://codepen.io/team/Vue/pen/YzXgGmv">
Expand All @@ -134,7 +134,7 @@ Result:
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

Our custom directive is now flexible enough to support a few different use cases. To make it even more dynamic, we can also allow to modify a bound value. Let's create an additional property `pinPadding` and bind it to the `<input type="range">`
このカスタムディレクティブは、いくつかの違うユースケースをサポートできるほど柔軟になりました。さらに動的にするには、束縛した値を修正できるようにすれば良いでしょう。`pinPadding` という追加のプロパティを作成して、`<input type="range">` に束縛してみましょう。

```vue-html{4}
<div id="dynamicexample">
Expand All @@ -155,7 +155,7 @@ const app = Vue.createApp({
})
```

Now let's extend our directive logic to recalculate the distance to pin on component update:
さらにコンポーネントの更新に従ってピンとの距離を再計算できるようにディレクティブのロジックを拡張しましょう:

```js{7-10}
app.directive('pin', {
Expand All @@ -171,7 +171,7 @@ app.directive('pin', {
})
```

Result:
結果:

<p class="codepen" data-height="300" data-theme-id="39028" data-default-tab="result" data-user="Vue" data-slug-hash="rNOaZpj" data-editable="true" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Custom directives: dynamic arguments + dynamic binding">
<span>See the Pen <a href="https://codepen.io/team/Vue/pen/rNOaZpj">
Expand All @@ -180,9 +180,9 @@ Result:
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## Function Shorthand
## 関数による省略記法

In previous example, you may want the same behavior on `mounted` and `updated`, but don't care about the other hooks. You can do it by passing the callback to directive:
前回の例では、`mounted` `updated` に同じ振る舞いを欲しかったでしょう。しかし、その他のフック関数を気にしてはいけません。ディレクティブにコールバックを渡すことで実現できます:

```js
app.directive('pin', (el, binding) => {
Expand All @@ -192,9 +192,9 @@ app.directive('pin', (el, binding) => {
})
```

## Object Literals
## オブジェクトリテラル

If your directive needs multiple values, you can also pass in a JavaScript object literal. Remember, directives can take any valid JavaScript expression.
ディレクティブに複数の値が必要な場合、JavaScript のオブジェクトリテラルを渡すこともできます。覚えておいてください、ディレクティブはあらゆる妥当な JavaScript 式を取ることができます。

```vue-html
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Expand All @@ -207,42 +207,42 @@ app.directive('demo', (el, binding) => {
})
```

## Usage on Components
## コンポーネントにおける使用法

In 3.0, with fragments support, components can potentially have more than one root nodes. This creates an issue when a custom directive is used on a component with multiple root nodes.
3.0 ではフラグメントがサポートされているため、コンポーネントは潜在的に1つ以上のルートノードを持つことができます。これは複数のルートノードを持つ1つのコンポーネントにカスタムディレクティブが使用された時に、問題を引き起こします。

To explain the details of how custom directives will work on components in 3.0, we need to first understand how custom directives are compiled in 3.0. For a directive like this:
3.0 のコンポーネント上でどのようにカスタムディレクティブが動作するかを詳細に説明するために、3.0 においてカスタムディレクティブがどのようにコンパイルされるのかをまずは理解する必要があります。以下のようなディレクティブは:

```vue-html
<div v-demo="test"></div>
```

Will roughly compile into this:
おおよそ以下のようにコンパイルされます:

```js
const vDemo = resolveDirective('demo')

return withDirectives(h('div'), [[vDemo, test]])
```

Where `vDemo` will be the directive object written by the user, which contains hooks like `mounted` and `updated`.
ここで `vDemo` はユーザによって記述されたディレクティブオブジェクトで、それは `mounted` `updated` のフック関数を含みます。

`withDirectives` returns a cloned VNode with the user hooks wrapped and injected as VNode lifecycle hooks (see [Render Function](render-function.html) for more details):
`withDirectives` は複製した VNode を返します。複製された VNode VNode のライフサイクルフック (詳細は[描画関数](render-function.html)を参照) としてラップ、注入されたユーザのフック関数を持ちます:

```js
{
onVnodeMounted(vnode) {
// call vDemo.mounted(...)
// vDemo.mounted(...) を呼びます
}
}
```

**As a result, custom directives are fully included as part of a VNode's data. When a custom directive is used on a component, these `onVnodeXXX` hooks are passed down to the component as extraneous props and end up in `this.$attrs`.**
**結果として、VNode のデータの一部としてカスタムディレクティブは全て含まれます。カスタムディレクティブがコンポーネントで利用される場合、これらの `onVnodeXXX` フック関数は無関係な props としてコンポーネントに渡され、最終的に `this.$attrs` になります。**

This also means it's possible to directly hook into an element's lifecycle like this in the template, which can be handy when a custom directive is too involved:
これは以下のようなテンプレートのように、要素のライフサイクルに直接フックできることを意味しています。これはカスタムディレクティブが複雑すぎる場合に便利です:

```vue-html
<div @vnodeMounted="myHook" />
```

This is consistent with the [attribute fallthrough behavior](component-attrs.html). So, the rule for custom directives on a component will be the same as other extraneous attributes: it is up to the child component to decide where and whether to apply it. When the child component uses `v-bind="$attrs"` on an inner element, it will apply any custom directives used on it as well.
これは [属性のフォールスロー](component-attrs.html) と一貫性があります。つまり、コンポーネントにおけるカスタムディレクティブのルールは、その他の異質な属性と同じです: それをどこにまた適用するかどうかを決めるのは、子コンポーネント次第です。子コンポーネントが内部の要素に `v-bind="$attrs"` を利用している場合、あらゆるカスタムディレクティブもその要素に適用されます。