uni-app 实现 fullpage 组件(适用于微信小程序,h5 等)
纯业务需求
1.组件 src/components/FullPage/index.vue
1 | <template> |
2 | <view class="full-page-container"> |
3 | <view |
4 | class="full-page-main" |
5 | @touchstart="handleTouchStart" |
6 | @touchmove="handleTouchMove" |
7 | @touchend="handleTouchEnd" |
8 | :style="style" |
9 | > |
10 | <slot /> |
11 | </view> |
12 | </view> |
13 | </template> |
14 | |
15 | <script> |
16 | export default { |
17 | name: 'FullPage', |
18 | props: { |
19 | // 触发翻页的临界值 |
20 | critical: { |
21 | type: Number, |
22 | default: 50, |
23 | }, |
24 | // 总共页面数 |
25 | totalPage: { |
26 | type: Number, |
27 | required: true, |
28 | default: 0, |
29 | }, |
30 | // 当前页面的索引值 |
31 | activeIndex: { |
32 | type: Number, |
33 | required: true, |
34 | default: 0, |
35 | }, |
36 | }, |
37 | data() { |
38 | return { |
39 | pageIndex: 0, // 当前页面的索引值 |
40 | startPageY: 0, // 开始的位置 |
41 | endPageY: 0, // 结束的位置 |
42 | marginTop: 0, // 滑动下拉(上拉)距离 |
43 | } |
44 | }, |
45 | mounted() { |
46 | this.pageIndex = this.activeIndex |
47 | }, |
48 | computed: { |
49 | style() { |
50 | return `transform:translateY(-${this.pageIndex * 100}%);margin-top:${ |
51 | this.marginTop |
52 | }px` |
53 | }, |
54 | }, |
55 | watch: { |
56 | activeIndex(value) { |
57 | this.pageIndex = value |
58 | }, |
59 | }, |
60 | methods: { |
61 | // 开始滑动 |
62 | handleTouchStart(e) { |
63 | const { pageY } = e.touches[0] |
64 | this.startPageY = pageY |
65 | }, |
66 | // 滑动中 |
67 | handleTouchMove(e) { |
68 | const { pageY } = e.touches[0] |
69 | if ( |
70 | pageY - this.startPageY < this.critical && |
71 | pageY - this.startPageY > -this.critical |
72 | ) { |
73 | this.marginTop = pageY - this.startPageY |
74 | } |
75 | this.endPageY = pageY |
76 | }, |
77 | // 滑动结束 |
78 | handleTouchEnd() { |
79 | if (!this.endPageY) { |
80 | return |
81 | } |
82 | if ( |
83 | this.endPageY - this.startPageY > this.critical && |
84 | this.pageIndex > 0 |
85 | ) { |
86 | this.pageIndex -= 1 |
87 | } else if ( |
88 | this.endPageY - this.startPageY < -this.critical && |
89 | this.pageIndex < this.totalPage - 1 |
90 | ) { |
91 | this.pageIndex += 1 |
92 | } |
93 | this.$emit('update:activeIndex', this.pageIndex) |
94 | this.startPageY = 0 |
95 | this.endPageY = 0 |
96 | this.marginTop = 0 |
97 | }, |
98 | }, |
99 | } |
100 | </script> |
101 | |
102 | <style lang="scss" scoped> |
103 | .full-page-container { |
104 | height: 100%; |
105 | overflow: hidden; |
106 | .full-page-main { |
107 | height: 100%; |
108 | transition: all 0.3s; |
109 | } |
110 | } |
111 | </style> |
2.使用 /src/pages/index/index.vue
1 | <template> |
2 | <full-page :active-index.sync="activeIndex" :total-page="totalPage"> |
3 | <view |
4 | class="section" |
5 | v-for="(item, index) in totalPage" |
6 | :key="index" |
7 | :style="getRandomStyle()" |
8 | > |
9 | <div :class="'page page-' + index"> |
10 | {{ index + 1 }} |
11 | <button type="primary" @click="toPage(1)"> |
12 | 跳转到第1页 |
13 | </button> |
14 | <button type="primary" @click="toPage(10)"> |
15 | 跳转到第10页 |
16 | </button> |
17 | </div> |
18 | </view> |
19 | </full-page> |
20 | </template> |
21 | |
22 | <script> |
23 | import FullPage from '@/components/FullPage' |
24 | export default { |
25 | components: { |
26 | FullPage, |
27 | }, |
28 | data() { |
29 | return { |
30 | totalPage: 10, |
31 | activeIndex: 0, |
32 | } |
33 | }, |
34 | methods: { |
35 | getRandomStyle() { |
36 | const r = Math.floor(Math.random() * 256) |
37 | const g = Math.floor(Math.random() * 256) |
38 | const b = Math.floor(Math.random() * 256) |
39 | const color = '#' + r.toString(16) + g.toString(16) + b.toString(16) |
40 | return `background-color:${color}` |
41 | }, |
42 | toPage(index) { |
43 | this.activeIndex = index - 1 |
44 | }, |
45 | }, |
46 | } |
47 | </script> |
48 | <style lang="scss" scoped> |
49 | page { |
50 | height: 100%; |
51 | } |
52 | .section { |
53 | height: 100%; |
54 | width: 100%; |
55 | position: relative; |
56 | } |
57 | .page { |
58 | height: 100%; |
59 | width: 100%; |
60 | text-align: center; |
61 | font-size: 50rpx; |
62 | padding-top: 150rpx; |
63 | box-sizing: border-box; |
64 | } |
65 | button { |
66 | font-size: 30rpx; |
67 | width: 400rpx; |
68 | margin: 50rpx; |
69 | } |
70 | </style> |
3.实现效果
参考链接