u-scroll-list.vue 6.02 KB
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
<template>
<view
class="u-scroll-list"
ref="u-scroll-list"
>
<!-- #ifdef APP-NVUE -->
<!-- nvue使用bindingX实现,以得到更好的性能 -->
<scroller
class="u-scroll-list__scroll-view"
ref="u-scroll-list__scroll-view"
scroll-direction="horizontal"
:show-scrollbar="false"
:offset-accuracy="1"
@scroll="nvueScrollHandler"
>
<view class="u-scroll-list__scroll-view__content">
<slot />
</view>
</scroller>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<!-- #ifdef MP-WEIXIN || APP-VUE || H5 || MP-QQ -->
<!-- 以上平台,支持wxs -->
<scroll-view
class="u-scroll-list__scroll-view"
scroll-x
@scroll="wxs.scroll"
@scrolltoupper="wxs.scrolltoupper"
@scrolltolower="wxs.scrolltolower"
:data-scrollWidth="scrollWidth"
:data-barWidth="$u.getPx(indicatorBarWidth)"
:data-indicatorWidth="$u.getPx(indicatorWidth)"
:show-scrollbar="false"
:upper-threshold="0"
:lower-threshold="0"
>
<!-- #endif -->
<!-- #ifndef APP-NVUE || MP-WEIXIN || H5 || APP-VUE || MP-QQ -->
<!-- 非以上平台,只能使用普通js实现 -->
<scroll-view
class="u-scroll-list__scroll-view"
scroll-x
@scroll="scrollHandler"
@scrolltoupper="scrolltoupperHandler"
@scrolltolower="scrolltolowerHandler"
:show-scrollbar="false"
:upper-threshold="0"
:lower-threshold="0"
>
<!-- #endif -->
<view class="u-scroll-list__scroll-view__content">
<slot />
</view>
</scroll-view>
<!-- #endif -->
<view
class="u-scroll-list__indicator"
v-if="indicator"
:style="[$u.addStyle(indicatorStyle)]"
>
<view
class="u-scroll-list__indicator__line"
:style="[lineStyle]"
>
<view
class="u-scroll-list__indicator__line__bar"
:style="[barStyle]"
ref="u-scroll-list__indicator__line__bar"
></view>
</view>
</view>
</view>
</template>

<script
src="./scrollWxs.wxs"
module="wxs"
lang="wxs"
></script>

<script>
/**
* scrollList 横向滚动列表
* @description 该组件一般用于同时展示多个商品、分类的场景,也可以完成左右滑动的列表。
* @tutorial https://www.uviewui.com/components/scrollList.html
* @property {String | Number} indicatorWidth 指示器的整体宽度 (默认 50 )
* @property {String | Number} indicatorBarWidth 滑块的宽度 (默认 20 )
* @property {Boolean} indicator 是否显示面板指示器 (默认 true )
* @property {String} indicatorColor 指示器非激活颜色 (默认 '#f2f2f2' )
* @property {String} indicatorActiveColor 指示器的激活颜色 (默认 '#3c9cff' )
* @property {String | Object} indicatorStyle 指示器样式,可通过bottom,left,right进行定位
* @event {Function} left 滑动到左边时触发
* @event {Function} right 滑动到右边时触发
* @example
*/
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom')
import nvueMixin from "./nvue.js"
// #endif
import props from './props.js';
export default {
name: 'u-scroll-list',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
// #ifdef APP-NVUE
mixins: [uni.$u.mpMixin, uni.$u.mixin, nvueMixin, props],
// #endif
data() {
return {
scrollInfo: {
scrollLeft: 0,
scrollWidth: 0
},
scrollWidth: 0
}
},
computed: {
// 指示器为线型的样式
barStyle() {
const style = {}
// #ifndef APP-NVUE || MP-WEIXIN || H5 || APP-VUE || MP-QQ
// 此为普通js方案,只有在非nvue和不支持wxs方案的端才使用、
// 此处的计算理由为:scroll-view的滚动距离与目标滚动距离(scroll-view的实际宽度减去包裹元素的宽度)之比,等于滑块当前移动距离与总需
// 滑动距离(指示器的总宽度减去滑块宽度)的比值
const scrollLeft = this.scrollInfo.scrollLeft,
scrollWidth = this.scrollInfo.scrollWidth,
barAllMoveWidth = this.indicatorWidth - this.indicatorBarWidth
const x = scrollLeft / (scrollWidth - this.scrollWidth) * barAllMoveWidth
style.transform = `translateX(${ x }px)`
// #endif
// 设置滑块的宽度和背景色,是每个平台都需要的
style.width = uni.$u.addUnit(this.indicatorBarWidth)
style.backgroundColor = this.indicatorActiveColor
return style
},
lineStyle() {
const style = {}
// 指示器整体的样式,需要设置其宽度和背景色
style.width = uni.$u.addUnit(this.indicatorWidth)
style.backgroundColor = this.indicatorColor
return style
}
},
mounted() {
this.init()
},
methods: {
init() {
this.getComponentWidth()
},
// #ifndef APP-NVUE || MP-WEIXIN || H5 || APP-VUE || MP-QQ
// scroll-view触发滚动事件
scrollHandler(e) {
this.scrollInfo = e.detail
},
scrolltoupperHandler() {
this.scrollEvent('left')
this.scrollInfo.scrollLeft = 0
},
scrolltolowerHandler() {
this.scrollEvent('right')
// 在普通js方案中,滚动到右边时,通过设置this.scrollInfo,模拟出滚动到右边的情况
// 因为上方是用过computed计算的,设置后,会自动调整滑块的位置
this.scrollInfo.scrollLeft = uni.$u.getPx(this.indicatorWidth) - uni.$u.getPx(this.indicatorBarWidth)
},
// #endif
//
scrollEvent(status) {
this.$emit(status)
},
// 获取组件的宽度
async getComponentWidth() {
// 延时一定时间,以获取dom尺寸
await uni.$u.sleep(30)
// #ifndef APP-NVUE
this.$uGetRect('.u-scroll-list').then(size => {
this.scrollWidth = size.width
})
// #endif

// #ifdef APP-NVUE
const ref = this.$refs['u-scroll-list']
ref && dom.getComponentRect(ref, (res) => {
this.scrollWidth = res.size.width
})
// #endif
},
}
}
</script>

<style lang="scss" scoped>
@import "../../libs/css/components.scss";

.u-scroll-list {
padding-bottom: 10px;

&__scroll-view {
@include flex;

&__content {
@include flex;
}
}

&__indicator {
@include flex;
justify-content: center;
margin-top: 15px;

&__line {
width: 60px;
height: 4px;
border-radius: 100px;
overflow: hidden;

&__bar {
width: 20px;
height: 4px;
border-radius: 100px;
}
}
}
}
</style>