扩展Vue.js SFC组件

扩展Vue.js SFC组件,vue.js,vue-component,Vue.js,Vue Component,我还没有找到扩展Vue.js组件的好资源。在我参与的每个项目中,不管使用的是什么UI组件库,都有一些应用程序基础组件,它们扩展UI库组件以强制执行公司/应用程序默认值和标准 我正在尝试扩展Vue Multiselect:它有大约30个道具和12个插槽。我正在扩展的组件并不重要——我之所以提到它,是因为理想情况下,我不想在我的实现中重复30个道具和12个插槽 我只想对组件的行为进行两个更改: 使禁用道具更智能一点 Vue Multiselect组件有一个标准的禁用的道具,该道具按预期工作: <

我还没有找到扩展Vue.js组件的好资源。在我参与的每个项目中,不管使用的是什么UI组件库,都有一些应用程序基础组件,它们扩展UI库组件以强制执行公司/应用程序默认值和标准

我正在尝试扩展Vue Multiselect:它有大约30个道具和12个插槽。我正在扩展的组件并不重要——我之所以提到它,是因为理想情况下,我不想在我的实现中重复30个道具和12个插槽

我只想对组件的行为进行两个更改:

使
禁用
道具更智能一点

Vue Multiselect组件有一个标准的
禁用的
道具,该道具按预期工作:

<Multiselect :disabled="isDisabled" ...>

在我们的应用程序中,Vuex中有全局状态,用于确定应用程序是否为只读。我想要避免的是要求开发人员将此状态传递给每个表单字段:

<Multiselect :disabled="readOnly || isDisabled" ...>
<OtherComponent :disabled="readOnly || someOtherCondition" ...>
...

...
因此,my base component的用户只需关心影响禁用状态的本地UI状态:

<BaseCombo :disabled="!emailValid" ...>

这将处理90%的表单字段在应用程序为只读时被锁定的情况,对于我们希望忽略全局只读状态的情况,我可以使用额外的道具

<BaseCombo :disabled="!emailValid" :ignoreReadOnly="true" ...>


提供默认值

其次,我只想覆盖一些默认的prop值。这篇文章讨论了提供默认值的问题:

在我试图修改我前面提到的残疾人道具的行为之前,这是非常有效的


我试图解决这个问题的方法是包装或扩展组件。如果可能的话,我真的想避免重新说明所有的道具

<template>
  <Multiselect
    :disabled="myCustomDisabled"
    :value="value"
    @input="$emit('input', $event)"
    :options="options"
    :label="label"
    :track-by="trackBy"
    :placeholder="placeholder"
    ... repeat for all 30 options

<script>
import Multiselect from 'vue-multiselect'

export default {
  name: "BaseCombo",
  extends: Multiselect, // extend or simply wrap?
  computed: {
    myCustomDisabled() {
      this.props.disabled || ... use disabled from Vuex state
    }
  },
  props: {
    disabled: Boolean,
    placeholder: {
      type: String,
      default: 'My Default Value',
    },
  ... repeat for all props


您可以使用
this.$props
访问props属性中定义的道具。同样,您可以使用
this.$attrs
访问属性(您没有定义为道具的东西)。最后,您可以使用
v-bind=“someVariable”
绑定道具

如果将这些结合起来,您可以执行以下操作:

<!-- App.vue -->
<template>
  <component-a msg="Hello world" :fancy="{ test: 1 }" />
</template>


导出默认值{
名称:“组件A”
}

{{msg}}
{{fancy}
导出默认值{
道具:{
msg:String,
幻想:对象
},
挂载(){
console.log(这是$props);
}
}

在本例中,组件B将是您尝试扩展的组件。

您可以使用
this.$props
访问props属性中定义的props。同样,您可以使用
this.$attrs
访问属性(您没有定义为道具的东西)。最后,您可以使用
v-bind=“someVariable”
绑定道具

如果将这些结合起来,您可以执行以下操作:

<!-- App.vue -->
<template>
  <component-a msg="Hello world" :fancy="{ test: 1 }" />
</template>


导出默认值{
名称:“组件A”
}

{{msg}}
{{fancy}
导出默认值{
道具:{
msg:String,
幻想:对象
},
挂载(){
console.log(这是$props);
}
}

在本例中,组件B将是您尝试扩展的组件。

以下是一个基于Sumurai8的答案和motia的评论的完整示例

<template>
  <Multiselect v-bind="childProps" v-on="$listeners">
    <slot v-for="(_, name) in $slots" :name="name" :slot="name" />
    <template v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData">
      <slot :name="name" v-bind="slotData" />
    </template>
  </Multiselect>
</template>

<script>
  import Multiselect from 'vue-multiselect'

  export default {
    name: "BaseCombo",
    props: {
      placeholder: {
        type: String,
        default: 'This is my default',
      },
      disabled: {
        type: Boolean,
        default: false,
      },
    },
    components: {
      Multiselect,
    },
    computed: {
      childProps() {
        return { ...this.$props, ...this.$attrs, disabled: this.isDisabled };
      },
      appReadOnly() {
        return this.$store.state.appReadOnly;
      },
      isDisabled() {
        return this.disabled || this.appReadOnly;
      }
    },
  }
</script>

从“vue Multiselect”导入Multiselect
导出默认值{
名称:“BaseCombo”,
道具:{
占位符:{
类型:字符串,
默认值:“这是我的默认值”,
},
残疾人士:{
类型:布尔型,
默认值:false,
},
},
组成部分:{
多选,
},
计算:{
儿童道具(){
返回{…this.$props,…this.$attrs,disabled:this.isDisabled};
},
appReadOnly(){
返回此。$store.state.appReadOnly;
},
isDisabled(){
返回this.disabled | | this.appReadOnly;
}
},
}

以下是一个基于Sumurai8答案和motia评论的完整示例

<template>
  <Multiselect v-bind="childProps" v-on="$listeners">
    <slot v-for="(_, name) in $slots" :name="name" :slot="name" />
    <template v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData">
      <slot :name="name" v-bind="slotData" />
    </template>
  </Multiselect>
</template>

<script>
  import Multiselect from 'vue-multiselect'

  export default {
    name: "BaseCombo",
    props: {
      placeholder: {
        type: String,
        default: 'This is my default',
      },
      disabled: {
        type: Boolean,
        default: false,
      },
    },
    components: {
      Multiselect,
    },
    computed: {
      childProps() {
        return { ...this.$props, ...this.$attrs, disabled: this.isDisabled };
      },
      appReadOnly() {
        return this.$store.state.appReadOnly;
      },
      isDisabled() {
        return this.disabled || this.appReadOnly;
      }
    },
  }
</script>

从“vue Multiselect”导入Multiselect
导出默认值{
名称:“BaseCombo”,
道具:{
占位符:{
类型:字符串,
默认值:“这是我的默认值”,
},
残疾人士:{
类型:布尔型,
默认值:false,
},
},
组成部分:{
多选,
},
计算:{
儿童道具(){
返回{…this.$props,…this.$attrs,disabled:this.isDisabled};
},
appReadOnly(){
返回此。$store.state.appReadOnly;
},
isDisabled(){
返回this.disabled | | this.appReadOnly;
}
},
}

谢谢。如果组件B有插槽呢?Multiselect组件有12个插槽。除了现在的
this.$slots
之外,其他都是相同的想法。我不久前在“谢谢”上写了一个关于这个问题的答案,它似乎工作得很好。我借用了这个要点中的scopedSlot示例,它与您的帖子类似:@nogridbag,我认为您还需要公开Mulitselect发出的事件。谢谢。我贴出了一个答案,看起来很有效。我相信唯一剩下的事情就是像你说的那样揭露剩下的事件。谢谢。如果组件B有插槽呢?Multiselect组件有12个插槽。除了现在的
this.$slots
之外,其他都是相同的想法。我不久前在“谢谢”上写了一个关于这个问题的答案,它似乎工作得很好。我借用了这个要点中的scopedSlot示例,它与您的帖子类似:@nogridbag,我认为您还需要公开Mulitselect发出的事件。谢谢。我贴出了一个答案,看起来很有效。我相信剩下的事情就是像你说的那样公开剩下的事件。当使用
扩展:Multiselect时,你不需要
。。。对所有道具重复此操作
,因为扩展中给出的道具与原始道具合并。模板更改确实需要重复所有属性,但对于您的场景,您可能不必触摸模板(只需在扩展组件中忽略它)。相反,你可能会成功