As this QA mentioned, we can make a variable play as a class name in less.
but how to make that in vue?
<script setup>
const uuid = 'data-v-123'
</script>
<style lang="less">
@dynamicVar: xxxx; // how to pass uuid as a less variable?
.@{dynamicVar} {
color: red;
}
// Or, how to pass a vue variable as a class name?
.[dynamicVar] { // this is the placement I want to inject
color: red;
}
</style>
Here I have a Popover Component which is being used in every table cloumn:
I want to make a random string complied as a CSS class name in Vue3 (Vite).
In vue, we can get the component's scope id via Vue's API getCurrentInstance().type.__scopeId, so here is the consensus: the scope id is a unique string, every component have a scope id and difference from others.
So, we can use the scope id as a unique class name for the component, so we have applied it to the component's class list.
But there is a problem: how to define the styles for this unique class name?
We know it is dynamic,
and it is unknown to write as a certain string into the <style></style> sheet,
until Vite build the code.
here is demo for ElementUi's ElTooltip component. The uuid variable is the thing I want to use as a class name.
You can see, there is a way we can use v-bind:uuid="''", apply the unique calss name as html dataset attribute,
<template>
<el-table :[uuid]="''">
</el-table>
</template>
<script setup>
const uuid = 'data-123'
</script >
<style scoped>
.el-table:deep { // :deep is the scopeId
background-color: red !important
}
</style>
Vite will complied this into:
<div class="el-table" data-123>
</div>
<style>
.el-table[data-v-123]{
background-color: red !important
}
</style>
But this can't use to ElTooltip, first, you can't use scoped for the style, cause the tooltip component is applied into the body.
Second, the dataset won't be applied into html dataset attribute in this case, perhaps ElementUi filtered it. you can see this in the demo.
So there is only one fantasy left, which is to let Vite compile this variable into a class name.
Well, there is a way to doing this, but not very close to the original thought, that's Vue's module CSS:
<template>
<el-table :class="[{$styles.table}]">
</el-table>
</template>
<style module>
.table{
background-color: red !important
}
</style>
Vite will complied this into:
<div class="_table_1ok_2">
</div>
<style>
._table_1ok_2{ // somethins like this, just for demo
background-color: red !important
}
</style>
Wow, is that the exact what we want? well, sit down. When there are nested styles we need to define:
<template>
<el-tooltip :popper-class="{$styles.table}">
<div class="text-wrapper">
<span class="text-inner">
</span>
</div>
</el-tooltip>
</template>
<style module>
.el-tooltip{
background-color: red !important
.text-wrapper {
border: 1px solid yellow;
.text-inner {
font-size: 24px;
}
}
}
</style>
Vite will complied this into:
<div class="_el-tooltip_1ok_2">
<div class="_text-wrapper_mono1">
<span class="_text-inner_mmxr">
</span>
</div>
</div>
<style>
._el-tooltip_1ok_2{
background-color: red !important
}
._el-tooltip_1ok_2 ._text-wrapper_mono1 {
border: 1px solid yellow;
}
._el-tooltip_1ok_2 ._text-wrapper_mono1 ._text-inner_mmxr {
font-size: 24px;
}
</style>
this is not what we want, we only bind the el-tooltip module class name, not the children's, so we need it been complied into this:
<style>
._el-tooltip_1ok_2{
background-color: red !important
}
._el-tooltip_1ok_2 .text-wrapper {
border: 1px solid yellow;
}
._el-tooltip_1ok_2 .text-wrapper .text-inner {
font-size: 24px;
}
</style>
well, Vue allow us to doing this, if we use :global() commant:
<style module>
.el-tooltip{
background-color: red !important
:global(.text-wrapper) {
border: 1px solid yellow;
:global(.text-inner) {
font-size: 24px;
}
:global(.Another-Child-Class-Name) {
// your code
}
}
}
</style>
you see, we need to use :global commant wrap the class name. But we can't just wrap only a parent class name, but all class name inside the parent class name. Vite won't treat those children class name as a global style if we don't wrap the global command with them.
Don't you think this is so tedious?
Now we're back to the topic we were discussing earlier. How can we achieve this?