Skip to content

插槽

¥Slots

Vue Test Utils 提供了一些使用 slots 测试组件的有用功能。

¥Vue Test Utils provides some useful features for testing components using slots.

一个简单的例子

¥A Simple Example

你可能有一个通用 <layout> 组件,它使用默认插槽来渲染某些内容。例如:

¥You might have a generic <layout> component that uses a default slot to render some content. For example:

js
const Layout = {
  template: `
    <div>
      <h1>Welcome!</h1>
      <main>
        <slot />
      </main>
      <footer>
        Thanks for visiting.
      </footer>
    </div>
  `
}

你可能需要编写一个测试来确保渲染默认槽内容。为此,VTU 提供了 slots 挂载选项:

¥You might want to write a test to ensure the default slot content is rendered. VTU provides the slots mounting option for this purpose:

js
test('layout default slot', () => {
  const wrapper = mount(Layout, {
    slots: {
      default: 'Main Content'
    }
  })

  expect(wrapper.html()).toContain('Main Content')
})

它过去了!在此示例中,我们将一些文本内容传递到默认槽。如果你想要更具体,并验证默认插槽内容是否在 <main> 内渲染,你可以更改断言:

¥It passes! In this example, we are passing some text content to the default slot. If you want to be even more specific, and verify the default slot content is rendered inside <main>, you could change the assertion:

js
test('layout default slot', () => {
  const wrapper = mount(Layout, {
    slots: {
      default: 'Main Content'
    }
  })

  expect(wrapper.find('main').text()).toContain('Main Content')
})

命名插槽

¥Named Slots

你可能有更复杂的 <layout> 组件,其中包含一些命名插槽。例如:

¥You may have more complex <layout> component with some named slots. For example:

js
const Layout = {
  template: `
    <div>
      <header>
        <slot name="header" />
      </header>

      <main>
        <slot name="main" />
      </main>
      <footer>
        <slot name="footer" />
      </footer>
    </div>
  `
}

VTU 也支持这一点。你可以按如下方式编写测试。请注意,在此示例中,我们将 HTML 而不是文本内容传递到插槽。

¥VTU also supports this. You can write a test as follows. Note that in this example we are passing HTML instead of text content to the slots.

js
test('layout full page layout', () => {
  const wrapper = mount(Layout, {
    slots: {
      header: '<div>Header</div>',
      main: '<div>Main Content</div>',
      footer: '<div>Footer</div>'
    }
  })

  expect(wrapper.html()).toContain('<div>Header</div>')
  expect(wrapper.html()).toContain('<div>Main Content</div>')
  expect(wrapper.html()).toContain('<div>Footer</div>')
})

多个插槽

¥Multiple Slots

你也可以传递插槽数组:

¥You can pass an array of slots, too:

js
test('layout full page layout', () => {
  const wrapper = mount(Layout, {
    slots: {
      default: [
        '<div id="one">One</div>',
        '<div id="two">Two</div>'
      ]
    }
  })

  expect(wrapper.find('#one').exists()).toBe(true)
  expect(wrapper.find('#two').exists()).toBe(true)
})

高级用法

¥Advanced Usage

你还可以将从 vue 文件导入的渲染函数、带有模板的对象甚至 SFC 传递到插槽挂载选项:

¥You can also pass a render function, an object with template or even an SFC imported from a vue file to a slot mounting option:

js
import { h } from 'vue'
import Header from './Header.vue'

test('layout full page layout', () => {
  const wrapper = mount(Layout, {
    slots: {
      header: Header,
      main: h('div', 'Main Content'),
      sidebar: { template: '<div>Sidebar</div>' },
      footer: '<div>Footer</div>'
    }
  })

  expect(wrapper.html()).toContain('<div>Header</div>')
  expect(wrapper.html()).toContain('<div>Main Content</div>')
  expect(wrapper.html()).toContain('<div>Footer</div>')
})

参考测试 了解更多示例和用例。

¥Refer to the tests for more examples and use cases.

范围插槽

¥Scoped Slots

还支持 作用域插槽 和绑定。

¥Scoped slots and bindings are also supported.

js
const ComponentWithSlots = {
  template: `
    <div class="scoped">
      <slot name="scoped" v-bind="{ msg }" />
    </div>
  `,
  data() {
    return {
      msg: 'world'
    }
  }
}

test('scoped slots', () => {
  const wrapper = mount(ComponentWithSlots, {
    slots: {
      scoped: `<template #scoped="scope">
        Hello {{ scope.msg }}
        </template>
      `
    }
  })

  expect(wrapper.html()).toContain('Hello world')
})

当对槽内容使用字符串模板时,如果未使用封装 <template #scoped="scopeVar"> 标记显式定义,则在评估槽时,槽范围将作为 params 对象可用。

¥When using string templates for slot content, if not explicitly defined using a wrapping <template #scoped="scopeVar"> tag, slot scope becomes available as a params object when the slot is evaluated.

js
test('scoped slots', () => {
  const wrapper = mount(ComponentWithSlots, {
    slots: {
      scoped: `Hello {{ params.msg }}` // no wrapping template tag provided, slot scope exposed as "params"
    }
  })

  expect(wrapper.html()).toContain('Hello world')
})

结论

¥Conclusion

  • 使用 slots 挂载选项来测试使用 <slot> 的组件是否正确渲染内容。

    ¥Use the slots mounting option to test components using <slot> are rendering content correctly.

  • 内容可以是字符串、渲染函数或导入的 SFC。

    ¥Content can either be a string, a render function or an imported SFC.

  • 使用 default 作为默认插槽,并使用正确的名称作为命名插槽。

    ¥Use default for the default slot, and the correct name for a named slots.

  • 还支持作用域插槽和 # 简写。

    ¥scoped slots and the # shorthand is also supported.

Vue Test Utils 中文网 - 粤ICP备13048890号