🔥 (#141) Contextually-Aware Components, reactive SVGs, and preventing navigation
Hey there!
I want to remind you that Clean Components Toolkit has a 33% discount for only 2 more days!
I've got updates on a live preview of the toolkit as well as support for purchasing power parity.
But first, I wanted to share this incredible email that Albert sent me after he bought the toolkit:
If you want to know what Albert's talking about, you can take the toolkit for a test drive:
https://michaelnthiessen.com/clean-components-toolkit/preview
Also, I've added support for purchasing power parity, if you need it.
If you're in a country where the dollar conversion is low (like Brazil 🇧🇷, for example), this can make it easier for you to afford.
Here's a link to get the Clean Components Toolkit.
Oh, and here are your regularly scheduled tips.
Enjoy!
— Michael
🔥 Define multiple components in a single file
Every now and then, you just need a small component, one that's not worth an entirely new file:
// A small, secondary component const SmallComponent = { // Create a component like you normally would data() { //... }, computedProps: { //... }, // Use the template property instead of a template block template: ` <div>Hello!</div> ` }; // Your main component export default { components: { SmallComponent }, // ... };
This is perfect for reusing code within a component where a v-for
doesn't work.
However, if the code is more complex or is likely to be used by other components, making a proper reusable component is the best way to go.
Note: You can get proper syntax highlighting of the HTML string using this VSCode extension.
🔥 Creating Magic with Context-Aware Components
Context-aware components are "magical" — they adapt to what's going on around them automatically, handling edge cases, state sharing, and more.
There are 3 main types of context-aware components, but configuration is the one I find most interesting.
1. State Sharing
When you break up a large component into smaller ones, they often still need to share state.
Instead of pushing that work on whoever's consuming the components, you can make this happen "behind the scenes."
To give you more flexibility, you may break up a Dropdown
component into Select
and Option
components. But to make it easier to use, the Select
and Option
components share the selected
state with each other:
<!-- Used as a single component for simplicity --> <Dropdown v-model="selected" :options="[]" /> <!-- Split up for more flexibility --> <Select v-model="selected"> <Option value="mustard">Mustard</Option> <Option value="ketchup">Ketchup</Option> <div class="relish-wrapper"> <Option value="relish">Relish</Option> </div> </Select>
2. Configuration
Sometimes component behaviour needs to change based on what's going on in the rest of the application. This is often done to automagically handle edge cases that would otherwise be annoying to deal with.
A Popup
or Tooltip
should reposition itself so it doesn't overflow out of the page. But if that component is inside a modal, it should move, so it doesn't overflow out of the modal.
This can be done automagically if the Tooltip
knows when it's inside a modal.
3. Styling
You already create context-aware CSS, applying different styles based on what's happening in parent or sibling elements.
.statistic { color: black; font-size: 24px; font-weight: bold; } /* Give some separation between stats that are right beside each other */ .statistic + .statistic { margin-left: 10px; }
CSS variables let us push this further, allowing us to set different values in different parts of the page.
🔥 Prevent Navigation Away
We can use the native beforeunload
event to detect when a user is about to navigate away or refresh the page:
// Use `beforeMount` to avoid running during SSR onBeforeMount(() => { // We use the native `beforeunload` event window.addEventListener("beforeunload", preventNav); }); // Make sure to always clean up after yourself! onBeforeUnmount(() => { window.removeEventListener("beforeunload", preventNav); });
The method to actually block the navigation uses preventDefault
:
const blockNavigation = ref(false); const preventNav = event => { if (!blockNavigation.value) return; event.preventDefault(); // Chrome requires returnValue to be set event.returnValue = ""; };
Here's the full example:
<script setup> import { ref, onBeforeMount, onBeforeUnmount } from 'vue'; // Method to block navigation const blockNavigation = ref(false); const preventNav = event => { if (!blockNavigation.value) return; event.preventDefault(); // Chrome requires returnValue to be set event.returnValue = ""; }; // Use `beforeMount` to avoid running during SSR onBeforeMount(() => { // We use the native `beforeunload` event window.addEventListener("beforeunload", preventNav); }); // Make sure to always clean up after yourself! onBeforeUnmount(() => { window.removeEventListener("beforeunload", preventNav); }); </script>
📜 Coding Better Composables: Flexible Arguments (2/5)
I teamed up with Vue Mastery to create this series on coding better composables.
In this series we cover five different patterns.
For each, we show how you can implement it and then we see it in action with a composable from VueUse.
This second article is on using ref
and unref
to make the arguments more flexible.
Check it out here: Coding Better Composables: Flexible Arguments (2/5)
💬 Simplicity
"Complicated code is a sign that you don't understand your program well enough to make it simple." — Steve McConnell
🧠 Spaced-repetition: Reactive SVG components
The best way to commit something to long-term memory is to periodically review it, gradually increasing the time between reviews 👨🔬
Actually remembering these tips is much more useful than just a quick distraction, so here's a tip from a couple weeks ago to jog your memory.
SVGs can be reactive components, too.
After all, they're HTML elements just like div
, span
, and button
.
Here's an SVG component that has a prop to change it's fill colour:
<template> <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> <circle cx="50" cy="50" r="50" :fill="color" /> </svg> </template>
<script> export default { name: "SVGComponent", props: { color: String, }, }; </script>
I'm sure you can build some pretty wild things if you dig into different SVG elements and attributes.
Scoped slots and SVGs? Why not...
Here's a demo if you want to see this example in action.
p.s. I also have four products/courses: Vue Tips Collection, Mastering Nuxt 3, Reusable Components and Clean Components Toolkit
评论
发表评论