6

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:

  1. onClickOutside
  2. useFocusTrap
  3. useHead
  4. useStorage
  5. useVModel
  6. useImage
  7. 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> :

  1. title
  2. meta tags
  3. link tags
  4. base tag
  5. style tags
  6. script tags
  7. html attributes
  8. 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.


王大冶
68.2k 声望105k 粉丝