要求实现一个日签功能,提供一个背景图片集合,文案集合,点击按钮可随机组合,形成一张海报,可支持下载。
功能点:
- 点击换个背景按钮,随机替换图片
- 点击换个灵感按钮,随机替换文案
- 右下角logo可以由用户选择上传,并需要裁剪,裁剪宽高比1:1
- 点击下载海报,将图片生成保存到相册
第一次接触小程序,花了将近一周的时间写出了两个页面,一个是首页,一个是预览海报页面,如下图。还包括上面提到的一些功能实现。
点击预览,跳转到预览页面
预览页
页面搭建没太多要说的,只要能够灵活使用定位,浮动和层级这些,很快就能把样式搭出来。我们来着重说下功能。
功能描述
当点击换个背景时,中间区域的图片会随机更换,点击换个背景时,图片下方的文字也会随机更换,这两个功能其实是一个功能,实现方式一样,就是随机获取data中的图片数组和文字数组的下标,再渲染到页面上,我是这么实现的
data:
imgUrls: [
'http://img02.tooopen.com/images/20150928/tooopen_sy_143912755726.jpg',
'http://img06.tooopen.com/images/20160818/tooopen_sy_175866434296.jpg',
'http://img06.tooopen.com/images/20160818/tooopen_sy_175833047715.jpg'],
imgIndex:0,
texts:[
'早上叫我起床的不是贫穷而是闹钟',
'人所缺乏的不是才干而是志向。',
'勇敢坚毅真正之才智乃刚毅之志向。',
],
textIndex:0,
函数实现
//实现换个背景功能
changeBg:function(e){
var imgIndex=Math.floor(Math.random() * this.data.imgUrls.length)
console.log('图片选择改变,携带值为',this.data.imgIndex=imgIndex,this.data.imgUrls[imgIndex])
this.setData({
imgIndex:imgIndex
})
console.log(this.data.imgIndex);
},
//实现换个灵感功能
changeMind:function(e){
var textIndex=Math.floor(Math.random() * 3)
console.log('文字选择改变,携带值为',this.data.textIndex=textIndex)
this.setData({
textIndex:this.data.textIndex
})
},
在index.wxml页面通过bindtap='函数名'来调用函数
在前端页面是这样取到js获得的数据
<view class="bgImg">
<block range= "{{imgUrls}}" value = "{{imgIndex}}">
<image src="{{imgUrls[imgIndex]}}" class="slide-image"/>
</block>
</view>
<view class="text">
<block range= "{{texts}}" value = "{{textIndex}}">
{{texts[textIndex]}}
</block>
</view>
好啦,这样就实现了两个功能!
在开始第三个功能时,我发现文字左下角还要获取当天的日期,毕竟是日签嘛。
在小程序中,新建项目时,就会有一个utils.js文件,就是获取日期和时间的
但这里只要日期,于是我修改了一下
util.js
const formatTime = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return [month, day].map(formatNumber).join('-')
}
const formatNumber = n => {
n = n.toString()
return n[1] ? n : '0' + n
}
module.exports = {
formatTime: formatTime
}
在index.js的onload函数里
var time = util.formatTime(new Date());
this.setData({
time:time
});
index.wxml
<view class="time">{{time}}</view>
改一改样式,就可以在自己想要的位置显示日期啦~
实现第三个函数时,在右下角logo那里绑定一个点击事件,调用上传函数
index.wxml
<image class="camera" src="{{smallImg}}" bindtap='upload'></image>
index.js
//从本地上传图片
upload () {
wx.chooseImage({
count: 1, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success (res) {
const src = res.tempFilePaths[0]
wx.redirectTo({
url: `../upload/upload?src=${src}`//将该图片的临时路径传到upload.js里
})
}
})
},
利用wx.redirectTo重定向到upload页面
upload.png
upload.wxml
<import src="../../we-cropper/we-cropper.wxml"/>
<view class="cropper-wrapper">
<template is="we-cropper" data="{{...cropperOpt}}"/>
<view class="cropper-buttons">
<view
class="upload"
bindtap="uploadTap">
重新选择
</view>
<view
class="getCropperImage"
bindtap="getCropperImage">
确定
</view>
</view>
</view>
upload.js
import WeCropper from '../../we-cropper/we-cropper.js'
const device = wx.getSystemInfoSync()
const width = device.windowWidth
const height = device.windowHeight - 50
Page({
data: {
cropperOpt: {
id: 'cropper',
width,
height,
scale: 2.5,
zoom: 8,
cut: {
x: (width - 100) / 2,
y: (height - 100) / 2,
width: 100,
height: 100
}
}
},
touchStart (e) {
this.wecropper.touchStart(e)
},
touchMove (e) {
this.wecropper.touchMove(e)
},
touchEnd (e) {
this.wecropper.touchEnd(e)
},
getCropperImage () {
this.wecropper.getCropperImage((avatar) => {
if (avatar) {
// 获取到裁剪后的图片
wx.redirectTo({
url: `../index/index?imgSrc=${avatar}`
})
} else {
console.log('获取图片失败,请稍后重试')
}
})
},
uploadTap () {
const self = this
wx.chooseImage({
count: 1, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success (res) {
const src = res.tempFilePaths[0]
// 获取裁剪图片资源后,给data添加src属性及其值
self.wecropper.pushOrign(src)
}
})
},
onLoad (option) {
const { cropperOpt } = this.data
if (option.src) {
cropperOpt.src = option.src
new WeCropper(cropperOpt)
.on('ready', (ctx) => {
console.log(`wecropper is ready for work!`)
})
.on('beforeImageLoad', (ctx) => {
console.log(`before picture loaded, i can do something`)
console.log(`current canvas context:`, ctx)
wx.showToast({
title: '上传中',
icon: 'loading',
duration: 20000
})
})
.on('imageLoad', (ctx) => {
console.log(`picture loaded`)
console.log(`current canvas context:`, ctx)
wx.hideToast()
})
.on('beforeDraw', (ctx, instance) => {
console.log(`before canvas draw,i can do something`)
console.log(`current canvas context:`, ctx)
})
.updateCanvas()
}
}
})
这里用到了cropper裁剪插件
具体代码就不放上来了,你们可以自己看
we-cropper插件是网上GitHub大神写的,
项目地址:
到这里就完成了前三个功能,最后一个绘图并下载海报花了我两天的时间才做好,有些麻烦。
要画中间区域的部分,有三张图片和3段文字
index.js
//得到三张图片的信息
let promise1 = new Promise(function (resolve,reject)
{
console.log('00000');
wx.getImageInfo({
src:'../../images/招生赢家2@2x.png',
success:function(res){
console.log(res)
resolve(res);
}
})
});
let promise2 = new Promise(function(resolve,reject){
console.log(that.data.imgIndex);
wx.getImageInfo({
src:that.data.imgUrls[that.data.imgIndex],
success:function(res){
console.log(res)
resolve(res);
}
})
});
let promise3 = new Promise(function(resolve,reject){
wx.getImageInfo({
src:that.data.smallImg,
success:function(res){
console.log(res)
resolve(res);
}
})
});
//成功得到图片信息后,开始绘图
Promise.all([
promise1,promise2,promise3
]).then(res => {
// console.log('11111');
//如果为网络图片,最好先执行下载操作
wx.downloadFile({
url: that.data.imgUrls[that.data.imgIndex],
success: function (res) {
that.setData({
canvasimgbg: res.tempFilePath
})
}
})
console.log(res)
const ctx = wx.createCanvasContext('shareImg')
console.log('ctx'+ctx)
ctx.setFillStyle('white')
ctx.fillRect(0, 0, 600, 732);
ctx.drawImage('../../images/招生赢家2@2x.png',8,5,243,21)//相对于canvas
ctx.drawImage(that.data.imgUrls[that.data.imgIndex],15,65,228,152)
ctx.drawImage(that.data.smallImg,197,270,37,37)//相对于父容器
ctx.setTextAlign('left')
// ctx.setFillStyle('white')
ctx.setFontSize(16)
// console.log('222222');
ctx.setFillStyle('black')
ctx.fillText('—— 满天星教育培训机构 ——',18,55)
//使文字换行显示
const textHeight = that.fillTextWrap(ctx,that.data.texts[that.data.textIndex],15,240,200)
ctx.setFillStyle('red');
ctx.fillText(that.data.time,14,300)
ctx.stroke()
ctx.draw()
})
在canvas里是不支持对文本的换行的,所以要自己写方法来实现换行,下面的方法实现是我借鉴的大神的方法,你们自己也可以在网上找到,懒得找可以把我这个直接拿过去,就可以实现
// 文字换行
fillTextWrap(ctx, text, x, y, maxWidth, lineHeight) {
// 设定默认最大宽度
const systemInfo = wx.getSystemInfoSync();
const deciveWidth = systemInfo.screenWidth;
// 默认参数
maxWidth = maxWidth || deciveWidth;
lineHeight = lineHeight || 20;
// 校验参数
if (typeof text !== 'string' || typeof x !== 'number' || typeof y !== 'number') {
return;
}
// 字符串分割为数组
const arrText = text.split('');
// 当前字符串及宽度
let currentText = '';
let currentWidth;
for (let letter of arrText) {
currentText += letter;
currentWidth = ctx.measureText(currentText).width;
if (currentWidth > maxWidth) {
ctx.fillText(currentText, x, y);
currentText = '';
y += lineHeight;
}
}
if (currentText) {
ctx.fillText(currentText, x, y);
}
}
canvas里有很多方法可以用,比如drawImage,setFillStyle等,用到的时候可以自行去小程序官方文档
下面是下载和分享功能的实现
index.js
//将绘图结果显示出来
share:function(){
var that = this;
// console.log(that.data.imgIndex);
wx.showLoading({
title:'努力生成中...'
})
wx.canvasToTempFilePath({
x:0,
y:0,
width:600,
height:732,
destWidth: 600,
destHeight: 732,
canvasId:'shareImg',
success:function(res){
// console.log('res.tempFilePath'+res.tempFilePath);
that.setData({
preurl:res.tempFilePath,
previewHidden:false,
})
wx.hideLoading()
},
fail:function(res){
console.log(res)
}
})
},
/**
* 保存到相册
*/
save: function () {
var that = this
// 生产环境时 记得这里要加入获取相册授权的代码
// 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.writePhotosAlbum" 这个 scope
wx.getSetting({
success(res) {
if (!res.authSetting['scope.writePhotosAlbum']) {
wx.authorize({
scope: 'scope.writePhotosAlbum',
success() {
// 用户已经同意小程序相册功能,后续调用 wx.saveImageToPhotosAlbum 接口不会弹窗询问
that.startSaveImage()
}
})
}else{
that.startSaveImage()
}
}
})
},
startSaveImage: function () {
let that = this;
wx.saveImageToPhotosAlbum({
filePath: that.data.preurl,
success(res) {
wx.showModal({
content: '图片已保存到相册,赶紧晒一下吧~',
showCancel: false,
confirmText: '好哒',
confirmColor: '#72B9C3',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定');
that.setData({
previewHidden: true
})
}
}
})
}
})
},
index.wxml
<!-- 画布大小按需定制 -->
<canvas canvas-id="shareImg" style="width:600rpx;height:732rpx"></canvas>
<!-- 预览区域 -->
<view hidden='{{previewHidden}}' class='preview'>
<image src='{{preurl}}' mode='widthFix' class='previewImg'></image>
<button type='primary' bindtap='save'>保存分享图</button>
</view>
<!-- 预览与下载start -->
<view class="fore_down">
<button class="foresee" bindtap='foreseePage'>预览海报</button>
<button class="download" bindtap='share'>下载海报</button>
</view>
到这里,全部功能都实现啦!!!
希望大家指正~~~
网友评论