效果如下图:

代码如下:

<view class='sudoku'>
<scroll-view scroll-x scroll-y class='canvas-box'>
<canvas canvas-id='canvasIn' id='canvas' class='canvas canvas-in' style='{{canvasWH}}'></canvas>
<!-- wx:if='{{canvasIn}}' -->
<!-- <canvas canvas-id='canvasOut' id='canvasOut' class='canvas canvas-out' style='{{canvasWH}}'></canvas> -->
</scroll-view>
<cover-view class='imgs'>
<cover-view class='imgs-box'>
<cover-image class='img' data-idx='{{index+1}}' src='{{item}}' style='{{maxHeight}}' wx:for='{{imgUrls}}' wx:key='{{index}}' bindtap='saveImg'></cover-image>
</cover-view>
</cover-view>
<cover-view class='btns-box'>
<button bindtap='uploadImg' class='btn btn-cut'>上传</button>
<button bindtap='saveAll' class='btn btn-save'>保存</button>
</cover-view>
</view>
let _this
Page({ /**
* 页面的初始数据
*/
data: {
canvasWH: '',
imgW: 0,
imgH: 0,
uploadFlag: false,
imgUrls: [],
maxHeight: ''
}, /* 上传图片 */
uploadImg() {
const query = wx.createSelectorQuery()
query.select('#canvas').boundingClientRect(function(res) {
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
// sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success(res) {
// 图片大小限制为 最大2M
const imgSize = res.tempFiles[0].size
console.log(res, imgSize, '已选择图片大小') if (imgSize > 1000000) {
wx.showModal({
title: '温馨提示',
content: '图片最大不能超过1M',
showCancel: false
})
return
} const ctx = wx.createCanvasContext('canvasIn')
const canvasW = res.width
const canvasH = res.height
ctx.fillStyle = '#fff'
ctx.fillRect(0, 0, canvasW, canvasH)
ctx.draw() // 获取图片信息
wx.getImageInfo({
src: res.tempFilePaths[0],
success(imgInfo) {
console.log(imgInfo, 'imgInfo')
const imgW = imgInfo.width
const imgH = imgInfo.height _this.setData({
canvasWH: `width: ${imgW}px;height: ${imgH}px`,
imgW,
imgH
}) // 获取图片的大小
ctx.drawImage(res.tempFilePaths[0], 0, 0, imgW, imgH)
ctx.draw()
// 展示新图片
_this.showMiniImg()
},
fail(err) {
console.log(err, '图片信息获取失败')
wx.showModal({
title: '温馨提示',
content: '暂不支持此图片格式',
showCancel: false
})
}
})
},
fail (err) {
console.log(err, '图片选择失败')
}
})
})
query.exec()
}, /* 展示小图 */
showMiniImg() {
let x = 0
let y = 0
let count = 0
let imgUrls = []
const {
imgW,
imgH
} = _this.data const cutW = imgW / 3
const cutH = imgH / 3 const cfgSave = {
x: 0,
y: 0,
width: cutW,
height: cutH,
destWidth: cutW,
destHeight: cutH,
canvasId: 'canvasIn'
}
_this.cutFlag = true const timer = setInterval(() => {
if (_this.cutFlag) {
_this.cutFlag = false
console.log(count, 'cutFlag')
switch (count) {
case 0:
x = 0
y = 0
break
case 1:
x = 1
y = 0
break
case 2:
x = 2
y = 0
break
case 3:
x = 0
y = 1
break
case 4:
x = 1
y = 1
break
case 5:
x = 2
y = 1
break
case 6:
x = 0
y = 2
break
case 7:
x = 1
y = 2
break
case 8:
x = 2
y = 2
break
default:
break
}
cfgSave.x = cutW * x
cfgSave.y = cutH * y wx.canvasToTempFilePath({
...cfgSave,
success(res) {
console.log(res, '剪切') _this.cutFlag = true
count++
wx.showLoading({
title: `裁剪中 ${count}/9`,
mask: true
})
imgUrls.push(res.tempFilePath)
if (count == 9) {
if (imgUrls.length < 9) {
imgUrls = []
cut()
return
}
wx.hideLoading()
_this.setData({
uploadFlag: true,
imgUrls
})
clearInterval(timer)
}
},
fail (err) {
console.log(err , '剪切图片失败')
}
})
}
}, 100)
}, /* 保存图片(单图 / 所有) */
saveImgHandle(e) {
const {
imgW,
imgH,
imgUrls
} = _this.data const cutW = imgW / 3
const cutH = imgH / 3 const cfgSave = {
x: 0,
y: 0,
width: cutW,
height: cutH,
destWidth: cutW,
destHeight: cutH,
canvasId: 'canvasIn',
} if (e) { //保存单张图片
switch (e.currentTarget.dataset.idx) {
case 1:
cfgSave.x = cutW * 0
cfgSave.y = cutH * 0
break
case 2:
cfgSave.x = cutW * 1
cfgSave.y = cutH * 0
break
case 3:
cfgSave.x = cutW * 2
cfgSave.y = cutH * 0
break
case 4:
cfgSave.x = cutW * 0
cfgSave.y = cutH * 1
break
case 5:
cfgSave.x = cutW * 1
cfgSave.y = cutH * 1
break
case 6:
cfgSave.x = cutW * 2
cfgSave.y = cutH * 1
break
case 7:
cfgSave.x = cutW * 0
cfgSave.y = cutH * 2
break
case 8:
cfgSave.x = cutW * 1
cfgSave.y = cutH * 2
break
case 9:
cfgSave.x = cutW * 2
cfgSave.y = cutH * 2
break
default:
break
}
wx.canvasToTempFilePath({
...cfgSave,
success(res) {
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success(resPhoto) {
wx.showToast({
title: '保存成功'
})
}
})
}
})
} else { //保存所有
let pathArr = []
let x = 0
let y = 0
let count = 0
_this.saveFlag = true const timer = setInterval(() => {
if (_this.saveFlag) { _this.saveFlag = false
console.log(count, 'saveFlag')
switch (count) {
case 0:
x = 0
y = 0
break
case 1:
x = 1
y = 0
break
case 2:
x = 2
y = 0
break
case 3:
x = 0
y = 1
break
case 4:
x = 1
y = 1
break
case 5:
x = 2
y = 1
break
case 6:
x = 0
y = 2
break
case 7:
x = 1
y = 2
break
case 8:
x = 2
y = 2
break
default:
break
}
cfgSave.x = cutW * x
cfgSave.y = cutH * y
wx.canvasToTempFilePath({
...cfgSave,
success(res) {
console.log(res, '保存所有') pathArr.push(res.tempFilePath)
count++
wx.showLoading({
title: `保存中${count}/9`,
})
_this.saveFlag = true
if (count == 9) {
clearInterval(timer)
console.log(pathArr)
// 保存到相册
for (let i = 0; i < pathArr.length; i++) {
wx.saveImageToPhotosAlbum({
filePath: pathArr[i],
success(resPhoto) {
_this.saveFlag = true
if (i == pathArr.length - 1) {
wx.hideLoading()
wx.showToast({
title: '保存成功'
})
}
}
})
}
}
}
})
}
}, 100)
}
}, /* 保存单张图片 */
saveImg(e) {
const {
uploadFlag
} = _this.data
// 判断是否已上传图片
if (uploadFlag) {
wx.showModal({
title: '温馨提示',
content: '要将该图片保存到相册吗?',
success(confirm) {
if (confirm.confirm) {
_this.photoAuthorization(e)
}
}
}) } else {
wx.showModal({
title: '温馨提示',
content: '请先上传图片',
showCancel: false
})
} }, /* 一键保存 */
saveAll() {
const {
uploadFlag
} = _this.data
// 判断是否已上传图片
if (uploadFlag) {
_this.photoAuthorization()
} else {
wx.showModal({
title: '温馨提示',
content: '请先上传图片',
showCancel: false
})
}
}, /* 设置显示图片的最大高度为屏幕高 */
setMaxHeight() {
wx.getSystemInfo({
success: function(res) {
console.log(res)
const windowH = res.windowHeight
const maxHeight = parseInt(windowH / 3)
_this.setData({
maxHeight: `max-height: ${maxHeight}px`
})
},
})
}, /* 相册授权 */
photoAuthorization(event) {
wx.getSetting({
success(res) {
if (res.authSetting['scope.writePhotosAlbum']) {
// 已授权
if (event) {
_this.saveImgHandle(event)
} else {
_this.saveImgHandle()
}
} else {
wx.authorize({
scope: 'scope.writePhotosAlbum',
success() {
// 已授权
if (event) {
_this.saveImgHandle(event)
} else {
_this.saveImgHandle()
}
},
fail() {
// 未授权
wx.showModal({
title: '温馨提示',
content: '需要获取相册权限',
success(resOpenSetting) {
if (resOpenSetting.confirm) {
wx.openSetting({
success(res) {
if (res.authSetting['scope.writePhotosAlbum']) {
// 已授权
if (event) {
_this.saveImgHandle(event)
} else {
_this.saveImgHandle()
}
} else {
wx.showModal({
title: '温馨提示',
content: '未获取到授权信息',
showCancel: false
})
}
}
})
}
}
})
}
})
}
}
})
}, /**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
_this = this
_this.setMaxHeight()
}, /**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function() { }, /**
* 生命周期函数--监听页面显示
*/
onShow: function() { }, /**
* 生命周期函数--监听页面隐藏
*/
onHide: function() { }, /**
* 生命周期函数--监听页面卸载
*/
onUnload: function() { }, /**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function() { }, /**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function() { }, /**
* 用户点击右上角分享
*/
onShareAppMessage: function() { }
})
page {
height: %;
background-color: #fff;
overflow: hidden;
} .sudoku {
height: %;
} .canvas-box {
position: relative;
width: %;
height: %;
overflow: auto;
} .canvas {
min-width: %;
height: %;
position: absolute;
top: ;
} .canvas-in {
z-index: ;
} .canvas-out {
z-index: ;
background-color: #fff;
} .imgs{
width: %;
height: %;
position: absolute;
top: ;
z-index: ;
background-color: #fff;
} .imgs-box{
width: %;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
padding: 8rpx;
box-sizing: border-box;
} .img{
flex-shrink: ;
width: 33.3%;
padding: 5rpx;
box-sizing: border-box;
} .btns-box {
position: fixed;
right: 30rpx;
bottom: 120rpx;
z-index: ;
display: flex;
justify-content: space-evenly;
flex-direction: column;
height: 300rpx;
} .btn {
color: #fff;
width: 100rpx;
height: 100rpx;
border: none;
border-radius: %;
} .wx-button-cover-view-wrapper {
width: %;
height: %;
display: flex;
justify-content: center;
align-items: center;
} .wx-button-cover-view-inner {
width: %;
height: %;
display: flex;
justify-content: center;
align-items: center;
} .btn::after {
border: none;
} .btn-cut {
background-color: rgba(, , , 0.5);
} .btn-save {
background-color: rgba(, , , 0.5);
}

微信小程序实现九宫格切图,保存功能!的更多相关文章

  1. 微信小程序的轮播图swiper问题

    微信小程序的轮播图swiper,调用后,怎样覆盖系统的 点,达到自己想要的效果 不多说,先上一图望大家多给意见: 这个是效果图: 微信小程序效果图就成这样子: <view class=" ...

  2. 微信小程序登陆流程图时序图

    微信小程序登录 小程序可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系. 微信小程序登录流程时序图 说明 调用 wx.login() 获取 临时登录凭证cod ...

  3. 微信小程序 获取用户信息并保存登录状态

    微信小程序 获取用户信息并保存登录状态:http://www.360doc.com/content/18/0124/11/9200790_724662071.shtml

  4. 微信小程序0.11.122100版本新功能解析

    微信小程序0.11.122100版本新功能解析   新版本就不再吐槽了,整的自己跟个愤青似的.人老了,喷不动了,把机会留给年轻人吧.下午随着新版本开放,微信居然破天荒的开放了开发者论坛.我很是担心官方 ...

  5. 如何自定义微信小程序swiper轮播图面板指示点的样式

    https://www.cnblogs.com/myboogle/p/6278163.html 微信小程序的swiper组件是滑块视图容器,也就是说平常我们看到的轮播图就可以用它来做,不过这个组件有很 ...

  6. 微信小程序之雪碧图(css script)

    今天有朋友问我关于微信小程序中如何在不占用大量网络带宽的情况下快速加载图片,我给他推荐了两种方式 1.雪碧图(css script),有过前端经验的朋友应该都有接触过. 2.懒加载. 由于时间关系我就 ...

  7. 微信小程序之tabbar切卡

    最近在研究小程序的时候,遇到了一个问题,就是tabbar切卡,在android上有fragment,在RN上也有提供一个第三方的组件来用,微信小程序,好像没有专门的一个组件来实现这个功能,度娘了大半天 ...

  8. 自定义微信小程序swiper轮播图面板指示点的样式

    微信小程序的swiper组件是滑块视图容器,也就是说平常我们看到的轮播图就可以用它来做,不过这个组件有很多样式是固定的,但是,有时候我们的设计稿的面板指示点是需要个性化的,那么如何去修改swiper组 ...

  9. 【自定义轮播图】微信小程序自定义轮播图无缝滚动

    先试试效果,可以通过设置参数调整样式 微信小程序中的轮播图可以直接使用swiper组件,如下: <swiper indicator-dots="{{indicatorDots}}&qu ...

随机推荐

  1. Java连载33-对象的创建和使用、内存分析

    一.创建一个学生类 每个学生都有学号信息,但是每一个学生的学号都是不同的,所以要访问这个学号必须先创建对象,通过对象去访问学号信息,学号信息不能直接通过“类”去访问,所以这种成员变量又被称为“实例变量 ...

  2. 引用、浅拷贝及深拷贝 到 Map、Set(含对象assign、freeze方法、WeakMap、WeakSet及数组map、reduce等等方法)

    从引用聊到深浅拷贝,从深拷贝过渡到ES6新数据结构Map及Set,再到另一个map即Array.map()和与其类似的Array.flatMap(),中间会有其他相关话题,例如Object.freez ...

  3. Windows(Win7)搭建RabbitMQ服务器

    首先安装Erlang环境,RabbitMQ的运行依赖于Erlang.可以在官网链接http://www.erlang.org/downloads 页面找到对应的开发环境安装包.例如64位Windows ...

  4. Spring Boot(三) 使用Lombok

        C#写的多了用习惯了众多的语法糖,再写起来Java总会有一些非常不舒服的地方.比如用惯了C#的属性在用起来Java的属性,写起来就会感觉不够优雅.如:定义一个Person类 public cl ...

  5. Android 禁止Edittext弹出系统软键盘 的几种方法

    第一种方法:在XML文件下添加: android:focusable="true" android:focusableInTouchMode="true" 第二 ...

  6. SharePoint 2013 Sandbox Solution

    昨天在写SharePoint EventReceiver的时候遇到一个问题,创建了一个local farm SharePoint solution,添加了一个ItemAdded(SPItemEvent ...

  7. windows如何利用计划任务自动关机?

    第一步打开控制面板,然后选择计划任务,打开它 选择创建基本任务 输入任务名称,描述,选择下一步 根据需要选择,我这里选择的是每天,然后选择下一步 选择任务开始时间,然后选择下一步 选择启动程序,然后选 ...

  8. java 中使用StopWatch来计算时间差

    以前在进行时间耗时时我们通常的做法是先给出计算前后两个的时间值,然后通过详见来计算耗时时长. eg: long start = System.currentTimeMillis(); ......业务 ...

  9. 构建于 B/S 端的 3D 摄像头可视化监控方案

    前言 随着视频监控联网系统的不断普及和发展, 网络摄像机更多的应用于监控系统中,尤其是高清时代的来临,更加快了网络摄像机的发展和应用. 在监控摄像机数量的不断庞大的同时,在监控系统中面临着严峻的现状问 ...

  10. PHP获取客户端的真实IP

    REMOTE_ADDR只能获取访问者本地连接中设置的IP,如中南民族大学校园网中自己设置的10.X.XXX.XXX系列IP,而这个函数获取的是局域网网关出口的IP地址, 如果访问者使用代理服务器,将不 ...