ホームページ >ウェブフロントエンド >jsチュートリアル >Vue.js コンポーネントの使用法と開発例のチュートリアル
コンポーネント
コンポーネントは、HTML 要素を拡張し、再利用可能なコードをカプセル化できます。高レベルでは、コンポーネントは、vue.js のコンパイラーによって特別な機能を追加することもできます。 is 属性で拡張されたネイティブ HTML 要素。
Vue.js コンポーネントは、事前定義された動作を持つ ViewModel クラスとして理解できます。コンポーネントは多くのオプションを事前定義できますが、主なものは次のとおりです:
テンプレート (テンプレート): テンプレートは、データと最終的にユーザーに表示される DOM の間のマッピング関係を宣言します。
初期データ (data): コンポーネントの初期データ状態。再利用可能なコンポーネントの場合、これは通常プライベート状態です。
受け入れられる外部パラメータ (小道具): データはパラメータを通じてコンポーネント間で転送および共有されます。パラメータはデフォルトで一方向 (上から下) にバインドされますが、明示的に双方向として宣言することもできます。
メソッド: データへの変更は通常、コンポーネントのメソッド内で実行されます。ユーザー入力イベントとコンポーネント メソッドは、v-on ディレクティブを通じてバインドできます。
ライフサイクルフック: コンポーネントは、作成、アタッチ、破棄などの複数のライフサイクルフック関数をトリガーします。これらのフック関数では、いくつかのカスタム ロジックをカプセル化できます。従来の MVC と比較すると、Controller のロジックがこれらのフック関数に分散されていることがわかります。
プライベートリソース (アセット): Vue.js では、ユーザー定義の命令、フィルター、コンポーネントなどを総称してリソースと呼びます。グローバルに登録されたリソースは名前の競合を引き起こしやすいため、コンポーネントは独自のプライベート リソースを宣言できます。プライベート リソースは、コンポーネントとそのサブコンポーネントによってのみ呼び出すことができます。
さらに、同じコンポーネント ツリー内のコンポーネントは、組み込みのイベント API を通じて通信することもできます。 Vue.js は、コンポーネントの定義、再利用、ネストのための完全な API を提供し、開発者がコンポーネントを使用してビルディング ブロックのようにアプリケーション インターフェイス全体を構築できるようにします。
コンポーネントは、コードの効率、保守性、再利用性を大幅に向上させます。
コンポーネントを使用する
登録
1. コンポーネント コンストラクターを作成します:
var MyComponent = Vue.extend({ //选项 })
2. コンストラクターをコンポーネントとして使用し、Vue.component(tag,constructor) に登録します:
Vue.component('my-component',MyComponent)
3. 親インスタンスのモジュールでカスタム要素 b98f2d1b8b5d79f8c1b053de334aa7b5 として使用します:
<div id = "example"> <my-component></my-component> </div>
例:
<div id="example"> <my-component></my-component> </div> // 定义 var MyComponent = Vue.extend({ template: '<div>A custom component!</div>' }) // 注册 Vue.component('my-component', MyComponent) // 创建根实例 new Vue({ el: '#example' })
レンダリング:
<div id = "example"> <div>A custom component!</div> </div>
コンポーネントテンプレートは、マウント ポイントとしてのみ機能するカスタム要素を置き換えます。インスタンス オプション replace を使用して、置換するかどうかを決定できます。
部分登録
各コンポーネントをグローバルに登録する必要はありません:
var Child = Vue.extend({ /* ... */ }) var Parent = Vue.extend({ template: '...', components: { // <my-component> 只能用在父组件模板内 'my-component': Child } })
この種のカプセル化は他のリソースにも適しています。 、命令、フィルター、トランジションなど。
登録構文シュガー
// 在一个步骤中扩展与注册 Vue.component('my-component', { template: '<div>A custom component!</div>' }) // 局部注册也可以这么做 var Parent = Vue.extend({ components: { 'my-component': { template: '<div>A custom component!</div>' } } })
コンポーネントオプションの問題
単にオブジェクトを使用する場合、Vue コンストラクターに渡されるオプションのほとんどは、data と el に加えて Vue.extend() でも使用できます。データ オプションとして Vue.extend() に渡されると、すべてのインスタンスが同じデータ オブジェクトを共有するため、データ オプションとして関数を使用し、この関数が新しいオブジェクトを返すようにする必要があります:
var MyComponent = Vue.extend({ data: function () { return { a: 1 } } })
テンプレート解析
Vue テンプレートはブラウザーのネイティブ パーサーを使用する DOM テンプレートであるため、有効な HTML フラグメントである必要があります。一部の HTML 要素には、その中に配置できる要素に制限があります。
a には他のインタラクティブな要素を含めることはできません。 (ボタン、リンクなど)
ul と ol には li のみを直接含めることができます
select には option と optgroup のみを含めることができます
table には thead、tbody、tfoot、tr、caption、col、colgroup のみを直接含めることができます
tr は可能ですth と td のみを直接含めます
実際には、これらの制限により予期しない結果が生じる可能性があります。単純な場合には機能する可能性がありますが、ブラウザーがカスタム コンポーネントを検証するまでは、カスタム コンポーネントの展開の結果に依存することはできません。たとえば、
750d7c37f87c44b67b1e945084b6bc455a07473c87748fb1bf73f23d45547ab8...4afa15d3069109ac30911f04c56f3338c3b6035d40e49dd3cf5dfe627a1d2a00 は、my-select コンポーネントが最終的に 221f08282418e2996498697df914ce4e に展開される場合でも、有効なテンプレートではありません。 ..選択>。
もう 1 つの結果は、カスタム タグ (8c05085041e56efcb85463966dd1cb7e、d477f9ce7bf77f53fbcf36bec1b69b7a、ec872302d9f7ec49547f9998f4be2186 などのカスタム要素および特殊タグを含む) を、内部制限のある ul、select、table などでは使用できないことです。ラベル内の要素。これらの要素内に配置されたカスタム タグは要素の外側に持ち上げられ、正しくレンダリングされません。
カスタム要素の場合は、is 属性を使用する必要があります:
f5d188ed2c074f8b944552db028f98a1
<tr is="my-component"></tr> </table> //<template> 不能用在 <table> 内,这时应使用 <tbody>,<table> 可以有多个 <tbody> <table> <tbody v-for="item in items"> <tr>Even row</tr> <tr>Odd row</tr> </tbody> </table>
Props
データを渡すには props を使用します
コンポーネント インスタンスのスコープは分離されており、props を使用できます子コンポーネントの場合、props は親コンポーネントから渡されることが期待されるコンポーネント データのフィールドです。子コンポーネントは props オプション:
Vue.component('child', { // 声明 props props: ['msg'], // prop 可以用在模板内 // 可以用 `this.msg` 设置 template: '<span>{{ msg }}</span>' })
を使用して明示的に宣言する必要があります。通常の文字列を渡します:
<child msg="hello!"></child>
Dynamic props
用v-bind绑定动态props到父组件的数据,每当父组件的数据变化时,也会传导给子组件:
<div> <input v-model="parentMsg"> <child v-bind:my-message="parentMsg"></child> //<child :my-message="parentMsg"></child> </div>
props绑定类型
prop默认是单向绑定,当父组件的属性变化时,将传导给子组件,但是反过来不会,这是为了防止子组件无意修改了父组件的状态,可以使用.sync或.once绑定修饰符显式地强制双向或单次绑定:
<!-- 默认为单向绑定 --> <child :msg="parentMsg"></child> <!-- 双向绑定 --> <child :msg.sync="parentMsg"></child> <!-- 单次绑定 --> <child :msg.once="parentMsg"></child>
如果 prop 是一个对象或数组,是按引用传递。在子组件内修改它会影响父组件的状态,不管是使用哪种绑定类型。
父子组件通信
父链
子组件可以用this.$parent访问它的父组件,根实例的后代可以用this.$root访问它,父组件有一个数组this.$children,包含它所有的子元素
自定义事件
Vue实例实现了一个自定义事件接口,用于在组件树中通信,这个事件系统独立于原生DOM事件,用法也不同,每一个Vue实例都是一个事件触发器:
使用 $on() 监听事件;
使用 $emit() 在它上面触发事件;
使用 $dispatch() 派发事件,事件沿着父链冒泡;
使用 $broadcast() 广播事件,事件向下传导给所有的后代。
不同于 DOM 事件,Vue 事件在冒泡过程中第一次触发回调之后自动停止冒泡,除非回调明确返回 true。
<!-- 子组件模板 --> <template id="child-template"> <input v-model="msg"> <button v-on:click="notify">Dispatch Event</button> </template> <!-- 父组件模板 --> <div id="events-example"> <p>Messages: {{ messages | json }}</p> <child></child> </div> // 注册子组件 // 将当前消息派发出去 Vue.component('child', { template: '#child-template', data: function () { return { msg: 'hello' } }, methods: { notify: function () { if (this.msg.trim()) { this.$dispatch('child-msg', this.msg) this.msg = '' } } } }) // 初始化父组件 // 将收到消息时将事件推入一个数组 var parent = new Vue({ el: '#events-example', data: { messages: [] }, // 在创建实例时 `events` 选项简单地调用 `$on` events: { 'child-msg': function (msg) { // 事件回调内的 `this` 自动绑定到注册它的实例上 this.messages.push(msg) } } })
效果:
使用v-on绑定自定义事件
在模板中子组件用到的地方声明事件处理器,为此子组件可以用v-on监听自定义事件:
4084e2349312ebcd04e4de37381def6c7d4dd9c7239aac360e401efe89cbb393
当子组件触发了 "child-msg" 事件,父组件的 handleIt 方法将被调用。所有影响父组件状态的代码放到父组件的 handleIt 方法中;子组件只关注触发事件。
子组件索引
使用v-ref为子组件指定一个索引ID,可以直接访问子组件
<div id="parent"> <user-profile v-ref:profile></user-profile> </div> var parent = new Vue({ el: '#parent' }) // 访问子组件 var child = parent.$refs.profile
使用Slot分发内容
内容分发:混合父组件的内容与子组件自己的模板的方式,使用特殊的58cb293b8600657fad49ec2c8d37b472元素作为原始内容的插槽。
编译作用域
父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。
绑定子组件内的指令到一个组件的根节点:
Vue.component('child-component', { // 有效,因为是在正确的作用域内 template: '<div v-show="someChildProperty">Child</div>', data: function () { return { someChildProperty: true } } })
类似地,分发内容是在父组件作用域内编译。
单个slot
父组件的内容将被抛弃,除非子组件模板包含58cb293b8600657fad49ec2c8d37b472,如果子组件模板只有一个没有特性的slot,父组件的整个内容将插到slot所在的地方并替换它。
58cb293b8600657fad49ec2c8d37b472 标签的内容视为回退内容。回退内容在子组件的作用域内编译,当宿主元素为空并且没有内容供插入时显示这个回退内容。
假定 my-component 组件有下面模板:
<div> <h1>This is my component!</h1> <slot>
如果没有分发内容则显示我。
</slot> </div>
父组件模板:
<my-component> <p>This is some original content</p> <p>This is some more original content</p> </my-component>
渲染结果:
<div> <h1>This is my component!</h1> <p>This is some original content</p> <p>This is some more original content</p> </div>
具名slot
58cb293b8600657fad49ec2c8d37b472元素可以用一个特殊特性name配置如何分发内容,多个slot可以有不同的名字,具名slot将匹配内容片段中有对应slot特性的元素。
仍然可以有一个匿名 slot,它是默认 slot,作为找不到匹配的内容片段的回退插槽。如果没有默认的 slot,这些找不到匹配的内容片段将被抛弃。
动态组件
多个组件可以使用同一个挂载点,然后动态地在它们之间切换,使用保留的8c05085041e56efcb85463966dd1cb7e元素,动态地绑定到它的is特性:
new Vue({ el: 'body', data: { currentView: 'home' }, components: { home: { /* ... */ }, posts: { /* ... */ }, archive: { /* ... */ } } }) <component :is="currentView"> <!-- 组件在 vm.currentview 变化时改变 --> </component> keep-alive
把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。
39a981128a40da37853cce84bffb2ba2
b2b0822175891cddec63f9cdd3f18ba9
2724ec0ed5bf474563ac7616c8d7a3cd
activate钩子
控制组件切换时长,activate 钩子只作用于动态组件切换或静态组件初始化渲染的过程中,不作用于使用实例方法手工插入的过程中。
Vue.component('activate-example', { activate: function (done) { var self = this loadDataAsync(function (data) { self.someData = data done() }) } })
transition-mode
transition-mode 特性用于指定两个动态组件之间如何过渡。
在默认情况下,进入与离开平滑地过渡。这个特性可以指定另外两种模式:
in-out:新组件先过渡进入,等它的过渡完成之后当前组件过渡出去。
out-in:当前组件先过渡出去,等它的过渡完成之后新组件过渡进入。
示例:
<!-- 先淡出再淡入 --> <component :is="view" transition="fade" transition-mode="out-in"> </component> .fade-transition { transition: opacity .3s ease; } .fade-enter, .fade-leave { opacity: 0; }
Vue.js 组件 API 来自三部分——prop,事件和 slot:
prop 允许外部环境传递数据给组件;
事件 允许组件触发外部环境的 action;
スロットを使用すると、外部環境がコンポーネントのビュー構造にコンテンツを挿入できるようになります。