实现前提要景:
1.本次实现双指缩放 是用css3中的scale配合translate 实现
2.小程序 不支持动态改变scale的大小 即使在写在行内样式中也不生效(在调试中不生效)故需借助小程序自己的API animation动画函数进行实现动态scale 和translate实现
3.zoom在其实也能实现 但是在小程序调试中也不生效
4.了解小程序 touchMove 属性 (双指缩放监听)
5.报表缩放时 需要保持长宽不变 即报表始终要占满手机屏幕 (造成用户进行双指缩放 感官上只是字体大小进行缩放) 所以要根据缩放程度 动态计算长宽 以及平移距离
6.在实际的平移过程中translate的值也会乘上你的scale中的参数。
所以在对scale之后的元素通过平移来实现到达某个位置时,translate中的参数为:实际平移值/scale的倍数。
具体事例:缩放和平移的影响
7.了解小程序createSelectorQuery boundingClientRect 函数 我们需要借助它 记录当前报表的长宽 方便后续进行缩放计算(不同的用户 手机宽高不同 不能写死宽高)
<view class="wx_table" animation="{{animation}}" capture-bind:touchmove="touchMove" catch:touchend="touchEnd" style=" height:{{scaleHeight + '%'}} ;width:{{scaleWidth + '%'}}; " >
<view class="table_top">
<view class="table_header" style="left: {{footerScrollLeft}}px">
<view class="th" style = "{{item.minWidth ? 'width:'+item.minWidth+';':'flex:1;'}}" wx:for="{{columns}}" wx:key="index">
{{item.label}}
</view>
</view>
</view>
<scroll-view class="table_center" scroll-x scroll-y bindscroll='handleInit' enhanced="{{true}}" bounces="{{fasle}}" lower-threshold="10" bindscrolltolower="hadlePaging">
<view style="display: inline-block" class="content" wx:if="{{tableDate.length}}">
<view class="tr {{index % 2 == 0 ? 'bgc' : '' }}" wx:for="{{tableDate}}" wx:for-item="date" wx:key="index">
<view class="td " style = "{{column.minWidth ? 'width:'+column.minWidth+';':'flex:1;'}}" wx:for="{{columns}}" wx:for-item="column" wx:for-index="columnIndex" wx:key="columnIndex">
{{table.formaTableDate(date,column.columnKey)}}
</view>
</view>
</view>
<view style="display: inline-block" class="content" wx:if="{{!tableDate.length}}">
<view class="tr">
<view class="td " style = "width : {{column.minWidth?column.minWidth:'calc(350vmin / 7.5)'}}" wx:for="{{columns}}" wx:for-item="column" wx:for-index="columnIndex" wx:key="columnIndex">
</view>
</view>
<view class="no_content">
<view>暂无记录</view>
</view>
</view>
</scroll-view>
<view class="table_bottom" wx:if="{{showFooter && tableDate.length}}">
<view class="table_footer" style="left: {{footerScrollLeft}}px">
<view class="td" style = "{{item.minWidth ? 'width:'+item.minWidth+';':'flex:1;'}}" wx:for="{{columns}}" wx:key="index">
{{index==0? '共' + sumArray[index] + '项': sumArray[index]}}
</view>
</view>
</view>
</view>
<wxs module="table">
module.exports = {
formaTableDate: function (date,columnKey) {
if(columnKey.indexOf('.')) {
var key = ''
columnArray = columnKey.split('.')
for(var index = 0; index < columnArray.length; index++) {
var element = columnArray[index];
if(!key) {
key = date[element]
}else {
key = key[element]
}
}
return key;
} else {
return date[columnKey];
}
}
}
</wxs>
// pages/template/table/table.js
Component({
properties: {
columns: {
type: Array,
},
tableDate : {
type: Array,
},
showFooter : {
type: Boolean,
value : true
},
sumArray : {
type: Array,
value : new Array(15).fill('--')
}
},
data: {
// 距左边的距离
footerScrollLeft : 0,
scale : 1,
scaleHeight : '100',
scaleWidth : '100',
distance : '',
Xcenter : 0, // 进来会计算 表格的X轴的长度 即Width
Ycenter : 0,// 进来会计算 表格的Y轴的长度 即 Height
animation:{}
},
methods :{
// 双指缩放 监听双指触压屏幕事件
touchMove(e) {
const touches = e.touches // touches 数组 当双指的时候 该数组有两个对象
// pageX pageY 为当前手指距X轴 Y轴的距离
const { pageX: onePageX, pageY: onePageY } = touches[0]
// distance 双指之间直线距离 第一次进入页面 默认为0
const {scale, distance: oldDistance,} = this.data
if (touches.length === 2) {
const { pageX: twoPageX, pageY: twoPageY } = touches[1]
// distance 勾股定理 计算双指之间直线距离
let distance = Math.sqrt((twoPageX - onePageX) ** 2 + (twoPageY - onePageY) ** 2)
this.data.distance = distance
// 通过双指直线距离的变化 对缩放倍数进行计算
let NewScale = (scale * (distance / (oldDistance || distance)))
this.handleAlintest(NewScale)
}
},
// 双指离开
touchEnd(e) {
this.setData({
distance : 0
})
},
handleAlintest(newScale) {
const {scale,Xcenter,Ycenter} = this.data
if(newScale) {
// 判断表格缩放 表格缩放scale 默认是根据中心焦点进行缩放 所以我们需要平移还原原来位置 平移也是根据中心焦点平移
// 当scale 和平移同时用的时候 平移过程中translate的值会乘上scale中的参数 所以translate中的参数为:实际平移值/scale的倍数
// 不仅要回到初始位置 还需要将X Y 长度扩大 即原点也会进行变更 所以translate中的参数为:实际平移值/scale的倍数/scale的倍数
// 缩
if (scale >= newScale ) {
let alin = newScale < 0.4 ? 0.4 : newScale
// 缩放的同时 对其进行平移
this.animation.scale(alin).translate(- (((Xcenter / 2 - (Xcenter * alin /2)) / alin)) / alin,- (((Ycenter / 2 - (Ycenter * alin /2) )/ alin)) / alin).step()
this.setData({
animation: this.animation.export() ,
scale: alin, //输出动画
scaleHeight: (1 / alin ) * 100,
scaleWidth:(1 / alin) * 100,
})
} else { // 放
let alin = newScale > 2 ? 2 : newScale
this.animation.scale(alin).translate(- (((Xcenter / 2 - (Xcenter * alin /2)) / alin)) / alin,- (((Ycenter / 2 - (Ycenter * alin /2) )/ alin)) / alin).step()
this.setData({
scale: alin,
animation: this.animation.export() ,
scale: alin, //输出动画
scaleHeight: (1 / alin ) * 100,
scaleWidth:(1 / alin) * 100,
})
}
}
},
// 调整表头表尾的位置
handleInit(e) {
this.setData({
footerScrollLeft : -(e.detail.scrollLeft)
})
},
hadlePaging(e) {
if(e.detail.direction == 'bottom') {
this.triggerEvent('parent')
}
}
},
lifetimes: {
attached: function() {
},
ready() {
this.animation = wx.createAnimation({
timingFunction:'step-start',
duration : 0
})
let query = this.createSelectorQuery();
console.log(query);
let that = this;
query.select('.wx_table').boundingClientRect(function (rect) {
console.log(rect,'====>');
that.setData({
Xcenter : rect.width ,
Ycenter : rect.height,
})
that.handleAlintest(.5)
}).exec();
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
})