Skip to content

The v-show Directive

Consider a component like the following.

vue
<script setup>
import { ref } from "vue";
const flag = ref("");
</script>

<template>
  <p v-show="flag">Hello, v-show!</p>
</template>

Compilation Result and Overview

The compilation result is as follows.

js
const _sfc_main = {
  vapor: true,
  __name: "App",
  setup(__props, { expose: __expose }) {
    __expose();

    const flag = ref("");

    const __returned__ = { flag, ref };
    Object.defineProperty(__returned__, "__isScriptSetup", {
      enumerable: false,
      value: true,
    });
    return __returned__;
  },
};

import {
  vShow as _vShow,
  withDirectives as _withDirectives,
  template as _template,
} from "vue/vapor";

const t0 = _template("<p>Hello, v-show!</p>");

function _sfc_render(_ctx) {
  const n0 = t0();
  _withDirectives(n0, [[_vShow, () => _ctx.flag]]);
  return n0;
}

What stands out is the part _withDirectives(n0, [[_vShow, () => _ctx.flag]]);.
Continuing from last time, it uses the withDirectives function again, but this time it uses the vShow function as the runtimeDirective.

Reading the Compiler

We will follow transformElement -> buildProps -> transformProps -> directiveTransform -> transformVShow.

It's very simple, so I'll include the entire text.

1import { DOMErrorCodes, createDOMCompilerError } from '@vue/compiler-dom'
2import type { DirectiveTransform } from '../transform'
3import { IRNodeTypes } from '../ir'
4
5export const transformVShow: DirectiveTransform = (dir, node, context) => {
6  const { exp, loc } = dir
7  if (!exp) {
8    context.options.onError(
9      createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION, loc),
10    )
11  }
12
13  context.registerOperation({
14    type: IRNodeTypes.WITH_DIRECTIVE,
15    element: context.reference(),
16    dir,
17    name: 'vShow',
18    builtin: true,
19  })
20}

It's just registering WITH_DIRECTIVE with name: 'vShow'.

Reading the Runtime

This is also simple, so I'll include the entire text.

It simply sets el.style.display to none or "" in beforeMount, updated, and beforeUnmount.

1import type { ObjectDirective } from '../directives'
2
3const vShowMap = new WeakMap<HTMLElement, string>()
4
5export const vShow: ObjectDirective<HTMLElement> = {
6  beforeMount(node, { value }) {
7    vShowMap.set(node, node.style.display === 'none' ? '' : node.style.display)
8    setDisplay(node, value)
9  },
10
11  updated(node, { value, oldValue }) {
12    if (!value === !oldValue) return
13    setDisplay(node, value)
14  },
15
16  beforeUnmount(node, { value }) {
17    setDisplay(node, value)
18  },
19}
20
21function setDisplay(el: HTMLElement, value: unknown): void {
22  el.style.display = value ? vShowMap.get(el)! : 'none'
23}

And that's everything!