Skip to content

Commit

Permalink
feat(loading): loading新增attach、fullscreen属性,支持函数式调用 (#1444)
Browse files Browse the repository at this point in the history
* feat(loading): loading新增attach、fullscreen属性,支持函数式调用

* feat(loading): 组件示例更新

* fix: fix lint

* chore(Loading): add loadingPlugin to plugins file

---------

Co-authored-by: anlyyao <[email protected]>
  • Loading branch information
dexterBo and anlyyao committed Jun 11, 2024
1 parent 1665eeb commit c777ca0
Show file tree
Hide file tree
Showing 14 changed files with 345 additions and 3 deletions.
13 changes: 13 additions & 0 deletions src/loading/__test__/__snapshots__/demo.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,19 @@ exports[`Loading > Loading mobileVue demo works fine 1`] = `
</div>
</div>
<!-- 视觉稿待定,暂时注释 -->
<!-- &lt;tdesign-demo-block title="04 全屏加载" summary="全屏展示加载状态,阻止用户操作。"&gt;
&lt;fullscreen /&gt;
&lt;/tdesign-demo-block&gt;
&lt;tdesign-demo-block
title="05 挂载到指定元素"
summary="可通过 attach 挂载到指定元素。注:被挂载元素(loading的父元素)需设置:position: relative;"
&gt;
&lt;attach /&gt;
&lt;/tdesign-demo-block&gt;
&lt;tdesign-demo-block title="06 函数方式调用"&gt;
&lt;service /&gt;
&lt;/tdesign-demo-block&gt; -->
</div>
`;

Expand Down
25 changes: 25 additions & 0 deletions src/loading/demos/attach.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<template>
<div class="loading-demo">
<div id="alice" class="loading-attach-demo__title">Hello, I'm Alice. I'm going to be a front-end developer.</div>
<t-loading attach="#alice" size="small" :loading="loading"></t-loading>
<t-switch v-model="loading" :custom-value="[true, false]" size="small" :label="['', '']" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Switch as TSwitch } from 'tdesign-mobile-vue';
const loading = ref(false);
</script>

<style scoped>
.loading-demo {
padding: 0 16px;
}
.loading-attach-demo__title {
/** `position: relative` is required as a parent node */
position: relative;
width: 360px;
text-align: center;
}
</style>
32 changes: 32 additions & 0 deletions src/loading/demos/fullscreen.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<template>
<div class="loading-demo">
<t-loading :loading="loading" text="加载中..." fullscreen />
<div>
全局加载开关(开启加载1秒后自动归位):
<t-switch v-model="loading" size="small"></t-switch>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import { Switch as TSwitch } from 'tdesign-mobile-vue';
const loading = ref(false);
watch(
() => loading.value,
(v) => {
if (!v) return;
const timer = setTimeout(() => {
loading.value = false;
clearTimeout(timer);
}, 1000);
},
);
</script>

<style lang="less" scoped>
.loading-demo {
padding: 0 16px;
}
</style>
16 changes: 16 additions & 0 deletions src/loading/demos/mobile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@
<tdesign-demo-block title="03 加载速度" summary="加载速度调整">
<speed />
</tdesign-demo-block>
<!-- 视觉稿待定,暂时注释 -->
<!-- <tdesign-demo-block title="04 全屏加载" summary="全屏展示加载状态,阻止用户操作。">
<fullscreen />
</tdesign-demo-block>
<tdesign-demo-block
title="05 挂载到指定元素"
summary="可通过 attach 挂载到指定元素。注:被挂载元素(loading的父元素)需设置:position: relative;"
>
<attach />
</tdesign-demo-block>
<tdesign-demo-block title="06 函数方式调用">
<service />
</tdesign-demo-block> -->
</div>
</template>

Expand All @@ -38,6 +51,9 @@ import vert from './vert.vue';
import pureText from './pure-text.vue';
import speed from './speed.vue';
import size from './size.vue';
import service from './service.vue';
import fullscreen from './fullscreen.vue';
import attach from './attach.vue';
</script>

<style scoped lang="less">
Expand Down
62 changes: 62 additions & 0 deletions src/loading/demos/service.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<template>
<div class="loading-demo">
<div id="loading-service-demo" ref="content" class="loading-service-demo">Loading 挂载容器</div>
<div class="space">
<t-button class="t-loading__btn" size="small" :disabled="attachLoading" @click="showAttach">
函数方式加载(局部)
</t-button>
<t-button size="small" @click="showFullScreen">函数方式加载(全屏)</t-button>
</div>
</div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { LoadingPlugin, Button as TButton } from 'tdesign-mobile-vue';
const content = ref(null);
const attachLoading = ref(false);
// 函数式:局部加载
const showAttach = () => {
const loadingAttachInstance = LoadingPlugin({
attach: () => content.value, // 等于 attach: '#loading-service-demo'
size: '20px',
});
attachLoading.value = true;
const timer = setTimeout(() => {
loadingAttachInstance.hide();
attachLoading.value = false;
clearTimeout(timer);
}, 1000);
};
// 函数式:全屏加载,防止滚动穿透
const showFullScreen = () => {
LoadingPlugin(true);
const timer = setTimeout(() => {
LoadingPlugin(false);
clearTimeout(timer);
}, 1000);
};
</script>

<style scoped>
.loading-demo {
padding: 0 16px;
}
.space {
display: flex;
margin-top: 8px;
gap: 6px;
}
.loading-service-demo {
position: relative;
width: 100%;
height: 64px;
display: flex;
align-items: center;
justify-content: center;
border: 1px var(--component-border, #eee) solid;
}
</style>
3 changes: 3 additions & 0 deletions src/loading/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { TdLoadingProps } from './type';
import './style';

export * from './type';
export * from './plugin';
export { default as LoadingPlugin } from './plugin';

export type LoadingProps = TdLoadingProps;

const _Loading: WithInstallType<typeof Loading> = withInstall(Loading);
Expand Down
12 changes: 12 additions & 0 deletions src/loading/loading.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

name | type | default | description | required
-- | -- | -- | -- | --
attach | String / Function | '' | Typescript:`AttachNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
content | String / Slot / Function | - | Typescript:`string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
default | String / Slot / Function | - | Typescript:`string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
delay | Number | 0 | \- | N
duration | Number | 800 | \- | N
fullscreen | Boolean | false | \- | N
indicator | Boolean / Slot / Function | true | Typescript:`boolean \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
inheritColor | Boolean | false | \- | N
layout | String | horizontal | options: horizontal/vertical | N
Expand All @@ -20,6 +22,16 @@ size | String | '20px' | \- | N
text | String / Slot / Function | - | Typescript:`string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
theme | String | circular | options: circular/spinner/dots | N

### LoadingPlugin

同时也支持 `this.$loading`

name | params | default | description
-- | -- | -- | --
options | Function | - | required。Typescript:`boolean \| TdLoadingProps`

插件返回值:`LoadingInstance【interface LoadingInstance { hide: () => void }】`

### CSS Variables

The component provides the following CSS variables, which can be used to customize styles.
Expand Down
12 changes: 12 additions & 0 deletions src/loading/loading.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
attach | String / Function | '' | 挂载元素,默认挂载到组件本身所在的位置。数据类型为 String 时,会被当作选择器处理,进行节点查询。示例:'body' 或 () => document.body。TS 类型:`AttachNode`[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
content | String / Slot / Function | - | 子元素。TS 类型:`string \| TNode`[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
default | String / Slot / Function | - | 子元素,同 content。TS 类型:`string \| TNode`[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
delay | Number | 0 | 延迟显示加载效果的时间,用于防止请求速度过快引起的加载闪烁,单位:毫秒 | N
duration | Number | 800 | 加载动画执行完成一次的时间,单位:毫秒 | N
fullscreen | Boolean | false | 是否显示为全屏加载 | N
indicator | Boolean / Slot / Function | true | 加载指示符,值为 true 显示默认指示符,值为 false 则不显示,也可以自定义指示符。TS 类型:`boolean \| TNode`[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
inheritColor | Boolean | false | 是否继承父元素颜色 | N
layout | String | horizontal | 对齐方式。可选项:horizontal/vertical | N
Expand All @@ -20,6 +22,16 @@ size | String | '20px' | 尺寸,示例:20px | N
text | String / Slot / Function | - | 加载提示文案。TS 类型:`string \| TNode`[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
theme | String | circular | 加载组件类型。可选项:circular/spinner/dots | N

### LoadingPlugin

同时也支持 `this.$loading`

参数名称 | 参数类型 | 参数默认值 | 参数描述
-- | -- | -- | --
options | Function | - | 必需。TS 类型:`boolean \| TdLoadingProps`

插件返回值:`LoadingInstance【interface LoadingInstance { hide: () => void }】`

### CSS Variables

组件提供了下列 CSS 变量,可用于自定义样式。
Expand Down
46 changes: 45 additions & 1 deletion src/loading/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { defineComponent, computed, ref, watch, h, setBlockTracking } from 'vue';
import { defineComponent, computed, ref, watch, h, setBlockTracking, Teleport, onMounted } from 'vue';
import TGradientIcon from './icon/gradient';
import SpinnerIcon from './icon/spinner';

import config from '../config';
import props from './props';
import { useContent, useTNodeJSX } from '../hooks/tnode';
import { usePrefixClass } from '../hooks/useClass';
import { addClass, getAttach, removeClass } from '@/shared/dom';

const { prefix } = config;

Expand All @@ -18,6 +19,7 @@ export default defineComponent({
const loadingClass = usePrefixClass('loading');

const delayShowLoading = ref(false);
const teleportElement = ref();

const countDelay = () => {
delayShowLoading.value = false;
Expand All @@ -44,6 +46,8 @@ export default defineComponent({
const rootClass = computed(() => [
loadingClass.value,
{ [`${loadingClass.value}--vertical`]: props.layout === 'vertical' },
{ [`${loadingClass.value}--fullscreen`]: props.fullscreen },
{ [`${loadingClass.value}--full`]: !props.fullscreen && !!props.attach },
]);

const textClass = computed(() => [
Expand All @@ -69,6 +73,20 @@ export default defineComponent({
spinner: SpinnerIcon,
};

onMounted(() => {
if (props.attach) {
const attach = getAttach(props.attach);
if (!attach) {
console.error('attach is not exist');
} else {
teleportElement.value = attach;
}
}
if (props.fullscreen) {
teleportElement.value = getAttach('body');
}
});

const dotsLoading = computed(() => {
setBlockTracking(-1);
const node = (
Expand Down Expand Up @@ -119,12 +137,38 @@ export default defineComponent({
return node;
});

watch(
() => props.loading,
(isLoading) => {
if (isLoading && props.fullscreen) {
countDelay();
addClass(document.body, `${loadingClass.value}--lock`);
} else {
removeClass(document.body, `${loadingClass.value}--lock`);
}
},
);

return () => {
const indicator = renderTNodeJSX('indicator', {
defaultNode: props.theme === 'dots' ? dotsLoading.value : defaultLoading.value,
});
const text = renderTNodeJSX('text');
const TNodeContent = renderTNodeContent('default', 'content');

if (props.fullscreen || props.attach) {
if (!props.loading) return null;
return (
<Teleport disabled={!props.attach || !teleportElement.value} to={teleportElement.value}>
<div class={rootClass.value} style={rootStyle.value}>
{realLoading.value && indicator}
{text && realLoading.value && <span class={textClass.value}>{text}</span>}
{TNodeContent}
</div>
</Teleport>
);
}

return (
<div class={rootClass.value} style={rootStyle.value}>
{realLoading.value && indicator}
Expand Down
Loading

0 comments on commit c777ca0

Please sign in to comment.