mosowe-swiper.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. <template>
  2. <view class="mosowe-swiper" :style="'height:'+height+'rpx'">
  3. <swiper
  4. class="uni-swiper"
  5. :indicator-dots="false"
  6. :indicator-color="indicatorColor"
  7. :indicator-active-color="indicatorActiveColor"
  8. :autoplay="autoplay"
  9. :current="active"
  10. :interval="interval"
  11. :duration="duration"
  12. :vertical="vertical"
  13. :disable-touch="touchable"
  14. :previous-margin="canPyramid ? pyramidMargin : ''"
  15. :next-margin="canPyramid ? pyramidMargin : ''"
  16. :display-multiple-items="canPyramid ? 1 : itemNums"
  17. circular
  18. @change="bannerChange"
  19. >
  20. <!-- 非微信小程序 -->
  21. <!-- #ifndef MP-WEIXIN -->
  22. <swiper-item
  23. class="item"
  24. v-for="(item,index) of lists"
  25. :key="index"
  26. :class="canPyramid && active !== index ? 'swiper-pyramid' : canPyramid && active === index ? 'swiper-active' : ''"
  27. @click="bannerClick({item,index})"
  28. >
  29. <!-- 仅图片展示 -->
  30. <image :src="imageKey ? item[imageKey] : item" class="image" v-if="swiperType === 'image'"></image>
  31. <!-- 仅文字展示 -->
  32. <text class="text" v-if="swiperType === 'text'">{{textKey ? item[textKey] : item}}</text>
  33. <!-- 图文左右轮播 -->
  34. <view class="imageTextLine" v-if="swiperType === 'imageTextLine'">
  35. <image class="avatar" :src="item[imageKey]" />
  36. <text class="content">{{item[textKey]}}</text>
  37. </view>
  38. <view style="display: flex;flex-wrap: wrap;">
  39. <view v-for="(child,idx) in item.tagGroups" :key="idx" @tap.stop="onCategory(child)" style="width: 142upx;display: flex;flex-direction: column;align-items: center;justify-content: center;margin-top: 20upx;">
  40. <image :src="child.path1" mode="aspectFit" style="width: 100upx;height: 100upx;"></image>
  41. <view style="font-size: 24upx;margin-top: 20upx;">{{child.name}}</view>
  42. </view>
  43. </view>
  44. </swiper-item>
  45. <!-- #endif -->
  46. <!-- 微信小程序内 -->
  47. <!-- #ifdef MP-WEIXIN -->
  48. <!-- 可手动滑动 -->
  49. <block v-if="!touchable">
  50. <swiper-item
  51. class="item"
  52. v-for="(item,index) of lists"
  53. :key="index"
  54. :class="canPyramid && active !== index ? 'swiper-pyramid' : canPyramid && active === index ? 'swiper-active' : ''"
  55. @click="bannerClick({item,index})"
  56. >
  57. <!-- 仅图片展示 -->
  58. <image :src="imageKey ? item[imageKey] : item" class="image" v-if="swiperType === 'image'"></image>
  59. <!-- 仅文字展示 -->
  60. <text class="text" v-if="swiperType === 'text'">{{textKey ? item[textKey] : item}}</text>
  61. <!-- 图文左右轮播 -->
  62. <view class="imageTextLine" v-if="swiperType === 'imageTextLine'">
  63. <image class="avatar" :src="item[imageKey]" />
  64. <text class="content">{{item[textKey]}}</text>
  65. </view>
  66. <view style="display: flex;flex-wrap: wrap;">
  67. <view v-for="(child,idx) in item.tagGroups" :key="idx" @tap.stop="onCategory(child)" style="width: 142upx;display: flex;flex-direction: column;align-items: center;justify-content: center;margin-top: 20upx;">
  68. <image :src="child.path1" mode="aspectFit" style="width: 100upx;height: 100upx;"></image>
  69. <view style="font-size: 24upx;margin-top: 20upx;">{{child.name}}</view>
  70. </view>
  71. </view>
  72. </swiper-item>
  73. </block>
  74. <!-- 禁用手动滑动 -->
  75. <block v-if="touchable">
  76. <swiper-item
  77. class="item"
  78. v-for="(item,index) of lists"
  79. :key="index"
  80. :class="canPyramid && active !== index ? 'swiper-pyramid' : canPyramid && active === index ? 'swiper-active' : ''"
  81. @touchstart.stop="WXAPP_bannerTouch"
  82. @touchend="WXAPP_bannerTouchEnd({item,index})"
  83. >
  84. <!-- 仅图片展示 -->
  85. <image :src="imageKey ? item[imageKey] : item" class="image" v-if="swiperType === 'image'" />
  86. <!-- 仅文字展示 -->
  87. <view class="text" v-if="swiperType === 'text'"><text>{{textKey ? item[textKey] : item}}</text></view>
  88. <!-- 图文左右轮播 -->
  89. <view class="imageTextLine" v-if="swiperType === 'imageTextLine'">
  90. <image class="avatar" :src="item[imageKey]" />
  91. <text class="content">{{item[textKey]}}</text>
  92. </view>
  93. <view style="display: flex;flex-wrap: wrap;">
  94. <view v-for="(child,idx) in item.tagGroups" :key="idx" @tap.stop="onCategory(child)" style="width: 142upx;display: flex;flex-direction: column;align-items: center;justify-content: center;margin-top: 20upx;">
  95. <image :src="child.path1" mode="aspectFit" style="width: 100upx;height: 100upx;"></image>
  96. <view style="font-size: 24upx;margin-top: 20upx;">{{child.name}}</view>
  97. </view>
  98. </view>
  99. </swiper-item>
  100. </block>
  101. <!-- #endif -->
  102. </swiper>
  103. <!-- 数字指示 -->
  104. <view class="custom-indicator" v-if="indicator === 'number'">
  105. {{ active + 1 }}/{{lists.length}}
  106. </view>
  107. <view class="custom-rectangle" v-if="indicator === 'rectangle'&&lists.length>1">
  108. <view class="content">
  109. <view v-for="(item,index) in lists" :index="index" :key="index" :class="{'rectangleActive': index == active}" class="rectangle"></view>
  110. </view>
  111. </view>
  112. </view>
  113. </template>
  114. <script>
  115. export default {
  116. name: 'mosowe-swiper',
  117. components: {},
  118. props: {
  119. current: { // 当前展示的索引
  120. type:Number,
  121. default: 0
  122. },
  123. autoplay: { // 是否自动切换
  124. type: Boolean,
  125. default: true
  126. },
  127. interval: { // 自动切换时间间隔
  128. type: Number,
  129. default: 3000
  130. },
  131. duration: { // 切换动画时长
  132. type: Number,
  133. default: 500
  134. },
  135. vertical: { // 滑动方向是否为纵向
  136. type: Boolean,
  137. default: false
  138. },
  139. indicator: { // 指示点样式:dots点,number数字右下角,空则不会显示
  140. type: String,
  141. default: 'rectangle'
  142. },
  143. indicatorColor: { // dot点样式:默认颜色
  144. type: String,
  145. default: '#C1C1C1'
  146. },
  147. indicatorActiveColor: { // dot点选中样式:高亮颜色
  148. type: String,
  149. default: '#C1C1C1'
  150. },
  151. scene: { // 场景值
  152. type: String,
  153. default: ''
  154. },
  155. touchable: { // 是否禁用手动滑动
  156. type: Boolean,
  157. default: false
  158. },
  159. lists: { // 轮播列表
  160. type: Array,
  161. default: () => {
  162. return [];
  163. }
  164. },
  165. swiperType: { // 轮播类型:image图片轮播,imageTextLine图文一行轮播,text文本轮播
  166. type: String,
  167. default: 'image'
  168. },
  169. previewImage: { // 开启图片预览
  170. type: Boolean,
  171. default: false
  172. },
  173. imageKey: { // 图片的key值,重复使用的组件可能遇到不同的key,此处传图片的key
  174. type: String,
  175. default: ''
  176. },
  177. textKey: { // 文本的key值,重复使用的组件可能遇到不同的key,此处传文本的key
  178. type: String,
  179. default: ''
  180. },
  181. height: { // 轮播区的高度,单位rpx
  182. type: Number,
  183. default: 300
  184. },
  185. pyramid: { // 金字塔式,横向且纯图模式有效,开启金字塔模式时,active初始化最少为1,最大为this.lists.length -2
  186. type: Boolean,
  187. default: false
  188. },
  189. pyramidMargin: { // 金字塔式,前后露出的距离,单位rpx,px
  190. type: String,
  191. default: '30rpx'
  192. },
  193. itemNums: { // 同时展示个数,开启金字塔模式时, itemNums = 1
  194. type: String,
  195. default: '1'
  196. }
  197. },
  198. data () {
  199. return {
  200. active: 0,
  201. activePrev: -1,
  202. activeNext: -1,
  203. canPyramid: false,
  204. touchStartTime:0, // 微信小程序端:触摸事件判断点击或滑动
  205. };
  206. },
  207. created () {
  208. this.active = this.current
  209. if (this.pyramid && this.swiperType === 'image' && !this.vertical) {
  210. this.canPyramid = true
  211. if (this.active === 0 || this.active < 0 || this.active > this.lists.length - 1) {
  212. this.active = 1
  213. } else if (this.active === this.lists.length - 1) {
  214. this.active = this.lists.length -2
  215. }
  216. }
  217. },
  218. methods: {
  219. onCategory(item){
  220. if(item.id){
  221. uni.setStorage({
  222. key: 'categoryId',
  223. data: item.id,
  224. success: function() {
  225. uni.navigateTo({
  226. url:"/pagesM/pages/category"
  227. })
  228. }
  229. })
  230. }
  231. },
  232. onMore(item) {
  233. let params = item.param;
  234. uni.navigateTo({
  235. url: "/pagesM/pages/category?params=" + JSON.stringify(params)
  236. })
  237. },
  238. // 微信小程序:banner触摸时,禁止手动滑动的时候触发
  239. WXAPP_bannerTouch () {
  240. if(this.previewImage) {
  241. this.touchStartTime = new Date().getTime()
  242. }
  243. },
  244. // 微信小程序:触摸完
  245. WXAPP_bannerTouchEnd (item) {
  246. let t = new Date().getTime()
  247. if (t-this.touchStartTime <= 200) { // 点击
  248. this.bannerClick(item)
  249. } else {
  250. if (this.touchable) {
  251. return false
  252. }
  253. }
  254. },
  255. // banner轮播时
  256. bannerChange (e) {
  257. this.active = e.detail.current;
  258. this.$emit('change', e.detail.current);
  259. },
  260. // banner点击时
  261. bannerClick (item) {
  262. console.log(item);
  263. if (this.swiperType === 'image' && this.previewImage) { // 纯图片模式下,开启预览模式
  264. let urls = [];
  265. if (this.imageKey) {
  266. for (let image of this.lists) {
  267. urls.push(image[this.imageKey]);
  268. }
  269. } else {
  270. urls = this.lists;
  271. }
  272. console.log(urls)
  273. uni.previewImage({
  274. current: item.index,
  275. urls: urls
  276. });
  277. }
  278. this.$emit('bclick', item);
  279. },
  280. }
  281. };
  282. </script>
  283. <style lang="scss">
  284. .mosowe-swiper{
  285. position: relative;
  286. .uni-swiper {
  287. height: inherit;
  288. .uni-swiper-dot{
  289. width: 20px !important;
  290. height: 8px !important;
  291. border-radius: 4px;
  292. }
  293. .item {
  294. box-sizing: border-box;
  295. .image{
  296. width: 100%;
  297. height: 100%;
  298. }
  299. // 支付宝
  300. /* #ifdef MP-ALIPAY */
  301. &.swiper-pyramid{
  302. padding: 0 30rpx;
  303. }
  304. /* #endif */
  305. // 非支付宝
  306. /* #ifndef MP-ALIPAY */
  307. &.swiper-pyramid{
  308. padding: 30rpx;
  309. }
  310. &.swiper-prev {
  311. animation: prev .5s forwards;
  312. }
  313. &.swiper-next {
  314. animation: next .5s forwards;
  315. }
  316. &.swiper-active {
  317. animation: actives .5s forwards;
  318. }
  319. /* #endif */
  320. }
  321. }
  322. // 纯图
  323. .image{
  324. width: 100%;
  325. height: 100%;
  326. }
  327. // 纯文
  328. .text{
  329. overflow: hidden;
  330. text-overflow: ellipsis;
  331. white-space: nowrap;
  332. width: 100%;
  333. display: block;
  334. }
  335. // 图文一行
  336. .imageTextLine {
  337. overflow: hidden;
  338. width: 100%;
  339. display: flex;
  340. align-items: center;
  341. .avatar{
  342. flex: 0 0 50rpx;
  343. height: 50rpx;
  344. border-radius: 50%;
  345. margin-right: 10rpx;
  346. }
  347. .content{
  348. flex: 1;
  349. white-space: nowrap;
  350. text-overflow: ellipsis;
  351. overflow: hidden;
  352. }
  353. }
  354. .custom-indicator{
  355. position: absolute;
  356. right: 30rpx;
  357. bottom: 30rpx;
  358. background: rgba(0, 0, 0, 0.2);
  359. width: 80rpx;
  360. height: 40rpx;
  361. line-height: 40rpx;
  362. font-size: 24rpx;
  363. color: #fff;
  364. border-radius: 30rpx;
  365. text-align: center;
  366. }
  367. .custom-rectangle{
  368. position: absolute;
  369. left: 0;
  370. right: 0;
  371. bottom: 20upx;
  372. display: flex;
  373. justify-content: center;
  374. .content{
  375. width: auto;
  376. background-color: #C1C1C1;
  377. display: flex;
  378. border-radius: 4upx;
  379. overflow: hidden;
  380. .rectangle{
  381. width: 44upx;
  382. height: 6upx;
  383. border-radius: 4upx;
  384. background-color: #C1C1C1;
  385. opacity:0.35;
  386. }
  387. .rectangleActive{
  388. width: 44upx;
  389. height: 6upx;
  390. border-radius: 4upx;
  391. background-color: #DB4444;
  392. opacity:1;
  393. }
  394. }
  395. }
  396. }
  397. @keyframes prev {
  398. 0%{
  399. padding: 0;
  400. }
  401. 100% {
  402. padding: 30rpx;
  403. }
  404. }
  405. @keyframes next {
  406. 0%{
  407. padding: 0;
  408. }
  409. 100% {
  410. padding: 30rpx;
  411. }
  412. }
  413. @keyframes actives {
  414. 0%{
  415. padding: 30rpx;
  416. }
  417. 100% {
  418. padding: 0;
  419. }
  420. }
  421. </style>