ホームページ  >  記事  >  ウェブフロントエンド  >  Vue.js で毎日学ぶ必要があるコンポーネント間の通信

Vue.js で毎日学ぶ必要があるコンポーネント間の通信

高洛峰
高洛峰オリジナル
2017-01-03 17:26:191197ブラウズ

コンポーネントとは何ですか?

コンポーネントは、Vue.js の最も強力な機能の 1 つです。コンポーネントは HTML 要素を拡張し、再利用可能なコードをカプセル化できます。大まかに言うと、コンポーネントは、Vue.js のコンパイラーが特別な機能を追加するカスタム要素です。場合によっては、コンポーネントは、 is 属性で拡張されたネイティブ HTML 要素の形式を取ることもできます。

コンポーネントを使用する

登録

前に述べたように、Vue.extend() を使用してコンポーネント コンストラクターを作成できます:

var MyComponent = Vue.extend({
 // 选项...
})

このコンストラクターをコンポーネントとして使用するには、 `Vue.component を使用する必要があります。 (tag , コンストラクター)` **登録**:

// 全局注册组件,tag 为 my-component
Vue.component('my-component', MyComponent)

a619d07b01ad263fab71d64125f6401dカスタム タグ名の場合、Vue.js は W3C ルール (小文字でダッシュを含む) を強制しません )ただし、このルールに従う方が良いでしょう。

コンポーネントが登録されると、親インスタンスのモジュールでカスタム要素 b98f2d1b8b5d79f8c1b053de334aa7b5 として使用できます。ルート インスタンスを初期化する前に必ずコンポーネントを登録してください:

<div id="example">
 <my-component></my-component>
</div>
 
// 定义
var MyComponent = Vue.extend({
 template: &#39;<div>A custom component!</div>&#39;
})
 
// 注册
Vue.component(&#39;my-component&#39;, MyComponent)
 
// 创建根实例
new Vue({
 el: &#39;#example&#39;
})

次のようにレンダリングされます:

<div id="example">
 <div>A custom component!</div>
</div>

コンポーネントのテンプレートは、マウント ポイントとしてのみ機能するカスタム要素を置き換えることに注意してください。インスタンス オプション replace を使用して、置換するかどうかを決定できます。

ローカル登録

各コンポーネントをグローバルに登録する必要はありません。コンポーネントをインスタンス オプション コンポーネントに登録することで、他のコンポーネント内でのみ使用できるようにすることができます:

var Child = Vue.extend({ /* ... */ })
 
var Parent = Vue.extend({
 template: &#39;...&#39;,
 components: {
 // <my-component> 只能用在父组件模板内
 &#39;my-component&#39;: Child
 }
})

このカプセル化は、ディレクティブ、フィルター、トランジションなどの他のリソースにも適用されます。

糖衣登録構文

イベントを簡単にするために、コンストラクターの代わりにオプション オブジェクトを Vue.component() とコンポーネント オプションに直接渡すことができます。 Vue.js は自動的に舞台裏で Vue.extend() を呼び出します:

// 在一个步骤中扩展与注册
Vue.component(&#39;my-component&#39;, {
 template: &#39;<div>A custom component!</div>&#39;
})
 
// 局部注册也可以这么做
var Parent = Vue.extend({
 components: {
 &#39;my-component&#39;: {
  template: &#39;<div>A custom component!</div>&#39;
 }
 }
})

コンポーネント オプションの問題

Vue コンストラクターに渡されるほとんどのオプションは Vue.extend() でも使用できますが、2 つの特殊なケースがあります。 : データとエル。単にオブジェクトを data オプションとして Vue.extend() に渡した場合を想像してください。

var data = { a: 1 }
var MyComponent = Vue.extend({
 data: data
})

これの問題は、`MyComponent` のすべてのインスタンスが同じ `data` オブジェクトを共有することです。これは基本的に私たちが望んでいることではないので、`data` オプションとして関数を使用し、この関数が新しいオブジェクトを返すようにする必要があります:

var MyComponent = Vue.extend({
 data: function () {
 return { a: 1 }
 }
})

同様に、`el` オプションは `Vue.extend で使用されます。 () ` も関数でなければなりません。

テンプレート解析

Vue のテンプレートは DOM テンプレートであり、自分で実装するのではなく、ブラウザーのネイティブ パーサーを使用します。 DOM テンプレートには文字列テンプレートに比べていくつかの利点がありますが、有効な HTML フラグメントである必要があるという問題もあります。一部の HTML 要素には、その中に配置できる要素に制限があります。一般的な制限事項:
•a には他のインタラクティブな要素 (ボタン、リンクなど) を含めることはできません
•ul と ol には li のみを直接含めることができます
•select には option と optgroup のみを含めることができます
•table には thead、tbody、tfoot 、 tr、caption、col、colgroup
•tr には th と td のみを直接含めることができます

実際には、これらの制限により予期しない結果が生じる可能性があります。単純な場合には機能する可能性がありますが、ブラウザーがカスタム コンポーネントを検証するまでは、カスタム コンポーネントの展開の結果に依存することはできません。たとえば、 は、たとえ my-select コンポーネントが最終的に c03eb2bef9520681d7d3c2e87e8a9a9d。

もう 1 つの結果は、カスタム タグ (8c05085041e56efcb85463966dd1cb7e、d477f9ce7bf77f53fbcf36bec1b69b7a、ec872302d9f7ec49547f9998f4be2186 などのカスタム要素および特殊タグを含む) を、内部制限のある ul、select、table などでは使用できないことです。ラベル内の要素。これらの要素内に配置されたカスタム タグは要素の外側に持ち上げられ、正しくレンダリングされません。

カスタム要素の場合、 is 属性を使用する必要があります:

<table>
 <tr is="my-component"></tr>
</table>

`` を `` 内で使用することはできません。この場合、`` を使用する必要があります。 `
` には複数の `` を含めることができます:

<table>
 <tbody v-for="item in items">
 <tr>Even row</tr>
 <tr>Odd row</tr>
 </tbody>
</table>

Props

Props を使用してデータを渡します

コンポーネント インスタンスのスコープは分離されています。これは、親コンポーネントのデータを子コンポーネントのテンプレート内で直接参照できないし、参照すべきではないことを意味します。 props を使用してデータを子コンポーネントに渡すことができます。

"prop" は、親コンポーネントから渡されることが期待されるコンポーネント データのフィールドです。子コンポーネントは、props オプション:

Vue.component(&#39;child&#39;, {
 // 声明 props
 props: [&#39;msg&#39;],
 // prop 可以用在模板内
 // 可以用 `this.msg` 设置
 template: &#39;<span>{{ msg }}</span>&#39;
})

を使用して props を明示的に宣言し、それに通常の文字列を渡す必要があります:
914bfc256b255241d41492f651d390d27d4dd9c7239aac360e401efe89cbb393

キャメルケース vs.バー スタイル

HTML 機能では大文字と小文字が区別されません。 CamelCase という名前の prop が機能として使用される場合、kebab-case に変換する必要があります (ダッシュで区切ります):

Vue.component(&#39;child&#39;, {
 // camelCase in JavaScript
 props: [&#39;myMessage&#39;],
 template: &#39;<span>{{ myMessage }}</span>&#39;
})
 
<!-- kebab-case in HTML -->
<child my-message="hello!"></child>

Dynamic Props

は v-bind を使用してバインドするのと似ていますHTML 機能を式に結合するだけでなく、v-bind を使用して動的 Props を親コンポーネントのデータにバインドすることもできます。親コンポーネントのデータが変更されると、そのデータは子コンポーネントにも送信されます:

<div>
 <input v-model="parentMsg">
 <br>
 <child v-bind:my-message="parentMsg"></child>
</div>

使用 `v-bind` 的缩写语法通常更简单: 
bd42d8e16231fee4b53c33c5ae90f1427d4dd9c7239aac360e401efe89cbb393

字面量语法 vs. 动态语法

初学者常犯的一个错误是使用字面量语法传递数值:

f0c719b41b2444c4dcad2b080dcdc8ea
4b3995833ef6b5c3dd766ff223ff2442f939a29b40f7380e5948c73965a66a8e
因为它是一个字面 prop,它的值以字符串 `”1”` 而不是以实际的数字传下去。如果想传递一个实际的 JavaScript 数字,需要使用动态语法,从而让它的值被当作 JavaScript 表达式计算:
 9f2d9e4b4b7c979b3472073d04508f03
4be8778d271aa63d943a0a34a5a1cce6f939a29b40f7380e5948c73965a66a8e

Prop 绑定类型

prop 默认是单向绑定:当父组件的属性变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。不过,也可以使用 .sync 或 .once 绑定修饰符显式地强制双向或单次绑定:

比较语法:

<!-- 默认为单向绑定 -->
<child :msg="parentMsg"></child>
 
<!-- 双向绑定 -->
<child :msg.sync="parentMsg"></child>
 
<!-- 单次绑定 -->
<child :msg.once="parentMsg"></child>

   

双向绑定会把子组件的 msg 属性同步回父组件的 parentMsg 属性。单次绑定在建立之后不会同步之后的变化。

注意如果 prop 是一个对象或数组,是按引用传递。在子组件内修改它会影响父组件的状态,不管是使用哪种绑定类型。

Prop 验证

组件可以为 props 指定验证要求。当组件给其他人使用时这很有用,因为这些验证要求构成了组件的 API,确保其他人正确地使用组件。此时 props 的值是一个对象,包含验证要求:

Vue.component(&#39;example&#39;, {
 props: {
 // 基础类型检测 (`null` 意思是任何类型都可以)
 propA: Number,
 // 多种类型 (1.0.21+)
 propM: [String, Number],
 // 必需且是字符串
 propB: {
  type: String,
  required: true
 },
 // 数字,有默认值
 propC: {
  type: Number,
  default: 100
 },
 // 对象/数组的默认值应当由一个函数返回
 propD: {
  type: Object,
  default: function () {
  return { msg: &#39;hello&#39; }
  }
 },
 // 指定这个 prop 为双向绑定
 // 如果绑定类型不对将抛出一条警告
 propE: {
  twoWay: true
 },
 // 自定义验证函数
 propF: {
  validator: function (value) {
  return value > 10
  }
 },
 // 转换函数(1.0.12 新增)
 // 在设置值之前转换值
 propG: {
  coerce: function (val) {
  return val + &#39;&#39; // 将值转换为字符串
  }
 },
 propH: {
  coerce: function (val) {
  return JSON.parse(val) // 将 JSON 字符串转换为对象
  }
 }
 }
})

   

type 可以是下面原生构造器:
 •String
 •Number
 •Boolean
 •Function
 •Object
 •Array 

type 也可以是一个自定义构造器,使用 instanceof 检测。

当 prop 验证失败了,Vue 将拒绝在子组件上设置此值,如果使用的是开发版本会抛出一条警告。

父子组件通信

父链

子组件可以用 this.$parent 访问它的父组件。根实例的后代可以用 this.$root 访问它。父组件有一个数组 this.$children,包含它所有的子元素。

尽管可以访问父链上任意的实例,不过子组件应当避免直接依赖父组件的数据,尽量显式地使用 props 传递数据。另外,在子组件中修改父组件的状态是非常糟糕的做法,因为:
 1.这让父组件与子组件紧密地耦合;

 2.只看父组件,很难理解父组件的状态。因为它可能被任意子组件修改!理想情况下,只有组件自己能修改它的状态。

自定义事件

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(&#39;child&#39;, {
 template: &#39;#child-template&#39;,
 data: function () {
 return { msg: &#39;hello&#39; }
 },
 methods: {
 notify: function () {
  if (this.msg.trim()) {
  this.$dispatch(&#39;child-msg&#39;, this.msg)
  this.msg = &#39;&#39;
  }
 }
 }
})
 
// 初始化父组件
// 将收到消息时将事件推入一个数组
var parent = new Vue({
 el: &#39;#events-example&#39;,
 data: {
 messages: []
 },
 // 在创建实例时 `events` 选项简单地调用 `$on`
 events: {
 &#39;child-msg&#39;: function (msg) {
  // 事件回调内的 `this` 自动绑定到注册它的实例上
  this.messages.push(msg)
 }
 }
})

   

使用 v-on 绑定自定义事件

上例非常好,不过从父组件的代码中不能直观的看到 "child-msg" 事件来自哪里。如果我们在模板中子组件用到的地方声明事件处理器会更好。为此子组件可以用 v-on 监听自定义事件:

4084e2349312ebcd04e4de37381def6c7d4dd9c7239aac360e401efe89cbb393
这样就很清楚了:当子组件触发了 `”child-msg”` 事件,父组件的 `handleIt` 方法将被调用。所有影响父组件状态的代码放到父组件的 `handleIt` 方法中;子组件只关注触发事件。
 子组件索引

尽管有 props 和 events,但是有时仍然需要在 JavaScript 中直接访问子组件。为此可以使用 v-ref 为子组件指定一个索引 ID。例如:

<div id="parent">
 <user-profile v-ref:profile></user-profile>
</div>
 
var parent = new Vue({ el: &#39;#parent&#39; })
// 访问子组件
var child = parent.$refs.profile

   

v-ref 和 v-for 一起用时,ref 是一个数组或对象,包含相应的子组件。

使用 Slot 分发内容

在使用组件时,常常要像这样组合它们:

<app>
 <app-header></app-header>
 <app-footer></app-footer>
</app>

   

注意两点:
 1.7ab1d477d2ef4cffc4b2f0ef9c222635 组件不知道它的挂载点会有什么内容,挂载点的内容是由 7ab1d477d2ef4cffc4b2f0ef9c222635 的父组件决定的。

 2.7ab1d477d2ef4cffc4b2f0ef9c222635 组件很可能有它自己的模板。

为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个处理称为内容分发(或 “transclusion”,如果你熟悉 Angular)。Vue.js 实现了一个内容分发 API,参照了当前 Web 组件规范草稿,使用特殊的 58cb293b8600657fad49ec2c8d37b472 元素作为原始内容的插槽。

编译作用域

在深入内容分发 API 之前,我们先明确内容的编译作用域。假定模板为:

6520631531c208a38051e59cee36c278
  {{ msg }}
53b801b01e70268453ed301cb998e90c

msg 应该绑定到父组件的数据,还是绑定到子组件的数据?答案是父组件。组件作用域简单地说是:

父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译
一个常见错误是试图在父组件模板内将一个指令绑定到子组件的属性/方法:

28f4e97653235e70fa02b96a2a29310c
68cc734b6c13c190f565c55929cd8b5e53b801b01e70268453ed301cb998e90c

假定 someChildProperty 是子组件的属性,上例不会如预期那样工作。父组件模板不应该知道子组件的状态。

如果要绑定子组件内的指令到一个组件的根节点,应当在它的模板内这么做:

Vue.component(&#39;child-component&#39;, {
 // 有效,因为是在正确的作用域内
 template: &#39;<div v-show="someChildProperty">Child</div>&#39;,
 data: function () {
 return {
  someChildProperty: true
 }
 }
})

   

类似地,分发内容是在父组件作用域内编译。 

单个 Slot

父组件的内容将被抛弃,除非子组件模板包含 58cb293b8600657fad49ec2c8d37b472。如果子组件模板只有一个没有特性的 slot,父组件的整个内容将插到 slot 所在的地方并替换它。

58cb293b8600657fad49ec2c8d37b472 标签的内容视为回退内容。回退内容在子组件的作用域内编译,当宿主元素为空并且没有内容供插入时显示这个回退内容。

假定 my-component 组件有下面模板:

<div>
 <h1>This is my component!</h1>
 <slot>
 如果没有分发内容则显示我。
 </slot>
</div>

   

父组件模板: 
b98f2d1b8b5d79f8c1b053de334aa7b5
  e388a4556c0f65e1904146cc1a846beeThis is some original content94b3e26ee717c64999d7867364b1b4a3
  e388a4556c0f65e1904146cc1a846beeThis is some more original content94b3e26ee717c64999d7867364b1b4a3
83153a5025b2246e72401680bb5dd683
渲染结果: 

<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,这些找不到匹配的内容片段将被抛弃。

例如,假定我们有一个 multi-insertion 组件,它的模板为:

<div>
 <slot name="one"></slot>
 <slot></slot>
 <slot name="two"></slot>
</div>

   

父组件模板: 

<multi-insertion>
 <p slot="one">One</p>
 <p slot="two">Two</p>
 <p>Default A</p>
</multi-insertion>

   

渲染结果为: 

<div>
 <p slot="one">One</p>
 <p>Default A</p>
 <p slot="two">Two</p>
</div>

   

在组合组件时,内容分发 API 是非常有用的机制。 

动态组件

多个组件可以使用同一个挂载点,然后动态地在它们之间切换。使用保留的 8c05085041e56efcb85463966dd1cb7e 元素,动态地绑定到它的 is 特性:

new Vue({
 el: &#39;body&#39;,
 data: {
 currentView: &#39;home&#39;
 },
 components: {
 home: { /* ... */ },
 posts: { /* ... */ },
 archive: { /* ... */ }
 }
})
 
<component :is="currentView">
 <!-- 组件在 vm.currentview 变化时改变 -->
</component>

   

keep-alive

如果把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。为此可以添加一个 keep-alive 指令参数:

39a981128a40da37853cce84bffb2ba2
  b2b0822175891cddec63f9cdd3f18ba9
2724ec0ed5bf474563ac7616c8d7a3cd

activate 钩子

在切换组件时,切入组件在切入前可能需要进行一些异步操作。为了控制组件切换时长,给切入组件添加 activate 钩子:

Vue.component(&#39;activate-example&#39;, {
 activate: function (done) {
 var self = this
 loadDataAsync(function (data) {
  self.someData = data
  done()
 })
 }
})

   

注意 `activate` 钩子只作用于动态组件切换或静态组件初始化渲染的过程中,不作用于使用实例方法手工插入的过程中。 
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;
}

   

杂项

组件和 v-for

自定义组件可以像普通元素一样直接使用 v-for:

a9a1e7d04477c0e832f43883fce1bc2c83153a5025b2246e72401680bb5dd683

但是,不能传递数据给组件,因为组件的作用域是孤立的。为了传递数据给组件,应当使用 props:

35c87bd607c1909a6b5ef52c795f1ed7
83153a5025b2246e72401680bb5dd683

不自动把 item 注入组件的原因是这会导致组件跟当前 v-for 紧密耦合。显式声明数据来自哪里可以让组件复用在其它地方。

编写可复用组件

在编写组件时,记住是否要复用组件有好处。一次性组件跟其它组件紧密耦合没关系,但是可复用组件应当定义一个清晰的公开接口。

Vue.js 组件 API 来自三部分——prop,事件和 slot:
 •prop 允许外部环境传递数据给组件;

 •事件 允许组件触发外部环境的 action;

 •slot 允许外部环境插入内容到组件的视图结构内。

 使用 v-bind 和 v-on 的简写语法,模板的缩进清楚且简洁:

9f5a0aa3d537eedfa843e3c0a63d4317
  cb4e25d677c71b611af30b24ac580ce8
  2660389d9a6836ad2cf20a139757c02e
  17b047d0462086858c7d0a0ba5a2ece2Hello!94b3e26ee717c64999d7867364b1b4a3
83153a5025b2246e72401680bb5dd683

异步组件

在大型应用中,我们可能需要将应用拆分为小块,只在需要时才从服务器下载。为了让事情更简单,Vue.js 允许将组件定义为一个工厂函数,动态地解析组件的定义。Vue.js 只在组件需要渲染时触发工厂函数,并且把结果缓存起来,用于后面的再次渲染。例如:

Vue.component(&#39;async-example&#39;, function (resolve, reject) {
 setTimeout(function () {
 resolve({
  template: &#39;<div>I am async!</div>&#39;
 })
 }, 1000)
})

   

工厂函数接收一个 resolve 回调,在收到从服务器下载的组件定义时调用。也可以调用 reject(reason) 指示加载失败。这里 setTimeout 只是为了演示。怎么获取组件完全由你决定。推荐配合使用 Webpack 的代码分割功能:

Vue.component(&#39;async-webpack-example&#39;, function (resolve) {
 // 这个特殊的 require 语法告诉 webpack
 // 自动将编译后的代码分割成不同的块,
 // 这些块将通过 ajax 请求自动下载。
 require([&#39;./my-async-component&#39;], resolve)
})

   

资源命名约定

一些资源,如组件和指令,是以 HTML 特性或 HTML 自定义元素的形式出现在模板中。因为 HTML 特性的名字和标签的名字不区分大小写,所以资源的名字通常需使用 kebab-case 而不是 camelCase 的形式,这不大方便。

Vue.js 支持资源的名字使用 camelCase 或 PascalCase 的形式,并且在模板中自动将它们转为 kebab-case(类似于 prop 的命名约定):

// 在组件定义中
components: {
 // 使用 camelCase 形式注册
 myComponent: { /*... */ }
}
 
<!-- 在模板中使用 kebab-case 形式 -->
<my-component></my-component>
 
ES6 对象字面量缩写 也没问题:
 
// PascalCase
import TextBox from &#39;./components/text-box&#39;;
import DropdownMenu from &#39;./components/dropdown-menu&#39;;
 
export default {
 components: {
 // 在模板中写作 <text-box> 和 <dropdown-menu>
 TextBox,
 DropdownMenu
 }
}

   

递归组件

组件在它的模板内可以递归地调用自己,不过,只有当它有 name 选项时才可以:

var StackOverflow = Vue.extend({
 name: &#39;stack-overflow&#39;,
 template:
 &#39;<div>&#39; +
  // 递归地调用它自己
  &#39;<stack-overflow></stack-overflow>&#39; +
 &#39;</div>&#39;
})

   

上面组件会导致一个错误 “max stack size exceeded”,所以要确保递归调用有终止条件。当使用 Vue.component() 全局注册一个组件时,组件 ID 自动设置为组件的 name 选项。

片断实例

在使用 template 选项时,模板的内容将替换实例的挂载元素。因而推荐模板的顶级元素始终是单个元素。

不这么写模板:

dc6dce4a544fdca2df29d5ac0ea9906broot node 116b28748ea4df4d9c2150843fecfba68
dc6dce4a544fdca2df29d5ac0ea9906broot node 216b28748ea4df4d9c2150843fecfba68

推荐这么写:

dc6dce4a544fdca2df29d5ac0ea9906b
  I have a single root node!
  dc6dce4a544fdca2df29d5ac0ea9906bnode 116b28748ea4df4d9c2150843fecfba68
  dc6dce4a544fdca2df29d5ac0ea9906bnode 216b28748ea4df4d9c2150843fecfba68
16b28748ea4df4d9c2150843fecfba68

次の状況では、インスタンスがフラグメント インスタンスに変わります:
1. テンプレートには複数のトップレベル要素が含まれています。
2. テンプレートには通常のテキストのみが含まれています。
3. テンプレートには他のコンポーネントのみが含まれます (他のコンポーネントはフラグメント インスタンスである可能性があります)。
4. テンプレートには、 や vue-router の などの要素ディレクティブが 1 つだけ含まれています。
5. テンプレートのルートノードには、v-if や v-for などのフロー制御命令があります。

インスタンスに未知の数のトップレベル要素がある場合、その DOM コンテンツはフラグメントとして扱われます。フラグメント インスタンスは引き続きコンテンツを正しくレンダリングします。ただし、ルート ノードはなく、その $el は空のテキスト ノード (開発モードではコメント ノード) であるアンカー ノードを指します。

しかし、より重要なのは、バインドするルート要素がないため、コンポーネント要素の非フロー制御ディレクティブ、非プロパティ属性、およびトランジションは無視されます:

4e92cebc5ae303d7524339456edeb952
8def94b8d46f38a08d6e8969ceae86c04cddb7d8848582d36dd9716ae6c29b0b


c1edd33261770016656697f8523149d6
17572e7c10ef524d9de983dd599aa5994cddb7d8848582d36dd9716ae6c29b0b

もちろんフラグメント インスタンスには便利な機能がありますが、通常はコンポーネントにルート ノードを与える方が良いでしょう。これにより、コンポーネント要素のディレクティブとプロパティが正しく変換され、パフォーマンスがわずかに向上します。

インライン テンプレート

子コンポーネントに inline-template 属性がある場合、コンポーネントはそのコンテンツを分散コンテンツとして扱うのではなく、テンプレートとして扱います。これにより、テンプレートがより柔軟になります。

8283dd6e937edd85c001c6ec3509d95d
e388a4556c0f65e1904146cc1a846beeこれらはコンポーネント独自のテンプレートとしてコンパイルされます94b3e26ee717c64999d7867364b1b4a3
e388a4556c0f65e1904146cc1a846bee親のトランスクルージョンコンテンツではありません。94b3e26ee717c64999d7867364b1b4a3

しかし、inline-template ではテンプレートの範囲がわかりにくくなり、テンプレートのコンパイル結果をキャッシュできなくなります。ベスト プラクティスは、テンプレート オプションを使用してコンポーネント内でテンプレートを定義することです。

以上がこの記事の全内容です。皆さんの学習に役立つことを願っています。また、皆さんも PHP 中国語 Web サイトをサポートしていただければ幸いです。

Vue.js で毎日学習する必要があるコンポーネント間の通信に関するその他の記事については、PHP 中国語 Web サイトに注目してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。