122 lines
2.7 KiB
Markdown
Raw Normal View History

# Use Computed Properties for Complex Class Logic
## Rule
When class bindings involve multiple conditions or complex logic, extract them into computed properties rather than writing inline expressions in templates.
## Why This Matters
- Inline class expressions quickly become unreadable with multiple conditions
- Computed properties are cached and only re-evaluate when dependencies change
- Logic in computed properties is easier to test and debug
- Keeps templates focused on structure, not logic
## Bad Code
```vue
<template>
<!-- Hard to read, error-prone -->
<div :class="{
'btn': true,
'btn-primary': type === 'primary' && !disabled,
'btn-secondary': type === 'secondary' && !disabled,
'btn-disabled': disabled,
'btn-loading': isLoading,
'btn-large': size === 'large',
'btn-small': size === 'small'
}">
{{ label }}
</div>
<!-- Even worse: string concatenation -->
<div :class="'btn btn-' + type + (disabled ? ' btn-disabled' : '') + (isLoading ? ' btn-loading' : '')">
{{ label }}
</div>
</template>
```
## Good Code
```vue
<script setup>
import { computed } from 'vue'
const props = defineProps({
type: { type: String, default: 'primary' },
size: { type: String, default: 'medium' },
disabled: Boolean,
isLoading: Boolean,
label: String
})
const buttonClasses = computed(() => ({
'btn': true,
[`btn-${props.type}`]: !props.disabled,
'btn-disabled': props.disabled,
'btn-loading': props.isLoading,
'btn-large': props.size === 'large',
'btn-small': props.size === 'small'
}))
</script>
<template>
<div :class="buttonClasses">
{{ label }}
</div>
</template>
```
## Style Bindings Too
The same principle applies to style bindings:
```vue
<script setup>
import { computed } from 'vue'
const props = defineProps({
color: String,
fontSize: Number,
isHighlighted: Boolean
})
const textStyles = computed(() => ({
color: props.color,
fontSize: `${props.fontSize}px`,
backgroundColor: props.isHighlighted ? 'yellow' : 'transparent',
fontWeight: props.isHighlighted ? 'bold' : 'normal'
}))
</script>
<template>
<span :style="textStyles">Styled text</span>
</template>
```
## Combining Static and Dynamic Classes
Use array syntax to combine static classes with computed dynamic classes:
```vue
<script setup>
import { computed } from 'vue'
const dynamicClasses = computed(() => ({
'is-active': isActive.value,
'is-disabled': isDisabled.value
}))
</script>
<template>
<!-- Static 'card' class + dynamic classes -->
<div :class="['card', dynamicClasses]">
Content
</div>
</template>
```
## References
- [Class and Style Bindings](https://vuejs.org/guide/essentials/class-and-style.html)
- [Computed Properties](https://vuejs.org/guide/essentials/computed.html)