Skip to content

Mask — Overlay ​

17:06

Description ​

A full-screen fixed mask used to emphasize a specific element and block interaction with the content beneath. The node stays mounted and its visibility is toggled through visibility + opacity class channels; on close a visible window is kept until the fade-out (and content scaling) finishes. The component has no built-in close logic — the page controls show.

Compatibility ​

PlatformSupport
App✅ Supported (on HarmonyOS duration has no effect and the stylesheet base value of 300ms is used)
H5✅ Supported
WeChat Mini Program✅ Supported

Examples ​

Basic Usage ​

Tap the button to show the mask; tap the mask area to close it.

View source
vue
<template>
    <ux-button type="primary" @click="showMask">显示遮罩</ux-button>
    <ux-mask :show="show" :zoom="zoom" @click="closeMask"></ux-mask>
</template>

<script setup lang="uts">
const show = ref<boolean>(false);
const zoom = ref<boolean>(true);

function showMask(): void {
    show.value = true;
}

function closeMask(): void {
    show.value = false;
}
</script>

Zoom Effect (zoom) ​

When zoom=true the content animates with a scale (0.8 → 1 on open, back to 0.8 on close; the mask background does not scale); when zoom=false there is no zoom.

View source
vue
<template>
    <view class="btn-wrap">
        <ux-button :type="zoom ? 'primary' : 'default'" custom-class="btn-item" @click="setZoom(true)">开启缩放</ux-button>
        <ux-button :type="!zoom ? 'primary' : 'default'" custom-class="btn-item" @click="setZoom(false)">关闭缩放</ux-button>
    </view>
    <ux-mask :show="show" :zoom="zoom" @click="closeMask"></ux-mask>
</template>

<script setup lang="uts">
const show = ref<boolean>(false);
const zoom = ref<boolean>(true);

function setZoom(val: boolean): void {
    zoom.value = val;
    show.value = true;
}

function closeMask(): void {
    show.value = false;
}
</script>

<style scoped>
.btn-wrap {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
}
.btn-item {
    margin-right: 12px;
    margin-bottom: 12px;
}
</style>

Content Slot ​

Fill custom content inside the mask via the default slot; tapping the content will not close the mask.

View source
vue
<template>
    <ux-button type="primary" @click="showContent">显示内容</ux-button>
    <ux-mask :show="show" @click="closeMask">
        <view class="wrap">
            <view class="rect">
                <text class="rect-text">自定义内容</text>
            </view>
        </view>
    </ux-mask>
</template>

<script setup lang="uts">
const show = ref<boolean>(false);

function showContent(): void {
    show.value = true;
}

function closeMask(): void {
    show.value = false;
}
</script>

<style scoped>
.wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
}
.rect {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 240px;
    height: 240px;
    background-color: #ffffff;
    border-radius: 8px;
}
.rect-text {
    font-size: 14px;
    color: #606266;
}
</style>

Animation Duration (duration) ​

Set the show/hide animation duration of the mask in milliseconds via duration.

View source
vue
<template>
    <view class="btn-wrap">
        <ux-button v-for="(item, index) in durationList" :key="index" :type="duration == item.value ? 'primary' : 'default'" custom-class="btn-item" @click="setDuration(item.value)">{{ item.label }}</ux-button>
    </view>
    <ux-mask :show="show" :duration="duration" @click="closeMask"></ux-mask>
</template>

<script setup lang="uts">
const show = ref<boolean>(false);
const duration = ref<number>(300);

const durationList = [
    { value: 100, label: '100ms' },
    { value: 300, label: '300ms' },
    { value: 800, label: '800ms' }
];

function setDuration(val: number): void {
    duration.value = val;
    show.value = true;
}

function closeMask(): void {
    show.value = false;
}
</script>

<style scoped>
.btn-wrap {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
}
.btn-item {
    margin-right: 12px;
    margin-bottom: 12px;
}
</style>

Not Clickable to Close (mask-click-able) ​

When mask-click-able=false, tapping the mask will not close it; close it via the button inside the content instead.

View source
vue
<template>
    <ux-button type="primary" @click="showNotClickable">显示遮罩</ux-button>
    <ux-mask :show="show" :mask-click-able="false" @click="closeMask">
        <view class="wrap">
            <view class="rect" @click.stop>
                <text class="rect-text">点击遮罩无法关闭</text>
                <ux-button size="small" type="primary" @click="closeMask">关闭</ux-button>
            </view>
        </view>
    </ux-mask>
</template>

<script setup lang="uts">
const show = ref<boolean>(false);

function showNotClickable(): void {
    show.value = true;
}

function closeMask(): void {
    show.value = false;
}
</script>

<style scoped>
.wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
}
.rect {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 240px;
    height: 240px;
    background-color: #ffffff;
    border-radius: 8px;
}
.rect-text {
    font-size: 14px;
    color: #606266;
    margin-bottom: 16px;
}
</style>

API ​

Props ​

PropertyDescriptionTypeDefaultVersion
customStyleCustom root element stylestring | UTSJSONObject--
customClassCustom root element style classstring''-
showWhether to show the maskbooleanfalse-
zIndexz-index levelstring | number''-
zoomWhether to scale the content layer with scale (the mask background does not scale)booleantrue-
durationTransition duration of the mask, in msstring | number300-
maskClickAbleWhether the mask can be tapped to closebooleantrue-

Events ​

EventDescriptionParamsVersion
clickEmitted when the mask is tapped while maskClickAble is true--

Slots ​

SlotDescriptionVersion
defaultMask content, filling the whole mask; add @click.stop on the content box to keep taps from firing the mask's click-

Notes ​

  1. The component has no built-in close logic: setting show to false only plays the fade-out/scale-out transition, so the page must maintain the visible state; @click merely emits an event and never writes back to show.
  2. With mask-click-able=false, tapping the mask emits no click event at all (not merely "does not close"), so you must close it from a button inside the content — which is exactly what the demo does.
  3. zoom only affects the content layer; the mask background never scales. On close the content goes from scale(1) back to scale(0.8).
  4. The mask is position: fixed and stops touchmove internally, so the page beneath does not scroll while it is visible.
  5. The mask node stays mounted: after closing, a primary plus a fallback timer retract the visible window once the transition finishes, and rapid re-toggles clear the stale timers.
  6. An empty z-index falls back to the global mask level ($u.zIndex.mask); use it to control stacking order when several masks coexist.
  7. duration has no effect on HarmonyOS: the inline assignment is excluded by #ifndef APP-HARMONY, so the stylesheet base value of 300ms is always used.