Dynamic Class Directive in Vue
Custom directives in Vue allow you to extend HTML with custom behavior. This challenge asks you to implement a custom directive that dynamically applies CSS classes to an element based on a provided expression. This is useful for scenarios like conditional styling, highlighting, or applying classes based on data changes without cluttering your component logic.
Problem Description
You need to create a Vue 3 custom directive named dynamic-class. This directive will accept a string argument containing a comma-separated list of class names and an expression. The expression will be evaluated in the component's scope. If the expression evaluates to true, all classes listed in the argument string will be applied to the element. If the expression evaluates to false, no classes will be applied.
Key Requirements:
- The directive must be named
dynamic-class. - The directive must accept a single argument, which is a string containing a comma-separated list of class names (e.g., "active,highlighted,bold").
- The directive must evaluate an expression provided in the component's template.
- The directive must dynamically add or remove the specified classes based on the expression's truthiness.
- The directive should handle cases where the expression evaluates to
trueorfalse. - The directive should work correctly when the expression's value changes.
Expected Behavior:
When the directive is bound to an element, the element's class list will be updated based on the expression's value. If the expression is true, the classes specified in the argument will be added. If the expression is false, the classes will be removed. Changes to the expression should trigger an update to the element's class list.
Edge Cases to Consider:
- Empty class list argument: If the argument is an empty string, no classes should be added or removed.
- Invalid expression: The expression should be evaluated within the component's scope. Handle potential errors gracefully (though error handling isn't explicitly required for this challenge, consider how it might impact the user experience).
- Multiple instances of the directive on the same element: The directive should handle multiple instances correctly, applying or removing classes as needed for each instance.
- Changes to the expression after initial binding: The directive should react to changes in the expression's value.
Examples
Example 1:
<template>
<div v-dynamic-class="['active', 'highlighted']" :class="{ 'bold': isBold }" :is-bold="false">
This is a div.
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const isBold = ref(false);
</script>
Output: The div element will not have the classes "active" or "highlighted" because the expression isBold is initially false.
Explanation: The v-dynamic-class directive is bound to the div element with the argument "active,highlighted" and the expression isBold. Since isBold is initially false, no classes are applied.
Example 2:
<template>
<div v-dynamic-class="['active', 'highlighted']" :class="{ 'bold': isBold }" :is-bold="true">
This is a div.
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const isBold = ref(true);
</script>
Output: The div element will have the classes "active" and "highlighted".
Explanation: The v-dynamic-class directive is bound to the div element with the argument "active,highlighted" and the expression isBold. Since isBold is true, the classes "active" and "highlighted" are applied.
Example 3: (Expression Change)
<template>
<div v-dynamic-class="['active', 'highlighted']" :class="{ 'bold': isBold }" :is-bold="isBold">
This is a div.
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const isBold = ref(false);
function toggleBold() {
isBold.value = !isBold.value;
}
</script>
Output: Initially, the div element will not have the classes "active" or "highlighted". When the toggleBold function is called (e.g., on a button click), the div element will gain the classes "active" and "highlighted".
Explanation: The v-dynamic-class directive is bound to the div element. The expression isBold initially evaluates to false. When toggleBold is called, isBold becomes true, and the classes are added.
Constraints
- The solution must be written in TypeScript.
- The directive must be compatible with Vue 3.
- The argument string must be comma-separated.
- The expression must be evaluated in the component's scope.
- The solution should be reasonably performant. Avoid unnecessary DOM manipulations.
Notes
- Consider using the
elandbindingarguments provided to the directive hook. - The
binding.valueargument will contain the expression to evaluate. - The
binding.argargument will contain the comma-separated string of class names. - You'll need to use
Element.classListto add and remove classes. - Think about how to handle changes to the expression's value over time. Vue's reactivity system will be key here.
- Focus on the core functionality of dynamically adding/removing classes based on the expression. Advanced error handling or complex UI is not required.