wujingjing
2024-08-08 a689b45a6f80460f9891cc5a346036a7e4c4c0b5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
const getNowPage = () => {
  const pages = getCurrentPages()
  return pages[pages.length - 1]
}
 
function debounce(fun: (...args: any) => void, delay: number) {
  let timer: number | null = null
  return function (this: WechatMiniprogram.Component.Instance<InitData, InitProperty, InitMethod, {}, false>, ...args: any) {
    let _this = this
    let _args = args
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(function () {
      fun.call(_this, ..._args)
    }, delay)
  }
}
 
type InitData = {
  tableScrollViewHeight: string
  scrollTop: number,
  scrollLeftHeader: number,
  scrollLeftContent: number,
  scrollTag: 'content' | 'header' | null,
  touchStatus: 'start' | 'end'
  checkObj: {
    [key: string]: boolean,
  } // 用于存储勾选信息
}
 
type InitProperty = {
  rowKey: WechatMiniprogram.Component.FullProperty<StringConstructor>,
  tableHeight: WechatMiniprogram.Component.FullProperty<StringConstructor>,
  scrollX: WechatMiniprogram.Component.FullProperty<BooleanConstructor>,
  columns: WechatMiniprogram.Component.FullProperty<ArrayConstructor>,
  dataList: WechatMiniprogram.Component.FullProperty<ArrayConstructor>,
  getListLoading: WechatMiniprogram.Component.FullProperty<BooleanConstructor>,
  showTipImage: WechatMiniprogram.Component.FullProperty<BooleanConstructor>,
  tipTitle: WechatMiniprogram.Component.FullProperty<StringConstructor>,
  tipSubtitle: WechatMiniprogram.Component.FullProperty<StringConstructor>,
  select: WechatMiniprogram.Component.FullProperty<BooleanConstructor>,
  selectKeys: WechatMiniprogram.Component.FullProperty<ArrayConstructor>,
  isExpand: WechatMiniprogram.Component.FullProperty<BooleanConstructor>,
  expandValueKey: WechatMiniprogram.Component.FullProperty<StringConstructor>,
  initExpandValue: WechatMiniprogram.Component.FullProperty<StringConstructor>,
  expandStyle: WechatMiniprogram.Component.FullProperty<StringConstructor>,
  dynamicValue: WechatMiniprogram.Component.FullProperty<ObjectConstructor>,
}
 
type InitMethod = {
  createShowDataList(): void
  setScrollTop(): void,
  setScrollLeft(e: GlobalData.WxAppletsEvent): void,
  clearScrollTag(e: GlobalData.WxAppletsEvent): void,
  handleScroll(e: GlobalData.WxAppletsEvent): void
  handleTouchStart(e: GlobalData.WxAppletsEvent): void
  handleTouchEnd(e: GlobalData.WxAppletsEvent): void
  handleScrolltolower(): void,
  handleScrolltoupper(): void,
  handleClickListItem(e: GlobalData.WxAppletsEvent): void,
  handleClickAction(e: GlobalData.WxAppletsEvent): void,
  handleOnActionEvent(e: GlobalData.WxAppletsEvent): void,
  handleClickExpand(e: GlobalData.WxAppletsEvent): void,
  handleClickCheck(e: GlobalData.WxAppletsEvent): void
  getTableScrollViewHeight(): void,
  tipFc(): void
}
 
Component<InitData, InitProperty, InitMethod>({
  options: {
    addGlobalClass: true,
  },
  /**
   * 组件的属性列表
   */
  properties: {
    rowKey: {
      type: String,
      value: 'id'
    }, // 指明datalist里item的哪一项可以用作是key
    tableHeight: {
      type: String,
      value: '600rpx',
    }, // 表格高度
    scrollX: {
      type: Boolean,
      value: false
    }, // 指明datalist里item的哪一项可以用作是key
    columns: {
      type: Array,
      value: []
    }, // 表头
    dataList: {
      type: Array,
      value: []
    }, // 数据
    getListLoading: {
      type: Boolean,
      value: false
    }, // 数据请求
    showTipImage: {
      type: Boolean,
      value: false
    }, // 是否出现提示块
    tipTitle: {
      type: String,
      value: '提示'
    },// 提示块内的标题文字
    tipSubtitle: {
      type: String,
      value: '暂无数据'
    },// 提示块内的副标题文字
    select: {
      type: Boolean,
      value: false
    }, // 是否开启勾选
    selectKeys: {
      type: Array,
      value: []
    }, // 勾选的初始rowKey列表
    isExpand: {
      type: Boolean,
      value: false
    },// 是否需要展开
    expandValueKey: {
      type: String,
    },// 展开的内容的key
    initExpandValue: {
      type: String,
    },// 展开内容为空时 显示的文字
    expandStyle: {
      type: String,
    },// 展开信息的div的样式
    dynamicValue: {
      type: Object,
      optionalTypes: [Array, String, Number, Boolean, null],
      value: {}
    },// 给action-td/expand-component传动态值
  },
  /**
   * 组件的初始数据
   */
  data: {
    tableScrollViewHeight: '0rpx',//表格滚动区域高度
    scrollTop: 0,// 设置回到顶部
    scrollLeftHeader: 0,
    scrollLeftContent: 0,
    scrollTag: null,
    touchStatus: 'end',
    checkObj: {},// 勾选的项的存储对象
  },
  observers: {
    'dataList': function (dataList: any[]) {
      if (dataList && dataList.length > 0) {
        this.createShowDataList()
      } else {
        this.setScrollTop()
      }
    },
    // selectKeys用于初始化勾选 每次改变都会更新勾选
    'selectKeys': function (selectKeys: any[]) {
      const newCheckObj: { [key: string]: boolean } = {}
      selectKeys.forEach(item => {
        newCheckObj[item] = true
      })
      this.setData({
        checkObj: newCheckObj
      })
    },
    // 当表格高度修改,则修改滚动区域高度
    'tableHeight': function () {
      this.getTableScrollViewHeight()
    }
  },
 
  /**
   * 组件的方法列表
   */
  methods: {
    // 创建展示列表
    createShowDataList() {
      const { columns, dataList, rowKey } = this.data
      const needReaderColums = columns.filter(item => item.render)
      this.setData({
        showDataList: dataList.map((item, index) => {
          let newItem = { ...item, row_key: `${item[rowKey]}` }
          needReaderColums.forEach((item1) => {
            newItem[item1.key] = item1.render(newItem[item1.key], item, index, getNowPage().data)
          })
          return newItem
        })
      })
    },
    // 设置当列表清空 滚回顶部
    setScrollTop() {
      this.setData({
        scrollTop: 0
      })
    },
    // 主要是为了监听横向滚动
    setScrollLeft(this: WechatMiniprogram.Component.Instance<InitData, InitProperty, InitMethod, {}, false>, e: GlobalData.WxAppletsEvent) {
      // console.log(`setScrollLeft`, e)
      const { tag } = e.currentTarget.dataset
      const { scrollLeft } = e.detail
      const { scrollTag } = this.data
      if (tag !== scrollTag) return
      if (tag === 'header') {
        this.setData({
          scrollLeftContent: scrollLeft
        })
      } else if (tag === 'content') {
        this.setData({
          scrollLeftHeader: scrollLeft
        })
      }
    },
    // 主要是为了监听横向滚动 当手指离开屏幕,处于最后的滑动时 触发防抖 监听最后一次清除滚动对象
    clearScrollTag: debounce(function (this: WechatMiniprogram.Component.Instance<InitData, InitProperty, InitMethod, {}, false>, e) {
      const { touchStatus } = this.data
      // 也许用户又开始下一次的滚动了 所以要清除这个命令 只有在用户手指离开屏幕才会清除滚动对象
      if (touchStatus === 'start') return
      this.setData({
        scrollTag: null
      })
    }, 100),
    // 主要是为了监听横向滚动
    handleScroll(e) {
      // console.log(`handleScroll`, e)
      const { scrollX, touchStatus } = this.data
      if (!scrollX) return
      this.setScrollLeft(e)
      if (touchStatus === 'end') {
        this.clearScrollTag(e)
      }
    },
    // 主要是为了监听横向滚动
    handleTouchStart(e) {
      const { scrollX, scrollTag, touchStatus } = this.data
      if (!scrollX) return
      if (scrollTag || touchStatus === 'start') return
      const { tag } = e.currentTarget.dataset
      this.setData({
        touchStatus: 'start',
        scrollTag: tag,
      })
    },
    // 主要是为了监听横向滚动
    handleTouchEnd(e) {
      // console.log(e)
      const { scrollX, scrollTag } = this.data
      if (!scrollX) return
      const { tag } = e.currentTarget.dataset
      if (tag !== scrollTag) return
      this.setData({
        touchStatus: 'end'
      })
    },
    // 滚动到底部触发
    handleScrolltolower() {
      const { showTipImage } = this.data
      if (showTipImage) return
      this.triggerEvent('scrolltolower')
    },
    // 滚动到顶部触发
    handleScrolltoupper() {
      this.triggerEvent('scrolltoupper')
    },
    // 点击表格中一项触发
    handleClickListItem(e) {
      this.triggerEvent('clicklistitem', {
        value: e.detail.value
      })
    },
    // 如果有action 里面有点击事件 怎触发该事件
    handleClickAction(e) {
      this.triggerEvent('clickaction', {
        value: e.detail.value
      })
    },
    // 如果有action 里面有对数据的操作 触发该事件
    handleOnActionEvent(e) {
      this.triggerEvent('onactionevent', {
        value: e.detail.value
      })
    },
    // 如果有expand 里面有点击事件 怎触发该事件
    handleClickExpand(e) {
      this.triggerEvent('clickexpand', {
        value: e.detail.value
      })
    },
    // 勾选事件 
    // 只记录勾选的rowKey 因为index和item在初始化的时候是无法获取的
    handleClickCheck(e) {
      const { item } = e.detail.value
      const { checkObj, rowKey } = this.data
      const newCheckObj = { ...checkObj }
      newCheckObj[item[rowKey]] = !newCheckObj[item[rowKey]]
      this.setData({
        checkObj: newCheckObj
      }, () => {
        const value = []
        for (let i in newCheckObj) {
          if (newCheckObj[i]) {
            value.push(i)
          }
        }
        this.triggerEvent('checkkey', {
          value
        })
      })
    },
    // 设置table高度
    getTableScrollViewHeight: function (this: WechatMiniprogram.Component.Instance<InitData, InitProperty, InitMethod, {}, false>) {
      try {
        const { tableHeight } = this.data
        const pageConfig = wx.getSystemInfoSync()
        const node = this.createSelectorQuery().select('.tr-th')
        node.boundingClientRect((rect) => {
          this.setData({
            tableScrollViewHeight: `calc(${tableHeight} - ${rect.height * pageConfig.pixelRatio}rpx)`
          })
        }).exec()
      } catch (e) {
        console.log(e)
      }
    },
    tipFc() {
      const { rowKey, columns } = this.data
      if (!rowKey) {
        console.error('table组件必须指明每一行的唯一标识的字段名,且必须为字符串,数字将会被转为字符串,for循环中的wx:key不使用该字段,用的是createShowDataList中设置的row_key字段')
      }
      if (!columns) {
        console.error('table组件必须指明columns')
      }
    }
  },
 
  lifetimes: {
    // 生命周期函数,可以为函数,或一个在methods段中定义的方法名
    attached: function () {
      this.tipFc()
    },
    ready: function () {
      this.getTableScrollViewHeight()
    },
    moved: function () { },
    detached: function () { },
  },
 
  pageLifetimes: {
    // 组件所在页面的生命周期函数
    show: function () { },
    hide: function () { },
    resize: function () { },
  },
 
})
 
export { }