Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(loading): loading新增attach、fullscreen属性,支持函数式调用 #1444

Merged
merged 4 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading