何がしたいか
- Bootstrap の Dropdown コンポーネントを Vue-Component 化したい。
- Vue-Componentは Slot を用いつつ再利用したい。
dropdown.vue
<template>
<div class="dropdown" v-bind="$attrs">
<button
class="btn dropdown-toggle"
type="button"
data-bs-toggle="dropdown"
data-bs-display="static"
aria-expanded="false"
>
<slot name="open-button">
<i class="bi bi-three-dots-vertical"></i>
</slot>
</button>
<div
class="dropdown-menu"
:aria-labelledby="$attrs.id"
>
<!-- このスロットに置き換わるであろう要素に class="dropdown-item" を強制したい-->
<slot />
</div>
</div>
</template>
結論
- Vue-Component の
mounted()
で、cssを付けちゃう。
dropdown.vue
<template>
<!-- 省略 -->
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
name:"dropdown",
mounted(){
// this.$el は div.dropdown 要素
const menus = this.$el.querySelectorAll(".dropdown-menu");
menus.forEach((menu) => {
//css scope
const scopes = Object.keys(menu.dataset).filter((key) => key.match(/v-*/));
menu.querySelectorAll(":is(button, a)").forEach((item) => {
// css scope があれば継承
if(0 < scopes.length){
scopes.forEach((scope) => child.dataset[scope] = ""));
}
// class を追加
item.classList.add("dropdown-item");
});
});
}
});
</script>
使い方
App.vue
<template>
<Dropdown>
<!-- items -->
<a href="#">item A</a>
<button type="button">item B</button>
</Dropdown>
</template>
サンプル
参考