首頁 >web前端 >Vue.js >Vue3 Composition API怎麼優雅封裝第三方元件

Vue3 Composition API怎麼優雅封裝第三方元件

WBOY
WBOY轉載
2023-05-11 19:13:091655瀏覽

前言

對於第三方元件,如何在保持第三方元件原始功能(屬性props、事件events、插槽slots、方法methods)的基礎上,優雅地進行功能的擴充了?

以Element Plus的el-input為例:

很有可能你以前是這樣玩的,封裝一個MyInput元件,把要使用的屬性props、事件events和插槽slots 、方法methods根據自己的需要再寫一遍:

// MyInput.vue
<template>
  <div class="my-input">
    <el-input v-model="inputVal" :clearable="clearable" @clear="clear">
    <template #prefix>
      <slot name="prefix"></slot>
    </template>
      <template #suffix>
      <slot name="suffix"></slot>
    </template>
    </el-input>
  </div>
</template>
<script setup>
import { computed } from &#39;vue&#39;
const props = defineProps({
  modelValue: {
    type: String,
    default: &#39;&#39;
  },
  clearable: {
    type: Boolean,
    default: false
  }
})
const emits = defineEmits([&#39;update:modelValue&#39;, &#39;clear&#39;])
const inputVal = computed({
  get: () => props.modelValue,
  set: (val) => {
    emits(&#39;update:modelValue&#39;, val)
  }
})
const clear = () => {
  emits(&#39;clear&#39;)
}
</script>

可過一段時間後,需求變更,又要在MyInput組件上添加el-input組件的其它功能,可el-input組件總共有20個多屬性,5個事件,4個插槽,那該怎麼辦呢,難道一個個傳進去,這樣不僅繁瑣而且可讀性差。

在Vue2中,我們可以這樣處理,點擊這裡查看封裝Vue第三方組件

此文詣在幫助大家做一個知識的遷移,探究如何使用Vue3 CompositionAPI優雅地封裝第三方元件~

一、對於第三方元件的屬性props、事件events

在Vue2中

  • $attrs: 包含了父作用域中不作為prop 被識別(且獲取) 的attribute 綁定(class 和style 除外)。當一個元件沒有宣告任何prop 時,這裡會包含所有父作用域的綁定(class 和style 除外),並且可以透過v-bind="$attrs" 傳入內部元件

  • ##$listeners:包含了父作用域中的(不含 .native 修飾器的) v-on 事件監聽器。它可以透過 v-on="$listeners" 傳入內部元件

#而在Vue3中

    ##$attrs:包含了父作用域中不作為元件 props 或自訂事件的attribute 綁定和事件(包括 class 和 style和自訂事件),同時可以透過v-bind="$attrs" 傳入內部元件。
  • $listeners 物件在 Vue 3 中已移除。事件監聽器現在是 $attrs 的一部分。
  • 在 5101c0cdbdc49998c642c71f6b6410a8中輔助函數useAttrs可以取得到$attrs。
  • //MyInput.vue 
    <template>
      <div class="my-input">
        <el-input v-bind="attrs"></el-input>
      </div>
    </template>
    <script setup>
    import { useAttrs } from &#39;vue&#39;
    const attrs = useAttrs()
    </script>
  • 當然,這樣還不夠。光這樣寫,我們綁定的屬性(包括 class 和 style)同時會在根元素(上面的例子是class="my-input"的Dom節點)上運作。要阻止這個預設行為,我們需要設定inheritAttrs為false。

下面我們來看看Vue3文件對inheritAttrs的解釋

預設情況下父作用域的不被認定props 的attribute 綁定(attribute bindings) 將會「回退」且作為普通的HTML attribute 應用在子元件的根元素上。當撰寫包裹一個目標元素或另一個元件的元件時,這可能不會總是符合預期行為。透過設定 inheritAttrs 到 false,這些預設行為將會被去掉。而透過實例 property $attrs 可以讓這些 attribute 生效,且可以透過 v-bind 顯性的綁定到非根元素上。

於是,我們對於第三方元件的屬性props、事件events處理,可以寫成如下程式碼:

// MyInput.vue 
<template>
  <div class="my-input">
    <el-input v-bind="attrs"></el-input>
  </div>
</template>
<script>
export default {
  name: &#39;MyInput&#39;,
  inheritAttrs: false
}
</script>
<script setup>
import { useAttrs } from &#39;vue&#39;
const attrs = useAttrs()
</script>

二、對於第三方元件的插槽slots

Vue3中

    $slots:我們可以透過其拿到父元件傳入的插槽
  • Vue3中移除了$scopedSlots,所有插槽都透過 $slots 作為函數來揭露
  • 在 5101c0cdbdc49998c642c71f6b6410a8中輔助函數useSlots可以取得到$slots。
  • 基於以上幾點,如果我們對於第三方元件的封裝沒有增加額外的插槽,且第三方元件的插槽處於同一個dom節點之中,我們也有一種取巧的封裝方式????, 透過遍歷$slots拿到插槽的name,動態添加子組件的插槽:
//MyInput.vue 
<template>
  <div class="my-input">
    <el-input v-bind="attrs">
      <template v-for="k in Object.keys(slots)" #[k] :key="k">
        <slot :name="k"></slot>
      </template>
    </el-input>
  </div>
</template>
<script>
export default {
  name: &#39;MyInput&#39;,
  inheritAttrs: false
}
</script>
<script setup>
import { useAttrs, useSlots } from &#39;vue&#39;
const attrs = useAttrs()
const slots = useSlots()
</script>

如果不滿足以上條件的話,咱還得老實在子元件中手動新增需要的第三方元件的插槽~

三、對於第三方元件的方法methods

對於第三方元件的方法,我們透過ref來實作。首先在MyInput元件中的el-input元件上加入一個ref="elInputRef"屬性,然後透過defineExpose把elInputRef暴露出去給父元件呼叫。

子元件:MyInput.vue

// MyInput.vue 
<template>
  <div class="my-input">
    <el-input v-bind="attrs" ref="elInputRef">
      <template v-for="k in Object.keys(slots)" #[k] :key="k">
        <slot :name="k"></slot>
      </template>
    </el-input>
  </div>
</template>
<script>
export default {
  name: &#39;MyInput&#39;,
  inheritAttrs: false
}
</script>
<script setup>
import { useAttrs, useSlots } from &#39;vue&#39;
const attrs = useAttrs()
const slots = useSlots()
const elInputRef = ref(null)
defineExpose({
  elInputRef  // <script setup>的组件里的属性默认是关闭的,需通过defineExpose暴露出去才能被调用
})
</script>

父親頁面:Index.vue的呼叫程式碼如下:

// Index.vue 
<template>
  <my-input v-model=&#39;input&#39; ref="myInput">
    <template #prefix>姓名</template>
  </my-input>
</template>
<script setup>
import MyInput from &#39;./components/MyInput.vue&#39;
import { ref, onMounted } from &#39;vue&#39;
const input = ref(&#39;&#39;)
const myInput = ref(null) // 组件实例
onMounted(()=> {
  myInput.value.elInputRef.focus() // 初始化时调用elInputRef实例的focus方法
})
</script>

以上是Vue3 Composition API怎麼優雅封裝第三方元件的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除