组件基础

175 阅读5分钟

1.基本实例

在典型的Vue应用中,我们使用单个文件组件而不是字符串模板。

  • 组件时带有名称的可复用实例,可以把组件作为一个根实例中的自定义元素来使用
  • 因为组件是可复用的组件实例,所以它们与根实例接收相同的选项,例如data、computed、watch、methods以及生命周期钩子等

2.组件的复用

  • 你可以将组件进行任意次数的复用
  • 每个组件都会各自独立维护它的变量,因为每用一次组件,就会有一个它的新实例被创建

3.组件的组织

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

  • 例如可能会有页头、侧边栏、内容区等组件,每个组件又包含了其他的像导航链接、博文之类的组件
  • 为了能在模板中使用,这些组件必须先注册以便Vue能够识别 有两种组件的注册类型:全局注册和局部注册。组件可以通过component方法全局注册。
  • const app = Vue.createApp({})
  • app.component('my-component-name', {}) 全局注册的组件可以在应用中的任何组件的模板中使用。

4.通过Prop向子组件传递数据

如果不能向组件传递某一篇博文的标题或内容之类的我们想展示的数据的话,它是没有办法使用的,这也正是prop的由来。

  • Prop是可以在组件上注册的一些自定义attribute,为了给博文组件传递一个标题,我们可以用props选项将其包含在该组件可接受的prop列表中
  • 当一个值被传递给一个prop attribute时,它就称为该组件实例中的一个property,该property的值可以在模板中访问,就像任何其他组件property一样
  • 一个组件默认可以拥有任意数量的prop,无论任何值都可以传递给prop
  • 在一个典型的应用中,可能在data里有一个博文的数组:return { posts:[] }
  • 可以使用v-bind来动态传递prop,这在一开始不清楚要渲染的具体内容时是非常有用的

5.监听子组件事件

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

  • 在其父组件中,我们可以通过添加一个postFontSize数据property来支持这个功能
  • 它可以在模板中用来控制所有博文的字号
  • 可以在博文正文之前添加一个按钮来放大字号
  • 点击按钮时,告诉父级组件放大所有博文的文本。组件实例提供了一个自定义事件的系统来解决这个问题,父级组件可以像处理原生DOM事件一样通过v-on或@监听子组件实例的任意事件(在组件属性添加监听事件)
  • 同时子组件可以通过调用内建的$emit()并传入事件名称来触发一个事件
  • 多亏子组件属性上的自定义事件监听器,父级组件能够接收事件并更新字号值
  • 我们可以在组件的emits选项中列出已抛出的事件,这将允许我们检查组件抛出的所有事件,还可以选择验证它们

5.1使用事件抛出一个值

有时候用一个事件来抛出一个特定的值是非常有用的。

  • 例如我们可能想让子组件决定它的文本要放大多少,这时可以使用$emit的第二个参数来提供这个值。
  • 然后当父级组件监听这个事件的时候,我们可以通过$event访问到被抛出的这个值 或者如果这个事件处理函数是一个方法,那么这个值将会作为第一个参数传入这个方法。

5.2在组件上使用v-model

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

  • v-model="searchText" 等价于 :value="searchText" @input="searchText = $event.target.value" 为了让组件正常工作,这个组件内的input必须:
  • 将其value attribute绑定到一个名叫modelValue的prop上
  • 在其input事件被触发时,将新的值通过自定义的update:modelValue事件抛出 在该组件中实现v-model的另一种方法是使用computed property的功能来定义getter和setter。get方法应返回modelValue property,set方法应该触发相应的事件。

6.通过插槽分发内容

和HTML元素一样,我们经常需要向一个组件传递内容。

  • 可以通过使用Vue的自定义slot元素来实现
  • 我们使用slot作为我们想要插入内容的占位符——就这么简单!

7.动态组件

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

  • 可以通过Vue的component元素加一个特殊的is attribute来实现
<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component :is="currentTabComponent"></component>

currentTabComponent可以包括:

  • 已注册组件的名字
  • 或者一个组件的选项对象

8.解析DOM模板时的注意事项

如果想在DOM中直接书写Vue模板,Vue不得不从DOM中获取字符串,这会因为浏览器的原生HTML解析行为而导致一些小问题。

8.1 Element Placement Restrictions

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

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

自定义组件blog-post-row会被作为无效的内容提升到外部,并导致最终渲染结果出错,我们可以使用特殊的is attribute作为一个变通的办法:

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

当它用于原生HTML元素时,is的值必须以vue:开头,才可以被解释为Vue组件,这是避免和原生自定义元素混淆。

8.2Case Insensitivity

另外,HTML attribute名不区分大小写,因此浏览器将所有大写字符解释为小写。这意味着当你在DOM模板中使用时,驼峰prop名称和event处理器参数需要使用它们的kebab-cased(横线字符分隔)等效值。

  • 在JavaScript中的驼峰:props: ['postTitle']
  • 在HTML则时横线字符分割:post-title="hello!"