mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat: loading component
This commit is contained in:
parent
e671e22ea5
commit
e0f9382123
60
src-next/loading/README.md
Normal file
60
src-next/loading/README.md
Normal file
@ -0,0 +1,60 @@
|
||||
# Loading
|
||||
|
||||
### Install
|
||||
|
||||
```js
|
||||
import Vue from 'vue';
|
||||
import { Loading } from 'vant';
|
||||
|
||||
Vue.use(Loading);
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Type
|
||||
|
||||
```html
|
||||
<van-loading /> <van-loading type="spinner" />
|
||||
```
|
||||
|
||||
### Color
|
||||
|
||||
```html
|
||||
<van-loading color="#1989fa" /> <van-loading type="spinner" color="#1989fa" />
|
||||
```
|
||||
|
||||
### Size
|
||||
|
||||
```html
|
||||
<van-loading size="24" /> <van-loading type="spinner" size="24px" />
|
||||
```
|
||||
|
||||
### Text
|
||||
|
||||
```html
|
||||
<van-loading size="24px">Loading...</van-loading>
|
||||
```
|
||||
|
||||
### Vertical
|
||||
|
||||
```html
|
||||
<van-loading size="24px" vertical>Loading...</van-loading>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| color | Loading color | _string_ | `#c9c9c9` |
|
||||
| type | Can be set to `spinner` | _string_ | `circular` |
|
||||
| size | Icon size | _number \| string_ | `30px` |
|
||||
| text-size | Text font size | _number \| string_ | `14px` |
|
||||
| vertical | Whether to arrange icons and text content vertically | _boolean_ | `false` |
|
||||
|
||||
### Slots
|
||||
|
||||
| Name | Description |
|
||||
| ------- | ------------ |
|
||||
| default | Loading text |
|
70
src-next/loading/README.zh-CN.md
Normal file
70
src-next/loading/README.zh-CN.md
Normal file
@ -0,0 +1,70 @@
|
||||
# Loading 加载
|
||||
|
||||
### 引入
|
||||
|
||||
```js
|
||||
import Vue from 'vue';
|
||||
import { Loading } from 'vant';
|
||||
|
||||
Vue.use(Loading);
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 加载类型
|
||||
|
||||
通过`type`属性可以设置加载图标的类型,默认为`circular`,可选值为`spinner`
|
||||
|
||||
```html
|
||||
<van-loading /> <van-loading type="spinner" />
|
||||
```
|
||||
|
||||
### 自定义颜色
|
||||
|
||||
通过`color`属性设置加载图标的颜色
|
||||
|
||||
```html
|
||||
<van-loading color="#1989fa" /> <van-loading type="spinner" color="#1989fa" />
|
||||
```
|
||||
|
||||
### 自定义大小
|
||||
|
||||
通过`size`属性设置加载图标的大小,默认单位为`px`
|
||||
|
||||
```html
|
||||
<van-loading size="24" /> <van-loading type="spinner" size="24px" />
|
||||
```
|
||||
|
||||
### 加载文案
|
||||
|
||||
可以使用默认插槽在图标的右侧插入加载文案
|
||||
|
||||
```html
|
||||
<van-loading size="24px">加载中...</van-loading>
|
||||
```
|
||||
|
||||
### 垂直排列
|
||||
|
||||
设置`vertical`属性后,图标和文案会垂直排列
|
||||
|
||||
```html
|
||||
<van-loading size="24px" vertical>加载中...</van-loading>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --------- | ---------------------------- | ------------------ | ---------- |
|
||||
| color | 颜色 | _string_ | `#c9c9c9` |
|
||||
| type | 类型,可选值为 `spinner` | _string_ | `circular` |
|
||||
| size | 加载图标大小,默认单位为`px` | _number \| string_ | `30px` |
|
||||
| text-size | 文字大小,默认单位为`px` | _number \| string_ | `14px` |
|
||||
| vertical | 是否垂直排列图标和文字内容 | _boolean_ | `false` |
|
||||
|
||||
### Slots
|
||||
|
||||
| 名称 | 说明 |
|
||||
| ------- | -------- |
|
||||
| default | 加载文案 |
|
68
src-next/loading/demo/index.vue
Normal file
68
src-next/loading/demo/index.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<demo-section>
|
||||
<demo-block :title="t('type')">
|
||||
<van-loading />
|
||||
<van-loading type="spinner" />
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="t('color')">
|
||||
<van-loading color="#1989fa" />
|
||||
<van-loading type="spinner" color="#1989fa" />
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="t('size')">
|
||||
<van-loading size="24" />
|
||||
<van-loading type="spinner" size="24" />
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="t('text')">
|
||||
<van-loading size="24px">
|
||||
{{ t('loading') }}
|
||||
</van-loading>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="t('vertical')">
|
||||
<van-loading size="24px" vertical>
|
||||
{{ t('loading') }}
|
||||
</van-loading>
|
||||
</demo-block>
|
||||
</demo-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
i18n: {
|
||||
'zh-CN': {
|
||||
type: '加载类型',
|
||||
text: '加载文案',
|
||||
size: '自定义大小',
|
||||
color: '自定义颜色',
|
||||
vertical: '垂直排列',
|
||||
},
|
||||
'en-US': {
|
||||
type: 'Type',
|
||||
text: 'Text',
|
||||
size: 'Size',
|
||||
color: 'Color',
|
||||
vertical: 'Vertical',
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../style/var';
|
||||
|
||||
.demo-loading {
|
||||
background: @white;
|
||||
|
||||
.van-loading {
|
||||
display: inline-block;
|
||||
margin: 5px 0 5px 20px;
|
||||
|
||||
&--vertical {
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
64
src-next/loading/index.js
Normal file
64
src-next/loading/index.js
Normal file
@ -0,0 +1,64 @@
|
||||
// Utils
|
||||
import { createNamespace, addUnit } from '../utils';
|
||||
|
||||
const [createComponent, bem] = createNamespace('loading');
|
||||
|
||||
const SpinIcon = [];
|
||||
for (let i = 0; i < 12; i++) {
|
||||
SpinIcon.push(<i />);
|
||||
}
|
||||
|
||||
const CircularIcon = (
|
||||
<svg class={bem('circular')} viewBox="25 25 50 50">
|
||||
<circle cx="50" cy="50" r="20" fill="none" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default createComponent({
|
||||
props: {
|
||||
color: String,
|
||||
size: [Number, String],
|
||||
vertical: Boolean,
|
||||
textSize: [Number, String],
|
||||
type: {
|
||||
type: String,
|
||||
default: 'circular',
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
genLoadingText() {
|
||||
if (this.$slots.default) {
|
||||
const style = this.textSize && {
|
||||
fontSize: addUnit(this.textSize),
|
||||
};
|
||||
|
||||
return (
|
||||
<span class={bem('text')} style={style}>
|
||||
{this.$slots.default()}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
const { color, size, type, vertical } = this;
|
||||
|
||||
const style = { color };
|
||||
if (size) {
|
||||
const iconSize = addUnit(size);
|
||||
style.width = iconSize;
|
||||
style.height = iconSize;
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={bem([type, { vertical }])}>
|
||||
<span class={bem('spinner', type)} style={style}>
|
||||
{type === 'spinner' ? SpinIcon : CircularIcon}
|
||||
</span>
|
||||
{this.genLoadingText()}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
103
src-next/loading/index.less
Normal file
103
src-next/loading/index.less
Normal file
@ -0,0 +1,103 @@
|
||||
@import '../style/var';
|
||||
|
||||
.van-loading {
|
||||
position: relative;
|
||||
color: @loading-spinner-color;
|
||||
font-size: 0;
|
||||
vertical-align: middle;
|
||||
|
||||
&__spinner {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: @loading-spinner-size;
|
||||
// compatible for 1.x, users may set width or height in root element
|
||||
max-width: 100%;
|
||||
height: @loading-spinner-size;
|
||||
max-height: 100%;
|
||||
vertical-align: middle;
|
||||
animation: van-rotate @loading-spinner-animation-duration linear infinite;
|
||||
|
||||
&--spinner {
|
||||
animation-timing-function: steps(12);
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&::before {
|
||||
display: block;
|
||||
width: 2px;
|
||||
height: 25%;
|
||||
margin: 0 auto;
|
||||
background-color: currentColor;
|
||||
border-radius: 40%;
|
||||
content: ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--circular {
|
||||
animation-duration: 2s;
|
||||
}
|
||||
}
|
||||
|
||||
&__circular {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
circle {
|
||||
animation: van-circular 1.5s ease-in-out infinite;
|
||||
stroke: currentColor;
|
||||
stroke-width: 3;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
}
|
||||
|
||||
&__text {
|
||||
display: inline-block;
|
||||
margin-left: @padding-xs;
|
||||
color: @loading-text-color;
|
||||
font-size: @loading-text-font-size;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&--vertical {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.van-loading__text {
|
||||
margin: @padding-xs 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes van-circular {
|
||||
0% {
|
||||
stroke-dasharray: 1, 200;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
stroke-dasharray: 90, 150;
|
||||
stroke-dashoffset: -40;
|
||||
}
|
||||
|
||||
100% {
|
||||
stroke-dasharray: 90, 150;
|
||||
stroke-dashoffset: -120;
|
||||
}
|
||||
}
|
||||
|
||||
.generate-spinner(@n, @i: 1) when (@i =< @n) {
|
||||
.van-loading__spinner--spinner i:nth-of-type(@{i}) {
|
||||
transform: rotate(@i * 30deg);
|
||||
opacity: 1 - (0.75 / 12) * (@i - 1);
|
||||
}
|
||||
.generate-spinner(@n, (@i + 1));
|
||||
}
|
||||
.generate-spinner(12);
|
28
src-next/loading/test/__snapshots__/demo.spec.js.snap
Normal file
28
src-next/loading/test/__snapshots__/demo.spec.js.snap
Normal file
@ -0,0 +1,28 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders demo correctly 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<div class="van-loading van-loading--circular"><span class="van-loading__spinner van-loading__spinner--circular"><svg viewBox="25 25 50 50" class="van-loading__circular"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span></div>
|
||||
<div class="van-loading van-loading--spinner"><span class="van-loading__spinner van-loading__spinner--spinner"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></span></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-loading van-loading--circular"><span class="van-loading__spinner van-loading__spinner--circular" style="color: rgb(25, 137, 250);"><svg viewBox="25 25 50 50" class="van-loading__circular"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span></div>
|
||||
<div class="van-loading van-loading--spinner"><span class="van-loading__spinner van-loading__spinner--spinner" style="color: rgb(25, 137, 250);"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></span></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-loading van-loading--circular"><span class="van-loading__spinner van-loading__spinner--circular" style="width: 24px; height: 24px;"><svg viewBox="25 25 50 50" class="van-loading__circular"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span></div>
|
||||
<div class="van-loading van-loading--spinner"><span class="van-loading__spinner van-loading__spinner--spinner" style="width: 24px; height: 24px;"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></span></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-loading van-loading--circular"><span class="van-loading__spinner van-loading__spinner--circular" style="width: 24px; height: 24px;"><svg viewBox="25 25 50 50" class="van-loading__circular"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span><span class="van-loading__text">
|
||||
加载中...
|
||||
</span></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-loading van-loading--circular van-loading--vertical"><span class="van-loading__spinner van-loading__spinner--circular" style="width: 24px; height: 24px;"><svg viewBox="25 25 50 50" class="van-loading__circular"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span><span class="van-loading__text">
|
||||
加载中...
|
||||
</span></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
5
src-next/loading/test/__snapshots__/index.spec.js.snap
Normal file
5
src-next/loading/test/__snapshots__/index.spec.js.snap
Normal file
@ -0,0 +1,5 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`size prop 1`] = `<div class="van-loading van-loading--circular"><span class="van-loading__spinner van-loading__spinner--circular" style="width: 20px; height: 20px;"><svg viewBox="25 25 50 50" class="van-loading__circular"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span></div>`;
|
||||
|
||||
exports[`text-size prop 1`] = `<div class="van-loading van-loading--circular"><span class="van-loading__spinner van-loading__spinner--circular"><svg viewBox="25 25 50 50" class="van-loading__circular"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span><span class="van-loading__text" style="font-size: 20px;">Text</span></div>`;
|
4
src-next/loading/test/demo.spec.js
Normal file
4
src-next/loading/test/demo.spec.js
Normal file
@ -0,0 +1,4 @@
|
||||
import Demo from '../demo';
|
||||
import { snapshotDemo } from '../../../test/demo';
|
||||
|
||||
snapshotDemo(Demo);
|
25
src-next/loading/test/index.spec.js
Normal file
25
src-next/loading/test/index.spec.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { mount } from '../../../test';
|
||||
import Loading from '..';
|
||||
|
||||
test('size prop', () => {
|
||||
const wrapper = mount(Loading, {
|
||||
propsData: {
|
||||
size: 20,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('text-size prop', () => {
|
||||
const wrapper = mount(Loading, {
|
||||
propsData: {
|
||||
textSize: 20,
|
||||
},
|
||||
scopedSlots: {
|
||||
default: () => 'Text',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
@ -192,10 +192,10 @@ module.exports = {
|
||||
// path: 'dropdown-menu',
|
||||
// title: 'DropdownMenu 下拉菜单',
|
||||
// },
|
||||
// {
|
||||
// path: 'loading',
|
||||
// title: 'Loading 加载',
|
||||
// },
|
||||
{
|
||||
path: 'loading',
|
||||
title: 'Loading 加载',
|
||||
},
|
||||
// {
|
||||
// path: 'notify',
|
||||
// title: 'Notify 消息通知',
|
||||
@ -543,10 +543,10 @@ module.exports = {
|
||||
// path: 'dropdown-menu',
|
||||
// title: 'DropdownMenu',
|
||||
// },
|
||||
// {
|
||||
// path: 'loading',
|
||||
// title: 'Loading',
|
||||
// },
|
||||
{
|
||||
path: 'loading',
|
||||
title: 'Loading',
|
||||
},
|
||||
// {
|
||||
// path: 'notify',
|
||||
// title: 'Notify',
|
||||
|
Loading…
x
Reference in New Issue
Block a user