You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
63 lines
1.6 KiB
63 lines
1.6 KiB
<script lang="ts">
|
|
import {
|
|
cloneVNode,
|
|
createElementBlock,
|
|
defineComponent,
|
|
getCurrentInstance,
|
|
h,
|
|
InjectionKey,
|
|
onMounted,
|
|
provide,
|
|
shallowRef,
|
|
SlotsType,
|
|
VNode,
|
|
} from "vue";
|
|
|
|
export const clientOnlySymbol: InjectionKey<boolean> =
|
|
Symbol.for("nuxt:client-only");
|
|
|
|
export default defineComponent({
|
|
name: "ClientOnly",
|
|
inheritAttrs: false,
|
|
props: ["fallback", "placeholder", "placeholderTag", "fallbackTag"],
|
|
...(import.meta.env.DEV && {
|
|
slots: Object as SlotsType<{
|
|
default?: () => VNode[];
|
|
|
|
/**
|
|
* Specify a content to be rendered on the server and displayed until `<ClientOnly>` is mounted in the browser.
|
|
*/
|
|
fallback?: () => VNode[];
|
|
placeholder?: () => VNode[];
|
|
}>,
|
|
}),
|
|
setup(props, { slots, attrs }) {
|
|
const mounted = shallowRef(false);
|
|
onMounted(() => {
|
|
mounted.value = true;
|
|
});
|
|
// 这里没什么用,先去掉
|
|
// const vm = getCurrentInstance();
|
|
// if (vm) {
|
|
// vm._nuxtClientOnly = true;
|
|
// }
|
|
provide(clientOnlySymbol, true);
|
|
return () => {
|
|
if (mounted.value) {
|
|
const vnodes = slots.default?.();
|
|
if (vnodes && vnodes.length === 1) {
|
|
return [cloneVNode(vnodes[0]!, attrs)];
|
|
}
|
|
return vnodes;
|
|
}
|
|
const slot = slots.fallback || slots.placeholder;
|
|
if (slot) {
|
|
return h(slot);
|
|
}
|
|
const fallbackStr = props.fallback || props.placeholder || "";
|
|
const fallbackTag = props.fallbackTag || props.placeholderTag || "span";
|
|
return createElementBlock(fallbackTag, attrs, fallbackStr);
|
|
};
|
|
},
|
|
});
|
|
</script>
|
|
|