index2.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. <template>
  2. <view class="swiperContent">
  3. <swiper
  4. @transition='transition'
  5. @change="change"
  6. @animationfinish="animationfinish"
  7. :indicator-dots="indicatorDots"
  8. :indicator-active-color="indicatorActiveColor"
  9. :indicator-color="indicatorColor"
  10. :autoplay="autoplay && !videoPlaySataus"
  11. :current="activeCurrent"
  12. :interval="interval"
  13. :duration="duration"
  14. :circular="circular"
  15. :vertical="vertical"
  16. :previous-margin="effect3d ? effect3dMargin : previousMargin"
  17. :next-margin="effect3d ? effect3dMargin : nextMargin"
  18. :display-multiple-items="displayMultipleItems"
  19. :skip-hidden-item-layout="skipHiddenItemLayout"
  20. :style="{'height':swiperHeight+'px'}"
  21. :class="{
  22. 'effect3D':effect3d && displayMultipleItems ==1,
  23. 'effect3D-X':effect3d && !vertical,
  24. 'effect3D-Y':effect3d && vertical}"
  25. class="z-screen-swiper">
  26. <swiper-item
  27. class="z-swiper-item"
  28. v-for="(item,index) in swiperList"
  29. :key="index"
  30. :class="{'active-swiper':activeCurrent===index}"
  31. :style="{'backgroundColor':`${bgColor}`,'border-radius': contentRadius,'overflow': 'hidden'}"
  32. @tap="clickItem(index)">
  33. <view class="swiper-box" :style="{'backgroundColor':`${bgColorItem}`}">
  34. <view
  35. class="swiper-top"
  36. :class="{'isFloat':topFloat}"
  37. @click="$emit('clickTop',{item,index})">
  38. <slot :row='item' :index='index' name="top">
  39. <!-- 顶部占位 无值则不占位 -->
  40. <view v-if="item[topTextKey]"
  41. :style="{'text-align':`${topTextAlign}`,
  42. 'color':`${topColor}`,
  43. 'background-color':`${topBackground}`}">
  44. <text v-text="item[topTextKey]"></text>
  45. </view>
  46. </slot>
  47. </view>
  48. <view class="swiper-content">
  49. <slot :row='item' :index='index'>
  50. <image v-if="item[fileType]==='image'" :src="item[imageKey]" :mode='imgMode'>
  51. <template v-else-if="item[fileType]==='video'">
  52. <!-- :style="{'height':fullScreen ? '':'100%' }" 解决非全屏video显示问题 -->
  53. <zVideo
  54. :ignoreTip='false'
  55. :ref='`video_${index}`'
  56. :index='index'
  57. :src="item[videoKey]"
  58. :poster="item.poster"
  59. :moveX='moveX'
  60. :initial-time="item.currentTime || 0 "
  61. ></zVideo>
  62. </template>
  63. </slot>
  64. </view>
  65. <view
  66. class="swiper-fotter"
  67. :class="{'isFloat':fotterFloat}"
  68. @click="$emit('clickBottom',{item,index})">
  69. <slot :row='item' :index='index' name="fotter">
  70. <!-- 底部盒子 不传值则不占位 -->
  71. <view v-if="item[bottomTextKey]"
  72. :style="{'text-align':`${bottomTextAlign}`,
  73. 'color':`${bottomColor}`,
  74. 'background-color':`${bottomBackground}`}">
  75. <text v-text="item[bottomTextKey]"></text>
  76. </view>
  77. </slot>
  78. </view>
  79. </view>
  80. </swiper-item>
  81. </swiper>
  82. <!-- indicatorDots 原生指示器开启时不显示下面自定义指示器
  83. vertical为true 垂直方向 只写了支持右侧定位
  84. -->
  85. <div
  86. v-if="!indicatorDots && list.length>1"
  87. :style="{'margin':`0 ${effect3d? effect3dMargin:0}`}"
  88. :class="['dot',vertical ? 'verticalDot':`${indicatorPos}`]"
  89. >
  90. <slot :list='list' :total='list.length' :activeIndex='activeCurrent' name="dot">
  91. <!-- 指示器自定义-返回列表数据list 数组长度total 选中项索引activeIndex -->
  92. <template v-if="mode==='number'">
  93. <div>
  94. {{activeCurrent+1}}/{{list.length}}
  95. </div>
  96. </template>
  97. <template v-else>
  98. <div
  99. v-for="(item,index) in list"
  100. :key="index"
  101. @click="activeCurrent=index"
  102. :style="{'background-color': activeCurrent==index ? indicatorActiveColor:indicatorColor}"
  103. :class="['dotItem',`${mode}`, `${ activeCurrent==index ? 'defautActive':'' }` ]">
  104. <span v-if="mode ==='index'">{{index+1}}</span>
  105. </div>
  106. </template>
  107. </slot>
  108. </div>
  109. </view>
  110. </template>
  111. <script>
  112. import zVideo from './video.vue'
  113. export default {
  114. name:'z-swiper',
  115. components:{zVideo},
  116. props: {
  117. list:{//滑块视图容器数据
  118. type:Array,
  119. default:_=>[
  120. {
  121. type:'video',
  122. topTip:'顶部提示',
  123. poster:'https://img2.baidu.com/it/u=2141851239,1037607188&fm=26&fmt=auto&gp=0.jpg',
  124. src:'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/360e4b20-4f4b-11eb-8a36-ebb87efcf8c0.mp4',
  125. bottomTip:'底部提示',
  126. },
  127. {type:'image', src:'https://img0.baidu.com/it/u=1570602913,157918019&fm=26&fmt=auto&gp=0.jpg'},
  128. {type:'image', src:'https://img0.baidu.com/it/u=3464142916,229554071&fm=26&fmt=auto&gp=0.jpg'},
  129. {
  130. type:'video',
  131. currentTime:120,//初始帧时间---默认缓存存储
  132. poster:'https://img1.baidu.com/it/u=1297253752,1185196455&fm=26&fmt=auto&gp=0.jpg',
  133. src:'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/a876efc0-4f35-11eb-97b7-0dc4655d6e68.mp4',
  134. },
  135. {type:'image', src:'https://img1.baidu.com/it/u=2057763469,3313822915&fm=26&fmt=auto&gp=0.jpg'},
  136. {type:'image', src:'https://img0.baidu.com/it/u=1570602913,157918019&fm=26&fmt=auto&gp=0.jpg'},
  137. ]
  138. },
  139. fileType: { type: String, default: 'type' }, // 文件类型映射
  140. videoKey:{ type:String, default:'src'},// 视频映射的键
  141. imageKey:{ type:String, default:'src'},//图片映射的键
  142. indicatorPos:{ type:String, default:'bottomCenter'},//指示器的位置:topLeft/topCenter/topRight/bottomLeft/bottomCenter/bottomRight
  143. mode:{ type:String, default:'round' },//指示器样式: default circle round index number none时不显示
  144. fullScreen:{ type:Boolean, default:false }, //是否全屏
  145. navHeight:{type:Number, default:44},//顶部导航高度,默认44---垂直全屏状态无导航栏可设置为0
  146. height:{ type:Number, default:160 },//swiper 高度单位px
  147. contentRadius:{ type:String, default:'0rpx' },//盒子圆角设置
  148. topFloat:{ type:Boolean, default:true },//顶部不占位-浮动定位
  149. fotterFloat:{ type:Boolean, default:true },//底部不占位-浮动定位
  150. effect3d:{ type:Boolean, default:false },//是否开启3D效果 注:只有在displayMultipleItems=1时有效
  151. effect3dMargin:{type: String, default: '40rpx'},//effect3d=true模式下前后间距接受px和rpx值
  152. imgMode:{type: String, default: 'scaleToFill'},//图片的裁剪模式,详见https://uniapp.dcloud.io/component/image
  153. bgColor:{type: String, default: '#f3f4f6'},//swiper背景色
  154. bgColorItem:{type: String, default: 'rgba(0,0,0,0)'},//swiper当前项背景色
  155. //顶部与底部设置-注:-顶部与底部根据需求自己拓展---也可用插槽自定义内容
  156. topTextKey:{ type:String, default:'topTip'},//顶部文字说明映射的键
  157. topColor:{ type:String, default:'#FFF'},//顶部文字颜色
  158. topBackground:{ type:String, default:'rgba(0, 0, 0, 0)'},//顶部背景色
  159. topTextAlign:{ type:String, default:'left'},//顶部文字位置
  160. bottomTextKey:{ type:String, default:'bottomTip'},//底部文字说明映射的键
  161. bottomColor:{ type:String, default:'#00F'},//底部文字颜色
  162. bottomBackground:{ type:String, default:'rgba(0, 0, 0, 0)'},//底部背景色
  163. bottomTextAlign:{ type:String, default:'left'},//底部文字位置
  164. //---end
  165. // ---swiper原生属性-参考https://uniapp.dcloud.io/component/swiper
  166. skipHiddenItemLayout:{ //是否跳过未显示的滑块布局,设为 true 可优化复杂情况下的滑动性能,但会丢失隐藏状态滑块的布局信息
  167. type:Boolean,
  168. default:false
  169. },
  170. displayMultipleItems:{ type:Number,default:1 },//同时显示的滑块数量
  171. nextMargin:{ // 后边距,可用于露出后一项的一小部分,接受 px 和 rpx 值 头条小程序不支持
  172. type:String,
  173. default:'0rpx'
  174. },
  175. previousMargin:{//前边距,可用于露出前一项的一小部分,接受 px 和 rpx 值头条小程序不支持
  176. type:String,
  177. default:'0rpx'
  178. },
  179. vertical:{ type:Boolean, default:false },//滑动方向是否为纵向 卡牌不支持纵向以及同时显示的2块以上滑块数量
  180. circular:{ type:Boolean, default:true },//是否采用衔接滑动
  181. duration:{ type:Number, default:400 },// 滑动动画时长
  182. interval:{ type:Number, default:2500 },// 自动切换时间间隔
  183. current:{ type:Number, default:0 },// 初始化时,默认显示第几项
  184. autoplay:{ type:Boolean, default:true },// 是否自动切换
  185. indicatorDots: { type: Boolean, default: false },//是否显示面板指示点--默认关闭使用自定义指示器mode设置指示器,原生指示器为true时 则不显示自定义指示器
  186. indicatorColor:{ type:String, default:'rgba(0,0,0,0.3)' },// 指示点颜色
  187. indicatorActiveColor: { type: String, default: '#F1F1F1' },// 选中项指示点颜色
  188. },
  189. data() {
  190. return {
  191. swiperList:[],//列表数据
  192. videoContent:'',//视频实例
  193. videoPlaySataus:false, //视频播放状态---默认禁用
  194. activeCurrent:0,//当前选中索引
  195. swiperHeight:0, //轮播图高度
  196. moveX:0,
  197. }
  198. },
  199. watch: {
  200. height:{//swiper高度
  201. handler(newValue) {
  202. this.swiperHeight = newValue
  203. },
  204. immediate:true
  205. },
  206. current:{//初始化选中项
  207. handler(newValue) {
  208. this.activeCurrent = newValue
  209. },
  210. immediate:true
  211. },
  212. list:{//初始化数据列表--- 处理vue不能直接改变prpos属性
  213. handler(newValue) {
  214. this.swiperList = newValue || []
  215. },
  216. immediate:true
  217. },
  218. fullScreen:{
  219. handler(newValue) {
  220. if(this.fullScreen){//全屏设置---默认初始化设置一次
  221. uni.getSystemInfo({
  222. success:(e)=>{
  223. console.log('e',e);
  224. this.swiperHeight = e.screenHeight - this.navHeight
  225. // #ifdef APP-PLUS || MP-WEIXIN
  226. this.swiperHeight = e.screenHeight - this.navHeight - e.statusBarHeight
  227. // #endif
  228. }
  229. })
  230. }else{
  231. this.swiperHeight = this.height
  232. }
  233. },
  234. immediate:true
  235. }
  236. },
  237. mounted(){
  238. },
  239. methods: {
  240. timeupdate(e){//播放进度变化时触发--更新播放缓存
  241. this.$set(this.swiperList[this.activeCurrent],'currentTime',e.detail.currentTime)
  242. },
  243. clickItem(index){
  244. if(this.list.length>0){
  245. this.$emit('clickItem',this.list[index])
  246. }
  247. },
  248. change(e){//轮播改变触发
  249. try{// 切换前暂停之前视频
  250. let preSwiper = this.swiperList[this.activeCurrent]
  251. if(preSwiper[this.fileType]==='video'){
  252. // uni.createVideoContext(`video_${this.activeCurrent}`,this).pause();
  253. this.$refs[`video_${this.activeCurrent}`][0].pausePlay()
  254. }
  255. }catch(e){
  256. //TODO handle the exception
  257. }
  258. this.videoPlaySataus = false //自动切换关闭视频播放状态
  259. this.activeCurrent = e.detail.current;
  260. this.$emit('change',e)
  261. },
  262. animationfinish(e){//动画结束后调用
  263. this.moveX = 0
  264. this.$emit('animationfinish',e)
  265. },
  266. transition(e){//滑动
  267. // #ifdef APP-PLUS
  268. this.moveX = e.detail.dx
  269. // #endif
  270. },
  271. touchStart(e){//触摸
  272. console.log("e触摸: ",e);
  273. },
  274. touchEnd(e){//触摸
  275. console.log("e触摸结束: ",e);
  276. },
  277. clickCover(e){
  278. console.log("点击: ",e);
  279. },
  280. touchmove(e){
  281. console.log("滑动中: ",e);
  282. }
  283. }
  284. }
  285. </script>
  286. <style lang="scss" scoped>
  287. .swiperContent{//容器
  288. width:100%;
  289. position: relative;
  290. // background-color: #ccc;
  291. .z-screen-swiper {//轮播图
  292. min-height: 320rpx;
  293. // background-color: rgb(211, 235, 107); //--调试样式
  294. box-sizing: border-box;
  295. .z-swiper-item{
  296. box-sizing: border-box;
  297. overflow: initial;
  298. .swiper-box{//轮播图内容
  299. // background-color: #e7ca8f;//--调试样式
  300. // background-color: rgba(0,0,0,0.1);//swiper当前项 背景色---已改为配置
  301. box-sizing: border-box;
  302. width: 100%;
  303. height: 100%;
  304. overflow: hidden;
  305. display: flex;
  306. flex-direction: column;
  307. justify-content: space-between;
  308. position: relative;
  309. color: #FFF;
  310. .swiper-top{
  311. top: 0;
  312. // background-color: rgba(0,0,0,0.2);//背景色---已改为配置
  313. }
  314. .swiper-content{
  315. // background-color: rgb(61, 41, 175);
  316. flex: 1;
  317. display: flex;
  318. flex-direction: column;
  319. justify-content: center;
  320. image{
  321. width:100%;
  322. height: 100%;
  323. max-height: 100%;
  324. }
  325. video {// 视频默认不全屏高度---防止全屏swiper滑动切换
  326. width: 100%;
  327. max-height: 100%;
  328. // pointer-events: auto;
  329. }
  330. }
  331. .swiper-fotter{
  332. bottom: 0;
  333. // background-color: rgba(0, 0, 0, 0.2); //背景色---已改为配置
  334. }
  335. .isFloat{//是否浮动 顶部、底部定位
  336. position: absolute;
  337. left: 0;
  338. right: 0;
  339. z-index: 999;
  340. }
  341. }
  342. }
  343. }
  344. .effect3D{//3d模式样式
  345. .z-swiper-item{//3d模式基础样式
  346. .swiper-box{
  347. border-radius: 10rpx;
  348. opacity: 0.7;
  349. transition: all 0.1s ease-in 0s;
  350. }
  351. }
  352. &.effect3D-X{
  353. .z-swiper-item{ //选项卡间隔
  354. padding: 0 10rpx;
  355. }
  356. .swiper-box{
  357. transform: scale(1,0.9);
  358. }
  359. }
  360. &.effect3D-Y{
  361. .z-swiper-item{ //选项卡间隔
  362. padding:10rpx 0;
  363. }
  364. .swiper-box{
  365. transform: scale(0.9,1);
  366. }
  367. }
  368. .active-swiper{//选中样式恢复
  369. .swiper-box{
  370. transform:initial;
  371. opacity: 1;
  372. transition: all 0.1s ease-in 0s;
  373. }
  374. }
  375. }
  376. .dot{//指示器
  377. position: absolute;
  378. // z-index: 9999;
  379. display: flex;
  380. color: #FFF;
  381. .dotItem{//指示器 颜色与形状
  382. background-color: #fff;
  383. font-size: 24rpx;
  384. color: #e2e2e2;
  385. margin-right: 10rpx;
  386. &.default{ /*默认条状 */
  387. height: 8rpx;
  388. width: 40rpx;
  389. }
  390. &.circle{ /* 圆 */
  391. height: 20rpx;
  392. width: 20rpx;
  393. border-radius: 50%;
  394. }
  395. &.index{ /* 数字索引 */
  396. height: 30rpx;
  397. width: 30rpx;
  398. display: flex;
  399. justify-content: center;
  400. align-content: center;
  401. border-radius: 50%;
  402. }
  403. &.defautActive{//选中项设置
  404. transition: background-color 0.3s ease-out 0s; //选中动画
  405. }
  406. &.round{ /* 弧形 */
  407. height: 20rpx;
  408. width: 20rpx;
  409. border-radius: 50%;
  410. &.defautActive{//弧形选中项设置
  411. width: 60rpx;
  412. height: 20rpx;
  413. border-radius: 10px;
  414. transition: background-color 0.3s ease-out 0s; //
  415. }
  416. }
  417. }
  418. // 定位位置
  419. &.verticalDot{//垂直方向 只写了支持右侧定位
  420. right: 20rpx;
  421. top: 50%;
  422. transform: translateY(-50%);
  423. display: block;
  424. margin: 0 !important;
  425. .dotItem{
  426. margin: 0;
  427. margin-bottom: 10rpx;
  428. &.round{ /* 弧形 */
  429. height: 20rpx;
  430. width: 20rpx;
  431. border-radius: 50%;
  432. &.defautActive{//弧形选中
  433. width: 20rpx;
  434. height: 60rpx;
  435. border-radius: 10px;
  436. }
  437. }
  438. }
  439. }
  440. &.bottomLeft{//左上角
  441. left: 20rpx;
  442. bottom: 20rpx;
  443. }
  444. &.bottomCenter{//
  445. left: 50%;
  446. bottom: 20rpx;
  447. transform: translateX(-50%);
  448. }
  449. &.bottomRight{
  450. right: 20rpx;
  451. bottom: 20rpx;
  452. }
  453. &.topLeft{
  454. left: 20rpx;
  455. top: 10rpx;
  456. }
  457. &.topCenter{
  458. left: 50%;
  459. top: 10rpx;
  460. transform: translateX(-50%);
  461. }
  462. &.topRight{
  463. right: 20rpx;
  464. top: 10rpx;
  465. }
  466. }
  467. }
  468. </style>
  469. <style lang="scss" scoped>
  470. #coverViewVideo{
  471. // height: 200rpx;
  472. background-color: #ccc;
  473. width: 100%;
  474. }
  475. </style>