From 5218f9cad4abcf163baab6c30852b8ad15b09465 Mon Sep 17 00:00:00 2001 From: ayang <473033518@qq.com> Date: Fri, 25 Feb 2022 23:13:25 +0800 Subject: [PATCH] feat(ui/swipe): add component swipe --- packages/varlet-vue2-ui/src/col/Col.vue | 11 +- packages/varlet-vue2-ui/src/row/Row.vue | 9 +- .../src/swipe-item/SwipeItem.vue | 48 +++ .../src/swipe-item/docs/zh-CN.md | 1 + .../varlet-vue2-ui/src/swipe-item/index.ts | 10 + .../src/swipe-item/swipeItem.less | 5 + packages/varlet-vue2-ui/src/swipe/Swipe.vue | 380 ++++++++++++++++++ .../__snapshots__/index.spec.js.snap | 106 +++++ .../src/swipe/__tests__/index.spec.js | 206 ++++++++++ .../varlet-vue2-ui/src/swipe/docs/en-US.md | 206 ++++++++++ .../varlet-vue2-ui/src/swipe/docs/zh-CN.md | 206 ++++++++++ .../src/swipe/example/index.vue | 150 +++++++ .../src/swipe/example/locale/en-US.ts | 8 + .../src/swipe/example/locale/index.ts | 23 ++ .../src/swipe/example/locale/zh-CN.ts | 8 + packages/varlet-vue2-ui/src/swipe/index.ts | 10 + packages/varlet-vue2-ui/src/swipe/props.ts | 37 ++ packages/varlet-vue2-ui/src/swipe/swipe.less | 59 +++ packages/varlet-vue2-ui/src/utils/elements.ts | 14 +- packages/varlet-vue2-ui/types/index.d.ts | 2 + packages/varlet-vue2-ui/types/swipe.d.ts | 27 ++ packages/varlet-vue2-ui/types/swipeItem.d.ts | 5 + 22 files changed, 1524 insertions(+), 7 deletions(-) create mode 100644 packages/varlet-vue2-ui/src/swipe-item/SwipeItem.vue create mode 100644 packages/varlet-vue2-ui/src/swipe-item/docs/zh-CN.md create mode 100644 packages/varlet-vue2-ui/src/swipe-item/index.ts create mode 100644 packages/varlet-vue2-ui/src/swipe-item/swipeItem.less create mode 100644 packages/varlet-vue2-ui/src/swipe/Swipe.vue create mode 100644 packages/varlet-vue2-ui/src/swipe/__tests__/__snapshots__/index.spec.js.snap create mode 100644 packages/varlet-vue2-ui/src/swipe/__tests__/index.spec.js create mode 100644 packages/varlet-vue2-ui/src/swipe/docs/en-US.md create mode 100644 packages/varlet-vue2-ui/src/swipe/docs/zh-CN.md create mode 100644 packages/varlet-vue2-ui/src/swipe/example/index.vue create mode 100644 packages/varlet-vue2-ui/src/swipe/example/locale/en-US.ts create mode 100644 packages/varlet-vue2-ui/src/swipe/example/locale/index.ts create mode 100644 packages/varlet-vue2-ui/src/swipe/example/locale/zh-CN.ts create mode 100644 packages/varlet-vue2-ui/src/swipe/index.ts create mode 100644 packages/varlet-vue2-ui/src/swipe/props.ts create mode 100644 packages/varlet-vue2-ui/src/swipe/swipe.less create mode 100644 packages/varlet-vue2-ui/types/swipe.d.ts create mode 100644 packages/varlet-vue2-ui/types/swipeItem.d.ts diff --git a/packages/varlet-vue2-ui/src/col/Col.vue b/packages/varlet-vue2-ui/src/col/Col.vue index 83d656e..6e4b18e 100644 --- a/packages/varlet-vue2-ui/src/col/Col.vue +++ b/packages/varlet-vue2-ui/src/col/Col.vue @@ -29,12 +29,16 @@ import { createChildrenMixin } from '../utils/mixins/relation' export default defineComponent({ name: 'VarCol', + + mixins: [createChildrenMixin('row', { childrenKey: 'cols' })], + + props, + data: () => ({ padding: { left: 0, right: 0 }, toSizeUnit, }), - mixins: [createChildrenMixin('row', { childrenKey: 'cols' })], - props, + watch: { span: { handler() { @@ -43,6 +47,7 @@ export default defineComponent({ immediate: true, }, }, + methods: { handleClick(e) { const { getListeners } = this @@ -53,9 +58,11 @@ export default defineComponent({ } onClick(e) }, + setPadding(pad) { this.padding = pad }, + getSize(mode, size) { const classes = [] diff --git a/packages/varlet-vue2-ui/src/row/Row.vue b/packages/varlet-vue2-ui/src/row/Row.vue index 05d970a..5774187 100644 --- a/packages/varlet-vue2-ui/src/row/Row.vue +++ b/packages/varlet-vue2-ui/src/row/Row.vue @@ -22,21 +22,27 @@ import { createParentMixin } from '../utils/mixins/relation' export default defineComponent({ name: 'VarRow', - props, + mixins: [createParentMixin('row', { childrenKey: 'cols' })], + + props, + computed: { average() { return toPxNum(this.gutter) / 2 }, }, + watch: { gutter() { this.computePadding() }, + cols() { this.computePadding() }, }, + methods: { computePadding() { const { average } = this @@ -44,6 +50,7 @@ export default defineComponent({ col.setPadding({ left: average.value, right: average.value }) }) }, + handleClick(e) { const { getListeners } = this const { onClick } = getListeners() diff --git a/packages/varlet-vue2-ui/src/swipe-item/SwipeItem.vue b/packages/varlet-vue2-ui/src/swipe-item/SwipeItem.vue new file mode 100644 index 0000000..a253352 --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe-item/SwipeItem.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/packages/varlet-vue2-ui/src/swipe-item/docs/zh-CN.md b/packages/varlet-vue2-ui/src/swipe-item/docs/zh-CN.md new file mode 100644 index 0000000..5d5ae50 --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe-item/docs/zh-CN.md @@ -0,0 +1 @@ +# 轮播项 \ No newline at end of file diff --git a/packages/varlet-vue2-ui/src/swipe-item/index.ts b/packages/varlet-vue2-ui/src/swipe-item/index.ts new file mode 100644 index 0000000..21b9e74 --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe-item/index.ts @@ -0,0 +1,10 @@ +import type { VueConstructor } from 'vue' +import SwipeItem from './SwipeItem.vue' + +SwipeItem.install = function (app: VueConstructor) { + app.component(SwipeItem.name, SwipeItem) +} + +export const _SwipeItemComponent = SwipeItem + +export default SwipeItem diff --git a/packages/varlet-vue2-ui/src/swipe-item/swipeItem.less b/packages/varlet-vue2-ui/src/swipe-item/swipeItem.less new file mode 100644 index 0000000..6b73d41 --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe-item/swipeItem.less @@ -0,0 +1,5 @@ +.var-swipe-item { + flex-shrink: 0; + width: 100%; + height: 100%; +} diff --git a/packages/varlet-vue2-ui/src/swipe/Swipe.vue b/packages/varlet-vue2-ui/src/swipe/Swipe.vue new file mode 100644 index 0000000..7bcc849 --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/Swipe.vue @@ -0,0 +1,380 @@ + + + + + diff --git a/packages/varlet-vue2-ui/src/swipe/__tests__/__snapshots__/index.spec.js.snap b/packages/varlet-vue2-ui/src/swipe/__tests__/__snapshots__/index.spec.js.snap new file mode 100644 index 0000000..8918f67 --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/__tests__/__snapshots__/index.spec.js.snap @@ -0,0 +1,106 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`test render initial index 1`] = ` +"
+
+
1
+
2
+
3
+
+
+
+
+
+
+
" +`; + +exports[`test swipe next & prev & to method 1`] = ` +"
+
+
1
+
2
+
3
+
+
+
+
+
+
+
" +`; + +exports[`test swipe next & prev & to method 2`] = ` +"
+
+
1
+
2
+
3
+
+
+
+
+
+
+
" +`; + +exports[`test swipe next & prev & to method 3`] = ` +"
+
+
1
+
2
+
3
+
+
+
+
+
+
+
" +`; + +exports[`test swipe next & prev & to method 4`] = ` +"
+
+
1
+
2
+
3
+
+
+
+
+
+
+
" +`; + +exports[`test swipe next & prev & to method 5`] = ` +"
+
+
1
+
2
+
3
+
+
+
+
+
+
+
" +`; + +exports[`test swipe next & prev & to method 6`] = ` +"
+
+
1
+
2
+
3
+
+
+
+
+
+
+
" +`; diff --git a/packages/varlet-vue2-ui/src/swipe/__tests__/index.spec.js b/packages/varlet-vue2-ui/src/swipe/__tests__/index.spec.js new file mode 100644 index 0000000..dfdf2b3 --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/__tests__/index.spec.js @@ -0,0 +1,206 @@ +import Swipe from '..' +import SwipeItem from '../../swipe-item' +import VarSwipe from '../Swipe' +import VarSwipeItem from '../../swipe-item/SwipeItem' +import { mount } from '@vue/test-utils' +import Vue from 'vue' +import { delay, mockOffset, triggerDrag } from '../../utils/jest' + +mockOffset() + +test('test swipe & swipe-item plugin', () => { + Vue.use(Swipe).use(SwipeItem) + expect(Vue.component(Swipe.name)).toBeTruthy() + expect(Vue.component(SwipeItem.name)).toBeTruthy() +}) + +const Wrapper = { + components: { + [VarSwipe.name]: VarSwipe, + [VarSwipeItem.name]: VarSwipeItem, + }, + props: ['onChange', 'initialIndex'], + template: ` + + 1 + 2 + 3 + + `, +} + +test('test swipe next & prev & to method', async () => { + const onChange = jest.fn() + + const wrapper = mount(Wrapper, { + listeners: { + change: onChange, + }, + }) + await delay(50) + + const { + swipe: { prev, next, to }, + } = wrapper.vm.$refs + + to(0) + expect(onChange).toHaveBeenCalledTimes(0) + await delay(100) + expect(wrapper.html()).toMatchSnapshot() + + next() + expect(onChange).toHaveBeenLastCalledWith(1) + await delay(100) + expect(wrapper.html()).toMatchSnapshot() + + prev() + expect(onChange).toHaveBeenLastCalledWith(0) + await delay(100) + expect(wrapper.html()).toMatchSnapshot() + + to(2) + expect(onChange).toHaveBeenLastCalledWith(2) + await delay(100) + expect(wrapper.html()).toMatchSnapshot() + + next() + expect(onChange).toHaveBeenLastCalledWith(0) + await delay(100) + expect(wrapper.html()).toMatchSnapshot() + + prev() + expect(onChange).toHaveBeenLastCalledWith(2) + await delay(100) + expect(wrapper.html()).toMatchSnapshot() + + wrapper.destroy() +}) + +test('test render initial index', async () => { + const wrapper = mount(Wrapper, { + propsData: { + initialIndex: 2, + }, + }) + await delay(50) + expect(wrapper.html()).toMatchSnapshot() + wrapper.destroy() +}) + +test('test touch with loop', async () => { + const onChange = jest.fn() + + const wrapper = mount(Wrapper, { + listeners: { + change: onChange, + }, + }) + await delay(50) + + const track = wrapper.find('.var-swipe__track') + + await triggerDrag(track, -100, 0) + expect(onChange).toHaveBeenLastCalledWith(1) + await triggerDrag(track, -100, 0) + expect(onChange).toHaveBeenLastCalledWith(2) + await triggerDrag(track, -100, 0) + expect(onChange).toHaveBeenLastCalledWith(0) + await triggerDrag(track, 100, 0) + expect(onChange).toHaveBeenLastCalledWith(2) + await triggerDrag(track, 100, 0) + expect(onChange).toHaveBeenLastCalledWith(1) + await triggerDrag(track, 100, 0) + expect(onChange).toHaveBeenLastCalledWith(0) + + wrapper.destroy() +}) + +test('test touch without loop', async () => { + const onChange = jest.fn() + + const wrapper = mount(Wrapper, { + propsData: { + loop: false, + }, + listeners: { + change: onChange, + }, + }) + await delay(50) + + const track = wrapper.find('.var-swipe__track') + + await triggerDrag(track, 100, 0) + expect(onChange).toHaveBeenCalledTimes(0) + await triggerDrag(track, -100, 0) + expect(onChange).toHaveBeenLastCalledWith(1) + await triggerDrag(track, -100, 0) + expect(onChange).toHaveBeenLastCalledWith(2) + await triggerDrag(track, -100, 0) + expect(onChange).toHaveBeenLastCalledWith(2) + + wrapper.destroy() +}) + +test('test touch with vertical', async () => { + const onChange = jest.fn() + + const wrapper = mount(Wrapper, { + propsData: { + vertical: true, + }, + listeners: { + change: onChange, + }, + }) + await delay(50) + + const track = wrapper.find('.var-swipe__track') + + await triggerDrag(track, 0, -100) + expect(onChange).toHaveBeenCalledTimes(1) + await triggerDrag(track, 0, -100) + expect(onChange).toHaveBeenLastCalledWith(2) + + wrapper.destroy() +}) + +test('test touch forbid touchable', async () => { + const onChange = jest.fn() + + const wrapper = mount(Wrapper, { + propsData: { + touchable: false, + }, + listeners: { + change: onChange, + }, + }) + await delay(50) + + const track = wrapper.find('.var-swipe__track') + + await triggerDrag(track, -100, 0) + expect(onChange).toHaveBeenCalledTimes(0) + + wrapper.destroy() +}) + +test('test autoplay', async () => { + const onChange = jest.fn() + + const wrapper = mount(Wrapper, { + propsData: { + autoplay: 100, + }, + listeners: { + change: onChange, + }, + }) + await delay(100) + await delay(100) + expect(onChange).toHaveBeenLastCalledWith(1) + await delay(100) + expect(onChange).toHaveBeenLastCalledWith(2) + wrapper.destroy() +}) diff --git a/packages/varlet-vue2-ui/src/swipe/docs/en-US.md b/packages/varlet-vue2-ui/src/swipe/docs/en-US.md new file mode 100644 index 0000000..83beeab --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/docs/en-US.md @@ -0,0 +1,206 @@ +# Swipe + +### Install + +```js +import Vue from 'vue' +import { Swipe, SwipeItem } from '@varlet-vue2/ui' + +Vue.use(Swipe).use(SwipeItem) +``` + +### Basic Usage + +```html + + + + + + + + + + + +``` + +```css +.swipe { + height: 160px; +} + +.swipe-item { + width: 100%; + height: 100%; + object-fit: cover; +} +``` + +### Forbid Loop + +```html + + + + + + + + + + + +``` + +### Autoplay + +```html + + + + + + + + + + + +``` + +### Vertical Swipe + +```html + + + + + + + + + + + +``` + +### Handle Change + +```html + + + + + + + + + + + +``` + +```js +import { Snackbar } from '@varlet-vue2/ui' + +export default { + methods: { + Snackbar + } +} +``` + +### Custom Indicator + +```html + + + + + +``` + +```css +.swipe { + height: 160px; +} + +.swipe-item { + width: 100%; + height: 100%; + object-fit: cover; +} + +.indicators { + position: absolute; + bottom: 0; + width: 100%; + text-align: center; + padding: 4px 0; + color: #fff; + font-size: 14px; + background: rgba(0, 0, 0, 0.6); +} +``` + +## API + +### Props + +| Prop | Description | Type | Default | +| --- | --- | --- | --- | +| `loop` | Whether to swipe the loop | _boolean_ | `true` | +| `autoplay` | Auto play interval time(ms) | _string \| number_ | `-` | +| `duration` | Transition time | _string \| number_ | `300` | +| `initial-index` | Initializes the index displayed | _string \| number_ | `0` | +| `indicator` | Whether to display the indicator | _boolean_ | `true` | +| `indicator-color` | Indicator color | _string_ | `-` | +| `vertical` | Whether to enable vertical swipe | _boolean_ | `false` | +| `touchable` | Whether to enable touch | _boolean_ | `true` | + +### Methods + +| Method | Description | Arguments | Return | +| --- | --- | --- | --- | +| `resize` | You can call this method to redraw when a tabs changes position size | `-` | `-` | +| `prev` | Previous page | `-` | `-` | +| `next` | Next page | `-` | `-` | +| `to` | To index page | `index: number` | `-` | + +### Events + +| Event | Description | Arguments | +| --- | --- | --- | +| `change` | Triggered when change swipe | `index: number` swipe index | + +### Slots + +| Slot | Description | Arguments | +| --- | --- | --- | +| `default` | Swipe content | `-` | +| `indicator` | Swipe indicator content | `index: number`
`length: number` | + +### Style Variables + +Here are the CSS variables used by the component, Styles can be customized using [StyleProvider](#/en-US/style-provider) + +| Variable | Default | +| --- | --- | +| `--swipe-indicator-color` | `#fff` | +| `--swipe-indicators-offset` | `10px` | +| `--swipe-indicator-offset` | `4px` | \ No newline at end of file diff --git a/packages/varlet-vue2-ui/src/swipe/docs/zh-CN.md b/packages/varlet-vue2-ui/src/swipe/docs/zh-CN.md new file mode 100644 index 0000000..f65234a --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/docs/zh-CN.md @@ -0,0 +1,206 @@ +# 轮播 + +### 引入 + +```js +import Vue from 'vue' +import { Swipe, SwipeItem } from '@varlet-vue2/ui' + +Vue.use(Swipe).use(SwipeItem) +``` + +### 基本使用 + +```html + + + + + + + + + + + +``` + +```css +.swipe { + height: 160px; +} + +.swipe-item { + width: 100%; + height: 100%; + object-fit: cover; +} +``` + +### 禁止循环轮播 + +```html + + + + + + + + + + + +``` + +### 开启自动播放 + +```html + + + + + + + + + + + +``` + +### 垂直轮播 + +```html + + + + + + + + + + + +``` + +### 监听切换 + +```html + + + + + + + + + + + +``` + +```js +import { Snackbar } from '@varlet-vue2/ui' + +export default { + methods: { + Snackbar + } +} +``` + +### 自定义指示器 + +```html + + + + + +``` + +```css +.swipe { + height: 160px; +} + +.swipe-item { + width: 100%; + height: 100%; + object-fit: cover; +} + +.indicators { + position: absolute; + bottom: 0; + width: 100%; + text-align: center; + padding: 4px 0; + color: #fff; + font-size: 14px; + background: rgba(0, 0, 0, 0.6); +} +``` + +## API + +### 属性 + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| `loop` | 是否开启循环轮播 | _boolean_ | `true` | +| `autoplay` | 自动播放间隔时间 (ms) | _string \| number_ | `-` | +| `duration` | 切换过度时间 | _string \| number_ | `300` | +| `initial-index` | 初始化显示的索引 | _string \| number_ | `0` | +| `indicator` | 是否显示指示器 | _boolean_ | `true` | +| `indicator-color` | 指示器颜色 | _string_ | `-` | +| `vertical` | 是否开启垂直轮播 | _boolean_ | `false` | +| `touchable` | 是否可以拖动 | _boolean_ | `true` | + +### 方法 + +| 方法名 | 说明 | 参数 | 返回值 | +| --- | --- | --- | --- | +| `resize` | 产生位置大小变化时可以调用此方法进行重绘 | `-` | `-` | +| `prev` | 上一页 | `-` | `-` | +| `next` | 下一页 | `-` | `-` | +| `to` | 跳转到指定下标 | `index: number` | `-` | + +### 事件 + +| 事件名 | 说明 | 参数 | +| --- | --- | --- | +| `change` | 切换轮播时触发 | `index: number` 轮播索引 | + +### 插槽 + +| 插槽名 | 说明 | 参数 | +| --- | --- | --- | +| `default` | 轮播内容 | `-` | +| `indicator` | 指示器内容 | `index: number` 轮播索引
`length: number` 轮播总数 | + +### 样式变量 + +以下为组件使用的 css 变量,可以使用 [StyleProvider 组件](#/zh-CN/style-provider)进行样式定制 + +| 变量名 | 默认值 | +| --- | --- | +| `--swipe-indicator-color` | `#fff` | +| `--swipe-indicators-offset` | `10px` | +| `--swipe-indicator-offset` | `4px` | diff --git a/packages/varlet-vue2-ui/src/swipe/example/index.vue b/packages/varlet-vue2-ui/src/swipe/example/index.vue new file mode 100644 index 0000000..2d8929e --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/example/index.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/packages/varlet-vue2-ui/src/swipe/example/locale/en-US.ts b/packages/varlet-vue2-ui/src/swipe/example/locale/en-US.ts new file mode 100644 index 0000000..ce45a75 --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/example/locale/en-US.ts @@ -0,0 +1,8 @@ +export default { + basicUsage: 'Basic Usage', + forbidLoop: 'Forbid Loop', + autoplay: 'Autoplay', + vertical: 'Vertical Swipe', + handleChange: 'Handle Change', + customIndicator: 'Custom Indicator', +} diff --git a/packages/varlet-vue2-ui/src/swipe/example/locale/index.ts b/packages/varlet-vue2-ui/src/swipe/example/locale/index.ts new file mode 100644 index 0000000..d2e375e --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/example/locale/index.ts @@ -0,0 +1,23 @@ +// lib +import _zhCN from '../../../locale/zh-CN' +import _enCN from '../../../locale/en-US' +// mobile example doc +import zhCN from './zh-CN' +import enUS from './en-US' +import { useLocale, add as _add, use as _use } from '../../../locale' + +const { add, use: exampleUse, pack, packs, merge } = useLocale() + +const use = (lang: string) => { + _use(lang) + exampleUse(lang) +} + +export { add, pack, packs, merge, use } + +// lib +_add('zh-CN', _zhCN) +_add('en-US', _enCN) +// mobile example doc +add('zh-CN', zhCN as any) +add('en-US', enUS as any) diff --git a/packages/varlet-vue2-ui/src/swipe/example/locale/zh-CN.ts b/packages/varlet-vue2-ui/src/swipe/example/locale/zh-CN.ts new file mode 100644 index 0000000..8a53444 --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/example/locale/zh-CN.ts @@ -0,0 +1,8 @@ +export default { + basicUsage: '基本使用', + forbidLoop: '禁止循环轮播', + autoplay: '开启自动播放', + vertical: '垂直轮播', + handleChange: '监听切换', + customIndicator: '自定义指示器', +} diff --git a/packages/varlet-vue2-ui/src/swipe/index.ts b/packages/varlet-vue2-ui/src/swipe/index.ts new file mode 100644 index 0000000..d02db4e --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/index.ts @@ -0,0 +1,10 @@ +import type { VueConstructor } from 'vue' +import Swipe from './Swipe.vue' + +Swipe.install = function (app: VueConstructor) { + app.component(Swipe.name, Swipe) +} + +export const _SwipeComponent = Swipe + +export default Swipe diff --git a/packages/varlet-vue2-ui/src/swipe/props.ts b/packages/varlet-vue2-ui/src/swipe/props.ts new file mode 100644 index 0000000..a076ba5 --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/props.ts @@ -0,0 +1,37 @@ +import type { PropType } from 'vue' + +export const props = { + loop: { + type: Boolean, + default: true, + }, + autoplay: { + type: [String, Number], + }, + duration: { + type: [String, Number], + default: 300, + }, + initialIndex: { + type: [String, Number], + default: 0, + }, + indicator: { + type: Boolean, + default: true, + }, + indicatorColor: { + type: String, + }, + vertical: { + type: Boolean, + default: false, + }, + touchable: { + type: Boolean, + default: true, + }, + onChange: { + type: Function as PropType<(index: number) => void>, + }, +} diff --git a/packages/varlet-vue2-ui/src/swipe/swipe.less b/packages/varlet-vue2-ui/src/swipe/swipe.less new file mode 100644 index 0000000..086cbb4 --- /dev/null +++ b/packages/varlet-vue2-ui/src/swipe/swipe.less @@ -0,0 +1,59 @@ +@swipe-indicator-color: #fff; +@swipe-indicators-offset: 10px; +@swipe-indicator-offset: 4px; + +:root { + --swipe-indicator-color: @swipe-indicator-color; + --swipe-indicators-offset: @swipe-indicators-offset; + --swipe-indicator-offset: @swipe-indicator-offset; +} + +.var-swipe { + position: relative; + overflow: hidden; + user-select: none; + + &__track { + width: 100%; + height: 100%; + display: flex; + transition-property: transform; + } + + &__indicators { + position: absolute; + display: flex; + bottom: var(--swipe-indicators-offset); + left: 50%; + transform: translateX(-50%); + } + + &__indicator { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--swipe-indicator-color); + opacity: 0.3; + margin: 0 var(--swipe-indicator-offset); + transition: opacity 0.3s; + } + + &--vertical { + flex-direction: column; + } + + &--indicators-vertical { + flex-direction: column; + left: var(--swipe-indicators-offset); + bottom: 50%; + transform: translateY(50%); + } + + &--indicator-active { + opacity: 1; + } + + &--indicator-vertical { + margin: var(--swipe-indicator-offset) 0; + } +} diff --git a/packages/varlet-vue2-ui/src/utils/elements.ts b/packages/varlet-vue2-ui/src/utils/elements.ts index da84a91..2bfd0f6 100644 --- a/packages/varlet-vue2-ui/src/utils/elements.ts +++ b/packages/varlet-vue2-ui/src/utils/elements.ts @@ -33,6 +33,12 @@ export function doubleRaf() { }) } +export function nextTickFrame(fn: FrameRequestCallback) { + window.requestAnimationFrame(() => { + window.requestAnimationFrame(fn) + }) +} + export async function inViewport(element: HTMLElement): Promise { await doubleRaf() const { top, bottom, left, right } = element.getBoundingClientRect() @@ -152,10 +158,10 @@ export function cancelAnimationFrame(handle: number): void { } interface ScrollToOptions { - top?: number; - left?: number; - duration?: number; - animation: (progress: number) => number; + top?: number + left?: number + duration?: number + animation: (progress: number) => number } export function scrollTo( diff --git a/packages/varlet-vue2-ui/types/index.d.ts b/packages/varlet-vue2-ui/types/index.d.ts index f5686d2..17249bd 100644 --- a/packages/varlet-vue2-ui/types/index.d.ts +++ b/packages/varlet-vue2-ui/types/index.d.ts @@ -38,5 +38,7 @@ export * from './timePicker' export * from './ripple' export * from './checkbox' export * from './checkboxGroup' +export * from './swipe' +export * from './swipeItem' export * from './varComponent' export * from './varDirective' diff --git a/packages/varlet-vue2-ui/types/swipe.d.ts b/packages/varlet-vue2-ui/types/swipe.d.ts new file mode 100644 index 0000000..34ba1fd --- /dev/null +++ b/packages/varlet-vue2-ui/types/swipe.d.ts @@ -0,0 +1,27 @@ +import { VarComponent } from './varComponent' + +export interface SwipeProps { + loop?: boolean + autoplay?: string | number + duration?: string | number + initialIndex?: string | number + indicator?: boolean + indicatorColor?: string + vertical?: boolean + touchable?: boolean + onChange?: (index: number) => void +} + +export class Swipe extends VarComponent { + $props: SwipeProps + + resize(): void + + prev(): void + + next(): void + + to(index: number): void +} + +export class _SwipeComponent extends Swipe {} diff --git a/packages/varlet-vue2-ui/types/swipeItem.d.ts b/packages/varlet-vue2-ui/types/swipeItem.d.ts new file mode 100644 index 0000000..13c579f --- /dev/null +++ b/packages/varlet-vue2-ui/types/swipeItem.d.ts @@ -0,0 +1,5 @@ +import { VarComponent } from './varComponent' + +export class SwipeItem extends VarComponent {} + +export class _SwipeItemComponent extends SwipeItem {}