stellar-ui-plus 1.23.13 → 1.23.15

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.
@@ -5,11 +5,11 @@ export default class TouchScaleing {
5
5
 
6
6
  startParam: {
7
7
  id1: number | null
8
- x1: number | null
9
- y1: number | null
8
+ x1?: number | null
9
+ y1?: number | null
10
10
  id2: number | null
11
- x2: number | null
12
- y2: number | null
11
+ x2?: number | null
12
+ y2?: number | null
13
13
  } = {
14
14
  id1: null,
15
15
  x1: null,
@@ -19,12 +19,17 @@ export default class TouchScaleing {
19
19
  y2: null,
20
20
  }
21
21
 
22
+ isScale = false
22
23
  scale = 1
24
+ baseScale = 1
23
25
 
24
26
  rotate = 0
27
+ baseRotate = 0
25
28
 
26
29
  translateX = 0
27
30
  translateY = 0
31
+ baseTranslateX = 0
32
+ baseTranslateY = 0
28
33
 
29
34
  private _setData(changedTouches: UniTouchList) {
30
35
  for (let i = 0; i < changedTouches.length; i++) {
@@ -77,23 +82,41 @@ export default class TouchScaleing {
77
82
  }
78
83
 
79
84
  touchMove(changedTouches: UniTouchList) {
80
- if (changedTouches.length < 2)
81
- return false
82
85
  this._setData(changedTouches)
83
86
 
84
- const param = this.startParam
85
- const [startX1, startY1, startX2, startY2] = [param.x1, param.y1, param.x2, param.y2] as number[]
86
- const [x1, y1, x2, y2] = this._getTouchPosition() as number[]
87
-
88
- this.scale
89
- = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
90
- / Math.sqrt((startX2 - startX1) ** 2 + (startY2 - startY1) ** 2)
91
- this.rotate
92
- = (Math.atan2(y2 - y1, x2 - x1) * 180) / Math.PI
93
- - (Math.atan2(startY2 - startY1, startX2 - startX1) * 180) / Math.PI
94
- this.translateX = (x1 + x2) / 2 - (startX1 + startX2) / 2
95
- this.translateY = (y1 + y2) / 2 - (startY1 + startY2) / 2
96
- return true
87
+ // 单指拖拽处理
88
+ if (this.isScale && changedTouches.length === 1) {
89
+ const param = this.startParam
90
+ const [x1, y1] = this._getTouchPosition() as number[]
91
+
92
+ // 如果之前有记录第一个触摸点,则计算移动距离
93
+ if (param.x1 && param.y1) {
94
+ this.translateX = this.baseTranslateX + (x1 - param.x1)
95
+ this.translateY = this.baseTranslateY + (y1 - param.y1)
96
+ }
97
+ return true
98
+ }
99
+
100
+ // 双指缩放处理
101
+ if (changedTouches.length >= 2) {
102
+ const param = this.startParam
103
+ const [startX1, startY1, startX2, startY2] = [param.x1, param.y1, param.x2, param.y2] as number[]
104
+ const [x1, y1, x2, y2] = this._getTouchPosition() as number[]
105
+
106
+ this.scale = this.baseScale *
107
+ (Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
108
+ / Math.sqrt((startX2 - startX1) ** 2 + (startY2 - startY1) ** 2))
109
+
110
+ this.rotate = this.baseRotate +
111
+ ((Math.atan2(y2 - y1, x2 - x1) * 180) / Math.PI
112
+ - (Math.atan2(startY2 - startY1, startX2 - startX1) * 180) / Math.PI)
113
+
114
+ this.translateX = this.baseTranslateX + ((x1 + x2) / 2 - (startX1 + startX2) / 2)
115
+ this.translateY = this.baseTranslateY + ((y1 + y2) / 2 - (startY1 + startY2) / 2)
116
+ return true
117
+ }
118
+
119
+ return false
97
120
  }
98
121
 
99
122
  touchEnd(changedTouches: UniTouchList) {
@@ -112,6 +135,26 @@ export default class TouchScaleing {
112
135
  this.startParam.x2 = null
113
136
  this.startParam.y2 = null
114
137
  }
138
+
139
+ // 保存当前状态作为基础值,以便下次操作基于此状态继续
140
+ this.baseScale = this.scale
141
+ this.baseRotate = this.rotate
142
+ this.baseTranslateX = this.translateX
143
+ this.baseTranslateY = this.translateY
144
+ this.isScale = this.scale > 1
115
145
  return !this.identifiers.length
116
146
  }
117
- }
147
+
148
+ // 重置所有变换状态
149
+ reset() {
150
+ this.isScale = false
151
+ this.scale = 1
152
+ this.baseScale = 1
153
+ this.rotate = 0
154
+ this.baseRotate = 0
155
+ this.translateX = 0
156
+ this.translateY = 0
157
+ this.baseTranslateX = 0
158
+ this.baseTranslateY = 0
159
+ }
160
+ }
@@ -42,7 +42,7 @@
42
42
  },
43
43
  {
44
44
  "name": "scale",
45
- "description": "是否支持双指缩放",
45
+ "description": "是否支持双指缩放,双击恢复缩放状态",
46
46
  "type": "boolean",
47
47
  "default": false
48
48
  },
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { onMounted, watch, computed } from 'vue';
2
+ import { onMounted, watch, computed, ref } from 'vue';
3
3
  import utils from '../../utils/utils';
4
4
  import propsData from './props';
5
5
  import useData from './useData';
@@ -18,7 +18,7 @@ const emits = defineEmits<{
18
18
 
19
19
  const { dataIndex, setDataIndex, dataShow, setDataShow, touch, setTouch, scaling, setScaling, translate, setTranslate, rotate, setRotate, transition, setTransition, dataShowmenu, setDataShowmenu } =
20
20
  useData();
21
-
21
+ const isScale = ref(false); // 是否缩放了
22
22
  const props = defineProps(propsData);
23
23
 
24
24
  const cmpUrls = computed<{ url: string; type: string | number; path?: string }[]>(() => {
@@ -43,11 +43,27 @@ watch(
43
43
  setDataIndex(props.index);
44
44
  }
45
45
  setDataShow(v);
46
+ // 当切换显示状态时,重置缩放和拖拽状态
47
+ if (!v && touch.value) {
48
+ touch.value.reset();
49
+ setScaling(1);
50
+ setTranslate('0');
51
+ setRotate(0);
52
+ }
46
53
  },
47
54
  { immediate: true }
48
55
  );
49
56
  watch(() => props.showmenu, setDataShowmenu, { immediate: true });
50
57
 
58
+ const resetScal = () => {
59
+ if (touch.value) {
60
+ touch.value.reset();
61
+ isScale.value = false;
62
+ setScaling(1);
63
+ setTranslate('0');
64
+ setRotate(0);
65
+ }
66
+ };
51
67
  const onClose = async () => {
52
68
  let next = true;
53
69
  const stop = new Promise((resolve, reject) => {
@@ -64,10 +80,12 @@ const onClose = async () => {
64
80
  setDataShow(false);
65
81
  emits('update:show', false);
66
82
  emits('close');
83
+ // 关闭时重置缩放和拖拽状态
84
+ resetScal();
67
85
  };
68
86
 
69
87
  const onTouchstart = (e: UniTouchEvent) => {
70
- if (props.scale) return;
88
+ if (!props.scale) return;
71
89
  const [x1, y1, x2, y2] = touch.value?.touchStart(e.changedTouches) || [];
72
90
  if (x1 && y1 && x2 && y2) {
73
91
  if (dataShowmenu) setDataShowmenu(false);
@@ -75,7 +93,7 @@ const onTouchstart = (e: UniTouchEvent) => {
75
93
  };
76
94
 
77
95
  const onTouchmove = (e: UniTouchEvent) => {
78
- if (props.scale) return;
96
+ if (!props.scale) return;
79
97
  const bool = touch.value?.touchMove(e.changedTouches);
80
98
  if (!bool) return;
81
99
  if (dataShowmenu) setDataShowmenu(false);
@@ -85,59 +103,91 @@ const onTouchmove = (e: UniTouchEvent) => {
85
103
  };
86
104
 
87
105
  const onTouchend = (e: UniTouchEvent) => {
88
- if (props.scale) return;
106
+ if (!props.scale) return;
89
107
  if (dataShowmenu.value !== props.showmenu) setDataShowmenu(props.showmenu);
90
108
  const bool = touch.value?.touchEnd(e.changedTouches);
91
109
  if (!bool) return;
92
- setTransition('300ms');
93
- setTimeout(() => {
94
- setScaling(1);
95
- setTranslate('0');
96
- setRotate(0);
97
- setTimeout(() => {
98
- setTransition('0');
99
- }, 100);
100
- }, 50);
110
+ isScale.value = touch.value?.isScale || false;
101
111
  };
102
112
 
103
113
  const onChange = (e: SwiperOnChangeEvent) => {
104
114
  setDataIndex(e.detail.current);
105
115
  emits('update:index', e.detail.current);
106
116
  emits('change', e.detail.current);
117
+ // 切换图片时重置缩放和拖拽状态
118
+ resetScal();
107
119
  };
108
120
 
109
121
  const onLongpress = () => {
110
122
  emits('longpress', dataIndex.value);
111
123
  };
112
-
113
- const getTransfrom = (i: number) => (dataIndex.value === i ? cmpTransform.value : {});
124
+ const currentItem = computed(() => {
125
+ return cmpUrls.value[dataIndex.value];
126
+ });
127
+ let clickNum = 0;
128
+ let clickTimer: any = 0;
129
+ const onClick = () => {
130
+ clearTimeout(clickTimer);
131
+ clickNum++;
132
+ if (clickNum > 1) {
133
+ clickNum = 0;
134
+ resetScal();
135
+ return;
136
+ }
137
+ clickTimer = setTimeout(() => {
138
+ clickNum = 0;
139
+ }, 300);
140
+ };
114
141
  </script>
115
142
  <template>
116
143
  <view class="ste-media-preview-root" data-test="media-preview" v-if="dataShow">
117
144
  <view class="media-preview-content">
118
- <swiper style="width: 100%; height: 100%" :autoplay="props.autoplay > 0" :interval="props.autoplay" :circular="props.loop" :current="dataIndex" @change="onChange">
119
- <swiper-item v-for="(item, index) in cmpUrls" :key="index">
120
- <view
121
- class="preview-item"
122
- data-test="media-preview-item"
123
- @click.stop="1"
124
- @touchstart="onTouchstart"
125
- @touchmove="onTouchmove"
126
- @touchend="onTouchend"
127
- @longpress="onLongpress"
128
- :style="[dataIndex === index ? cmpTransform : {}]"
129
- >
130
- <!-- #ifndef APP -->
131
- <video class="video" object-fit="contain" v-if="item.type === 'video'" :src="item.url || item.path" @click.stop="1" />
132
- <ste-image v-else class="image" :showMenuByLongpress="dataShowmenu" :src="item.url || item.path" mode="aspectFit" />
133
- <!-- #endif -->
134
- <!-- #ifdef APP -->
135
- <video class="video" object-fit="contain" v-if="item.type === 'video' && cmpUrls.length <= 1" :src="item.url || item.path" @click.stop="1" />
136
- <ste-image class="image" :showMenuByLongpress="dataShowmenu" :src="item.url || item.path" mode="aspectFit" />
137
- <!-- #endif -->
138
- </view>
139
- </swiper-item>
140
- </swiper>
145
+ <template v-if="isScale">
146
+ <view
147
+ class="preview-item"
148
+ data-test="media-preview-item"
149
+ @click.stop="onClick"
150
+ @touchstart="onTouchstart"
151
+ @touchmove="onTouchmove"
152
+ @touchend="onTouchend"
153
+ @longpress="onLongpress"
154
+ :style="[cmpTransform]"
155
+ >
156
+ <!-- #ifndef APP -->
157
+ <video class="video" object-fit="contain" v-if="currentItem.type === 'video'" :src="currentItem.url || currentItem.path" @click.stop="1" />
158
+ <image v-else class="image" :show-menu-by-longpress="dataShowmenu" :src="currentItem.url || currentItem.path" mode="aspectFit" />
159
+ <!-- #endif -->
160
+ <!-- #ifdef APP -->
161
+ <video class="video" object-fit="contain" v-if="currentItem.type === 'video' && cmpUrls.length <= 1" :src="currentItem.url || currentItem.path" @click.stop="1" />
162
+ <image v-else class="image" :show-menu-by-longpress="dataShowmenu" :src="currentItem.url || currentItem.path" mode="aspectFit" />
163
+ <!-- #endif -->
164
+ </view>
165
+ </template>
166
+ <template v-else>
167
+ <swiper style="width: 100%; height: 100%" :autoplay="props.autoplay > 0" :interval="props.autoplay" :circular="props.loop" :current="dataIndex" @change="onChange">
168
+ <swiper-item v-for="(item, index) in cmpUrls" :key="index">
169
+ <view
170
+ class="preview-item"
171
+ data-test="media-preview-item"
172
+ @click.stop="onClick"
173
+ @touchstart="onTouchstart"
174
+ @touchmove="onTouchmove"
175
+ @touchend="onTouchend"
176
+ @longpress="onLongpress"
177
+ :style="[dataIndex === index ? cmpTransform : {}]"
178
+ >
179
+ <!-- #ifndef APP -->
180
+ <video class="video" object-fit="contain" v-if="item.type === 'video'" :src="item.url || item.path" @click.stop="1" />
181
+ <ste-image v-else class="image" :showMenuByLongpress="dataShowmenu" :src="item.url || item.path" mode="aspectFit" />
182
+ <!-- #endif -->
183
+ <!-- #ifdef APP -->
184
+ <video class="video" object-fit="contain" v-if="item.type === 'video' && cmpUrls.length <= 1" :src="item.url || item.path" @click.stop="1" />
185
+ <ste-image v-else class="image" :showMenuByLongpress="dataShowmenu" :src="item.url || item.path" mode="aspectFit" />
186
+ <!-- #endif -->
187
+ </view>
188
+ </swiper-item>
189
+ </swiper>
190
+ </template>
141
191
  </view>
142
192
  <view class="media-preview-footer">
143
193
  <view class="footer-index">
@@ -106,7 +106,7 @@ const draw = (ctx: URCodeCanvasContext, canvas: any = null) => {
106
106
 
107
107
  // #endif
108
108
 
109
- // #ifdef H5
109
+ // #ifdef H5 || APP
110
110
  canvasWidth.value = qr.dynamicSize;
111
111
  canvasHeight.value = qr.dynamicSize;
112
112
  qr.loadImage = src => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stellar-ui-plus",
3
- "version": "1.23.13",
3
+ "version": "1.23.15",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "license": "MIT",