Asas Komponen


Direktori

  • Contoh asas

  • Penggunaan semula komponen

    • mesti ada fungsi
  • Organisasi komponen

  • Salurkan data kepada komponen kanak-kanak melalui Prop

  • Elemen punca tunggal

  • Dengar acara komponen kanak-kanak

    • acara nilai guna
    • Gunakan pada komponen v -model
  • Edarkan kandungan melalui slot
  • Komponen dinamik


Nota semasa parsing


Contoh asas

<button-counter>。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:

// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
<div id="components-demo">
  <button-counter></button-counter>
</div>

1.gif

因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。


组件的复用


你可以将组件进行任意次数的复用:

new Vue({ el: '#components-demo' })

1.jpg

注意当点击按钮时,每个组件都会各自独立维护它的 count。因为你每用一次组件,就会有一个它的新实例被创建。


data 必须是一个函数

当我们定义这个 <button-counter> 组件时,你可能会发现它的 data

🎜🎜 Berikut ialah contoh komponen Vue: 🎜
<div id="components-demo">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>
🎜 Komponen ialah tika Vue boleh guna semula dengan nama: dalam kes ini <button-counter>. Kita boleh menggunakan komponen ini sebagai elemen tersuai dalam contoh akar Vue yang dibuat melalui Vue baharu: 🎜
data: {
  count: 0
}
data: function () {
  return {
    count: 0
  }
}
🎜1.gif🎜🎜Oleh kerana komponen adalah contoh Vue yang boleh diguna semula, ia adalah sama seperti baharu Vue< /code> pilihan, seperti data, computed, watch, kaedah dan cangkuk kitaran hayat. Satu-satunya pengecualian ialah pilihan khusus contoh akar seperti el . 🎜🎜🎜🎜

🎜🎜Penggunaan semula komponen🎜🎜🎜🎜🎜Anda boleh menggunakan semula komponen beberapa kali: 🎜
Vue.component('my-component-name', {
  // ... options ...
})
🎜1.jpg🎜🎜Perhatikan bahawa apabila butang diklik, setiap komponen akan mengekalkannya secara berasingan < kod>kira< /kod>. Kerana setiap kali anda menggunakan komponen, contoh baharu komponen itu dibuat. 🎜🎜🎜🎜

🎜data🎜🎜🎜 Ia mestilah fungsi🎜🎜🎜🎜Apabila kami mentakrifkan komponen <button-counter> ini, anda mungkin mendapati bahawa datanya tidak memberikan objek seperti ini secara langsung : 🎜

Vue.component('blog-post', {
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})

Sebaliknya, pilihan data komponen mestilah fungsi, jadi setiap kejadian boleh mengekalkan salinan bebas objek yang dikembalikan: data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>

如果 Vue 没有这条规则,点击一个按钮就可能会像如下代码一样影响到其它所有实例:

2.gif


组件的组织


通常一个应用会以一棵嵌套的组件树的形式来组织:

1.png

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的:

new Vue({
  el: '#blog-post-demo',
  data: {
    posts: [
      { id: 1, title: 'My journey with Vue' },
      { id: 2, title: 'Blogging with Vue' },
      { id: 3, title: 'Why Vue is so fun' }
    ]
  }
})

全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。

到目前为止,关于组件注册你需要了解的就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把组件注册读完。


通过 Prop 向子组件传递数据


早些时候,我们提到了创建一个博文组件的事情。问题是如果你不能向这个组件传递某一篇博文的标题或内容之类的我们想展示的数据的话,它是没有办法使用的。这也正是 prop 的由来。

Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
></blog-post>

一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样。

一个 prop 被注册之后,你就可以像这样把数据作为一个自定义特性传递进来:

<h3>{{ title }}</h3>

2.jpg

然而在一个典型的应用中,你可能在 data

<h3>{{ title }}</h3>
<div v-html="content"></div>

Jika Vue tidak mematuhi peraturan ini, mengklik a butang boleh menjejaskan semua keadaan lain seperti kod berikut:

2.gif🎜🎜
🎜

🎜 Organisasi komponen< /h2>
🎜Biasanya aplikasi disusun dalam bentuk pokok komponen bersarang:
🎜🎜1.png🎜🎜Sebagai contoh, anda mungkin mempunyai pengepala dan bar sisi , kawasan kandungan dan komponen lain, setiap komponen mengandungi komponen lain seperti pautan navigasi, catatan blog dan sebagainya. 🎜🎜Untuk digunakan dalam templat, komponen ini mesti didaftarkan terlebih dahulu supaya Vue dapat mengenalinya. Terdapat dua jenis pendaftaran komponen: 🎜pendaftaran global dan 🎜pendaftaran tempatan. Setakat ini, komponen kami hanya didaftarkan secara global melalui Vue.component: 🎜
<div class="blog-post">
  <h3>{{ title }}</h3>
  <div v-html="content"></div>
</div>
🎜Komponen yang didaftarkan secara global boleh digunakan dalam apa-apa sahaja selepas ia didaftarkan (melalui Vue baru) tika akar Vue yang baru dibuat juga termasuk templat semua subkomponen dalam pepohon komponennya. 🎜🎜Setakat ini, itu sahaja yang anda perlu tahu tentang pendaftaran komponen Jika anda selesai membaca halaman ini dan menguasai kandungannya, kami akan mengesyorkan anda kembali dan Pendaftaran Komponen Selesai membaca. 🎜🎜
🎜

🎜Haruskan data kepada komponen anak melalui Prop


🎜Terdahulu, kami menyebut tentang membuat komponen catatan blog. Masalahnya ialah jika anda tidak boleh menghantar data yang ingin kami paparkan, seperti tajuk atau kandungan catatan blog, kepada komponen ini, ia tidak boleh digunakan. Di sinilah prop berasal. 🎜🎜Prop ialah beberapa sifat tersuai yang boleh anda daftarkan pada komponen. Apabila nilai dihantar kepada atribut prop, ia menjadi sifat contoh komponen itu. Untuk menghantar tajuk kepada komponen blog, kami boleh menggunakan pilihan props untuk memasukkannya ke dalam senarai prop yang diterima oleh komponen: 🎜
<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
  v-bind:content="post.content"
  v-bind:publishedAt="post.publishedAt"
  v-bind:comments="post.comments"
></blog-post>
🎜Sesuatu komponen boleh mempunyai sebarang bilangan prop secara lalai , dan sebarang nilai Boleh dihantar ke mana-mana prop. Dalam templat di atas, anda akan melihat bahawa kami boleh mengakses nilai ini dalam contoh komponen, sama seperti mengakses nilai dalam data. 🎜🎜Selepas prop didaftarkan, anda boleh menghantar data sebagai ciri tersuai seperti ini: 🎜
<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:post="post"
></blog-post>
🎜2.jpg🎜🎜Walau bagaimanapun, dalam aplikasi biasa, anda mungkin mempunyai tatasusunan catatan blog dalam data: 🎜
Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <div v-html="post.content"></div>
    </div>
  `
})
🎜 dan ingin membuat komponen untuk setiap catatan blog: 🎜
new Vue({
  el: '#blog-posts-events-demo',
  data: {
    posts: [/* ... */],
    postFontSize: 1
  }
})

Seperti yang ditunjukkan di atas, anda akan mendapati bahawa kami boleh menggunakan v-bind untuk menghantar props secara dinamik. Ini adalah apabila anda tidak mengetahui kandungan khusus yang akan dipaparkan pada mulanya, seperti mendapatkan senarai catatan blog daripada API sangat berguna. v-bind 来动态传递 prop。这在你一开始不清楚要渲染的具体内容,比如从一个 API 获取博文列表的时候,是非常有用的。

到目前为止,关于 prop 你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把 prop 读完。


单个根元素


当构建一个 <blog-post> 组件时,你的模板最终会包含的东西远不止一个标题:

<div id="blog-posts-events-demo">
  <div :style="{ fontSize: postFontSize + 'em' }">
    <blog-post
      v-for="post in posts"
      v-bind:key="post.id"
      v-bind:post="post"
    ></blog-post>
  </div>
</div>

最最起码,你会包含这篇博文的正文:

Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <button>
        Enlarge text
      </button>
      <div v-html="post.content"></div>
    </div>
  `
})

然而如果你在模板中尝试这样写,Vue 会显示一个错误,并解释道 every component must have a single root element (每个组件必须只有一个根元素)。你可以将模板的内容包裹在一个父元素内,来修复这个问题,例如:

<button>
  Enlarge text
</button>

看起来当组件变得越来越复杂的时候,我们的博文不只需要标题和内容,还需要发布日期、评论等等。为每个相关的信息定义一个 prop 会变得很麻烦:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += 0.1"
></blog-post>

所以是时候重构一下这个 <blog-post> 组件了,让它变成接受一个单独的 post prop:

<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button>
<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>

上述的这个和一些接下来的示例使用了 JavaScript 的模板字符串来让多行的模板更易读。它们在 IE 下并没有被支持,所以如果你需要在不 (经过 Babel 或 TypeScript 之类的工具) 编译的情况下支持 IE,请使用折行转义字符取而代之。

现在,不论何时为 post 对象添加一个新的属性,它都会自动地在 <blog-post> 内可用。


监听子组件事件


在我们开发 <blog-post> 组件时,它的一些功能可能要求我们和父级组件进行沟通。例如我们可能会引入一个辅助功能来放大博文的字号,同时让页面的其它部分保持默认的字号。

在其父组件中,我们可以通过添加一个 postFontSize

Setakat ini, itu sahaja yang anda perlu tahu tentang prop Jika anda selesai membaca halaman ini dan menguasai kandungannya, kami akan mengesyorkan anda kembali lagi prop Selesai membaca.


Elemen punca tunggal


Apabila membina komponen <blog-post>, templat anda akhirnya akan mengandungi lebih daripada sekadar tajuk:
🎜
<blog-post
  ...
  v-on:enlarge-text="postFontSize += $event"
></blog-post>
🎜Sekurang-kurangnya, anda akan Mengandungi teks catatan blog ini: 🎜
<blog-post
  ...
  v-on:enlarge-text="onEnlargeText"
></blog-post>
🎜 Walau bagaimanapun, jika anda cuba menulis ini dalam templat, Vue akan menunjukkan ralat dan menerangkan bahawasetiap komponen mesti mempunyai elemen akar tunggal (setiap komponen mesti mempunyai hanya satu unsur akar) . Anda boleh menyelesaikan masalah ini dengan membungkus kandungan templat dalam elemen induk, contohnya: 🎜
methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}
🎜 Nampaknya apabila komponen menjadi semakin kompleks, catatan blog kami bukan sahaja memerlukan tajuk dan kandungan, tetapi juga penerbitan tarikh, Komen dan banyak lagi. Menentukan prop untuk setiap siaran yang berkaitan boleh menjadi menyusahkan: 🎜
<input v-model="searchText">
🎜 Jadi sudah tiba masanya untuk memfaktorkan semula komponen <blog-post> untuk menerima satu prop code>post: 🎜
<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>
<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"
></custom-input>
🎜Ini dan beberapa contoh berikut menggunakan JavaScript Rentetan templat untuk menjadikan templat berbilang baris lebih mudah dibaca. Mereka tidak disokong di bawah IE, jadi jika anda perlu menyokong IE tanpa menyusun (melalui alat seperti Babel atau TypeScript), sila gunakan aksara melarikan diri garis putus sebaliknya. 🎜
🎜Kini, apabila anda menambahkan sifat baharu pada objek post, ia akan tersedia secara automatik dalam <blog-post>. 🎜🎜
🎜

Dengar acara komponen kanak-kanak


🎜Apabila kami membangunkan komponen <blog-post>, beberapa fungsinya mungkin memerlukan kami berkomunikasi dengan komponen induk. Sebagai contoh, kami mungkin memperkenalkan fungsi tambahan untuk meningkatkan saiz fon catatan blog sambil mengekalkan seluruh halaman pada saiz fon lalai.
🎜🎜Dalam komponen induknya, kami boleh menyokong ciri ini dengan menambahkan atribut data postFontSize: 🎜
Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})
🎜Ia boleh digunakan dalam templat untuk mengawal saiz fon semua catatan blog: 🎜
<custom-input v-model="searchText"></custom-input>
🎜Sekarang kami menambah butang sebelum setiap teks catatan blog untuk membesarkan saiz fon: 🎜
<alert-box>
  Something bad happened.
</alert-box>

Masalahnya ialah butang ini tidak melakukan apa-apa:

Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box">
      <strong>Error!</strong>
      <slot></slot>
    </div>
  `
})

Apabila butang ini diklik, kita perlu memberitahu komponen induk untuk membesarkan teks semua catatan blog. Nasib baik, kejadian Vue menyediakan sistem acara tersuai untuk menyelesaikan masalah ini. Komponen induk boleh mendengar sebarang peristiwa contoh komponen anak melalui v-on sama seperti mengendalikan acara DOM asli: v-on 监听子组件实例的任意事件:

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>

同时子组件可以通过调用内建的 $emit 方法 并传入事件名称来触发一个事件:

<table>
  <blog-post-row></blog-post-row>
</table>

有了这个 v-on:enlarge-text="postFontSize += 0.1" 监听器,父级组件就会接收该事件并更新 postFontSize 的值。

3.gif


使用事件抛出一个值

有的时候用一个事件来抛出一个特定的值是非常有用的。例如我们可能想让 <blog-post> 组件决定它的文本要放大多少。这时可以使用 $emit 的第二个参数来提供这个值:

<table>
  <tr is="blog-post-row"></tr>
</table>

然后当在父级组件监听这个事件的时候,我们可以通过 $event 访问到被抛出的这个值:

rrreee

或者,如果这个事件处理函数是一个方法:

rrreee

那么这个值将会作为第一个参数传入这个方法:

rrreee


在组件上使用 v-model

自定义事件也可以用于创建支持 v-model 的自定义输入组件。记住:

rrreee

等价于:

rrreee

当用在组件上时,v-model 则会这样:

rrreee

为了让它正常工作,这个组件内的 <input> 必须:

  • 将其 value 特性绑定到一个名叫 value 的 prop 上

  • 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出

写成代码之后是这样的:

rrreee

现在 v-modelrrreee

Pada masa yang sama, komponen anak boleh memanggil $emit kaedah

dan masukkan nama acara untuk mencetuskan acara: rrreeeDengan pendengarv-on:enlarge-text="postFontSize += 0.1" ini, komponen induk akan menerima acara dan mengemas kini nilai postFontSize.

3.gif

Gunakan acara untuk melontar nilaiKadang-kadang ia sangat berguna untuk menggunakan acara untuk melontar nilai tertentu . Sebagai contoh, kami mungkin mahu komponen <blog-post> menentukan berapa banyak teksnya perlu diperbesarkan. Pada masa ini, anda boleh menggunakan parameter kedua $emit untuk memberikan nilai ini:

rrreee
Kemudian apabila mendengar acara ini dalam komponen induk, kita boleh menghantar $event Akses nilai yang dilemparkan:

rrreee

Atau, jika pengendali acara ialah kaedah:

rrreee

maka nilai akan dihantar ke kaedah sebagai parameter pertama: 🎜rrreee🎜🎜🎜

🎜Gunakan v-model pada komponen🎜🎜🎜🎜Acara tersuai juga boleh digunakan untuk mencipta sokongan Komponen input tersuai untuk v -model. Ingat: 🎜rrreee🎜 adalah bersamaan dengan: 🎜rrreee🎜 Apabila digunakan pada komponen, v-model akan kelihatan seperti ini: 🎜rrreee🎜Untuk menjadikannya berfungsi dengan baik, di dalam komponen ini < ;input> mesti: 🎜

  • 🎜Ikat atribut valuenya pada objek bernama Pada prop bernilai🎜
  • 🎜Apabila acara inputnya dicetuskan, nilai baharu akan dilemparkan melalui acara input tersuai 🎜
🎜Selepas menulis kod, ia kelihatan seperti ini: 🎜rrreee🎜Kini v-model sepatutnya dapat berfungsi dengan sempurna pada komponen ini: 🎜rrreee🎜Setakat ini, itu tentang semua yang anda perlu tahu tentang acara tersuai komponen Jika anda selesai membaca halaman ini dan menguasai kandungannya, kami akan mengesyorkan anda untuk kembali dan membaca 🎜Acara Tersuai🎜. 🎜🎜🎜🎜🎜🎜🎜Mengedarkan kandungan melalui slot 🎜🎜🎜🎜🎜Seperti elemen HTML, kita selalunya perlu menghantar kandungan kepada komponen, seperti ini: 🎜rrreee🎜 mungkin menghasilkan sesuatu seperti ini:

3.jpg

Nasib baik, elemen <slot> tersuai Vue menjadikan ini sangat mudah: <slot> 元素让这变得非常简单:

rrreee

如你所见,我们只要在需要的地方加入插槽就行了——就这么简单!

到目前为止,关于插槽你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把插槽读完。


动态组件


有的时候,在不同组件之间进行动态切换是非常有用的,比如在一个多标签的界面里:

4.gif

上述内容可以通过 Vue 的 <component> 元素加一个特殊的 is 特性来实现:

rrreee

在上述示例中,currentTabComponent 可以包括

  • 已注册组件的名字,或

  • 一个组件的选项对象

你可以在这里查阅并体验完整的代码,或在这个版本了解绑定组件选项对象,而不是已注册组件名的示例。

到目前为止,关于动态组件你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把动态和异步组件读完。


解析 DOM 模板时的注意事项


有些 HTML 元素,诸如 <ul><ol><table><select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li><tr><option>,只能出现在其它某些特定的元素内部。

这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:

rrreee

这个自定义组件 <blog-post-row> 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is 特性给了我们一个变通的办法:

rrreee

需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在