VueのSFCでのCSSの命名について以前書いた。
nakajmg.hatenablog.com
このSFCSSをやってくうえでクラス名を記述するのをなんとか楽できないか考えた。
この記事はその試行錯誤の軌跡である。
はじめに結論
コンポーネントのname
からクラス名を付与するディレクティブを作ってプラグインをnpmに公開したが、最終的には普通にせっせと書くのが一番ベターなのでは?というところに辿りついたというお話。
めんどくさポイント
命名規則によって命名の手間は減ったが、class
をフルで記述する必要があって変わらずめんどうだった。
<template>
<div class="MyComponent">
<h1 class="MyComponent_Heading">
heading
</h1>
</div>
</template>
<script>
export default {
name: 'MyComponent',
}
</script>
<style lang="scss" scoped>
.MyComponent {
&Heading {}
}
</style>
name
をtemplate
で参照してなんとか楽をできないかと考えた。
コンポーネントのname
につけた名前は、$options._componentTag
で参照できるので、:class
を使って次のように書ける
<template>
<div :class="[$options._componentTag]">
<h1 :class="[`${$options._componentTag}_Heading`]">
heading
</h1>
</div>
</template>
が、かなりめんどうだしむしろ手間が増えてるような…🙄
methodsに定義してmixinとか…?
じゃあクラス名を返すメソッドを定義してヘルパーっぽく。mixinにすれば共通化できるし…
<template>
<div :class="[className()]">
<h1 :class="[className('_Heading')]">
heading
</h1>
</div>
</template>
<script>
export default {
name: 'MyComponent',
methods: {
className(childNode = '') {
return `${this.$options._componentTag}${childNode}`
}
}
}
</script>
うーん微妙。:class="[className()]"
とか毎回書くのだるそう
ならばディレクティブだ
ディレクティブにしたらまだマシになりそう
<template>
<div v-class-name>
<h1 v-class-name="'_Heading'">
heading
</h1>
</div>
</template>
<script>
function bindClassName(el, binding, vnode) {
const componentName = vnode.context.$options._componentTag
const className = `${componentName}${binding.value || ''}`
if (el.className.indexOf(className) !== -1) return
el.className = `${className}${el.className ? ' ' + el.className :''}`
}
export default {
name: 'MyComponent',
directives: {
className: {
bind: bindClassName,
update: bindClassName,
inserted: bindClassName,
}
}
}
</script>
ディレクティブに文字列として渡さないといけなくて"'_Heading'"
としないとならないのが癪に障るけど、それっぽさは出てる。
これがレンダリングされるとこうなる。
<div class="MyComponent">
<h1 class="MyComponent_Heading">
heading
</h1>
</div>
vue-class-nameプラグインとしてpublish
👆のやつをプラグインにしてnpmにpublishした。
www.npmjs.com
使い方
インストール
npm i vue-class-name
import vClassName from 'v-class-name'
import Vue from 'vue'
Vue.use(vClassName)
<template>
<div v-class-name>
<h1 v-class-name="'_Heading'">
heading
</h1>
<div>
</template>
<script>
export default {
name: 'MyComponent',
}
</script>
:class
での動的なクラスの切り替えと親コンポーネントからのclass
のマージについては動作確認済み。
おわりに
なんとかならんかと試して、最終的にプラグインとして公開してみたものの、処理の内容的にどこかしらパフォーマンスに影響でそうで微妙だから自分で使わなそう🤔
宣言的に書くのがtemplate
の良いところだと思うので、めんどくさくてもCSSのクラス名は静的に書くのがベターなのではと思った。
おしまい