LemonJournal-微信小程序Demo:柠檬手帐 - 界面精美的图片编辑应用,支持图片和文字的移动、旋转、缩放、保存编辑状态并生成预览图.zip

上传者: 38743481 | 上传时间: 2025-08-09 09:39:27 | 文件大小: 6.81MB | 文件类型: ZIP
参加比赛的作品,开发周期一个月,使用了 Wafer2 框架,后台采用腾讯云提供的 Node.js SDK 接入对象存储 API ,前端核心代码实现了类似于图片编辑器的功能,支持图片和文字的移动、旋转、缩放、生成预览图以及编辑状态的保存,动画部分采用 CSS 动画实现小程序中的模态输入框部分使用了自己封装的 InputBox 组件代码已移除 AppId 等敏感信息,可自行添加自己的 AppId 和 AppSecret 以配置后台环境,实现登录测试,详细添加方法见下文「使用方法」,若本地运行可通过修改 app.json 文件中 page 字段的顺序来查看不同页面微信小程序定制需求请联系作者微信:aweawds (注明来意)效果展示      使用方法首先点击右上角 Star ʕ •ᴥ•ʔ获取Demo代码执行 git clone https://github.com/goolhanrry/Weapp-Demo-LemonJournal.git或 点击此处 下载最新版本的代码解压后在微信开发者工具中打开 Weapp-Demo-LemonJournal 文件夹即可如需进行登录测试,还要执行以下步骤准备好自己的 AppId 和 AppSecret(可在微信公众平台注册后获取)在 project.config.json 的 appid 字段中填入 AppId在 /client/utils/util.js 中相应位置填入 AppId 和 AppSecret在微信开发者工具中重新导入整个项目,上传后台代码后编译运行即可核心代码组件的移动、旋转和缩放主要思路是把  标签(对应图片)和  标签(对应文字)封装在同一个自定义组件  中,通过对外暴露的 text 变量是否为空来进行条件渲染,然后绑定 onTouchStart() 、onTouchEnd() 和 onTouchMove() 三个事件来对整个组件的位置、角度、大小、层级以及 “旋转” 和 “移除” 两个按钮的行为进行操作onTouchStart: function (e) {
    // 若未选中则直接返回
    if (!this.data.selected) {
        return
    }

    switch (e.target.id) {
        case 'sticker': {
            this.touch_target = e.target.id
            this.start_x = e.touches[0].clientX * 2
            this.start_y = e.touches[0].clientY * 2
            break
        }
        case 'handle': {
            // 隐藏移除按钮
            this.setData({
                hideRemove: true
            })

            this.touch_target = e.target.id
            this.start_x = e.touches[0].clientX * 2
            this.start_y = e.touches[0].clientY * 2

            this.sticker_center_x = this.data.stickerCenterX;
            this.sticker_center_y = this.data.stickerCenterY;
            this.remove_center_x = this.data.removeCenterX;
            this.remove_center_y = this.data.removeCenterY;
            this.handle_center_x = this.data.handleCenterX;
            this.handle_center_y = this.data.handleCenterY;

            this.scale = this.data.scale;
            this.rotate = this.data.rotate;
            break
        }
    }
},

onTouchEnd: function (e) {
    this.active()
    this.touch_target = ''

    // 显示移除按钮
    this.setData({
        removeCenterX: 2 * this.data.stickerCenterX - this.data.handleCenterX,
        removeCenterY: 2 * this.data.stickerCenterY - this.data.handleCenterY,
        hideRemove: false
    })

    // 若点击移除按钮则触发移除事件,否则触发刷新数据事件
    if (e.target.id === 'remove') {
        this.triggerEvent('removeSticker', this.data.sticker_id)
    } else {
        this.triggerEvent('refreshData', this.data)
    }
},

onTouchMove: function (e) {
    // 若无选中目标则返回
    if (!this.touch_target) {
        return
    }

    var current_x = e.touches[0].clientX * 2
    var current_y = e.touches[0].clientY * 2
    var diff_x = current_x - this.start_x
    var diff_y = current_y - this.start_y

    switch (e.target.id) {
        case 'sticker': {
            // 拖动组件则所有控件同时移动
            this.setData({
                stickerCenterX: this.data.stickerCenterX   diff_x,
                stickerCenterY: this.data.stickerCenterY   diff_y,
                removeCenterX: this.data.removeCenterX   diff_x,
                removeCenterY: this.data.removeCenterY   diff_y,
                handleCenterX: this.data.handleCenterX   diff_x,
                handleCenterY: this.data.handleCenterY   diff_y
            })
            break
        }
        case 'handle': {
            // 拖动操作按钮则原地旋转缩放
            this.setData({
                handleCenterX: this.data.handleCenterX   diff_x,
                handleCenterY: this.data.handleCenterY   diff_y
            })

            var diff_x_before = this.handle_center_x - this.sticker_center_x;
            var diff_y_before = this.handle_center_y - this.sticker_center_y;
            var diff_x_after = this.data.handleCenterX - this.sticker_center_x;
            var diff_y_after = this.data.handleCenterY - this.sticker_center_y;
            var distance_before = Math.sqrt(diff_x_before * diff_x_before   diff_y_before * diff_y_before);
            var distance_after = Math.sqrt(diff_x_after * diff_x_after   diff_y_after * diff_y_after);
            var angle_before = Math.atan2(diff_y_before, diff_x_before) / Math.PI * 180;
            var angle_after = Math.atan2(diff_y_after, diff_x_after) / Math.PI * 180;

            this.setData({
                scale: distance_after / distance_before * this.scale,
                rotate: angle_after - angle_before   this.rotate
            })
            break
        }
    }

    this.start_x = current_x;
    this.start_y = current_y;
}编辑状态的保存一篇手帐包含的组件类型包括 sticker(软件自带的贴纸)、image(用户上传的图片)和 text(自定义文字)三种,全部保存在一个如下格式的 json 对象中,每个独立组件都包含了一个不重复的 id 以及相关的信息,保存时由客户端生成该对象并编码成 json 字符串存储在数据库,恢复编辑状态时通过解析 json 字符串获得对象,再由编辑页面渲染{
    "backgroundId": "5",                                        背景图id
    "assemblies": [
        {
            "id": "jhjg",                                       组件id
            "component_type": "image",                          组件类型(自定义图片)
            "image_url": "https://example.com/jhjg.png",        图片地址
            "stickerCenterX": 269,                              中心横坐标
            "stickerCenterY": 664,                              中心纵坐标
            "scale": 1.7123667831396403,                        缩放比例
            "rotate": -3.0127875041833434,                      旋转角度
            "wh_scale": 1,                                      图片宽高比
            "z_index": 19                                       组件层级
        },
        {
            "id": "gs47",
            "component_type": "text",                           组件类型(文字)
            "text": "test",                                     文字内容
            "stickerCenterX": 479,
            "stickerCenterY": 546,
            "scale": 1.808535318980528,
            "rotate": 29.11614626607893,
            "z_index": 10
        },
        {
            "id": "chjn",
            "component_type": "sticker",                        组件类型(贴纸)
            "sticker_type": "food",                             贴纸类型
            "sticker_id": "1",                                  贴纸id
            "image_url": "https://example.com/weapp/stickers/food/1.png",
            "stickerCenterX": 277,
            "stickerCenterY": 260,
            "scale": 1.3984276885130673,
            "rotate": -16.620756913892055,
            "z_index": 5
        }
    ]
}

文件下载

资源详情

[{"title":"( 1246 个子文件 6.81MB ) LemonJournal-微信小程序Demo:柠檬手帐 - 界面精美的图片编辑应用,支持图片和文字的移动、旋转、缩放、保存编辑状态并生成预览图.zip","children":[{"title":"sshpk-conv.1 <span style='color:#111;'> 3.90KB </span>","children":null,"spread":false},{"title":"sshpk-sign.1 <span style='color:#111;'> 2.42KB </span>","children":null,"spread":false},{"title":"sshpk-verify.1 <span style='color:#111;'> 2.16KB </span>","children":null,"spread":false},{"title":"address <span style='color:#111;'> 673B </span>","children":null,"spread":false},{"title":"AUTHORS <span style='color:#111;'> 217B </span>","children":null,"spread":false},{"title":"AUTHORS <span style='color:#111;'> 169B </span>","children":null,"spread":false},{"title":"README.md.bak <span style='color:#111;'> 6.97KB </span>","children":null,"spread":false},{"title":"calendar <span style='color:#111;'> 945B </span>","children":null,"spread":false},{"title":"card <span style='color:#111;'> 2.12KB </span>","children":null,"spread":false},{"title":"performance-now.coffee <span style='color:#111;'> 1.46KB </span>","children":null,"spread":false},{"title":"scripts.coffee <span style='color:#111;'> 1.28KB </span>","children":null,"spread":false},{"title":"performance-now.coffee <span style='color:#111;'> 553B </span>","children":null,"spread":false},{"title":"delayed-require.coffee <span style='color:#111;'> 362B </span>","children":null,"spread":false},{"title":"delayed-call.coffee <span style='color:#111;'> 358B </span>","children":null,"spread":false},{"title":"initial-value.coffee <span style='color:#111;'> 313B </span>","children":null,"spread":false},{"title":"difference.coffee <span style='color:#111;'> 175B </span>","children":null,"spread":false},{"title":"jsl.node.conf <span style='color:#111;'> 6.82KB </span>","children":null,"spread":false},{"title":"errors.def <span style='color:#111;'> 8.07KB </span>","children":null,"spread":false},{"title":"definitions.def <span style='color:#111;'> 3.80KB </span>","children":null,"spread":false},{"title":"coerce.def <span style='color:#111;'> 2.17KB </span>","children":null,"spread":false},{"title":"missing.def <span style='color:#111;'> 1.17KB </span>","children":null,"spread":false},{"title":"defaults.def <span style='color:#111;'> 859B </span>","children":null,"spread":false},{"title":".editorconfig <span style='color:#111;'> 399B </span>","children":null,"spread":false},{"title":".dir-locals.el <span style='color:#111;'> 178B </span>","children":null,"spread":false},{"title":".eslintignore <span style='color:#111;'> 5B </span>","children":null,"spread":false},{"title":".eslintrc <span style='color:#111;'> 554B </span>","children":null,"spread":false},{"title":".eslintrc <span style='color:#111;'> 397B </span>","children":null,"spread":false},{"title":".eslintrc <span style='color:#111;'> 348B </span>","children":null,"spread":false},{"title":".eslintrc <span style='color:#111;'> 219B </span>","children":null,"spread":false},{"title":".eslintrc <span style='color:#111;'> 180B </span>","children":null,"spread":false},{"title":"geo <span style='color:#111;'> 166B </span>","children":null,"spread":false},{"title":".gitattributes <span style='color:#111;'> 66B </span>","children":null,"spread":false},{"title":".gitignore <span style='color:#111;'> 26B </span>","children":null,"spread":false},{"title":".gitmodules <span style='color:#111;'> 0B </span>","children":null,"spread":false},{"title":"example.html <span style='color:#111;'> 200B </span>","children":null,"spread":false},{"title":"hyper-schema <span style='color:#111;'> 1.11KB </span>","children":null,"spread":false},{"title":"hyper-schema <span style='color:#111;'> 1.10KB </span>","children":null,"spread":false},{"title":"hyper-schema <span style='color:#111;'> 1.10KB </span>","children":null,"spread":false},{"title":"hyper-schema <span style='color:#111;'> 942B </span>","children":null,"spread":false},{"title":"hyper-schema <span style='color:#111;'> 936B </span>","children":null,"spread":false},{"title":"dashdash.bash_completion.in <span style='color:#111;'> 14.07KB </span>","children":null,"spread":false},{"title":"info <span style='color:#111;'> 289B </span>","children":null,"spread":false},{"title":"interfaces <span style='color:#111;'> 845B </span>","children":null,"spread":false},{"title":"wechat-pay.jpg <span style='color:#111;'> 190.00KB </span>","children":null,"spread":false},{"title":"alipay.jpg <span style='color:#111;'> 97.29KB </span>","children":null,"spread":false},{"title":"QR.jpg <span style='color:#111;'> 46.27KB </span>","children":null,"spread":false},{"title":"regenerator.min.js <span style='color:#111;'> 956.83KB </span>","children":null,"spread":false},{"title":"moment-with-locales.js <span style='color:#111;'> 514.10KB </span>","children":null,"spread":false},{"title":"locales.js <span style='color:#111;'> 371.30KB </span>","children":null,"spread":false},{"title":"moment-with-locales.min.js <span style='color:#111;'> 318.93KB </span>","children":null,"spread":false},{"title":"locales.min.js <span style='color:#111;'> 268.58KB </span>","children":null,"spread":false},{"title":"ajv.bundle.js <span style='color:#111;'> 254.72KB </span>","children":null,"spread":false},{"title":"nodent.min.js <span style='color:#111;'> 223.02KB </span>","children":null,"spread":false},{"title":"pubsuffix.js <span style='color:#111;'> 159.45KB </span>","children":null,"spread":false},{"title":"moment.js <span style='color:#111;'> 143.38KB </span>","children":null,"spread":false},{"title":"ajv.min.js <span style='color:#111;'> 113.42KB </span>","children":null,"spread":false},{"title":"base.js <span style='color:#111;'> 91.68KB </span>","children":null,"spread":false},{"title":"nacl-fast.js <span style='color:#111;'> 60.80KB </span>","children":null,"spread":false},{"title":"moment.min.js <span style='color:#111;'> 50.43KB </span>","children":null,"spread":false},{"title":"test.js <span style='color:#111;'> 49.58KB </span>","children":null,"spread":false},{"title":"request.js <span style='color:#111;'> 43.34KB </span>","children":null,"spread":false},{"title":"sax.js <span style='color:#111;'> 42.52KB </span>","children":null,"spread":false},{"title":"index.js <span style='color:#111;'> 40.84KB </span>","children":null,"spread":false},{"title":"cookie.js <span style='color:#111;'> 38.34KB </span>","children":null,"spread":false},{"title":"dashdash.js <span style='color:#111;'> 34.47KB </span>","children":null,"spread":false},{"title":"advance.js <span style='color:#111;'> 32.32KB </span>","children":null,"spread":false},{"title":"nacl.js <span style='color:#111;'> 32.18KB </span>","children":null,"spread":false},{"title":"nacl-fast.min.js <span style='color:#111;'> 31.86KB </span>","children":null,"spread":false},{"title":"index.js <span style='color:#111;'> 22.69KB </span>","children":null,"spread":false},{"title":"demo.js <span style='color:#111;'> 22.53KB </span>","children":null,"spread":false},{"title":"parse.js <span style='color:#111;'> 21.74KB </span>","children":null,"spread":false},{"title":"properties.js <span style='color:#111;'> 21.34KB </span>","children":null,"spread":false},{"title":"stringify.js <span style='color:#111;'> 20.30KB </span>","children":null,"spread":false},{"title":"qs.js <span style='color:#111;'> 18.94KB </span>","children":null,"spread":false},{"title":"util.js <span style='color:#111;'> 18.74KB </span>","children":null,"spread":false},{"title":"nacl.min.js <span style='color:#111;'> 18.64KB </span>","children":null,"spread":false},{"title":"x509.js <span style='color:#111;'> 18.61KB </span>","children":null,"spread":false},{"title":"validate.js <span style='color:#111;'> 18.04KB </span>","children":null,"spread":false},{"title":"jsprim.js <span style='color:#111;'> 16.67KB </span>","children":null,"spread":false},{"title":"ajv.js <span style='color:#111;'> 15.55KB </span>","children":null,"spread":false},{"title":"tests.js <span style='color:#111;'> 15.37KB </span>","children":null,"spread":false},{"title":"ec.js <span style='color:#111;'> 14.96KB </span>","children":null,"spread":false},{"title":"punycode.js <span style='color:#111;'> 14.33KB </span>","children":null,"spread":false},{"title":"pkcs8.js <span style='color:#111;'> 13.84KB </span>","children":null,"spread":false},{"title":"XMLNode.js <span style='color:#111;'> 12.97KB </span>","children":null,"spread":false},{"title":"signer.js <span style='color:#111;'> 12.71KB </span>","children":null,"spread":false},{"title":"XMLDocumentCB.js <span style='color:#111;'> 12.02KB </span>","children":null,"spread":false},{"title":"form_data.js <span style='color:#111;'> 11.96KB </span>","children":null,"spread":false},{"title":"required.js <span style='color:#111;'> 11.96KB </span>","children":null,"spread":false},{"title":"parser.js <span style='color:#111;'> 11.94KB </span>","children":null,"spread":false},{"title":"day-of-week.js <span style='color:#111;'> 11.69KB </span>","children":null,"spread":false},{"title":"verror.js <span style='color:#111;'> 11.59KB </span>","children":null,"spread":false},{"title":"formats.js <span style='color:#111;'> 11.46KB </span>","children":null,"spread":false},{"title":"edit.js <span style='color:#111;'> 11.18KB </span>","children":null,"spread":false},{"title":"XMLStringWriter.js <span style='color:#111;'> 11.16KB </span>","children":null,"spread":false},{"title":"dhe.js <span style='color:#111;'> 10.72KB </span>","children":null,"spread":false},{"title":"certificate.js <span style='color:#111;'> 10.51KB </span>","children":null,"spread":false},{"title":"aws4.js <span style='color:#111;'> 10.50KB </span>","children":null,"spread":false},{"title":"index.js <span style='color:#111;'> 10.42KB </span>","children":null,"spread":false},{"title":"validate.js <span style='color:#111;'> 10.42KB </span>","children":null,"spread":false},{"title":"......","children":null,"spread":false},{"title":"<span style='color:steelblue;'>文件过多,未全部展示</span>","children":null,"spread":false}],"spread":true}]

评论信息

免责申明

【只为小站】的资源来自网友分享,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,【只为小站】 无法对用户传输的作品、信息、内容的权属或合法性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论 【只为小站】 经营者是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。
本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二条之规定,若资源存在侵权或相关问题请联系本站客服人员,zhiweidada#qq.com,请把#换成@,本站将给予最大的支持与配合,做到及时反馈和处理。关于更多版权及免责申明参见 版权及免责申明