Vue.js知识库(五):自定义事件和插槽

自定义事件、插槽的作用域、​具名插槽。
245阅读 · 2020-8-28 23:47发布

自定义事件

事件名称

事件名称可以使用kebab-case(短横线分隔命名)命名,并且需要全部为小写(v-on事件监听器在 DOM 模板中会被自动转换为全小写)。

自定义组件的v-model

子组件里可以通过v-model来向父组件传递值,使父组件的属性更新。

Vue.component('base-checkbox', {
  <!--change事件时传递checked给v-model绑定的属性-->
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  <!--下面是通过$emit触发change事件给model-->
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})
<!--通过v-model绑定父组件中的lovingVue-->
<base-checkbox v-model="lovingVue"></base-checkbox>

绑定原生事件

根元素上监听原生事件,可以使用v-on.native修饰符。

<base-input v-on:focus.native="onFocus"></base-input>

.sync修饰符

可以通过sync修饰符,使子组件向父组件传递值并修改父组件的值。

this.$emit('update:title', newTitle)

<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>

//方面的写法和下面相同
<text-document v-bind:title.sync="doc.title"></text-document>

当我们用一个对象同时设置多个 prop 的时候,也可以将这个 .sync 修饰符和 v-bind 配合使用:

<text-document v-bind.sync="doc"></text-document>

插槽

  • 插槽使用元素表示。
  • 组件渲染时,会将替换为子组件元素之间的内容。
  • 如果组件中不包含,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

插槽的作用域

  • 插槽中的内容,只允许访问组件内部定义的属性。
  • 父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

插槽的默认内容

  • 如果之间有内容,父组件使用子组件时没有在子组件之间增内容。则最终会显示时间的内容。
// 子组件模板
<button type="submit">
  <slot>Submit</slot>
</button>

//父组件中调用
<submit-button></submit-button>

//最终渲染
<button type="submit">
  Submit
</button>

具名插槽

  • 如果一个页面中包含多个插槽,可以使用name属性给slot添加名称。
  • 一个不带name属性的会隐含名字default。
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

具名插槽的缩写

  • 2.6.0 新增。
  • 将【v-slot:】替换为字符【#】。
<base-layout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>
</base-layout>
  • 如果有参数,并且使用缩写,需要使用如下写法。
<current-user #default="{ user }">
  {{ user.firstName }}
</current-user>

作用域插槽

父级插槽中使用子组件数据

//方法一:绑定属性
<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

//方法二:使用插槽prop
<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

只有一个插槽时的简单写法

//和v-slot:default="slotProps"含义一样(仅限只有一个插槽时可以使用这种写法)
<current-user v-slot="slotProps">
  {{ slotProps.user.firstName }}
</current-user>

动态插槽名

动态指令参数也可以用在 v-slot 上,来定义动态的插槽名:

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>