如何封装/包装一个 VueJS 组件?
Posted
技术标签:
【中文标题】如何封装/包装一个 VueJS 组件?【英文标题】:How to encapsulate / wrap a VueJS component? 【发布时间】:2018-07-26 05:06:27 【问题描述】:大家好,请原谅我的英语:-)
我有一个可以采用动态插槽的 Vue 组件(插槽的名称将取决于道具)。
我在几个地方使用它,并且一些插槽总是存在的。
为了避免冗余,我正在寻找一种方法来创建一个“包装”最终组件的组件,以允许我只定义附加插槽。
如果有一个“明显”的方法来实现它,我可能会错过它:-)
代码示例
没有“包装组件”
<b-table
show-empty
small
hover
[...some others and always present props...]
:items="aDataVarThatWillChangeBasedOnTheContext"
[...some others and uniq props...]
>
<template slot="same-1">
A slot that will always be present with the same content (for example, a checkbox in the first column)
</template>
<template slot="same-2">
A slot that will always be present with the same content (for example, some action buttons in the last column)
</template>
[...some others and always present slots...]
<template slot="not-the-same">
A slot that is only used in this context (for example, a duration based on a row timestamp and a timestamp picked by the user)
</template>
[...some others and uniq slots...]
</b-table>
带有“包装组件”
<my-b-table
:items="aDataVarThatWillChangeBasedOnTheContext"
>
<template slot="not-the-same">
A slot that is only used in this context (for example, a duration based on a row timestamp and a timestamp picked by the user)
</template>
</my-b-table>
注意:动态插槽名称不可预测。 如果我突然需要一个“foo”列,我应该能够传递一个“foo”插槽(在我的情况下是一个“HEAD_foo”插槽)
一些研究
我读到here:
它们(功能组件)作为包装组件也非常有用。例如,当您需要:
以编程方式选择其他几个组件之一来委派给 在将子组件、道具或数据传递给子组件之前对其进行操作
而且“在将子组件、道具或数据传递给子组件之前对其进行操作”似乎正是我所需要的。
我查看了渲染函数,但很多东西似乎没有实现,比如 v-model,我很难弄清楚如何传递动态插槽......
提前感谢您的回答!
up:在 07.03.2018 我仍然不知道如何解决这个案子
【问题讨论】:
【参考方案1】:找到了那个月前我还不清楚的答案。
(“动态”在这里的意思是“不是由组件明确声明,而是由父级给出”)
包装组件
props 和 scoped slots 可以由 createElement
函数的 options
对象动态提供。
“简单”插槽可以由createElement
函数的childs
数组动态给出。
包装组件
除非组件具有功能性,否则道具不能是动态的。
插槽始终可以动态检索。
只有在组件不起作用时才能检索作用域插槽。
结论
不可能同时拥有动态道具和作用域插槽...
但是可以声明所有需要的道具,然后使用“非功能性”组件作为包装器和包装器。
如何
从非功能组件中检索
var component = Vue.component('component-name',
props: ['name', 'of', 'the', 'props'],
// [...]
aMethod: function ()
this._props // all the declared props
this.$slots // all the slots
this.$scopedSlots // all the scoped slots
);
从功能组件中检索
var component = Vue.component('component-name',
functional: true,
render: function (createElement, context)
context.props // all the props
context.children // all the slots as an array
context.slots() // all the slots as an object
);
给子组件
var component = Vue.component('component-name',
render: function (createElement)
return createElement(
childComponent,
props: propsToGive,
scopedSlots: scopedSlotsToGive
,
[
// non-scoped slots to give
createElement('slot-tag-name', slot: 'slot-name')
]
);
);
参考文献
https://vuejs.org/v2/guide/render-function.html
https://vuejs.org/v2/guide/render-function.html#createElement-Arguments
https://vuejs.org/v2/guide/render-function.html#Functional-Components
沙盒
https://jsfiddle.net/5umk7p52/
【讨论】:
【参考方案2】:只需从您自定义的<b-table>
中制作一个常规组件即可。
您需要为您的组件定义一个items
属性,以作为<b-table>
组件的items
传递。
而且,要为您的组件定义slot
,您需要使用<slot>
标记,并使用name
属性指定名称。
如果您想让<b-table>
组件中的一个插槽可以在<my-b-table>
组件中访问,只需将<slot>
标记作为自定义组件中插槽的内容传递。
看起来像这样:
Vue.component('my-b-table',
template: `
<b-table
show-empty
small
hover
:items="items"
>
<template slot="same-1">
Content to pass to the b-table's slot
</template>
<slot name="not-the-same">
A slot that is only used in this context
</slot>
<template slot="last_edit">
<slot name="last_edit">
A slot to pass content to the b-table component's slot
</slot>
</template>
</b-table>
`,
props: items: Array ,
);
【讨论】:
遗憾的是,这并不简单:使用 b-table 组件,您可以使用插槽以特定方式显示特定列。例如:如果您有一个名为“last_edit”的列,您可以使用这样的插槽:``` ``` 因为它是一个“动态”插槽,所以我想将它们“交给”b-table 子组件 我不确定我是否遵循。您的意思是您希望该插槽也出现在您的<my-b-table>
组件中?
是的,我需要能够为 b-table 通过 my-b-table 提供一个插槽
困难在于我事先不知道要通过 my-b-table 组件的插槽名称,因为它们在每种用法中都会有所不同:<template slot="<I-dont-know-for-now>"> <slot name="<I-dont-know-for-now>"> A slot to pass content to the b-table component's slot </slot> </template>
也许书籍页面会显示一个日期,并且文章页面将显示价格,两个“页面组件”都应该能够使用 my-b-table 来避免显示复选框、id 和其他相同字段的冗余,并且都应该能够描述如何处理特定字段
您能否将您的所有要求添加为您的问题的编辑,我会尝试看看是否可以提出不同的答案?以上是关于如何封装/包装一个 VueJS 组件?的主要内容,如果未能解决你的问题,请参考以下文章