Skip to content

Commit

Permalink
feat: pull-refresh done
Browse files Browse the repository at this point in the history
  • Loading branch information
BeADre committed Jan 3, 2021
1 parent 15a819b commit 152c90c
Show file tree
Hide file tree
Showing 12 changed files with 352 additions and 102 deletions.
1 change: 1 addition & 0 deletions packages/varlet-icons/svg/uF005-refresh.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/varlet-icons/svg/uF006-arrow-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
95 changes: 47 additions & 48 deletions packages/varlet-ui/src/icon/Icon.vue
Original file line number Diff line number Diff line change
@@ -1,57 +1,56 @@
<template>
<i
class="var-icon"
:class="[`${namespace}--set`, `${namespace}-${nextName}`, tickTransition ? 'var-icon--hidden' : null]"
:style="{
color: color,
'font-size': size,
transition: `transform ${transition}ms`,}"
v-bind="$attrs"
/>
<i
class="var-icon"
:class="[`${namespace}--set`, `${namespace}-${nextName}`, tickTransition ? 'var-icon--hidden' : null]"
:style="{
transition: `transform ${transition}ms`,
}"
v-bind="$attrs"
/>
</template>

<script lang="ts">
import { defineComponent, watch, ref, Ref, nextTick } from 'vue'
import { props } from './props'
export default defineComponent({
name: 'VarIcon',
inheritAttrs: false,
props,
setup(props) {
const nextName: Ref<string | undefined> = ref('')
const tickTransition: Ref<boolean> = ref(false)
watch(
() => props.name,
(newValue: string | undefined, oldValue: string | undefined) => {
if (oldValue === undefined) {
nextName.value = newValue
}
tickTransition.value = true
nextTick().then(() => {
setTimeout(() => {
if (oldValue !== undefined) {
nextName.value = newValue
}
tickTransition.value = false
}, props.transition)
})
},
{ immediate: true }
)
return {
nextName,
tickTransition
}
import { defineComponent, watch, ref, Ref, nextTick } from 'vue'
import { props } from './props'
export default defineComponent({
name: 'VarIcon',
inheritAttrs: false,
props,
setup(props) {
const nextName: Ref<string | undefined> = ref('')
const tickTransition: Ref<boolean> = ref(false)
watch(
() => props.name,
(newValue: string | undefined, oldValue: string | undefined) => {
if (oldValue === undefined) {
nextName.value = newValue
}
tickTransition.value = true
nextTick().then(() => {
setTimeout(() => {
if (oldValue !== undefined) {
nextName.value = newValue
}
tickTransition.value = false
}, props.transition)
})
},
{ immediate: true }
)
return {
nextName,
tickTransition,
}
})
},
})
</script>

<style lang="less">
@import './icon';
@import './icon';
</style>
6 changes: 3 additions & 3 deletions packages/varlet-ui/src/progress/example/index.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="progress-demo">
<h3>线性进度条</h3>
<h4>线性进度条</h4>
<div class="progress-demo__basic">
<app-type>基本使用</app-type>
<var-progress :value="20" />
Expand All @@ -26,7 +26,7 @@
<var-progress :value="60" show-action style="color: #72c140" />
</div>

<h3>环形进度条</h3>
<h4>环形进度条</h4>
<div>
<app-type>不同尺寸</app-type>
<div class="progress-demo__circle">
Expand Down Expand Up @@ -115,7 +115,7 @@ export default defineComponent({

<style lang="less" scoped>
.progress-demo {
h3 {
h4 {
margin: 0;
}
Expand Down
72 changes: 47 additions & 25 deletions packages/varlet-ui/src/pull-refresh/PullRefresh.vue
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
<template>
<div
ref="freshNode"
class="var-pull-refresh"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
@touchcancel="
{
touchEnd
}
"
@touchcancel="touchEnd"
>
<div
class="var-pull-refresh__control var-elevation--2"
:style="{
transform: `translate3d(0px, ${distance}px, 0px)`,
transition: isEnd ? `transform ${animationDuration}ms` : null,
}"
>
{{ textStatus }}
<div class="var-pull-refresh__control var-elevation--2" :style="controlStyle">
<var-icon :name="iconName" :transition="200" :class="iconClass" />
</div>
<slot></slot>
</div>
</template>

<script lang="ts">
import { defineComponent, ref, Ref, computed, watch } from 'vue'
import { defineComponent, ref, Ref, computed, watch, onMounted } from 'vue'
import Icon from '../icon'
import { getParentScroller, getScrollTop } from '../utils/elements'
import { props } from './props'
type RefreshStatus = 'default' | 'pulling' | 'loosing' | 'loading' | 'success'
Expand All @@ -33,15 +26,23 @@ const MAX_DISTANCE = 100
const CONTROL_POSITION = -50
let scroller: HTMLElement | Window = window
export default defineComponent({
name: 'VarPullRefresh',
components: {
[Icon.name]: Icon,
},
inheritAttrs: false,
props,
setup(props) {
const freshNode: Ref<HTMLElement | null> = ref(null)
const startPosition: Ref<number> = ref(0)
const distance: Ref<number> = ref(CONTROL_POSITION)
const textStatus: Ref<string> = ref('')
const iconName: Ref<string> = ref('arrow-down')
const refreshStatus: Ref<RefreshStatus> = ref('default')
Expand All @@ -51,27 +52,42 @@ export default defineComponent({
() => refreshStatus.value !== 'loading' && refreshStatus.value !== 'success' && !props.disable
)
const iconClass = computed(() => ({
'var-pull-refresh__animation': refreshStatus.value === 'loading',
}))
const controlStyle = computed(() => ({
transform: `translate3d(0px, ${distance.value}px, 0px) translate(-50%, 0)`,
transition: isEnd.value ? `transform ${props.animationDuration}ms` : null,
background: refreshStatus.value === 'success' ? props.successBgColor : props.bgColor,
color: refreshStatus.value === 'success' ? props.successColor : props.color,
}))
const touchStart = (event: TouchEvent) => {
if (!isTouchable.value) return
refreshStatus.value = 'pulling'
startPosition.value = event.touches[0].clientY
}
const touchMove = (event: TouchEvent) => {
if (!isTouchable.value || distance.value >= MAX_DISTANCE) return
distance.value = (event.touches[0].clientY - startPosition.value) / 2 + CONTROL_POSITION
textStatus.value = distance.value >= MAX_DISTANCE * 0.2 ? '' : ''
const scrollTop = getScrollTop(scroller)
if (scrollTop > 0 || !isTouchable.value) return
if (scrollTop === 0 && distance.value !== CONTROL_POSITION) event.cancelable && event.preventDefault()
const moveDistance = (event.touches[0].clientY - startPosition.value) / 2 + CONTROL_POSITION
distance.value = moveDistance >= MAX_DISTANCE ? MAX_DISTANCE : moveDistance
iconName.value = distance.value >= MAX_DISTANCE * 0.2 ? 'refresh' : 'arrow-down'
}
const touchEnd = () => {
if (!isTouchable.value) return
isEnd.value = true
if (distance.value >= MAX_DISTANCE * 0.2) {
refreshStatus.value = 'loading'
textStatus.value = ''
distance.value = MAX_DISTANCE * 0.3
props.onRefresh?.()
} else {
refreshStatus.value = 'loosing'
textStatus.value = ''
iconName.value = 'arrow-down'
distance.value = CONTROL_POSITION
setTimeout(() => {
isEnd.value = false
Expand All @@ -85,10 +101,10 @@ export default defineComponent({
if (newValue === false) {
isEnd.value = true
refreshStatus.value = 'success'
textStatus.value = 'ok'
iconName.value = 'checkbox-marked-circle'
setTimeout(() => {
refreshStatus.value = 'default'
textStatus.value = ''
iconName.value = 'arrow-down'
distance.value = CONTROL_POSITION
setTimeout(() => {
isEnd.value = false
Expand All @@ -97,13 +113,19 @@ export default defineComponent({
}
}
)
onMounted(() => {
scroller = getParentScroller(freshNode.value as HTMLElement, 'y')
})
return {
freshNode,
touchStart,
touchMove,
touchEnd,
distance,
textStatus,
isEnd,
iconName,
iconClass,
controlStyle,
}
},
})
Expand Down
85 changes: 85 additions & 0 deletions packages/varlet-ui/src/pull-refresh/docs/en_US.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# PullRefresh

### Introduce

Provides a drop-down refresh interaction。

### install

```js
import { PullRefresh } from '@varlet/ui'

export default defineComponent({
components: {
[PullRefresh.name]: PullRefresh,
},
})
```

### Basic Usage

The refresh event will be Emitted when pull refresh, you should set `v-model` to `true` at the beginning of the event indicates that loading is under way, and setting `v-model` to `false` after completion indicates that loading is over.

```html
<var-pull-refresh v-model="isRefresh" @refresh="refresh">
<ul class="pull-refresh__example">
<li v-for="(item, index) in data" :key="index">{{ item + ' ' + (index + 1) }}</li>
</ul>
</var-pull-refresh>
```
```javascript
import { defineComponent, ref } from 'vue'
import PullRefresh from '@varlet/ui'

const data1 = Array(10).fill('List Item')
const data2 = Array(10).fill('This is new List Item')

export default defineComponent({
components: {
[PullRefresh.name]: PullRefresh
},
setup() {
const isRefresh = ref(true)
const data = ref(data1)

const refresh = () => {
isRefresh.value = true
setTimeout(() => {
data.value = data.value[0] === 'List Item' ? data2 : data1
isRefresh.value = false
}, 2000)
}

return {
refresh,
isRefresh,
data
}
}
})
```

## API

### Props

| Attribute | Description | Type | Default |
| ----- | -------------- | -------- | ---------- |
| v-model | Loading status | _boolean_ | - |
| disabled | Whether to disable pull refresh | _boolean_ | `false` |
| animation-duration | Animation duration(ms) | _number__string_ | `300` |
| success-duration | Success text display duration(ms) | _number__string_ | `2000` |
| bgColor | BackgroundColor of control | _string_ | `#005CAF` |
| color | color of control | _string_ | `#ffffff` |
| successBgColor | BackgroundColor of control when the status is success | _string_ | `#4CAF50` |
| successColor | color of control when the status is success | _string_ | `ffffff` |

### Events
| Event | Description | Parameters |
| ----- | -------------- | -------- |
| refresh | Emitted after pulling refresh| - |

### Slots
| Name | Description | SlotProps |
| ----- | -------------- | -------- |
| default | Default slot | - |
Loading

0 comments on commit 152c90c

Please sign in to comment.