# 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(达到最大倍数再双击会还原成默认大小)的形式 ## 演示 | 启动动画 | 跳转动画 | 手势 | 下滑手势 | | ------------------------------ | ------------------------------ | -------------------------------- | -------------------------- | | ![lanuch](./images/lanuch.gif) | ![router](./images/router.gif) | ![gesture](./images/gesture.gif) | ![down](./images/down.gif) | ## 使用说明 ### -水波纹 | ![wave](./images/wave.gif) | | -------------------------- | ##### 引入 ````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 | 无 | 是 |