【譯】Vue 的小奇技(第七篇):在 vue-multiselect 基礎上建立 ImageSelect 元件

程式猿何大叔發表於2019-02-27

特別宣告:本文是作者 Alex Jover 釋出在 VueDose 上的一個系列。

版權歸作者所有。

譯者在翻譯前已經和作者溝通得到了翻譯整個系列的授權。

為了不影響大家閱讀,獲得授權的記錄會放在本文的最後。

第五篇文章 中,兩條 tips 讓你學習到了自適應元件的概念,以及怎麼通過使用 v-bindv-on 來代理 props 和 events,繼而建立自適應元件。

現在是時候實踐一下了。在此之前,要問一下,你知道 vue-multiselect 這個第三方庫嗎?這是一個很棒的,由 Damian Dulisz 寫的選擇器元件。因為其靈活和可自定義的特性,它適用於多種場景。

基於該元件文件中的 這個例子,我們一起來寫一個 ImageSelect 元件。在此,我們重新定義了一些 vue-multiselect 暴露的作用域插槽:

<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="$props"v-on="$listeners" 去代理 props 和 events。

因此現在你要重新宣告 props 來自於原始的 vue-multiselect 元件,你可以在該元件原始碼中的 MultiselectMixin 找到這些 props:

<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 這個 prop,然而事實上它現在還不是一個 prop,而僅是一個 attribute,並且他們可以在元件例項屬性中被訪問到。

為了修復這個問題,我要用一個計算屬性來合併 props 和 attributes:

<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>
複製程式碼

你可以在我為你準備的 這個 sandbox 上執行一下,你將會看到另外的一些自適應元件,比如像 SingleSelectMultiSelect

Pss: 它們其中有一些 css 的技巧,我們在下一節會講到。

你可以線上閱讀這篇 原文,裡面有可供複製貼上的原始碼。如果你喜歡這個系列的話,請分享給你的同事們!

結語

此係列的其他文章,會同步系列官網的釋出情況,及時地翻譯釋出到掘金。請持續關注「程式猿何大叔」,相信我會給大家帶來更多優質的內容,不要忘了點贊~

如果想要了解譯者的更多,請查閱如下:

請求翻譯授權記錄

請求翻譯授權記錄

微信公眾號
覺得本文不錯的話,分享一下給小夥伴吧~

相關文章