JSFiddle - React, Tailwind, and code Playground
HTML
<div id="app">
<input v-model="editMode" type="checkbox">
<input v-model="showGear" type="checkbox">
<input v-model="hasStub" type="checkbox">
<input v-model="hasParent" type="checkbox">
<div
:style="{
'border': editMode ? '1px dashed #000' : '',
'border-color': showGear ? '#333' : '#DEDEDE',
'border-bottom-left-radius': hasStub ? '0px' : '',
'border-bottom-right-radius': hasStub ? '0px' : '',
'border-bottom': hasStub ? '0px' : '',
'border-top-left-radius': hasParent ? '0px' : '',
'border-top-right-radius': hasParent ? '0px' : '',
'border-top': hasParent ? '0px' : ''
}"
>
In template approach.
It's kinda gnarly though, that's a lot of ternaries.
And ternaries are the enemy of readability.
Let's move this complexity down to a Computed instead.
We'll try two approaches, string concatenation, and
Vue's object syntax.
</div>
<div :style="stringConcatApproach">
See JS for details.
</div>
<div :style="objectApproach">
See JS for details.
</div>
<div
:class="{
editModeBorder: editMode,
showGearBorder: showGear,
hideGearBorder: !showGear,
hasStubBorder: hasStub,
hasParentBorder: hasParent
}"
>
This is much cleaner. It simplifies the logic and doesn't really even need to
be a computed at this point. It does require you to create classes to contain
each of these styles. But as you'll read below, that is well worth the effort
to avoid the negatives of inline-styles.
</div>
<div :class="borderStyles">
<p>
But if this logic is used by multiple compontents/elements, then making it
a computed means the class object will only need to be produced once and
all elements using it will get a cached copy (fast!).
</p>
<p>
Using classes on their own though is the real performance boost. Browser
rendering engines are specially optimized for classes. When a browser sees
...
SASS
$black: #000
$gray33: #333
$grayDE: #DEDEDE
body
background: #ABC
color: #123
font-family: 'Century Gothic', 'Trebuchet MS', sans-serif
=zeroOutBorderSide ($side)
border-#{$side}-left-radius: 0px
border-#{$side}-right-radius: 0px
border-#{$side}: 0px
.editModeBorder
border: 1px dashed $black
.showGearBorder
border-color: $gray33
.hideGearBorder
border-color: $grayDE
.hasStubBorder
+zeroOutBorderSide(bottom)
.hasParentBorder
+zeroOutBorderSide(top)
JavaScript
const app = new Vue({
el: '#app',
data: function () {
return {
editMode: false,
showGear: false,
hasStub: false,
hasParent: false
};
},
computed: {
// First we'll try creating vanilla HTML string from scratch.
// :style="'border: 1px dashed #000;border-color: #333'"
stringConcatApproach: function () {
let border = '';
let borderColor = 'border-color: #DEDEDE';
let borderBottomLeftRadius = '';
let borderBottomRightRadius = '';
let borderBottom = '';
let borderTopLeftRadius = '';
let borderTopRightRadius = '';
let borderTop = '';
if (this.editMode) {
border = 'border: 1px dashed #000';
}
if (this.showGear) {
borderColor = 'border-color: #333';
}
if (this.hasStub) {
borderBottomLeftRadius = 'border-bottom-left-radius: 0px';
borderBottomRightRadius = 'border-bottom-right-radius: 0px';
borderBottom = 'border-bottom: 0px';
}
if (this.hasParent) {
borderTopLeftRadius = 'border-top-left-radius: 0px';
borderTopRightRadius = 'border-top-right-radius: 0px';
borderTop = 'border-top: 0px';
}
return [
border,
borderColor,
borderBottomLeftRadius,
borderBottomRightRadius,
borderBottom,
borderTopLeftRadius,
borderTopRightRadius,
borderTop
].filter(Boolean).join(';');
},
// Next let's try using Vue's built in Object syntax for inline-styles
// This is nice because it ignores keys with falsy values for free.
objectApproach: function () {
let border = '';
let borderColor = '#DEDEDE';
let borderBottomLeftRadius = '';
let borderBottomRightRadius = '';
let borderBottom = '';
let borderTopLeftRadius = '';
let borderTopRightRadius = '';
let borderTop = '';
if (this.editMode) {
border = '1px dashed #000';
}
if...