小程序初体验

要求实现一个日签功能,提供一个背景图片集合,文案集合,点击按钮可随机组合,形成一张海报,可支持下载。

功能点:

  1. 点击换个背景按钮,随机替换图片
  2. 点击换个灵感按钮,随机替换文案
  3. 右下角logo可以由用户选择上传,并需要裁剪,裁剪宽高比1:1
  4. 点击下载海报,将图片生成保存到相册

第一次接触小程序,花了将近一周的时间写出了两个页面,一个是首页,一个是预览海报页面,如下图。还包括上面提到的一些功能实现。

首页

点击预览,跳转到预览页面
预览页

页面搭建没太多要说的,只要能够灵活使用定位,浮动和层级这些,很快就能把样式搭出来。我们来着重说下功能。
功能描述

当点击换个背景时,中间区域的图片会随机更换,点击换个背景时,图片下方的文字也会随机更换,这两个功能其实是一个功能,实现方式一样,就是随机获取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裁剪插件

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>

到这里,全部功能都实现啦!!!
希望大家指正~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,701评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,649评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,037评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,994评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,018评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,796评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,481评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,370评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,868评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,014评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,153评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,832评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,494评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,039评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,437评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,131评论 2 356

推荐阅读更多精彩内容