jufubao-movie 1.0.39-beta1 → 1.0.39-beta4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jufubao-movie",
3
- "version": "1.0.39-beta1",
3
+ "version": "1.0.39-beta4",
4
4
  "private": false,
5
5
  "description": "聚福宝在线选座业务组件插件包",
6
6
  "main": "index.js",
@@ -4,6 +4,17 @@ export default {
4
4
  style: [],
5
5
  advanced: [],
6
6
  content: [
7
+ {
8
+ label: '是否显示影院名称:',
9
+ ele: 'xd-radio',
10
+ valueKey: 'isShowTitle',
11
+ value: 'Y',
12
+ groupKey:'content',
13
+ list: [
14
+ {label: '是', value: 'Y'},
15
+ {label: '否', value: 'N'},
16
+ ]
17
+ },
7
18
  {
8
19
  label: '订单确认路径:',
9
20
  ele: 'xd-select-pages-path',
@@ -18,14 +18,23 @@
18
18
  <!-- #endif -->
19
19
  <view class="jfb-movie-line-line-seat__body">
20
20
  <view v-if="loadingList" class="skeleton-wrap">
21
- <view class="seat_head">
21
+ <view class="seat_head" v-if="isShowTitle === 'Y'">
22
22
  <view></view>
23
23
  <view></view>
24
24
  </view>
25
- <view class="seat_body">
26
- <view class="seat_line" v-for="i in 7" :key="i">
27
- <view class="seat_item" v-for="ii in 10" :key="ii"></view>
25
+ <view class="seat_tips">
26
+ <view></view>
27
+ <view></view>
28
+ <view></view>
29
+ <view></view>
30
+ <view></view>
31
+ </view>
32
+ <view class="seat_body" :class="{Y:this.isShowTitle ==='Y', 'N': isShowTitle ==='N'}">
33
+ <view class="seat_line" v-for="i in yItem" :key="i">
34
+ <view class="seat_item" v-for="ii in xItem" :key="ii"></view>
28
35
  </view>
36
+ <view v-if="isShowTitle === 'Y'" class="line-Y"></view>
37
+ <view v-else class="line-N"></view>
29
38
  </view>
30
39
  <view class="seat_notice"></view>
31
40
  <view class="seat_foot">
@@ -37,6 +46,7 @@
37
46
  <xd-online-seat
38
47
  v-if="filmId"
39
48
  ref="xdOnlineSeat"
49
+ :is-show-title="isShowTitle"
40
50
  :key="cinemaSeatKey"
41
51
  :is-old="false"
42
52
  :film-id="filmId"
@@ -84,8 +94,11 @@
84
94
  //面板
85
95
  payPath: "", //三方支付路径
86
96
  moviePayPath: "", //订单确认路径
97
+ isShowTitle:'Y',//是否显示影院名称
87
98
  timer: null,
88
99
  time: 0,
100
+ xItem: 10,
101
+ yItem: 7,
89
102
  }
90
103
  },
91
104
  watch: {
@@ -98,6 +111,7 @@
98
111
  this.init(this.container);
99
112
  let systemInfo = uni.getSystemInfoSync();
100
113
  getApp().globalData.$systemInfo = systemInfo;
114
+
101
115
  },
102
116
  methods: {
103
117
  onJfbLoad(options) {
@@ -152,7 +166,10 @@
152
166
  */
153
167
  init(container) {
154
168
  this.moviePayPath = getContainerPropsValue(container, 'content.movie_pay_path', {value: ""}).value;
155
- this.payPath = getContainerPropsValue(container, "content.payPath", {value: "/system/system/pay"}).value;
169
+ this.payPath = getContainerPropsValue(container, "content.payPath", {value: ""}).value;
170
+ this.isShowTitle = getContainerPropsValue(container, "content.isShowTitle", 'Y');
171
+ if(this.isShowTitle === 'Y') this.yItem = 7;
172
+ else this.yItem = 10;
156
173
  },
157
174
  handleGetFilm(resolve) {
158
175
  // console.log('11111', paiqi.result);
@@ -326,29 +343,75 @@
326
343
 
327
344
  .jfb-movie-line-line-seat {
328
345
  &__body {
346
+ background-color: #f8f8f8;
329
347
  .skeleton-wrap{
330
348
  height: 100vh;
349
+
331
350
  .seat_head{
332
- box-shadow: 0 0 7px rgba(0, 0, 0, 0.2);
333
- padding: 20rpx 40rpx;
334
- margin-bottom: 20rpx;
351
+ border-radius: 24rpx;
352
+ overflow: hidden;
353
+ margin: 20rpx 20rpx 5rpx;
354
+ box-shadow: 0 4rpx 40rpx rgba(0, 0, 0, 0.2);
355
+ position: relative;
356
+ padding: unit(20, rpx) unit(30, rpx);
357
+
335
358
  & > view:first-child{
336
- .skeleton-item(300rpx);
359
+ .skeleton-item(80%, 36rpx);
360
+ padding-bottom: 15rpx;
337
361
  }
338
362
  & > view:last-child{
339
363
  .skeleton-item(100%, 30rpx);
340
364
  margin-top: 10rpx;
341
365
  }
342
366
  }
367
+ .seat_tips {
368
+ display: flex;
369
+ justify-content: center;
370
+ align-items: center;
371
+ padding-top: 50rpx;
372
+ & > view {
373
+ .skeleton-item(80rpx, 40rpx);
374
+
375
+ margin-right: 20rpx;
376
+ & >view:last-child{
377
+ margin-right: 0;
378
+ }
379
+ }
380
+ }
343
381
  .seat_body{
344
- .skeleton-item(100%, 700rpx, 0, #FEFEFE);
382
+ position: relative;
383
+
384
+ & .line-N {
385
+ position: absolute;
386
+ left:20rpx;
387
+ top:40rpx;
388
+ .skeleton-item(25rpx, 580rpx);
389
+ }
390
+ & .line-Y {
391
+ position: absolute;
392
+ left:20rpx;
393
+ top:40rpx;
394
+ .skeleton-item(25rpx, 400rpx);
395
+ }
396
+
397
+ &.Y {
398
+ .skeleton-item(100%, 500rpx, 0, #FEFEFE);
399
+ }
400
+ &.N {
401
+ .skeleton-item(100%, 700rpx, 0, #FEFEFE);
402
+ }
403
+
404
+
405
+
345
406
  padding: 20rpx 100rpx;
346
407
  box-sizing: border-box;
347
408
  .seat_line{
348
409
  display: flex;
349
410
  margin: 20rpx;
350
411
  .seat_item{
351
- .skeleton-item(50rpx, 50rpx);
412
+ margin: 0 6rpx;
413
+ .skeleton-item(40rpx, 40rpx);
414
+ border-radius: 10rpx;
352
415
  }
353
416
  }
354
417
  }
@@ -1,21 +1,14 @@
1
1
  <template>
2
2
  <view class="xd-seat" v-if="paiqiStatus">
3
+ <view class="float"></view>
3
4
  <view
4
5
  class="xd-seat__title"
5
- v-if="filmInfo"
6
+ v-if="isShowTitle === 'Y' && filmInfo"
6
7
  id="xd-seat__title"
7
8
  :style="{ borderTopColor: styleMainColor }"
8
9
  >
9
- <view class="xd-seat__title-name">{{ filmInfo["film_name"] }}</view>
10
- <view class="xd-seat__title-address">{{cinemaInfo["cinema_name"] }}</view>
11
- <view class="xd-seat__title-back" v-if="show" @click.stop="back">
12
- <xd-font-icon
13
- icon="iconzhiyuanfanhui12"
14
- width="50"
15
- height="50"
16
- size="50"
17
- ></xd-font-icon>
18
- </view>
10
+ <view class="xd-seat__title-name" :style="{marginBottom:cinemaInfo['cinema_address']?'15rpx':0 }">{{ filmInfo["cinema_name"] }}</view>
11
+ <view class="xd-seat__title-address" v-if="cinemaInfo['cinema_address']">{{cinemaInfo["cinema_address"] }}</view>
19
12
  </view>
20
13
  <view class="xd-seat__content" v-if="height !== null" :style="getHeight">
21
14
  <xd-online-seat-move
@@ -38,9 +31,7 @@
38
31
  showIcon
39
32
  >
40
33
  <view
41
- style="
42
- padding: 10rpx 0rpx 10rpx 20rpx;
43
- "
34
+ style="padding: 10rpx 0rpx 10rpx 20rpx;"
44
35
  v-for="(item, index) in noticeList"
45
36
  :key="index"
46
37
  >{{ item }}</view>
@@ -225,6 +216,10 @@ export default {
225
216
  XdNoticeBar,
226
217
  },
227
218
  props: {
219
+ isShowTitle: {
220
+ type: String,
221
+ default:'Y'
222
+ },
228
223
  isOld: {
229
224
  type: Boolean,
230
225
  default: true,
@@ -361,7 +356,7 @@ export default {
361
356
  this.show = false;
362
357
  // #endif
363
358
  // #ifdef H5
364
- this.show = true;
359
+ this.show = false;
365
360
  // #endif
366
361
 
367
362
  this.getFilm();
@@ -477,6 +472,7 @@ export default {
477
472
  this.$emit("onGetFilm", (film) => {
478
473
  this.cinemaInfo = film["cinema_data"];
479
474
  this.filmInfo = this.getFilmInfo(film["film_data"]);
475
+ debugger
480
476
  this.getScheduleList(film["paiqi_data"]);
481
477
  console.log("getFilm", film);
482
478
  this.paiqiStatus = true;
@@ -491,10 +487,16 @@ export default {
491
487
  */
492
488
  setContent() {
493
489
  this.$nextTick(() => {
490
+ let elxs = [];
491
+ if(this.isShowTitle === 'Y') elxs.push('#xd-seat__title');
492
+ elxs.push('#xd-seat__footer');
494
493
  this.$xdUniHelper
495
- .getWindowHeight(["#xd-seat__title", "#xd-seat__footer"], this)
494
+ .getWindowHeight(elxs, this)
496
495
  .then((res) => {
497
- let top = res["#xd-seat__title"]["height"];
496
+ let top = 0;
497
+ if(this.isShowTitle === 'Y') {
498
+ top = res["#xd-seat__title"]["height"] ;
499
+ }
498
500
  let footer = res["#xd-seat__footer"]["height"];
499
501
  console.log("getFilm", top, footer);
500
502
  this.height = `calc(100vh - ${
@@ -648,6 +650,10 @@ export default {
648
650
  </script>
649
651
 
650
652
  <style scoped lang="less">
653
+ .float {
654
+ height: 1px;
655
+ width: 100%;
656
+ }
651
657
  .xd-seat {
652
658
  height: 100%;
653
659
  overflow-y: hidden;
@@ -702,22 +708,26 @@ export default {
702
708
  }
703
709
 
704
710
  &__title {
705
- border-top-width: unit(4, rpx);
706
- border-top-style: solid;
707
- box-shadow: 0 0 unit(15, rpx) rgba(0, 0, 0, 0.2);
711
+ border-radius: 24rpx;
712
+ overflow: hidden;
713
+ margin: 20rpx 20rpx 5rpx;
714
+ box-shadow: 0 4rpx 40rpx rgba(0, 0, 0, 0.2);
708
715
  position: relative;
709
- padding: unit(20, rpx) unit(20, rpx);
716
+ padding: unit(20, rpx) unit(30, rpx);
710
717
  z-index: 100;
711
718
 
712
719
  &-name {
713
- font-size: @xd-font-size-lg;
720
+ font-size: 36rpx;
714
721
  line-height: unit(40, rpx);
715
- padding-bottom: unit(10, rpx);
722
+ .uni-max-cut(1,40);
723
+ margin-bottom: 10rpx;
716
724
  }
717
725
 
718
726
  &-address {
719
- font-size: @xd-font-size-sm;
720
- color: #999;
727
+ font-size: 28rpx;
728
+ line-height: unit(36, rpx);
729
+ .uni-max-cut(1,36);
730
+ color: #A6A6A6;
721
731
  }
722
732
 
723
733
  &-back {
@@ -847,11 +857,11 @@ export default {
847
857
  &-input {
848
858
  font-size: @xd-font-size-base;
849
859
  background: #fff;
850
- border-radius: unit(25, rpx);
860
+ border-radius: unit(30, rpx);
851
861
  flex: 1;
852
862
  height: unit(50, rpx);
853
863
  line-height: unit(50, rpx);
854
- padding: unit(20,rpx) unit(25, rpx);
864
+ padding: unit(10,rpx) unit(25, rpx);
855
865
  background: #f8f8f8;
856
866
 
857
867
  // &:hover {
@@ -407,7 +407,6 @@
407
407
  :style="{
408
408
  top : seatOffsetTop + 'px',
409
409
  width: 30 * scale + 'rpx',
410
- background: styleMainColor
411
410
  }"
412
411
  >
413
412
  <view
@@ -1244,21 +1243,21 @@
1244
1243
  }
1245
1244
 
1246
1245
  &__stage {
1247
- background-image: url(@xd-bg-filmBg);
1246
+ background-image: url('https://img.jufubao.cn/common/stage.png?v1');
1248
1247
  background-size: 100%;
1249
1248
  background-position: top left;
1250
1249
  background-repeat: no-repeat;
1251
- color: @xd-text-color;
1250
+ color: #999;
1252
1251
  width: unit(533, rpx);
1253
1252
  height: unit(50, rpx);
1254
- font-size: @xd-font-size-base;
1253
+ font-size: 20rpx;
1255
1254
  text-align: center;
1256
1255
  margin: unit(20, rpx) auto unit(40, rpx);
1257
1256
  box-sizing: border-box;
1258
1257
 
1259
- *, text {
1258
+ & > text {
1260
1259
  display: inline-block;
1261
- padding: unit(30, rpx) 0 0;
1260
+ padding: unit(40, rpx) 0 0;
1262
1261
  }
1263
1262
  }
1264
1263
 
@@ -1280,7 +1279,7 @@
1280
1279
  justify-content: center;
1281
1280
  align-content: center;
1282
1281
  height: unit(50, rpx);
1283
- padding: unit(30, rpx) 0;
1282
+ padding: unit(20, rpx) 0 10rpx;
1284
1283
 
1285
1284
  &-item {
1286
1285
  font-size: @xd-font-size-base;
@@ -1344,7 +1343,7 @@
1344
1343
  &__left-bar {
1345
1344
  position: fixed;
1346
1345
  left: unit(10, rpx);
1347
- background-color: rgba(0, 0, 0, 0.3);
1346
+ background-color: #ACADAF;
1348
1347
  border-radius: unit(14, rpx);
1349
1348
  overflow: hidden;
1350
1349
  font-size: unit(20, rpx);
@@ -4,7 +4,7 @@
4
4
  class="image"
5
5
  :style="{marginRight: outSpacing + 'rpx',borderRadius:borderRadius+'rpx'}"
6
6
  >
7
- <image :src="item['poster']" :alt="item['show_name']"></image>
7
+ <image :src="item['poster']" :alt="item['show_name']" @error="handleError(item)"></image>
8
8
  </view>
9
9
  <view class="middle">
10
10
  <view class="name">{{item['show_name']}}</view>
@@ -84,6 +84,9 @@
84
84
 
85
85
  },
86
86
  methods:{
87
+ handleError(item){
88
+ item['poster'] = 'https://img.jufubao.cn/common/error_movie.png?v20'
89
+ },
87
90
  handleDetail(item){
88
91
  console.log('handleDetail.item',item,item.id);
89
92
  this.$emit('on-film-detail',item.id);
@@ -142,10 +145,9 @@
142
145
  align-items: flex-end;
143
146
  justify-content: flex-end;
144
147
  flex-flow: wrap;
145
- height: 100%;
146
148
  box-sizing: border-box;
147
149
  width: 160rpx;
148
- min-height: 200rpx;
150
+ height: 200rpx;
149
151
 
150
152
  & .score {
151
153
  height: 40rpx;
@@ -81,11 +81,16 @@
81
81
  </view>
82
82
  </view>
83
83
  <!--poster-->
84
+ <view id="content-ref" class="content-ref"></view>
84
85
  <!--film hot|rightnow-->
85
86
  <view
86
87
  v-if="type === 'hot' || type === 'rightnow'"
87
88
  class="list-cont"
88
- :style="{marginTop:outSpacing + 'rpx'}"
89
+ :style="{
90
+ marginTop:outSpacing + 'rpx',
91
+ paddingTop:paddingTop,
92
+ paddingBottom:paddingBottom,
93
+ }"
89
94
  >
90
95
  <view class="skeleton-wrap" v-if="dataList === null">
91
96
  <view
@@ -230,6 +235,37 @@
230
235
  ></view>
231
236
  </template>
232
237
  </view>
238
+ <view
239
+ id="preRendering"
240
+ class="preRendering"
241
+ v-if="type === 'list' && preRendering.length >0"
242
+ :style="{padding:outSpacing + 'rpx'}"
243
+ >
244
+ <view
245
+ class="list-cont-item"
246
+ v-for="(film,index) in preRendering"
247
+ :key="film.cinema_id"
248
+ :data-index="index"
249
+ :style="{
250
+ marginBottom:outSpacing + 'rpx',
251
+ padding:contMarginComp,
252
+ borderRadius:contRradius+ 'rpx',
253
+ border:contBorder,
254
+ boxShadow:contShadow,
255
+ backgroundColor:contBgColor,
256
+ height: 'auto'
257
+ }"
258
+ >
259
+ <content-cinema
260
+ style="width: 100%;height: 100%"
261
+ :item="film"
262
+ :out-spacing="outSpacing"
263
+ :color="{SEAT:mainColor,CODE:subMainColor,SELL:successColor}"
264
+ :type="type"
265
+ :border-radius="imgRradius"
266
+ ></content-cinema>
267
+ </view>
268
+ </view>
233
269
  <!--cinema-->
234
270
  <view class="hasNoData" v-if="dataList && dataList.length > 0 && pageToken === ''">已经到底没有更多数据了</view>
235
271
  </view>
@@ -260,6 +296,7 @@
260
296
  import XdQueryFilter from "./XdQueryFilter.vue";
261
297
  import {mapState} from "vuex";
262
298
  import Color from "color";
299
+ import VirtualList from "@/lib/VirtualList";
263
300
 
264
301
  export default {
265
302
  name: "JfbMovieTfkFilmList",
@@ -276,6 +313,8 @@
276
313
  ],
277
314
  data() {
278
315
  return {
316
+ /**@type {VirtualList}**/
317
+ virtualList:null,
279
318
  options: {},
280
319
  //hideMask: true,
281
320
  type:'', //hot rightnow
@@ -284,7 +323,7 @@
284
323
  backgroundColor:'',
285
324
  isPreview: false,
286
325
  pageToken:'1',
287
- pageSize: 20,
326
+ pageSize: 10,
288
327
  total: null,
289
328
  isFirstLoadingData: false,
290
329
  dataList:null,
@@ -347,7 +386,9 @@
347
386
 
348
387
  buyPath:'',
349
388
  fimeDetailPath:'',
350
-
389
+ paddingTop: 0,
390
+ paddingBottom: 0,
391
+ preRendering:[],
351
392
 
352
393
  }
353
394
  },
@@ -447,6 +488,17 @@
447
488
  this.clearDataVar();
448
489
  this.getList();
449
490
  },
491
+ preRendering(){
492
+ this.$nextTick(()=>{
493
+ const query = uni.createSelectorQuery().in(this);
494
+ query
495
+ .select('#preRendering > .list-cont-item')
496
+ .boundingClientRect((data) => {
497
+ console.log("得到布局位置信息" + JSON.stringify(data));
498
+ })
499
+ .exec();
500
+ })
501
+ }
450
502
  },
451
503
  created() {
452
504
  this.isPreview = this.$configProject.isPreview;
@@ -597,6 +649,7 @@
597
649
  //过滤之后不够分页直接返回值
598
650
  if(fitlerData.length <= this.pageSize) {
599
651
  this.dataList = this.$xdUniHelper.cloneDeep(fitlerData);
652
+ this.preRendering = this.$xdUniHelper.cloneDeep(fitlerData);
600
653
  this.pageToken = ''
601
654
  return;
602
655
  }
@@ -611,6 +664,7 @@
611
664
  return;
612
665
  }
613
666
 
667
+ this.preRendering = this.$xdUniHelper.cloneDeep(list);
614
668
  this.dataList = (this.dataList||[]).concat(this.$xdUniHelper.cloneDeep(list));
615
669
  if(this.pageSize < list.length) this.pageToken = '';
616
670
  else this.pageToken = (Number(this.pageToken)+1) + '';
@@ -618,6 +672,9 @@
618
672
 
619
673
  handleTab(value){
620
674
  if(value === this.type) return;
675
+ if(value === 'hot' || value === 'rightnow' ) {
676
+ this.virtualList.onChangeTab();
677
+ }
621
678
  this.type = value;
622
679
  this.dataList = null;
623
680
  this.pageToken = '1';
@@ -667,9 +724,11 @@
667
724
  }).then(res => {
668
725
  if(this.isFirstLoadingData) this.$xdHideLoading({});
669
726
 
727
+
670
728
  //影片列表处理
671
729
  if(this.type === 'rightnow' || this.type==='hot'){
672
- this.dataList = (this.dataList||[]).concat(res['list']);
730
+ //this.dataList = (this.dataList||[]).concat(res['list']);
731
+ this.virtualList.pushVirtualData(res['list']);
673
732
  this.pageToken = res.next_page_token;
674
733
  return;
675
734
  }
@@ -684,6 +743,7 @@
684
743
  //小于数量页面显示记录
685
744
  if(res['list'].length <= this.pageSize) {
686
745
  this.dataList = res['list'];
746
+ this.preRendering = this.$xdUniHelper.cloneDeep(res['list']);
687
747
  this.pageToken = '';
688
748
  return
689
749
  }
@@ -701,6 +761,33 @@
701
761
  onJfbLoad(options) {
702
762
  this.options = options;
703
763
 
764
+ this.virtualList = new VirtualList(this, '#content-ref', {
765
+ fixedHeight: 240 + Number(this.outSpacing) + 20 * 2 ,
766
+ otherHeight: Number(this.outSpacing),
767
+ //获取节点数据
768
+ getDom:(id)=>{
769
+ return new Promise((resolve,reject)=>{
770
+ uni.createSelectorQuery().in(this).select(id)
771
+ .boundingClientRect((data)=>{
772
+ if(data && data.top !== undefined) resolve(data);
773
+ else reject(null)
774
+ }).exec()
775
+ });
776
+ },
777
+ //获取当前this
778
+ getParentThis(){
779
+ return this
780
+ },
781
+ callback: ({data, paddingTop, paddingBottom}) =>{
782
+ if(this.type === 'hot' ||this.type ==='rightnow' ) {
783
+ this.paddingTop = paddingTop;
784
+ this.paddingBottom = paddingBottom;
785
+ this.dataList = data;
786
+ }
787
+
788
+ },
789
+ });
790
+
704
791
  jfbRootExec('getTFKPosterContent', {
705
792
  vm: this,
706
793
  data: {
@@ -782,6 +869,12 @@
782
869
  this.setShowTypeList();
783
870
  },
784
871
 
872
+ onJfbScroll(options){
873
+ if(this.type === 'hot' || this.type === 'rightnow'){
874
+ this.virtualList.onScrollEvent(options.e.scrollTop);
875
+ }
876
+ },
877
+
785
878
  setShowTypeList(){
786
879
  let list = [];
787
880
  if(this.showHot === 'Y') list.push(this.typeList["hot"]);
@@ -811,6 +904,7 @@
811
904
  this.$xdUniHelper.navigateBack();
812
905
  }
813
906
  },
907
+
814
908
  //重新回去广告位置工
815
909
  onJfbUpdate() {
816
910
  this.onJfbLoad(this.options)
@@ -853,6 +947,7 @@
853
947
  .list-cont {
854
948
  position: relative;
855
949
  z-index: 2;
950
+ min-height: 600rpx;
856
951
  .skeleton-wrap {
857
952
  .skeleton-wrap-item {
858
953
  height: 240rpx;
@@ -1011,6 +1106,17 @@
1011
1106
  font-size: 26rpx;
1012
1107
  }
1013
1108
 
1109
+ .preRendering {
1110
+ position: fixed;
1111
+ top: -9999px;
1112
+ left: -9999px;
1113
+ opacity: 0;
1114
+ z-index: 0;
1115
+ width: 100%;
1116
+ box-sizing: border-box;
1117
+ overflow: hidden;
1118
+ }
1119
+
1014
1120
  .hasNoData {
1015
1121
  height: 80rpx;
1016
1122
  line-height: 80rpx;
@@ -106,7 +106,7 @@
106
106
  @click="toFilmInfo(item.id)"
107
107
  >
108
108
  <view class="tfk-scroll-item-image" :style="{borderRadius:contItemRradius + 'rpx'}">
109
- <image :src="item.poster" :alt="item.show_name" mode="scaleToFill"></image>
109
+ <image :src="item.poster" :alt="item.show_name" mode="scaleToFill" @error="handleError(item)"></image>
110
110
  </view>
111
111
  <view class="tfk-scroll-item-title">{{item.show_name}}</view>
112
112
  <view class="tfk-scroll-item-btn">
@@ -310,6 +310,9 @@
310
310
  this.init(this.container);
311
311
  },
312
312
  methods: {
313
+ handleError(item){
314
+ item['poster'] = 'https://img.jufubao.cn/common/error_movie.png?v20'
315
+ },
313
316
  toFilmInfo(film_id){
314
317
  console.warn(`toFilmInfo(影片详情).${film_id}`)
315
318
  if(!this.fimeDetailPath) {
@@ -0,0 +1,184 @@
1
+ 'use strict';
2
+ //原点对象
3
+ let __orgUpdateTop = null;
4
+
5
+ export default class VirtualList {
6
+ virtualType='fixed';
7
+ virtualBufferHeight= 300;
8
+ virtualFixedItemHeight; //固定模式高度设置
9
+ virtualVue; //当前组件vm实例
10
+ virtualTotalData=[]; //数组长度
11
+ virtualHeightObj = {}; //高度序列index: {max:xx,min:xx}
12
+ $el= null; //开始点元素
13
+ offsetTop= null;//开始点元素的偏移量
14
+ eqMaxTimer = 0;//
15
+ otherHeight= 0; //调节高度
16
+ orgUpdateTop = 0; //开始点元素原点偏移量
17
+ isFirst = true;
18
+ startIndex= 0;
19
+ endIndex= 0;
20
+ screenHeight=0;//全屏高度
21
+
22
+ top=0;
23
+ bottom=0;
24
+ virtualCallback= ()=>{};
25
+ status= false
26
+
27
+ /**
28
+ * @description 初始化或者重置对象
29
+ * @param $vm {Vue} vue对象
30
+ * @param $el {string}
31
+ * @param params {Object}
32
+ * @param params.type {string} 元素高度为固定或者非固定 其值:auto|fixed
33
+ * @param params.fixedHeight {number} 固定(rpx)(fixed)模式 (必选)
34
+ * @param params.bufferHeight {number} 缓冲高度(rpx)
35
+ * @param params.otherHeight {number} 其他高度(rpx)
36
+ * @param params.callback {Function} 回调方法
37
+ */
38
+ constructor($vm,$el, params ) {
39
+ this.virtualVue = $vm;
40
+ this.virtualBufferHeight = 480 * this.virtualVue.$rpxNum;
41
+ if(params.type && ['auto','fixed'].includes(params.type)) this.virtualType = params.type;
42
+ if(params.bufferHeight) this.virtualBufferHeight = params.bufferHeight * this.virtualVue.$rpxNum;
43
+ if(params.otherHeight) this.otherHeight = params.otherHeight * this.virtualVue.$rpxNum;
44
+ if(this.virtualType === 'fixed'){
45
+ if(params.fixedHeight === undefined) throw new Error(`FixedHeight is require, got is ${params.fixedHeight}`);
46
+ else this.virtualFixedItemHeight = params.fixedHeight * this.virtualVue.$rpxNum;
47
+ }
48
+ this.virtualTotalData = [];
49
+ this.virtualVue.virtualViewData = null;
50
+ this.$el = $el;
51
+ this.virtualVue.$nextTick(()=>{
52
+ this.checkOffsetTop();
53
+ });
54
+ this.screenHeight = uni.getSystemInfoSync().safeArea.height;
55
+ if(typeof params.callback !== 'function') {
56
+ throw new Error(`FixedHeight is require, got is ${params.fixedHeight}`);
57
+ }else this.virtualCallback = params.callback;
58
+
59
+ }
60
+
61
+ checkOffsetTop(){
62
+ if(__orgUpdateTop) {
63
+ this.orgUpdateTop = __orgUpdateTop;
64
+ this.status = true;
65
+ return;
66
+ }
67
+ //相对了10次不在检查
68
+ if(this.eqMaxTimer >= 3) {
69
+ this.status = true;
70
+ __orgUpdateTop = this.orgUpdateTop;
71
+ return
72
+ }
73
+ if(this.virtualVue.$refs[this.$el]) {
74
+ let offsetTop = this.virtualVue.$refs[this.$el].$el.getBoundingClientRect().top;
75
+ if(this.offsetTop === offsetTop) {
76
+ this.eqMaxTimer++;
77
+ }
78
+ else this.offsetTop = offsetTop;
79
+ this.orgUpdateTop = offsetTop + this.otherHeight;
80
+ if(this.virtualType === 'fixed') this.computedMinAndMaxFixed();
81
+ }
82
+ setTimeout(()=>{
83
+ this.checkOffsetTop();
84
+ }, 200)
85
+ }
86
+
87
+ cloneDeep(data){
88
+ return JSON.parse(JSON.stringify(data));
89
+ }
90
+
91
+ computedMinAndMaxFixed(){
92
+ let itemHeight = this.virtualFixedItemHeight;
93
+ this.virtualTotalData.map((item,index)=>{
94
+ if(index === 0) {
95
+ this.virtualHeightObj[index] = {
96
+ min: this.orgUpdateTop,
97
+ max: this.orgUpdateTop + itemHeight
98
+ }
99
+ }
100
+ else {
101
+ let prev = this.virtualHeightObj[index-1];
102
+ this.virtualHeightObj[index] = {
103
+ min: prev.max,
104
+ max: prev.max + itemHeight
105
+ }
106
+ }
107
+ });
108
+ }
109
+
110
+ pushVirtualData(data, height){
111
+ //清空响应对象
112
+ this.virtualVue.virtualViewData = null;
113
+ if(this.virtualTotalData.length > 0) this.isFirst = false;
114
+
115
+ //非固定模式
116
+ if(this.virtualType === 'auto') {
117
+ if(!height) throw new Error(`height is require, got is ${height}`);
118
+ this.virtualHeightObj = Object.assign({},this.virtualHeightObj, this.cloneDeep(height));
119
+ }
120
+
121
+ //固定模式
122
+ if(this.virtualType === 'fixed') {
123
+ this.virtualTotalData = this.virtualTotalData.concat(this.cloneDeep(data));
124
+ this.computedMinAndMaxFixed();
125
+ if(this.isFirst) this.onScrollEvent(0);
126
+ }
127
+
128
+ this.isFirst = false
129
+ }
130
+
131
+ /**
132
+ * @description 滚动事件
133
+ * @param scrollTop
134
+ */
135
+ onScrollEvent(scrollTop) {
136
+ //非固定计算索引
137
+ let time = new Date().getTime();
138
+ //计算开始索引
139
+ Object.keys(this.virtualHeightObj).map((key,index)=>{
140
+ let top = scrollTop - this.virtualBufferHeight;
141
+
142
+ //滚动高度小于元素顶部与屏幕顶部偏移量直接取值0索引
143
+ if(top <= this.orgUpdateTop) {
144
+ this.startIndex = 0;
145
+ return;
146
+ }
147
+
148
+
149
+ ////距离底部有1屏幕高度
150
+ let maxScroll = this.virtualHeightObj[this.virtualTotalData.length -1].max - this.screenHeight;
151
+ if(scrollTop >= maxScroll) {
152
+ top = maxScroll;
153
+ }
154
+
155
+ if(top >= this.virtualHeightObj[key].min && top < this.virtualHeightObj[key].max){
156
+ this.startIndex = Number(key);
157
+ }
158
+ })
159
+
160
+ //计算结束索引
161
+ this.endIndex = this.virtualTotalData.length;
162
+ Object.keys(this.virtualHeightObj).map((key,index)=>{
163
+ let top = scrollTop <= this.orgUpdateTop ? this.orgUpdateTop : scrollTop
164
+ let endScrollTop = top + this.screenHeight + this.virtualBufferHeight;
165
+ if(endScrollTop >= this.virtualHeightObj[key].min && endScrollTop < this.virtualHeightObj[key].max){
166
+ this.endIndex = Number(key);
167
+ }
168
+ });
169
+
170
+
171
+ this.top = this.virtualHeightObj[this.startIndex].min - this.orgUpdateTop.toString() + 'px'
172
+ this.bottom = this.virtualHeightObj[this.virtualTotalData.length-1].max - this.virtualHeightObj[this.endIndex-1].max.toString() + 'px'
173
+ console.log('onScrollEvent.index',this.endIndex - this.startIndex, this.startIndex,this.endIndex, this.top, this.bottom)
174
+
175
+ /**@type Function **/
176
+ this.virtualCallback({
177
+ paddingTop:this.top,
178
+ paddingBottom: this.bottom,
179
+ data:this.cloneDeep(this.virtualTotalData).slice(this.startIndex, this.endIndex + 1)}
180
+ );
181
+ }
182
+ }
183
+
184
+