mosowe-swiper.vue 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. <template>
  2. <view class="mosowe-swiper" style="'height:240rpx'">
  3. <swiper
  4. class="uni-swiper"
  5. :indicator-dots="indicator === 'dots'"
  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. <view class="user">
  36. <image class="avatar" :src="item[imageKey]" />
  37. <text class="content">{{item[textKey]}} <span class="l">{{item[time]}}前</span>预览了</text>
  38. </view>
  39. <view class="shop">
  40. <image class="avatar" :src="item[imageshop]" />
  41. <text class="content">{{item[name]}}</text>
  42. </view>
  43. </view>
  44. </swiper-item>
  45. <!-- #endif -->
  46. </swiper>
  47. </view>
  48. </template>
  49. <script>
  50. /*
  51. 待增加:
  52. 1. dot自定义功能,加入slot插槽;
  53. 2. 考虑下nvue
  54. */
  55. export default {
  56. name: 'mosowe-swiper',
  57. components: {},
  58. props: {
  59. current: { // 当前展示的索引
  60. type: Number,
  61. default: 0
  62. },
  63. autoplay: { // 是否自动切换
  64. type: Boolean,
  65. default: true
  66. },
  67. interval: { // 自动切换时间间隔
  68. type: Number,
  69. default: 3000
  70. },
  71. duration: { // 切换动画时长
  72. type: Number,
  73. default: 500
  74. },
  75. vertical: { // 滑动方向是否为纵向
  76. type: Boolean,
  77. default: false
  78. },
  79. indicator: { // 指示点样式:dots点,number数字右下角,空则不会显示
  80. type: String,
  81. default: ''
  82. },
  83. indicatorColor: { // dot点样式:默认颜色
  84. type: String,
  85. default: 'rgba(255, 255, 255, 0.5)'
  86. },
  87. indicatorActiveColor: { // dot点选中样式:高亮颜色
  88. type: String,
  89. default: '#ffffff'
  90. },
  91. scene: { // 场景值
  92. type: String,
  93. default: ''
  94. },
  95. touchable: { // 是否禁用手动滑动
  96. type: Boolean,
  97. default: false
  98. },
  99. lists: { // 轮播列表
  100. type: Array,
  101. default: () => {
  102. return [];
  103. }
  104. },
  105. swiperType: { // 轮播类型:image图片轮播,imageTextLine图文一行轮播,text文本轮播
  106. type: String,
  107. default: 'image'
  108. },
  109. previewImage: { // 开启图片预览
  110. type: Boolean,
  111. default: false
  112. },
  113. imageKey: { // 图片的key值,重复使用的组件可能遇到不同的key,此处传图片的key
  114. type: String,
  115. default: ''
  116. },
  117. imageshop: { // 商品图片
  118. type: String,
  119. default: ''
  120. },
  121. name: { // 商品名字
  122. type: String,
  123. default: ''
  124. },
  125. textKey: { // 文本的key值,重复使用的组件可能遇到不同的key,此处传文本的key
  126. type: String,
  127. default: ''
  128. },
  129. time: {//时间
  130. type: String,
  131. default: ''
  132. },
  133. height: { // 轮播区的高度,单位rpx
  134. type: Number,
  135. default: 300
  136. },
  137. pyramid: { // 金字塔式,横向且纯图模式有效,开启金字塔模式时,active初始化最少为1,最大为this.lists.length -2
  138. type: Boolean,
  139. default: false
  140. },
  141. pyramidMargin: { // 金字塔式,前后露出的距离,单位rpx,px
  142. type: String,
  143. default: '30rpx'
  144. },
  145. itemNums: { // 同时展示个数,开启金字塔模式时, itemNums = 1
  146. type: String,
  147. default: '1'
  148. }
  149. },
  150. data () {
  151. return {
  152. active: 0,
  153. activePrev: -1,
  154. activeNext: -1,
  155. canPyramid: false,
  156. touchStartTime: 0, // 微信小程序端:触摸事件判断点击或滑动
  157. };
  158. },
  159. created () {
  160. this.active = this.current;
  161. if (this.pyramid && this.swiperType === 'image' && !this.vertical) {
  162. this.canPyramid = true;
  163. if (this.active === 0 || this.active < 0 || this.active > this.lists.length - 1) {
  164. this.lists.length ? '' : this.active = 1;
  165. } else if (this.active === this.lists.length - 1) {
  166. this.active = this.lists.length -2;
  167. }
  168. }
  169. },
  170. methods: {
  171. // 微信小程序:banner触摸时,禁止手动滑动的时候触发
  172. WXAPP_bannerTouch () {
  173. if(this.previewImage) {
  174. this.touchStartTime = new Date().getTime();
  175. }
  176. },
  177. // 微信小程序:触摸完
  178. WXAPP_bannerTouchEnd (item) {
  179. let t = new Date().getTime();
  180. if (t-this.touchStartTime <= 200) { // 点击
  181. this.bannerClick(item);
  182. } else {
  183. if (this.touchable) {
  184. return false;
  185. }
  186. }
  187. },
  188. // banner轮播时
  189. bannerChange (e) {
  190. this.active = e.detail.current;
  191. this.$emit('change', e.detail.current);
  192. },
  193. // banner点击时
  194. bannerClick (item) {
  195. console.log(item);
  196. if (this.swiperType === 'image' && this.previewImage) { // 纯图片模式下,开启预览模式
  197. let urls = [];
  198. if (this.imageKey) {
  199. for (let image of this.lists) {
  200. urls.push(image[this.imageKey]);
  201. }
  202. } else {
  203. urls = this.lists;
  204. }
  205. console.log(urls);
  206. uni.previewImage({
  207. current: item.index,
  208. urls: urls
  209. });
  210. }
  211. this.$emit('bclick', item);
  212. },
  213. }
  214. };
  215. </script>
  216. <style lang="scss">
  217. .shop{
  218. display: flex;
  219. }
  220. .user .content{
  221. margin-bottom:10rpx !important;
  222. }
  223. .shop .content{
  224. margin-top: 18rpx;
  225. }
  226. .imageTextLine{
  227. margin-left: 40rpx;
  228. }
  229. .imageTextLine image{
  230. width: 50rpx;
  231. }
  232. .l{
  233. color:#d8ad77;
  234. }
  235. .mosowe-swiper{
  236. width: 100%;
  237. position: relative;
  238. .uni-swiper {
  239. height: inherit;
  240. .uni-swiper-dot{
  241. width: 20px !important;
  242. height: 8px !important;
  243. border-radius: 4px;
  244. }
  245. .item {
  246. box-sizing: border-box;
  247. .image{
  248. width: 100%;
  249. height: 100%;
  250. }
  251. // 支付宝
  252. /* #ifdef MP-ALIPAY */
  253. &.swiper-pyramid{
  254. padding: 0 30rpx;
  255. }
  256. /* #endif */
  257. // 非支付宝
  258. /* #ifndef MP-ALIPAY */
  259. &.swiper-pyramid{
  260. padding: 30rpx;
  261. }
  262. &.swiper-prev {
  263. animation: prev .5s forwards;
  264. }
  265. &.swiper-next {
  266. animation: next .5s forwards;
  267. }
  268. &.swiper-active {
  269. animation: actives .5s forwards;
  270. }
  271. /* #endif */
  272. }
  273. }
  274. // 纯图
  275. .image{
  276. width: 100%;
  277. height: 100%;
  278. }
  279. // 纯文
  280. .text{
  281. overflow: hidden;
  282. text-overflow: ellipsis;
  283. white-space: nowrap;
  284. width: 100%;
  285. display: block;
  286. }
  287. // 图文一行
  288. .imageTextLine {
  289. height: 240rpx !important;
  290. overflow: hidden;
  291. width: 100%;
  292. align-items: center;
  293. .avatar{
  294. flex: 0 0 50rpx;
  295. height: 50rpx;
  296. border-radius: 50%;
  297. margin-right: 10rpx;
  298. }
  299. .content{
  300. width: 260rpx !important;
  301. // flex: 1;
  302. white-space: nowrap;
  303. text-overflow: ellipsis;
  304. overflow: hidden;
  305. }
  306. }
  307. .custom-indicator{
  308. position: absolute;
  309. right: 30rpx;
  310. bottom: 30rpx;
  311. background: rgba(0, 0, 0, 0.2);
  312. width: 80rpx;
  313. height: 40rpx;
  314. line-height: 40rpx;
  315. font-size: 24rpx;
  316. color: #fff;
  317. border-radius: 30rpx;
  318. text-align: center;
  319. }
  320. }
  321. @keyframes prev {
  322. 0%{
  323. padding: 0;
  324. }
  325. 100% {
  326. padding: 30rpx;
  327. }
  328. }
  329. @keyframes next {
  330. 0%{
  331. padding: 0;
  332. }
  333. 100% {
  334. padding: 30rpx;
  335. }
  336. }
  337. @keyframes actives {
  338. 0%{
  339. padding: 30rpx;
  340. }
  341. 100% {
  342. padding: 0;
  343. }
  344. }
  345. </style>