Vueの双方向結合原理と用法の解明
本論文の実例はVueの双方向結合原理と使い方を述べている。皆さんに参考にしてあげます。具体的には以下の通りです。
Vueで何を入力したいのかというと、自然に
Vueの一方通行のデータストリーム
Vueの一方向データストリームはReactと同様に、親コンポーネントは、サブアセンブリの属性(Props)を設定することによって、サブアセンブリにデータを転送することができ、親コンポーネントは、サブアセンブリのデータを取得したいので、サブアセンブリにイベントを登録し、サブアセンブリが嬉しいときに、このイベントをトリガしてデータを転送する。一言で言えば、Propsは下にデータを送り、イベントは上にデータを伝える。
上記の例では、は、 を使用する。バインディング )に接続されている。このデフォルトのイベントハンドラ関数は、イベントオブジェクトによって持ち込まれた値に基づいてバインディングされたデータを修正する(例: 。
カスタムコンポーネントのv-model
Vueはオリジナルのコンポーネントをカプセル化していますので、
Js FiddleのVueサンプル
Js FilddleのLogoをクリックして、上のポップアップパネルの中からVueサンプルを選択すればいいです。
サンプルコードにはHTMLとVue(js)の二つの部分が含まれています。コードは以下の通りです。
Js FiddleのVueテンプレートはデフォルトで一つのTodoリストの展示を実現します。データは固定されています。すべての内容は一つのテンプレートで完成します。まず私たちがやるべきことは一つのTodoを一つのサブアセンブリに変えることです。Js Fiddleでは多文書の形式が書けないので、コンポーネントは
対応するアプリ部分のテンプレートとコードはかなり減量されました。
Todo Listにカウントを追加します。
この数量はタイトルの中でサブコンポーネント とする。親コンポーネント
イベントハンドラ関数は、一般的に
一般的な方法は、
両者の違いに注意して、前者はバインディングの処理関数(参照)であり、後者はバインディングの表現(呼び出し)である。
今はイベント方式によって、予想通りの効果がありました。
v-modelに変換
前に私達はサブコンポーネントは、 。サブコンポーネントは、 親コンポーネントの中で をバインドする。
前に述べたように、Vue 2.2.0は
Vue 2.3.0は
例えば、
上記の例では、
上記の説明により、Vueの双方向バインディングは、実際には通常の一方向バインディングとイベントの組み合わせで行われていることがわかったと思いますが、
展望
現在Vueの双方向バインディングは、イベントをトリガすることによってデータフィードバックを実現する必要があります。これは多くの期待されているものとはまだ差があります。この差を作った主な原因は二つあります。は、イベントを通じてデータをフィードバックする必要がある 属性は に値しません。
現在のVueバージョンでは、計算属性を定義することによって簡略化することができます。
もちろんフレームとしては、問題を解決する時に、他の特性への影響やフレームの拡張性などを考慮しなければならないので、最終的には双方向バインディングはどのように進展しますか?
興味のある友達はオンラインHTML/CSS/JavaScriptコードを使ってツールを実行できます。http://tools.jb51.net/code/HtmlJsRun上記コードの運行効果をテストします。
ここで述べたように、皆さんのvue.jsプログラムの設計に役に立ちます。
Vueで何を入力したいのかというと、自然に
<input v-model="xxx" />
を使って双方向結合を実現したいと思います。以下は一番簡単な例です。
<div id="app">
<h2>What's your name:</h2>
<input v-model="name" />
<div>Hello {{ name }}</div>
</div>
new Vue({
el: "#app",
data: {
name: ""
}
});
この例の入力ボックスに入力された内容は、後で表示されます。これはVue原生による<input>
への良好なサポートであり、親コンポーネントとサブアセンブリとの間の双方向データ転送の典型的な例でもある。しかし、v-model
はVue 2.2.0のみが加入する新しい機能であり、これまでは、Vueは一方向のデータストリームのみをサポートしていた。Vueの一方通行のデータストリーム
Vueの一方向データストリームはReactと同様に、親コンポーネントは、サブアセンブリの属性(Props)を設定することによって、サブアセンブリにデータを転送することができ、親コンポーネントは、サブアセンブリのデータを取得したいので、サブアセンブリにイベントを登録し、サブアセンブリが嬉しいときに、このイベントをトリガしてデータを転送する。一言で言えば、Propsは下にデータを送り、イベントは上にデータを伝える。
上記の例では、
v-model
を使用しないと、そうなるはずです。
<input :value="name" @input="name = $event.target.value" />
イベントの処理はインラインモードになっていますので、シナリオ部分は修正する必要がありません。しかし、多くの場合、イベントは一つの方法として定義されています。コードは複雑になります。
<input :value="name" @input="updateName" />
new Vue({
// ....
methods: {
updateName(e) {
this.name = e.target.value;
}
}
})
上記の例から見て、v-model
は多くのコードを節約しています。最も重要なのは一つのイベント処理関数を少なく定義できることです。したがって、v-model
実際に行われたイベントは以下の通りです。v-bind
(:
)を使用して、一方向バインディングの属性(例::value="name"
)input
イベント(@input
)は、デフォルト実装のイベントハンドラ関数(例:@input=updateName
this.name = e.target.value
)カスタムコンポーネントのv-model
Vueはオリジナルのコンポーネントをカプセル化していますので、
<input>
は入力時にinput
イベントをトリガします。しかし、カスタムコンポーネントはどうなりますか?ここではJs Fiddle VueサンプルのTodo Listの例を借りることができます。Js FiddleのVueサンプル
Js FilddleのLogoをクリックして、上のポップアップパネルの中からVueサンプルを選択すればいいです。
サンプルコードにはHTMLとVue(js)の二つの部分が含まれています。コードは以下の通りです。
<div id="app">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos">
<label>
<input type="checkbox"
v-on:change="toggle(todo)"
v-bind:checked="todo.done">
<del v-if="todo.done">
{{ todo.text }}
</del>
<span v-else>
{{ todo.text }}
</span>
</label>
</li>
</ol>
</div>
new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript", done: false },
{ text: "Learn Vue", done: false },
{ text: "Play around in JSFiddle", done: true },
{ text: "Build something awesome", done: true }
]
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})
Todoコンポーネントを定義Js FiddleのVueテンプレートはデフォルトで一つのTodoリストの展示を実現します。データは固定されています。すべての内容は一つのテンプレートで完成します。まず私たちがやるべきことは一つのTodoを一つのサブアセンブリに変えることです。Js Fiddleでは多文書の形式が書けないので、コンポーネントは
Vue.component()
を使ってシナリオの中で定義されています。主に<li>
の内容の中の部分を持ち出します。
Vue.component("todo", {
template: `
<label>
<input type="checkbox" @change="toggle" :checked="isDone">
<del v-if="isDone">
{{ text }}
</del>
<span v-else>
{{ text }}
</span>
</label>
`,
props: ["text", "done"],
data() {
return {
isDone: this.done
};
},
methods: {
toggle() {
this.isDone = !this.isDone;
}
}
});
アプリで定義されているtoggle()
の方法も少し変更され、コンポーネント内に定義されました。toggle()
が呼び出したときに、完了したかどうかを示すdone
の値が修正されます。しかし、done
はprops
に定義された属性であり、直接値を割り当てることができないので、公式推薦の第1の方法を採用して、データisDone
を定義してthis.done
に初期化し、コンポーネント内でisDone
を使用して、この状態が完了するかどうかを制御する。対応するアプリ部分のテンプレートとコードはかなり減量されました。
<div id="app">
<h2>Todos:</h2>
<ol>
<li v-for="todo in todos">
<todo :text="todo.text" :done="todo.done"></todo>
</li>
</ol>
</div>
new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript", done: false },
{ text: "Learn Vue", done: false },
{ text: "Play around in JSFiddle", done: true },
{ text: "Build something awesome", done: true }
]
}
});
しかし、ここまでは、データはまだ一方的です。効果的には、チェックボックスをクリックすると線の削除効果がフィードバックされますが、これらの動的変化はすべてtodo
コンポーネントの内部で行われ、データバインディングの問題がありません。Todo Listにカウントを追加します。
todo
コンポーネント内部の状態変化をTodo Listに表示させるために、Todo Listにカウントを追加し、完了したTodoの数を示します。この数はtodo
コンポーネントの内部状態(データ)の影響を受けているので、todo
内部データの変化をその親のコンポーネントに反映させる必要があり、これはv-model
の利用可能な場所である。この数量はタイトルの中で
n/m
の形で現れます。例えば、2/4
の表現は全部で4つのTodoです。もう2つ完成しました。これはTodo Listのテンプレートとコード部分を修正し、countDone
とcount
の2つの計算属性を追加する必要があります。
<div id="app">
<h2>Todos ({{ countDone }}/{{ count }}):</h2>
<!-- ... -->
</div>
new Vue({
// ...
computed: {
count() {
return this.todos.length;
},
countDone() {
return this.todos.filter(todo => todo.done).length;
}
}
});
現在はカウントが出ていますが、タスクの状態が変わってもこのカウントには影響がありません。私たちはサブコンポーネントの変動が親コンポーネントのデータに影響を与えます。v-model
は後でまた話します。一番よくある方法を使ってください。イベント:todo
はtoggle()
においてtoggle
イベントをトリガし、isDone
をイベントパラメータtoggle
イベント定義イベント処理関数
Vue.component("todo", {
//...
methods: {
toggle(e) {
this.isDone = !this.isDone;
this.$emit("toggle", this.isDone);
}
}
});
<!-- #app -->
<todo :text="todo.text" :done="todo.done" @toggle="todo.done = $event"></todo>
ここで@toggle
をバインドした表現です。ここでtodo
は一時変数であるので、methods
において特定のイベントハンドラ関数を定義すると、この一時変数を過去にバインドするのは難しい(もちろん、一般的な方法は呼び出しの形で実現できると定義される)。イベントハンドラ関数は、一般的に
onToggle(e)
を定義するなど、処理すべきことに直接に対応し、@toggle="onToggle"
にバインディングされる。この場合、パラメータとしてtodo
に入ることはできません。一般的な方法は、
toggle(todo, e)
として定義され、イベント定義において、関数として式を呼び出す形式で呼び出される。@toggle="toggle(todo, $event)"。
todo.done=$event`同属式。両者の違いに注意して、前者はバインディングの処理関数(参照)であり、後者はバインディングの表現(呼び出し)である。
今はイベント方式によって、予想通りの効果がありました。
v-modelに変換
前に私達は
v-model
で実現すると言いましたが、今改造してみます。v-model
のいくつかの要素を実現するように注意してください。value
属性(Prop)を介して入力を受け付けるinput
イベントをトリガすることによって出力され、配列パラメータv-model
で
Vue.component("todo", {
// ...
props: ["text", "value"], // <-- done value
data() {
return {
isDone: this.value // <-- this.done this.value
};
},
methods: {
toggle(e) {
this.isDone = !this.isDone;
this.$emit("input", this.isDone); // <--
}
}
});
<!-- #app -->
<todo :text="todo.text" v-model="todo.done"></todo>
.syncは他のデーターバインディングを実現します。前に述べたように、Vue 2.2.0は
v-model
の特性を導入します。いくつかの理由で、入力属性はvalue
ですが、出力イベントはinput
です。v-model
、value
、input
の3つの名称は字面の上からいささかの関係が見えません。これはちょっと変わったように見えますが、これはポイントではなくて、コントロールは一つの属性を双方向に結合するしかないですか?Vue 2.3.0は
.sync
の修飾語を導入して、双方向結合にするv-bind
を修飾する。これは同様にシンタックス飴であり、:
によって修正されたデータバインディングは、.sync
のように、バインディングされたデータを自動的に登録することができる。この方法は、サブアセンブリが特定のイベントをトリガするのと同じである。しかし、このイベントの名前は、どうやらバインディング属性名と少し関係があり、バインディング属性名の前にv-model
プレフィックスを追加する。例えば、
update:
は、サブアセンブリの<sub :some.sync="any" />
属性を親コンポーネントのsome
データと結合し、サブコンポーネントの中でany
を介して変更をトリガする必要がある。上記の例では、
$emit("update:some", value)
を使用したバインディングは常に違和感を感じています。v-model
の字面の意味は、双方向結合された数値であり、未完成のv-model
は、実際には値ではなく状態であることを表しています。したがって、私たちは再びそれを修正し、依然としてdone
という属性名を使用して、done
を通じて双方向結合を実現しています。
Vue.component("todo", {
// ...
props: ["text", "done"], // <-- done
data() {
return {
isDone: this.done // <-- done
};
},
methods: {
toggle(e) {
this.isDone = !this.isDone;
this.$emit("update:done", this.isDone); // <-- :update:done
}
}
});
<!-- #app -->
<!-- v-model :done.sync, -->
<todo :text="todo.text" :done.sync="todo.done"></todo>
公開Vue双方向バインディング上記の説明により、Vueの双方向バインディングは、実際には通常の一方向バインディングとイベントの組み合わせで行われていることがわかったと思いますが、
value
と.sync
でデフォルトの処理関数を登録してデータを更新しました。Vueソースの中にはこのような段があります。
// @file: src/compiler/parser/index.js
if (modifiers.sync) {
addHandler(
el,
`update:${camelize(name)}`,
genAssignmentCode(value, `$event`)
)
}
このコードからは、v-model
双方向バインディングの際に、コンパイラは.sync
のイベントハンドラを追加してデータを割り当てていることが分かります。展望
現在Vueの双方向バインディングは、イベントをトリガすることによってデータフィードバックを実現する必要があります。これは多くの期待されているものとはまだ差があります。この差を作った主な原因は二つあります。
現在のVueバージョンでは、計算属性を定義することによって簡略化することができます。
computed: {
isDone: {
get() {
return this.done;
},
set(value) {
this.$emit("update:done", value);
}
}
}
実を言うと、同じ名前の変数名を多く定義するのも大変です。Vueは、将来のバージョンにおいて、属性宣言のために.sync
オプションを追加するなど、一定の技術的手段によって、このプロセスを減少させることができることが望ましい。もちろんフレームとしては、問題を解決する時に、他の特性への影響やフレームの拡張性などを考慮しなければならないので、最終的には双方向バインディングはどのように進展しますか?
興味のある友達はオンラインHTML/CSS/JavaScriptコードを使ってツールを実行できます。http://tools.jb51.net/code/HtmlJsRun上記コードの運行効果をテストします。
ここで述べたように、皆さんのvue.jsプログラムの設計に役に立ちます。