金诚优选前端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
11 KiB

  1. <template>
  2. <view class="u-swiper-wrap" :style="{borderRadius: `${borderRadius}rpx`}">
  3. <swiper :current="elCurrent" @change="change"
  4. @animationfinish="animationfinish"
  5. :interval="interval" :circular="circular"
  6. :duration="duration" :autoplay="autoplay"
  7. :previous-margin="effect3d ? effect3dPreviousMargin + 'rpx' : '0'"
  8. :next-margin="effect3d ? effect3dPreviousMargin + 'rpx' : '0'"
  9. :style="{height: height + 'rpx',backgroundColor: bgColor}">
  10. <swiper-item class="u-swiper-item" v-for="(item, index) in list" :key="index">
  11. <view class="u-list-image-wrap"
  12. @tap.stop.prevent="listClick(index)"
  13. :class="[uCurrent != index ? 'u-list-scale' : '']"
  14. :style="{borderRadius: `${borderRadius}rpx`,
  15. transform: effect3d && uCurrent != index ? 'scaleY(0.9)' : 'scaleY(1)',
  16. margin: effect3d && uCurrent != index ? '0 20rpx' : 0
  17. }">
  18. <!-- 图片 -->
  19. <image class="u-swiper-image" :src="item[name] || item" :mode="imgMode"></image>
  20. <!-- 自己加的内容 -->
  21. <view class="swiper-diy-left" @click.stop.prevent="$emit('clickDiy', {'index': index, 'type': 'btn1'})">
  22. <text>查看会员权益和细则</text>
  23. </view>
  24. <view class="swiper-diy-right" @click.stop.prevent="$emit('clickDiy', {'index': index, 'type': 'btn2'})">
  25. <text class="lf-iconfont icon-erweima lf-font-30"></text>
  26. </view>
  27. <view v-if="title && item.title" class="u-swiper-title u-line-1"
  28. :style="[{'padding-bottom': titlePaddingBottom}, titleStyle]">
  29. {{ item.title }}
  30. </view>
  31. </view>
  32. </swiper-item>
  33. </swiper>
  34. <view class="u-swiper-indicator" :style="{
  35. top: indicatorPos == 'topLeft' || indicatorPos == 'topCenter' || indicatorPos == 'topRight' ? '12rpx' : 'auto',
  36. bottom: indicatorPos == 'bottomLeft' || indicatorPos == 'bottomCenter' || indicatorPos == 'bottomRight' ? '12rpx' : 'auto',
  37. justifyContent: justifyContent,
  38. padding: `0 ${effect3d ? '74rpx' : '24rpx'}`
  39. }">
  40. <block v-if="mode == 'rect'">
  41. <view class="u-indicator-item-rect"
  42. :class="{ 'u-indicator-item-rect-active': index == uCurrent }"
  43. v-for="(item, index) in list" :key="index">
  44. </view>
  45. </block>
  46. <block v-if="mode == 'dot'">
  47. <view class="u-indicator-item-dot"
  48. :class="{ 'u-indicator-item-dot-active': index == uCurrent }"
  49. v-for="(item, index) in list" :key="index">
  50. </view>
  51. </block>
  52. <block v-if="mode == 'round'">
  53. <view class="u-indicator-item-round"
  54. :class="{ 'u-indicator-item-round-active': index == uCurrent }"
  55. v-for="(item, index) in list" :key="index">
  56. </view>
  57. </block>
  58. <block v-if="mode == 'number'">
  59. <view class="u-indicator-item-number">{{ uCurrent + 1 }}/{{ list.length }}</view>
  60. </block>
  61. </view>
  62. </view>
  63. </template>
  64. <script>
  65. /**
  66. * swiper 轮播图
  67. * @description 该组件一般用于导航轮播广告展示等场景,可开箱即用
  68. * @tutorial https://www.uviewui.com/components/swiper.html
  69. * @property {Array} list 轮播图数据见官网"基本使用"说明
  70. * @property {Boolean} title 是否显示标题文字需要配合list参数见官网说明默认false
  71. * @property {String} mode 指示器模式见官网说明默认round
  72. * @property {String Number} height 轮播图组件高度单位rpx默认250
  73. * @property {String} indicator-pos 指示器的位置默认bottomCenter
  74. * @property {Boolean} effect3d 是否开启3D效果默认false
  75. * @property {Boolean} autoplay 是否自动播放默认true
  76. * @property {String Number} interval 自动轮播时间间隔单位ms默认2500
  77. * @property {Boolean} circular 是否衔接播放见官网说明默认true
  78. * @property {String} bg-color 背景颜色默认#f3f4f6
  79. * @property {String Number} border-radius 轮播图圆角值单位rpx默认8
  80. * @property {Object} title-style 自定义标题样式
  81. * @property {String Number} effect3d-previous-margin mode = true模式的情况下激活项与前后项之间的距离单位rpx默认50
  82. * @property {String} img-mode 图片的裁剪模式详见image组件裁剪模式默认aspectFill
  83. * @event {Function} click 点击轮播图时触发
  84. * @example <u-swiper :list="list" mode="dot" indicator-pos="bottomRight"></u-swiper>
  85. */
  86. export default {
  87. name: "u-swiper",
  88. props: {
  89. // 轮播图的数据,格式如:[{image: 'xxxx', title: 'xxxx'},{image: 'yyyy', title: 'yyyy'}],其中title字段可选
  90. list: {
  91. type: Array,
  92. default () {
  93. return [];
  94. }
  95. },
  96. // 是否显示title标题
  97. title: {
  98. type: Boolean,
  99. default: false
  100. },
  101. // 用户自定义的指示器的样式
  102. indicator: {
  103. type: Object,
  104. default () {
  105. return {};
  106. }
  107. },
  108. // 圆角值
  109. borderRadius: {
  110. type: [Number, String],
  111. default: 8
  112. },
  113. // 隔多久自动切换
  114. interval: {
  115. type: [String, Number],
  116. default: 3000
  117. },
  118. // 指示器的模式,rect|dot|number|round
  119. mode: {
  120. type: String,
  121. default: 'round'
  122. },
  123. // list的高度,单位rpx
  124. height: {
  125. type: [Number, String],
  126. default: 250
  127. },
  128. // 指示器的位置,topLeft|topCenter|topRight|bottomLeft|bottomCenter|bottomRight
  129. indicatorPos: {
  130. type: String,
  131. default: 'bottomCenter'
  132. },
  133. // 是否开启缩放效果
  134. effect3d: {
  135. type: Boolean,
  136. default: false
  137. },
  138. // 3D模式的情况下,激活item与前后item之间的距离,单位rpx
  139. effect3dPreviousMargin: {
  140. type: [Number, String],
  141. default: 50
  142. },
  143. // 是否自动播放
  144. autoplay: {
  145. type: Boolean,
  146. default: true
  147. },
  148. // 自动轮播时间间隔,单位ms
  149. duration: {
  150. type: [Number, String],
  151. default: 500
  152. },
  153. // 是否衔接滑动,即到最后一张时接着滑动,是否自动切换到第一张
  154. circular: {
  155. type: Boolean,
  156. default: true
  157. },
  158. // 图片的裁剪模式
  159. imgMode: {
  160. type: String,
  161. default: 'aspectFill'
  162. },
  163. // 从list数组中读取的图片的属性名
  164. name: {
  165. type: String,
  166. default: 'image'
  167. },
  168. // 背景颜色
  169. bgColor: {
  170. type: String,
  171. default: '#f3f4f6'
  172. },
  173. // 初始化时,默认显示第几项
  174. current: {
  175. type: [Number, String],
  176. default: 0
  177. },
  178. // 标题的样式,对象形式
  179. titleStyle: {
  180. type: Object,
  181. default() {
  182. return {}
  183. }
  184. }
  185. },
  186. watch: {
  187. // 如果外部的list发生变化,判断长度是否被修改,如果前后长度不一致,重置uCurrent值,避免溢出
  188. list(nVal, oVal) {
  189. if(nVal.length !== oVal.length) this.uCurrent = 0;
  190. },
  191. // 监听外部current的变化,实时修改内部依赖于此测uCurrent值,如果更新了current,而不是更新uCurrent,
  192. // 就会错乱,因为指示器是依赖于uCurrent的
  193. current(n) {
  194. this.uCurrent = n;
  195. }
  196. },
  197. data() {
  198. return {
  199. uCurrent: this.current // 当前活跃的swiper-item的index
  200. };
  201. },
  202. computed: {
  203. justifyContent() {
  204. if (this.indicatorPos == 'topLeft' || this.indicatorPos == 'bottomLeft') return 'flex-start';
  205. if (this.indicatorPos == 'topCenter' || this.indicatorPos == 'bottomCenter') return 'center';
  206. if (this.indicatorPos == 'topRight' || this.indicatorPos == 'bottomRight') return 'flex-end';
  207. },
  208. titlePaddingBottom() {
  209. let tmp = 0;
  210. if (this.mode == 'none') return '12rpx';
  211. if (['bottomLeft', 'bottomCenter', 'bottomRight'].indexOf(this.indicatorPos) >= 0 && this.mode == 'number') {
  212. tmp = '60rpx';
  213. } else if (['bottomLeft', 'bottomCenter', 'bottomRight'].indexOf(this.indicatorPos) >= 0 && this.mode != 'number') {
  214. tmp = '40rpx';
  215. } else {
  216. tmp = '12rpx';
  217. }
  218. return tmp;
  219. },
  220. // 因为uni的swiper组件的current参数只接受Number类型,这里做一个转换
  221. elCurrent() {
  222. return Number(this.current);
  223. }
  224. },
  225. methods: {
  226. listClick(index) {
  227. this.$emit('click', index);
  228. },
  229. change(e) {
  230. let current = e.detail.current;
  231. this.uCurrent = current;
  232. // 发出change事件,表示当前自动切换的index,从0开始
  233. this.$emit('change', current);
  234. },
  235. // 头条小程序不支持animationfinish事件,改由change事件
  236. // 暂不监听此事件,因为不再给swiper绑定uCurrent属性
  237. animationfinish(e) {
  238. // #ifndef MP-TOUTIAO
  239. // this.uCurrent = e.detail.current;
  240. // #endif
  241. }
  242. }
  243. };
  244. </script>
  245. <style lang="scss" scoped>
  246. // @import "../../libs/css/style.components.scss";
  247. .u-swiper-wrap {
  248. position: relative;
  249. overflow: hidden;
  250. transform: translateY(0);
  251. }
  252. .u-swiper-image {
  253. width: 100%;
  254. will-change: transform;
  255. height: 100%;
  256. /* #ifndef APP-NVUE */
  257. display: block;
  258. /* #endif */
  259. /* #ifdef H5 */
  260. pointer-events: none;
  261. /* #endif */
  262. }
  263. .u-swiper-indicator {
  264. padding: 0 24rpx;
  265. position: absolute;
  266. // @include vue-flex;
  267. display: flex;
  268. flex-direction: row;
  269. width: 100%;
  270. z-index: 1;
  271. }
  272. .u-indicator-item-rect {
  273. width: 26rpx;
  274. height: 8rpx;
  275. margin: 0 6rpx;
  276. transition: all 0.5s;
  277. background-color: rgba(0, 0, 0, 0.3);
  278. }
  279. .u-indicator-item-rect-active {
  280. background-color: rgba(255, 255, 255, 0.8);
  281. }
  282. .u-indicator-item-dot {
  283. width: 14rpx;
  284. height: 14rpx;
  285. margin: 0 6rpx;
  286. border-radius: 20rpx;
  287. transition: all 0.5s;
  288. background-color: rgba(0, 0, 0, 0.3);
  289. }
  290. .u-indicator-item-dot-active {
  291. background-color: rgba(255, 255, 255, 0.8);
  292. }
  293. .u-indicator-item-round {
  294. width: 14rpx;
  295. height: 14rpx;
  296. margin: 0 6rpx;
  297. border-radius: 20rpx;
  298. transition: all 0.5s;
  299. background-color: rgba(0, 0, 0, 0.3);
  300. }
  301. .u-indicator-item-round-active {
  302. width: 34rpx;
  303. background-color: rgba(255, 255, 255, 0.8);
  304. }
  305. .u-indicator-item-number {
  306. padding: 6rpx 16rpx;
  307. line-height: 1;
  308. background-color: rgba(0, 0, 0, 0.3);
  309. border-radius: 100rpx;
  310. font-size: 26rpx;
  311. color: rgba(255, 255, 255, 0.8);
  312. }
  313. .u-list-scale {
  314. transform-origin: center center;
  315. }
  316. .u-list-image-wrap {
  317. width: 100%;
  318. height: 100%;
  319. flex: 1;
  320. transition: all 0.5s;
  321. overflow: hidden;
  322. box-sizing: content-box;
  323. position: relative;
  324. }
  325. .u-swiper-title {
  326. position: absolute;
  327. background-color: rgba(0, 0, 0, 0.3);
  328. bottom: 0;
  329. left: 0;
  330. width: 100%;
  331. font-size: 28rpx;
  332. padding: 12rpx 24rpx;
  333. color: rgba(255, 255, 255, 0.9);
  334. }
  335. .u-swiper-item {
  336. // @include vue-flex;
  337. overflow: hidden;
  338. align-items: center;
  339. display: flex;
  340. flex-direction: row;
  341. }
  342. .swiper-diy-left, .swiper-diy-right{
  343. position: absolute;
  344. bottom: 40rpx;
  345. color: #FFFFFF;
  346. display: flex;
  347. justify-content: center;
  348. align-items: center;
  349. }
  350. .swiper-diy-left{
  351. left: 40rpx;
  352. width: 246rpx;
  353. height: 49rpx;
  354. border-radius: 24rpx;
  355. border: 1rpx solid #FFFFFF;
  356. font-size: 24rpx;
  357. }
  358. .swiper-diy-right{
  359. right: 40rpx;
  360. width: 60rpx;
  361. height: 60rpx;
  362. border-radius: 50%;
  363. background-color: rgba(0,0,0,0.5);
  364. }
  365. </style>