If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.
Vueuse has tons of great combinations. But the volume is so large that trying to read them all can be confusing. Here are some useful combinations, they are as follows:
- onClickOutside
- useFocusTrap
- useHead
- useStorage
- useVModel
- useImage
- useDark
1. onClickOutside
Detecting clicks is very simple. But how can I detect when the click happens outside of an element? That's where it gets a little tricky. But it's easy to do this with the onClickOutside component in VueUse. code show as below:
<script setup>
import { ref } from 'vue'
import { onClickOutside } from '@vueuse/core'
const container = ref(null)
onClickOutside(container, () => alert('Good. Better to click outside.'))
</script>
<template>
<div>
<p>Hey there, here's some text.</p>
<div class="container" ref="container">
<p>Please don't click in here.</p>
</div>
</div>
</template>
Create a ref
container
element you want to track:
const container = ref(null);
Then we turn it into a template ref
with the ref
attribute on the element.
<div class="container" ref="container">
<p>Please don't click in here.</p>
</div>
After we have the container's ref
, we pass it along with a handler to the onClickOutside
composition.
onClickOutside(
container,
() => alert('Good. Better to click outside.')
)
This composability is useful for managing windows or dropdown menus. You can close it when the user clicks outside the dropdown menu.
Modal boxes also typically exhibit this behavior.
Example address: https://stackblitz.com/edit/vue3-script-setup-with-vite-18scsl?file=src%2FApp.vue
2. useFocusTrap
In order to have an accessible application, it is important to manage focus correctly.
There is nothing worse than accidentally adding a tab after a modal and not being able to return focus to the modal. That's what the focus trap does.
Locks the keyboard focus on a specific DOM element, not looping through the entire page, but in the browser itself, and the keyboard focus only loops through that DOM element.
Here is an example of useFocusTrap
using VueUse:
<script setup>
import { ref } from 'vue'
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
const container = ref(null)
useFocusTrap(container, { immediate: true })
</script>
<template>
<div>
<button tab-index="-1">Can't click me</button>
<div class="container" ref="container">
<button tab-index="-1">Inside the trap</button>
<button tab-index="-1">Can't break out</button>
<button tab-index="-1">Stuck here forever</button>
</div>
<button tab-index="-1">Can't click me</button>
</div>
</template>
Set immediate
to true
and when the page loads, focus will be placed in the container
element. Then, it is impossible to label outside of that container.
Once you reach the third button, hitting the tab
key again will bring you back to the first button.
Just like onClickOutside
, we first set the template ---249d26ae71d8326cd18c73b597665ba5--- for container
ref
.
const container = ref(null)
<div class="container" ref="container">
<button tab-index="-1">Inside the trap</button>
<button tab-index="-1">Can't break out</button>
<button tab-index="-1">Stuck here forever</button>
</div>
Then we pass this template reference to the useFocusTrap
combination.
useFocusTrap(container, { immediate: true });
The immediate
option will automatically set the focus to the first focusable element in the container.
Example address: https://stackblitz.com/edit/vue3-script-setup-with-vite-eocc6w?file=src%2FApp.vue
3. useHead
VueUse gives us an easy way to update the head section of our application -- the page title, scripts, and whatever else might go there.
The useHead composition requires us to first set up a plugin
import { createApp } from 'vue'
import { createHead } from '@vueuse/head'
import App from './App.vue'
const app = createApp(App)
const head = createHead()
app.use(head)
app.mount('#app')
Once we've used this plugin, we can update the header section however we want. In this example, we will inject some custom styles on a button.
<script setup>
import { ref } from 'vue'
import { useHead } from '@vueuse/head'
const styles = ref('')
useHead({
// Inject a style tag into the head
style: [{ children: styles }],
})
const injectStyles = () => {
styles.value = 'button { background: red }'
}
</script>
<template>
<div>
<button @click="injectStyles">Inject new styles</button>
</div>
</template>
First, we create a ref
to represent the style we want to inject, which is empty by default:
const styles = ref('');
Second, the settings useHead
inject styles into the page.
useHead({
// Inject a style tag into the head
style: [{ children: styles }],
})
Then, add a method to inject these styles:
const injectStyles = () => {
styles.value = 'button { background: red }'
}
Of course, we're not limited to injecting styles. We can add any of these to our <head>
:
- title
- meta tags
- link tags
- base tag
- style tags
- script tags
- html attributes
- body attributes
Example address: https://stackblitz.com/edit/vue3-script-setup-with-vite-szhedp?file=src%2FApp.vue
4. useStorage
useStorage
is really cool because it automatically ref
to localstorage, for example:
<script setup>
import { useStorage } from '@vueuse/core'
const input = useStorage('unique-key', 'Hello, world!')
</script>
<template>
<div>
<input v-model="input" />
</div>
</template>
When first loaded, input
shows 'Hello, world!', but at the end, it will show what you last typed in input
because it is saved in localstorage.
In addition to localstorage, we can also specify sessionstorage
:
const input = useStorage('unique-key', 'Hello, world!', sessionStorage)
Of course, you can also implement the storage system yourself, as long as it implements the StorageLike
interface.
export interface StorageLike {
getItem(key: string): string | null
setItem(key: string, value: string): void
removeItem(key: string): void
}
5. useVModel
v-model
Directives are nice syntactic sugar to make two-way data binding easier.
But useVModel
goes a step further and gets rid of a bunch of template code that nobody really wants to write.
<script setup>
import { useVModel } from '@vueuse/core'
const props = defineProps({
count: Number,
})
const emit = defineEmits(['update:count'])
const count = useVModel(props, 'count', emit)
</script>
<template>
<div>
<button @click="count = count - 1">-</button>
<button @click="count = 0">Reset to 0</button>
<button @click="count = count + 1">+</button>
</div>
</template>
In this example, we first define the props to be attached to v-model
:
const props = defineProps({
count: Number,
})
Then we emit an event, using the naming convention of v-model
update:<propName>
:
const emit = defineEmits(['update:count'])
Now, we can use the useVModel
combination to bind prop
and the event to one ref
.
const count = useVModel(props, 'count', emit)
Whenever prop changes, this count
changes. But as soon as it is changed from this component, it emits the update:count
event, which triggers the update via the v-model
instruction.
We can use this Input
component like this.
<script setup>
import { ref } from 'vue'
import Input from './components/Input.vue'
const count = ref(50)
</script>
<template>
<div>
<Input v-model:count="count" />
{{ count }}
</div>
</template>
Here count ref
is synchronized with Input
internal count ref
36ac5be2d2de81849f39--- through the v-model
binding.
Example address: https://stackblitz.com/edit/vue3-script-setup-with-vite-ut5ap8?file=src%2FApp.vue
6. useImage
Over time, images in web applications become more and more beautiful. We already have responsive images with srcset
a progressive loading library, and a library that only loads when the image is scrolled to the viewport.
But did you know that we can also access the loading and error status of the image itself?
I used to do this mostly by listening to the onload
and onerror
events emitted by each HTML element, but VueUse gives us an easier way, which is useImage
combination.
<script setup>
import { useImage } from '@vueuse/core'
// Change this to a non-existent URL to see the error state
const url = 'https://source.unsplash.com/random/400x300'
const { isLoading, error } = useImage(
{
src: url,
},
{
// Just to show the loading effect more clearly
delay: 2000,
}
)
</script>
<template>
<div>
<div v-if="isLoading" class="loading gradient"></div>
<div v-else-if="error">Couldn't load the image :(</div>
<img v-else :src="url" />
</div>
</template>
The first step is to set the picture's src
through useImage
d4de61cebdd500a05f44043f0b23c921---:
const { isLoading, error } = useImage({ src: url })
Get the isLoading
and error
references it returns in order to keep track of the state. This combination uses useAsyncState
internally, so it returns the same value as the combination.
Once arranged, useImage
will load our image and attach event handlers to it.
All we have to do is use the same URL in our template to use that image. Since the browser will reuse any cached image, it will reuse the image loaded by useImage
.
<template>
<div>
<div v-if="isLoading" class="loading gradient"></div>
<div v-else-if="error">Couldn't load the image :(</div>
<img v-else :src="url" />
</div>
</template>
Here we set up a basic loading and error status handler. While the image is loading, we show a placeholder with an animated gradient. If there is an error, we display an error message. Otherwise we can render the image.
UseImage has some other great features! If you want it to be a responsive image then it supports srcset
and sizes
properties which are passed behind the scenes to img
element.
There is also a no-render component if you want to put everything in the template. It works the same as the combined one:
<template>
<UseImage src="https://source.unsplash.com/random/401x301">
<template #loading>
<div class="loading gradient"></div>
</template>
<template #error>
Oops!
</template>
</UseImage>
</template>
Example: https://stackblitz.com/edit/vue3-script-setup-with-vite-d1jsec?file=src%2FApp.vue
7. Dark mode useDark
Every website and app seems to have a dark mode these days. The hardest part was the styling change. But once you have those, switching back and forth is simple.
If you're using Tailwind, you just need to add the dark class to the html element to enable it throughout the page.
<html class="dark"><!-- ... --></html>
However, there are a few things to consider when switching between dark and light modes. First, we have to take into account the user's system settings. Second, we have to remember whether they have overruled this choice.
VueUse's useDark
composability wraps all this stuff up for us. By default it looks at system settings, but any changes will be persisted to localStorage
, so the settings will be remembered.
<script setup>
import { useDark, useToggle } from '@vueuse/core'
const isDark = useDark()
const toggleDark = useToggle(isDark)
</script>
<template>
<div class="container">
Changes with dark/light mode.
<button @click="toggleDark()">
Enable {{ isDark ? 'Light' : 'Dark' }} Mode
</button>
</div>
</template>
Styles for dark mode:
.dark .container {
background: slategrey;
color: white;
border-color: black;
}
.dark button {
background: lightgrey;
color: black;
}
.dark body {
background: darkgrey;
}
If you're not using Tailwind, you can completely customize how dark mode applies by passing in an options object. Here is the default Tailwind:
const isDark = useDark({
selector: 'html',
attribute: 'class',
valueDark: 'dark',
valueLight: '',
})
It is also possible to provide an onChanged handler so you can write whatever Javascript you need. These two methods allow you to make it work with any styling system you already have.
Summarize
Vueuse has a huge library of great combinations, and we've only covered a small fraction of them here. I highly recommend that you take the time to explore the docs and see all that is available. This is a really good resource that will save you from a lot of template code and constantly reinventing the wheel.
The bugs that may exist in editing cannot be known in real time. In order to solve these bugs afterwards, a lot of time is spent on log debugging. By the way, here is a useful BUG monitoring tool , Fundebug .
Author: Noveo Translator: Xiaozhi Source: vuemastery
Original: https://www.vuemastery.com/blog/best-vueue-composables
comminicate
If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。