如何使用 Vue 命名插槽呈现静态内容列表?

Posted

技术标签:

【中文标题】如何使用 Vue 命名插槽呈现静态内容列表?【英文标题】:How to render a list of static content with Vue named slot? 【发布时间】:2018-08-05 02:53:21 【问题描述】:

我无法弄清楚如何让以下工作:

我的父模板

<comp>
  <a href="#" slot="links">link 1</a>
  <a href="#" slot="links">link 2</a>
</comp>

我的组件comp 模板如下所示:

<ul class="comp">
  <li class="comp-item"><slot name="links"></slot></li>
</ul>

目前我所有的锚点都指向那个 li 标签(这是预期的) 但我希望能够为我插入的每个命名插槽生成多个li,如下所示:

<ul class="comp">
  <li class="comp-item"><a href="#" slot="links">link 1</a></li>
  <li class="comp-item"><a href="#" slot="links">link 2</a></li>
</ul>

有什么方法可以在不使用作用域插槽的情况下实现我的需要?因为我的内容是纯 html,所以我觉得没有必要将静态内容放在 prop 中以呈现它们。

据我所知,大多数 vue UI 框架都要求您为列表项使用另一个自定义组件,我觉得这个问题已经过时了。有没有其他方法可以做到这一点?

【问题讨论】:

【参考方案1】:

如果您不喜欢将数据放入数组中,并使用v-for 呈现列表

你可以将它们全部放在组件中,没有插槽:

<ul class="comp">
  <li class="comp-item"><a href="#">link 1</a></li>
  <li class="comp-item"><a href="#">link 2</a></li>
</ul>

或带槽:

<comp>
  <ul class="comp" slot="links">
    <li class="comp-item"><a href="#">link 1</a></li>
    <li class="comp-item"><a href="#">link 2</a></li>
  </ul>
</comp>

【讨论】:

对于第一个解决方案,它不适合我的情况,因为我在不同情况下可能有不同的列表项。对于第二种解决方案,我的开槽 HTML 将需要知道组件所需的样式类是什么,我认为这不是非常模块化。【参考方案2】:

这可以通过渲染函数轻松完成。

Vue.component("comp", 
  render(h)
    let links = this.$slots.links.map(l => h('li', class: "comp-item", [l]))
    return h('ul', class: 'comp', links)
  
)

这是一个工作示例。

console.clear()

Vue.component("comp", 
  render(h)
    let links = this.$slots.links.map(l => h('li', class: "comp-item", [l]))
    return h('ul', class: 'comp', links)
  
)

new Vue(
  el: "#app"
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <comp>
    <a href="#" slot="links">link 1</a>
    <a href="#" slot="links">link 2</a>
  </comp>
</div>

或者借助一个用于渲染 vNode 的小型实用程序组件,您可以使用模板来执行此操作。

Vue.component("vnode", 
  functional: true,
  render(h, context)
    return context.props.node
  
)

Vue.component("comp", 
  template: `
    <ul class="comp">
      <li class="comp-item" v-for="link in $slots.links"><vnode :node="link" /></li>
    </ul>
  `
)

new Vue(
  el: "#app"
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <comp>
    <a href="#" slot="links">link 1</a>
    <a href="#" slot="links">link 2</a>
  </comp>
</div>

【讨论】:

谢谢! vnode 解决方案看起来很有趣,正是我所需要的,我不知道这种技术! 你也可以使用作用域槽,对吗?.. 对于这个特定的用例,渲染函数比作用域槽有什么优势:-) @VamsiKrishna 问题的前提是提供的链接不在数据中,而是“静态”(在插槽中硬编码)。所以,不,在这种情况下,我认为作用域插槽不会为您做任何事情。 @Bert 好的,你是对的......但仍然更新了我的答案以使用静态选项而不是将链接放在数据选项中【参考方案3】:

您可以使用scoped slots 代替插槽

你的comp 组件接收到一个属性links,它是一个链接数组(因为静态初始化为custom option)。遍历 links 并将 link 作为数据传递给插槽,就像将 props 传递给组件一样

   Vue.component("comp", 
  template: `
    <ul class="comp">
      <li class="comp-item" v-for="link in links">
          <slot v-bind="link"></slot>
      </li>
    </ul>
  `,
  props: ["links"]
)

new Vue(
  el: "#app",
  // custom static option , accessed using vm.$options.links
  links: [
      text: "link1",
      text: "link2",
      text: "lin3"
  ]
)

在使用 comp 组件的父级中,使用具有特殊属性 slot-scope&lt;template&gt; 元素,表明它是作用域插槽的模板。

slot-scope 的值将用作一个临时变量的名称,该变量保存从子传递的 props 对象:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <comp :links="$options.links">
      <template slot-scope="link">
          <a href="#">link.text</a>
      </template>
  </comp>
</div>

这里是working fiddle

【讨论】:

我发现插槽范围之外的两个链接没有在演示中呈现 @Stvyu 哦......他们被错误地添加到那里......正如我评论伯特的回答,他的回答会更有活力。要了解更多为什么您可以查看:adamwathan.me/renderless-components-in-vuejs/…

以上是关于如何使用 Vue 命名插槽呈现静态内容列表?的主要内容,如果未能解决你的问题,请参考以下文章

将动态插槽从父级传递到子级到孙子级

VUE-插槽slot

VUE-插槽slot

Vue.js 插槽 - 如何在计算属性中检索插槽内容

如何正确使用 vue js Web 组件内部的插槽并应用样式

如何在混合 VueJS 应用程序上使用(命名)插槽