Skip to content

Instantly share code, notes, and snippets.

@JamesBoon
Last active April 22, 2022 16:50
Show Gist options
  • Save JamesBoon/790c3635cdd37d361991edd93f80f18a to your computer and use it in GitHub Desktop.
Save JamesBoon/790c3635cdd37d361991edd93f80f18a to your computer and use it in GitHub Desktop.
Some directives for Vue 3

Some directives for Vue 3

There are three directives, which can be used like v-show. They all work with transitions too!

  • v-visible is a drop-in replacement for v-show, but it will set visibility: hidden instead of display: none.
  • v-trigger does nothing but trigger the transition.
  • v-cls:somecssclass will set somecssclass to the element.

They are all just a proof of concept. But feel free to use them for whatever you like.

You can try them out in the Vue SFC Playground.

<script setup>
import { ref } from 'vue'
const show = ref(true);
function toggleShow() {
show.value = !show.value;
}
// see https://github.com/vuejs/core/blob/v3.2.33/packages/runtime-dom/src/directives/vShow.ts
const vVisible = {
beforeMount(el, { value }, { transition }) {
el._vov = el.style.visibility === 'hidden' ? '' : el.style.visibility
if (transition && value) {
transition.beforeEnter(el)
} else {
setVisibility(el, value)
}
},
mounted(el, { value }, { transition }) {
if (transition && value) {
transition.enter(el)
}
},
updated(el, { value, oldValue }, { transition }) {
if (!value === !oldValue) return
if (transition) {
if (value) {
transition.beforeEnter(el)
setVisibility(el, true)
transition.enter(el)
} else {
transition.leave(el, () => {
setVisibility(el, false)
})
}
} else {
setVisibility(el, value)
}
},
beforeUnmount(el, { value }) {
setVisibility(el, value)
}
}
function setVisibility(el, value) {
el.style.visibility = value ? el._vov : 'hidden'
}
// just TRIGGER an animation!
const vTrigger = {
beforeMount(el, { value }, { transition }) {
if (transition && value) {
transition.beforeEnter(el)
}
},
mounted(el, { value }, { transition }) {
if (transition && value) {
transition.enter(el)
}
},
updated(el, { value, oldValue }, { transition }) {
if (!value === !oldValue) return
if (transition) {
if (value) {
transition.beforeEnter(el)
transition.enter(el)
} else {
transition.leave(el, () => {})
}
}
},
}
// set a css class given as argument
const vCls = {
beforeMount(el, { arg, value }, { transition }) {
if (transition && value) {
transition.beforeEnter(el)
} else {
setCls(el, arg, value)
}
},
mounted(el, { value }, { transition }) {
if (transition && value) {
transition.enter(el)
}
},
updated(el, { arg, value, oldValue }, { transition }) {
if (!value === !oldValue) return
if (transition) {
if (value) {
transition.beforeEnter(el)
setCls(el, arg, true)
transition.enter(el)
} else {
transition.leave(el, () => {
setCls(el, arg, false)
})
}
} else {
setCls(el, arg, value)
}
},
beforeUnmount(el, { arg, value }) {
setCls(el, arg, value)
}
}
function setCls(el, arg, value) {
if (value) {
el.classList.remove(arg);
} else {
el.classList.add(arg);
}
}
</script>
<template>
<button @click="toggleShow()">toggle</button>
<hr />
<transition>
<div v-visible="show">
<h1>Hello v-visible!</h1>
<p>This will affect the layout as normal.</p>
</div>
</transition>
<hr />
<transition>
<div v-show="show">
<h1>Hello v-show!</h1>
<p>This will be removed from the layout.</p>
</div>
</transition>
<hr />
<transition>
<div v-trigger="show" :class="{invisible:!show}">
<h1>Hello v-trigger!</h1>
<p>Same visible effect as <code>v-visible</code>, but actually <em>just</em> a trigger.</p>
</div>
</transition>
<hr />
<transition>
<div v-cls:invisible="show">
<h1>Hello v-cls!</h1>
<p>Same visible effect as <code>v-visible</code>, but sets a given css class.</p>
</div>
</transition>
<hr />
</template>
<style>
.v-enter-active {
animation: fade-in 1s;
}
.v-leave-active {
animation: fade-in 1s reverse;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.invisible {
opacity: 0;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment