Vue.js 你需要知道的 scopedSlots

gongph發表於2019-02-19

面試官:Vue如何在 Jsx 中使用 scopedSlots ?

自己先想一分鐘。

Vue.js 你需要知道的 scopedSlots

早先我在 Vue.js 你不知道的一些小技巧 一文中簡單介紹過 scopedSlots 的使用場景,但不是很詳細。群裡也有好多同學問關於 scopedSlots 如何使用,當然自己也有點小生疏。今天藉此機會重新梳理下,以便日後學習之用。文筆有限,有不對或闡述有誤的地方希望留言斧正!

誰可以看?

本文針對有下面情況的同學:

  • 經常使用 Render 函式 和 Jsx 語法開發元件的同學
  • 基礎薄弱想進一步提升的同學

你會學到什麼?

  • ScopedSlots 的使用

和 slot-scope 的區別?

下面的區別僅僅代表個人理解:

  • 作用相同:都是作用域插槽
  • 場景不同:slot-scope 是模板語法,scopedSlots 則是程式設計式語法
  • 使用不同:在 <template> 中使用 slot-scope,在 render() 函式中使用 scopedSlots

Tips: 歡迎留言補充~

在渲染函式中如何使用?

假設我們有一個叫 <base-layout> 的元件,它的模板內容如下:

<div class="child-node">
  <slot name="header" :text="headerText"></slot>
  <slot :text="defaultText"></slot>
  <slot name="footer" :text="footerText"></slot>
</div>
複製程式碼

可以看到,div#child-node 容器中有三個插槽,分別是 header, default, footer。正常情況下我們會用一個塊級標籤分別把他們包裹,這裡為了簡單起見我沒有這麼做。接下來我們在渲染函式(render)中重構上面的程式碼:

<script>
export default {
  data() {
    return {
      headerText: "child header text",
      defaultText: "child default text",
      footerText: "child footer text"
    };
  },
  render(h) {
    return h("div", { class: "child-node" }, [
      // 相當於 <slot name="header" :text="headerText"></slot>
      this.$scopedSlots.header({ text: this.headerText }),
      // 相當於 <slot :text="defaultText"></slot>
      this.$scopedSlots.default(this.defaultText),
      this.$scopedSlots.footer({ text: this.footerText })
    ]);
  }
};
</script>
複製程式碼

假設我們有一個叫 <scoped-slots> 的父元件。按照模板語法的定義,我們可以使用 slot-scope 或者 v-slot 獲取插值內容,從而達到自定義內容的效果,這裡我們使用 Vue@2.6.x 提供的最新語法 v-slot 的簡寫形式,來演示一下如何在父元件中使用:

<div class="parent-node">
  parent content
  <base-layout>
    <template #header="{ text }">
      <p style="color: red">{{ text }}</p>
    </template>
    <template #default="text">
      <!-- 預設內容是個字串直接輸出 -->
      <p style="color: deeppink">{{ slotProp }}</p>
    </template>
    <template #footer="{ text }">
      <p style="color: orange">{{ text }}</p>
    </template>
  </base-layout>
</div>
複製程式碼

上面程式碼輸出的結果是:

Vue.js 你需要知道的 scopedSlots

以上只是模板語法的寫法,接下來我們在渲染函式(render)中利用 scopedSlots 屬性重構上面的程式碼:

<script>
import BaseLayout from "./base-layout.vue";
export default {
  name: "ScopedSlots",
  components: {
    BaseLayout
  },
  render(h) {
    return h("div", { class: "parent-node" }, [
      this.$slots.default,
      h("base-layout", {
        scopedSlots: {
          // 相當於下面程式碼:
          // <template #header="props">
          //   <p style="color:red">
          //     {{ props.text }}
          //   </p>
          // <template>
          header: props => {
            return h("p", { style: { color: "red" } }, [props.text]);
          },
          default: props => {
            return h("p", { style: { color: "deeppink" } }, [props]);
          },
          footer: props => {
            return h("p", { style: { color: "orange" } }, [props.text]);
          }
        }
      })
    ]);
  }
};
</script>
複製程式碼

同樣的,上面程式碼的輸出結果是:

Vue.js 你需要知道的 scopedSlots

以上就是我要講的 scopedSlots 在 Render 函式中的用法了,你可以狠狠的戳這裡檢視沙箱中的示例。大家不妨跟著 demo 自己敲一遍體會後自然明白。

在 Jsx 中如何使用?

我們知道,Vue中的大部分語法在 Jsx 中的寫法是不一樣的,具體看這裡,本文不再贅述。但文件中並沒有介紹 scopedSlots 的用法,今天我們來看下如何使用。

使用之前我們需要安裝解析 Jsx 語法相關的外掛:

npm install\
  babel-plugin-syntax-jsx\
  babel-plugin-transform-vue-jsx\
  babel-helper-vue-jsx-merge-props\
  babel-preset-env\
  --save-dev
複製程式碼

接著配置 .babelrc 檔案:

{
  "presets": ["env"],
  "plugins": ["transform-vue-jsx"]
}
複製程式碼

最後我們使用 Jsx 語法重構上面 render 函式中的程式碼:

<script>
import BaseLayout from "./base-layout.vue";
export default {
  name: "ScopedSlots",
  render() {
    return (
      <div class="parent-node">
        parent content
        <BaseLayout
          {...{
            scopedSlots: {
              header: props => {
                return <p style={{ color: "red" }}>{props.text}</p>;
              },
              default: props => {
                return <p style={{ color: "deeppink" }}>{props}</p>;
              },
              footer: props => {
                return <p style={{ color: "orange" }}>{props.text}</p>;
              }
            }
          }}
        />
      </div>
    );
  }
};
</script>
複製程式碼

上面程式碼的輸出結果是:

Vue.js 你需要知道的 scopedSlots

你會發現跟 render 函式相比起來還是有些不同的:

以上就是我要講的 scopedSlots 在 Jsx 中的用法了,你可以狠狠的戳這裡檢視沙箱中的示例。同樣的大家不妨跟著 demo 自己敲一遍體會後自然就明白了。

參考

結尾!

囉嗦了這麼多,希望看到的同學或多或少有點收穫吧。不對的地方還請留言指正,不勝感激。俗話說,三人行則必有我師! 希望更多熱衷於 Vue 的小夥伴能聚在一起交流技術!下面是我維護的一個Q群,歡迎掃碼進群哦,讓我們一起交流學習吧。也可以加我個人微信:G911214255 ,備註 掘金 即可。

Q1769617251

相關文章