vuedose.tips(系列翻译七)
Create an ImageSelect component on top of vue-multiselect
在学习自适应组件的概念之前,有两个技巧,以及如何通过使用v-bind和v-on代理 props 和 events 来建立其基础。
现在是时候展示它了。 您有任何机会了解vue-multiselect吗? 这是Damian Dulisz构建的出色选择组件。 鉴于vue-multiselect的灵活性和可定制性,它可以以多种不同方式使用。 实际上,这是一种很好的第三方组件,以便可以重复使用。
根据其文档中的示例,我们构建一个ImageSelect组件。为此,该示例重新定义了vue-multiselect公开的一些作用域插槽:
Now it’s time to show it in action. By any chance, do you know aboutvue-multiselect? It’s an amazing select component built byDamian Dulisz. vue-multiselect can be used in many different ways given how flexible and customisable it is. That’s really how a fine third-party component should be in order to be reusable.
Based onthis examplefrom its documentation, let’s build an ImageSelect component. To do that, the example redefines some scoped slots that vue-multiselect exposes:
<multiselect v-model="value" :options="options">
<template slot="singleLabel" slot-scope="{ option }">
<img class="option__image" :src="option.img" alt="Sth" />
<span class="option__desc">
<span class="option__title">{{ option.title }}</span>
</span>
</template>
<template slot="option" slot-scope="{ option }">
<img class="option__image" :src="option.img" alt="Sth" />
<span class="option__desc">
<span class="option__title">{{ option.title }}</span>
<span class="option__small">{{ option.desc }}</span>
</span>
</template>
</multiselect>
我不会进入作用域插槽,只是假设代码可以正常工作,以防您不了解它们。这里的事情是我想在该代码之上构建一个ImageSelect组件。
从上一个技巧开始,您可能已经知道您需要使用v-bind =“ listeners”才能使对 props 和 events 的代理发生。
您还需要从原始的vue-multiselect组件中重新声明 propd,并且可以从其源代码的MultiselectMixin中获取它们:
<template>
<multiselect v-bind="$props" v-on="$listeners">
<template slot="singleLabel" slot-scope="{ option }">
<img class="option__image" :src="option.img" alt="No Man’s Sky" />
<span class="option__desc">
<span class="option__title">{{ option.title }}</span>
</span>
</template>
<template slot="option" slot-scope="{ option }">
<img class="option__image" :src="option.img" alt="No Man’s Sky" />
<span class="option__desc">
<span class="option__title">{{ option.title }}</span>
<span class="option__small">{{ option.desc }}</span>
</span>
</template>
</multiselect>
</template>
<script>
import Multiselect from "vue-multiselect";
import MultiselectMixin from "vue-multiselect/src/multiselectMixin";
export default {
components: {
Multiselect
},
props: MultiselectMixin.props
};
</script>
下面介绍了如何使用此ImageSelect组件,并传递最少的属性以使其正常工作
<template>
<ImageSelect
v-model="imageValue"
:options="imageOptions"
label="title"
track-by="title"
:show-labels="false"
/>
</template>
<script>
import ImageSelect from "./ImageSelect";
export default {
components: {
ImageSelect
},
data: () => ({
imageValue: null,
imageOptions: [
{ title: "Random img", img: "https://picsum.photos/300/150" },
{ title: "Cool image", img: "https://picsum.photos/300/151" }
]
})
};
</script>
如果运行此代码,您会发现有些东西无法正常工作。特别是show-labels属性。事实是,这不是 props,而是 attrs!并且可以通过$ attrs组件实例选项进行访问。
基本上,我们不仅需要代理 props,还需要代理 attrs 以使其工作。
为此,我将使用计算属性将 attrs合并到同一对象中:
<template>
<multiselect v-bind="allBindings" v-on="$listeners">
<!-- ... -->
</multiselect>
</template>
<script>
import Multiselect from "vue-multiselect";
import MultiselectMixin from "vue-multiselect/src/multiselectMixin";
export default {
components: {
Multiselect
},
props: MultiselectMixin.props,
computed: {
allBindings() {
// Need to proxify both props and attrs, for example for showLabels
return { ...this.$props, ...this.$attrs };
}
}
};
</script>
You can try yourself and run the code on this Codesandbox example I’ve prepared for you. You’ll see it has some additional Adaptive Components, such as SingleSelect and MultiSelect.
Pss: they have some CSS tricks we’ll cover on the next tips