# JsImagePreview
**Repository Path**: thoseyears/js-image-preview
## Basic Information
- **Project Name**: JsImagePreview
- **Description**: OpenHarmony Ace框架下的图片预览组件
- **Primary Language**: JavaScript
- **License**: MulanPSL-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2021-09-02
- **Last Updated**: 2021-09-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: OpenHarmony组件
## README
# JsImagePreview
> 为确保动画效果,请使用真机运行
基于OpenHarmony Ace JavaScript UI框架的图片预览组件,包含水波纹动画、跳转动画以及相关手势:
* 滚动 scroll
* 惯性滚动 fling
* 单击 tap
* 双击 doubleTap
* 长按 longPress
* 下滑 movingDown
> 由于TouchEvent内始终只有一组坐标,因此暂时未能实现缩放手势,而采用双击放大倍数+1(达到最大倍数再双击会还原成默认大小)的形式
## 演示
| 启动动画 | 跳转动画 | 手势 | 下滑手势 |
| ------------------------------ | ------------------------------ | -------------------------------- | -------------------------- |
|  |  |  |  |
## 使用说明
### -水波纹
|  |
| -------------------------- |
##### 引入
````html
````
##### 代码
````html
````
##### Props
| 参数 | 说明 | 类型 | 默认值 |
| ----- | ---------- | ------------ | --------- |
| color | 水波纹颜色 | color string | #99ffffff |
### -图片列表
##### 引入
````html
````
##### 代码
````html
````
````javascript
export default {
data: {
images: []
},
itemClick(e) {
const index = e.detail
...
},
onImageLoaded(e) {
const data = e.detail
...
}
}
````
##### Props
| 参数 | 说明 | 类型 | 默认值 |
| ------ | -------- | ------ | ------ |
| items | 数据列表 | array | 无 |
| column | 列数 | number | 3 |
Events
| 事件名 | 说明 | detail说明 |
| ------------ | ---------------------------- | ----------- |
| item-click | 当条目被点击时触发 | 条目的index |
| image-loaded | 当列表内的图片加载完成时触发 | 参考下方 |
````javascript
// image-loaded事件内detail对象的结构:
{
index: '条目的index',
size: {
wdith: '图片的宽',
height: '图片的高',
}
}
````
### -图片预览
##### 引入
````html
````
##### 代码
````html
````
````javascript
export default {
itemClick(e) {
...
this.$child('preview').show(this.images[index], this.x, this.y, size)
}
}
````
##### Props
| 参数 | 说明 | 类型 | 默认值 |
| ---------- | -------------- | ------------ | --------- |
| background | 预览时的背景色 | color string | #ffffffff |
| maxScale | 最大缩放倍数 | number | 4 |
##### 方法
| 方法名 | 说明 | 返回值 | 参数说明 |
| --------------------- | ------------------------------------------------------------ | ------ | ------------------------------------------------------------ |
| show(url, x, y, size) | 由于页面的跳转动画暂时无法满足需求,因此需要调用show函数来显示图片预览并加载跳转动画 | void | url:图片的绝对路径、x:跳转动画的起始x坐标、y:跳转动画的起始y坐标、size:图片的原始宽高,数据结构{width: 1, height: 1} |
| hide() | 隐藏图片预览并加载跳转动画 | void | 无 |
### -沉浸导航栏
##### 引入
````html
````
##### 代码
````html
````
##### Props
| 参数 | 说明 | 类型 | 默认值 |
| ---------- | -------------------------- | ------------ | ------------- |
| background | 背景色,包含状态栏 | color string | #ffffff |
| navHeight | 导航栏的高度,不包含状态栏 | number | 52 |
| title | 标题 | string | strings.title |
| titleColor | 标题文字颜色 | color string | #333333 |
### -Gesture.js
用于手势识别
##### 方法
| 方法名 | 说明 | 返回值 | 参数说明 |
| --------------------- | ------------------------------------------------------------ | ------ | ------------------ |
| setListener(listener) | 由于页面的跳转动画暂时无法满足需求,因此需要调用show函数来显示图片预览并加载跳转动画 | void | listener:手势回调 |
| onDown(e) | 在ontouchstart中调用此函数 | void | e:TouchEvent |
| onMove(e) | 在ontouchmove中调用此函数 | void | e:TouchEvent |
| onUp(e) | 在ontouchend中调用此函数 | void | e:TouchEvent |
##### 手势回调
* onScroll(e, distanceX, distanceY, diffX, diffY, up)
* e:TouchEvent
* distanceX:从手指按下,到当前的总x轴移动距离
* distanceY:从手指按下,到当前的总y轴移动距离
* diffX:与上一次触摸事件之间的x轴距离
* diffY:与上一次触摸事件之间的y轴距离
* up:是否是手指抬起的事件
* onTap(e)
* e:TouchEvent
* onDoubleTap(e)
* e:TouchEvent
* onLongPress(e)
* e:TouchEvent
* onFling(vx, vy, reached)
* vx:x轴的速度
* vy:y轴的速度
* reached:x或y轴速度是否达到了最低速度阈值
##### 下滑手势判断
下滑的手势与动画可以借助moving-down-handler.js实现
##### 代码示例
```html
```
```javascript
export default {
data: {
gesture: null,
...
},
async onInit() {
const that = this
this.gesture = new Gesture()
this.gesture.setListener({
onScroll: that.onScroll,
onDoubleTap: that.onDoubleTap,
onTap: that.onTap,
onLongPress: that.onLongPress,
onFling: that.onFling
})
},
onScroll(e, distanceX, distanceY, diffX, diffY, up) {
...
},
onTap(e) {
...
},
onDoubleTap(e) {
...
},
onLongPress(e) {
...
},
onFling(vx, vy, reached) {
...
},
down(e) {
this.gesture.onDown(e)
},
move(e) {
this.gesture.onMove(e)
},
up(e) {
this.gesture.onUp(e)
}
}
```
### -FlingAnimator.js
借助此类做惯性滚动动画
| 方法名 | 说明 | 返回值 | 参数说明 |
| ------------------------------------------------------------ | ---------------- | ------ | -------- |
| runFling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, task) | 开启惯性滚动动画 | void | 参考下方 |
* startX 动画开始时的x坐标
* startY 动画开始时的y坐标
* velocityX x轴的初始速度
* velocityY y轴的初始速度
* minX x轴最小滚动距离
* maxX x轴最大滚动距离
* minY y轴最小滚动距离
* maxY y轴最大滚动距离
* task(x, y) 动画每一帧的回调
* x 当前动画帧的x坐标
* y 当前动画帧的y坐标
##### 代码示例
```javascript
onFling(vx, vy, reached) {
const that = this
if (handler.handleFling(that, vx, vy) || !reached) return
const maxX = helper.calulateMaxTranslate(that.image.imageWidth, that.width)
const maxY = helper.calulateMaxTranslate(that.image.imageHeight, that.height)
that.fling.runFling(that.trans.transX, that.trans.transY, vx * 2, vy * 2, -maxX, maxX, -maxY, maxY, (x, y) => {
that.trans.transX = x
that.trans.transY = y
that.loadImage()
})
}
```
### -ScaleAnimator.js
借助此类做缩放动画
| 方法名 | 说明 | 返回值 | 参数说明 |
| ------------------------------------------------------------ | ------------------------ | ------ | ------------ |
| runScale(scale, startX, startY, finalX, finalY, task, duration) | 开启缩放动画 | void | 参考下方 |
| setSize(w, h) | 设置一倍缩放下,容器大小 | void | w:宽,h:高 |
| getWidth() | 获取一倍缩放下,容器的宽 | number | 无 |
| getHeight() | 获取一倍缩放下,容器的高 | number | 无 |
* scale 缩放倍数
* startX 动画开始时的x轴偏移
* startY 动画开始时的y轴偏移
* finalX 最终的x轴偏移
* finalY 最终的y轴偏移
* task(w, h, x, y) 动画每一帧的回调
* w 当前动画帧的图片的宽
* h 当前动画帧的图片的高
* x 当前动画帧的x轴偏移
* y 当前动画帧的y轴偏移
* duration 动画持续时间
##### 代码示例
```javascript
onDoubleTap(e) {
const that = this
const x = e.touches[0].globalX
const y = e.touches[0].globalY
const maxScale = parseInt(that.maxScale)
let scale = that.image.currScale
scale++
if (scale > maxScale) scale = 1
that.image.currScale = scale
const reset = scale == 1
const lastX = that.trans.transX
const lastY = that.trans.transY
const finalX = reset ? 0 : helper.calculateScaleTranslate(x, scale, that.image.initImageWidth, that.width, lastX)
const finalY = reset ? 0 : helper.calculateScaleTranslate(y, scale, that.image.initImageHeight, that.height, lastY)
that.scale.runScale(scale, lastX, lastY, finalX, finalY, (w, h, x, y) => {
that.clearCanvas = reset
that.image.imageWidth = w
that.image.imageHeight = h
that.trans.transX = x
that.trans.transY = y
that.loadImage()
})
}
```
### -velocity.js
取一系列触摸事件的滑动速度,单位为像素/秒
| 方法名 | 说明 | 返回值 | 参数说明 | 是否异步 |
| ------------------ | ------------------------------------------------------------ | -------------------------- | ------------------------------------------------------------ | -------- |
| addEvent(ac, x, y) | 添加触摸事件 | void | ac:触摸事件类型,取值为对应DOWN、MOVE、UP;x:手指的x坐标;y:手指的y坐标 | 否 |
| getVelocity() | 获取速度 | { x: x轴速度, y: y轴速度 } | 无 | 是 |
| clear() | 清除事件,在手指抬起并且计算过速度后调用 | void | 无 | 否 |
### -bridge.js
包含一些工具方法
| 方法名 | 说明 | 返回值 | 参数说明 | 是否异步 |
| ------------------------- | ------------------------------------------------------------ | ----------------------- | -------- | -------- |
| getStatusBarHeight() | 获取状态栏高度 | number | 无 | 是 |
| getScreenWidthAndHeight() | 获取屏幕的宽与高 | { width: 1, height: 1 } | 无 | 是 |
| getPPI() | 获取ppi | number | 无 | 是 |