【小程序】用canvas 实现一个简易的移动端名片可编辑小程序

本文介绍了一种使用微信小程序和canvas技术来创建个性化名片模板的方法。用户可以输入姓名、行业和联系电话等信息,实时预览并保存图片到相册。代码示例展示了如何监听用户输入、绘制canvas内容、保存图片到相册等功能,帮助开发者理解微信小程序中的canvas应用。
摘要由CSDN通过智能技术生成

效果预览:

请添加图片描述
信息输入完成后,点击【确定生成】,将生成图片,并出现【保存】&&【取消】按钮,点击保存即可保存到相册,取消则回到编辑页面:
请添加图片描述
请添加图片描述

保存的图片效果:
请添加图片描述
这个很简单,主要用微信小程序的canvas实现,具体代码:

card.wxml:

<view class="content">
  <scroll-view scroll-y="true" style="height: 1334rpx;" 
    bindscroll="scroll" scroll-into-view="{{toView}}" scroll-top="{{scrollTop}}">

    <!-- 模板生成弹框 -->
    <view class="canvas-content">
      <view class="con">
        <canvas canvas-id='myCanvas' class='canvas'></canvas>
        <view class="info">
          <!-- 行业 -->
          <view class="show-post-text">{{upost}}</view>
          <!-- 姓名 -->
          <view class="show-name-text">{{uname}}</view>
          <!-- 联系电话 -->
          <view class="show-company-text">{{ucompany}}</view>
        </view>
      </view>
      <view class="canvas-bottom" hidden="{{isHidde}}">
        <view class="btn-save" bindtap="saveImg">保存</view>
        <view class="btn-close" bindtap="closeDialog">取消</view>
      </view>
    </view>

    <!-- 编辑区域 -->
    <view class="edit-tips">编辑:</view>
    <view class="form-container">
      <view class="show-name item">
        <label class="name-label">姓名:</label>
        <input type="text" v-model="name" placeholder="" bindinput="onchangeName" class="input" />
      </view>
      <view class="line"></view>
      <view class="show-company item">
        <label class="company-name-label">联系电话:</label>
        <input type="text" v-model="company" placeholder="" bindinput="onchangeCompany" class="input" />
      </view>
      <view class="line"></view>
      <view class="show-post item">
        <label class="name-post-label">从业行业:</label>
        <input type="text" v-model="post" placeholder="" bindinput="onchangePost" class="input" />
      </view>
    </view>

    <view class="create-btn">
      <button bindtap="createImg" hidden="{{hiddeButton}}" class="btn">确定生成</button>
    </view>
  </scroll-view>
  
</view>

card.js:(主要的逻辑功能)

基本都有写上注释了,不清楚的可以看官方文档的API

Page({
  data: {
    imgUrl: "http://pic.51yuansu.com/backgd/cover/00/40/00/5be62bbb6ac3f.jpg!/fw/780/quality/90/unsharp/true/compress/true",
    isHidde: true,
    hiddeButton: false,
    ucompany: '',
    uname: '',
    upost:''
  },

  /* 监听input输入值的变化 实时更新*/
  onchangeCompany(e) {
    var that = this;
    that.setData({
      ucompany: e.detail.value,
    })
  },
  onchangePost(e) {
    var that = this;
    that.setData({
      upost:e.detail.value,
    })
  },
  onchangeName(e) {
    var that = this;
    that.setData({
      uname: e.detail.value
    })
    // console.log("输入监听变化:" + this.data.uname);
  },
  scrollToTop() {
    this.setAction({
      scrollTop: 0
    })
  },

  /* 初始化加载显示 */
  onLoad: function (options) {
    //把网络图片转成在本地
    wx.getImageInfo({
      src: this.data.imgUrl,
      success: (res) => {
        this.setData({
          imgUrl: res.path
        })
        this.getcanvas();
      }
    })
  },

  /* 生成图片 */
  createImg() {
    this.getcanvas();
    this.setData({
      isHidde: false,
      // hiddeButton: true,
      ucompany: '',
      uname: '',
      upost: ''
    })
  },

  /* 绘制canvas内容 */
  getcanvas() {
    let that = this;
    let ctx = wx.createCanvasContext('myCanvas');
    // ctx.setFillStyle('red');    
    let metrics = ctx.measureText(that.data.ucompany); // 获取字体的宽度
    let name = ctx.measureText(that.data.uname); // 获取字体的宽度
    let rpx = 1;
    wx.getSystemInfo({
      success(res) {
        rpx = res.windowWidth / 375; 

      },
    })
    ctx.drawImage(this.data.imgUrl, 0, 0, 300 * rpx, 460 * rpx);
        // 绘制行业文字
        ctx.setFontSize(20 * rpx);
        ctx.setFillStyle('#fff');
        ctx.setTextAlign('center');
        ctx.fillText(that.data.upost,60 * rpx,30* rpx); // 参数:文本内容,x,y
        // 绘制名字文字
        ctx.setFontSize(40 * rpx);
        ctx.setFillStyle('#fff');
        ctx.setTextAlign('center');
        ctx.fillText(that.data.uname, 150 * rpx, 80 * rpx); 
        //  绘制联系电话
        ctx.setFontSize(20 * rpx);
        ctx.setFillStyle('#fff');
        ctx.setTextAlign('left')
        ctx.fillText(that.data.ucompany, 80 * rpx, 120 * rpx);
        ctx.draw(); // 将内容添加到canvas上
  },

  /* 保存图片 */
  saveImg() {
    wx.showLoading({
      title: '正在保存',
      mask: true,
    })
    wx.canvasToTempFilePath({
      canvasId: 'myCanvas',
      success: (res) => {
        wx.hideLoading();
        wx.saveImageToPhotosAlbum({
          filePath: res.tempFilePath,
          success(res) {
            wx.showToast({
              title: '保存成功!',
            })
          }
        })
      }
    });
  },

  /* 取消保存 */
  closeDialog() {
    wx.showToast({
      title: '已取消保存!',
    });
    this.setData({
      isHidde: true,
    });
    this.resetCanvas();
  },

  /* 重置图片模板内容 */
  resetCanvas() {
    this.setData({
      hiddeButton: false,
    });
    this.getcanvas();
  },


})

其中还有一个就是用v-model绑定数据,通过bindinput绑定事件监听用户动态输入的信息,在事件处理中,通过setData 设置变量的值为所输入的信息:

    that.setData({
      ucompany: e.detail.value,
    })

其他也是类似如此。

card.wxss:

.canvas-bottom {
  display: flex;
  flex-direction: row;
  margin-top: 70rpx;
  width: auto;
  box-sizing: border-box;
  justify-content: space-around;
}

.btn-save {
  text-align: center;
  border-radius: 30rpx;
  /* margin-left: 50rpx; */
  width: 130rpx;
  font-size: 14px;
  padding: 13rpx 40rpx;
  /* background-color: #2fa5ff; */
  background-color:#7F7AA6 ;
  color: #fff;
}

.btn-close {
  text-align: center;
  border-radius: 30rpx;
  width: 130rpx;
  /* margin-right: 50rpx; */
  font-size: 14px;
  padding: 13rpx 40rpx;
  border: 1rpx solid #7F7AA6 ;
  color: #7F7AA6 ;
}

.create-btn {
  width: 100%;
  height: 60rpx;
  font-size: 14px;
  background-color: #7F7AA6 ;
}

.content {
  height: 100vh;
}

.canvas-content {
  background: #ffffff;
  position: relative;
  margin: 0 auto;
}

.canvas-content .con {
  /* background: #AE0001; */
  width: 690rpx;
  position: relative;
  margin: 0 auto;
}

.canvas {
  margin: 15rpx auto;
}


.canvas-content {
  width: 750rpx;
  padding-bottom: 60rpx;
}

.info {
  position: absolute;
  left: 0rpx;
  top: 0rpx;
  height: 300rpx;
}

.show-name-text {
  font-size: 72px;
  color: #fff;
  width: 600rpx;
  text-align: center;
}
.show-post-text {
  font-size: 32px;
  color: #fff;
  width: 600rpx;
  text-align: center;
}

.choose {
  width: 100vw;
  margin-top: 100rpx;
  display: flex;
  justify-content: center;
}

.choose .choose-btn {
  width: 60%;
  margin-top: 30rpx;
  display: flex;
  justify-content: space-around;
}

.choose .choose-btn .abtn,
.bbtn {
  margin-right: 20rpx;
  font-size: 16px;
  color: #424242;
  text-align: center;
}

.choose .choose-btn .abtn {
  border: 1rpx solid #7F7AA6 ;
  color: #7F7AA6 ;
}

.edit-tips {
  height: 160rpx;
  background: #eee;
  padding-left: 30rpx;
  font-size: 24rpx;
  color: #969696;
  line-height: 240rpx;
}

.edit-canvas {
  width: 750rpx;
  height: 300rpx;
  text-align: center;
  line-height: 300rpx;
  background: #F80101;
}

.line {
  width: 100%;
  height: 1rpx;
}

.company-text {
  line-height: 60rpx;
  height: 60rpx;
}

.show-company-text {
  line-height: 60rpx;
  height: 60rpx;
  padding-left: 30rpx;
  color: #fff;
  width: 750rpx;
  text-align: left;
  font-size: 40rpx;
}

.input {
  width: 440rpx;
  height:70rpx;
  margin-top: 15rpx;
  padding-left: 30rpx;
  border-radius: 44rpx;
  background: #f5f5f5; 
  display: inline-block;
}

.company-name-label,.name-post-label {
  float: left;
  margin-right: 30rpx;
  color: #747474;
}

.name-label,.post-label {
  float: left;
  color:  #747474;
  width: 160rpx;
}

.show-post{
  background: #fff;
  height: 80rpx;
  padding-left: 30rpx;
  line-height: 80rpx;
}

.show-company {
  background: #fff;
  height: 80rpx;
  padding-left: 30rpx;
  line-height: 80rpx;
}

.show-name {
  padding-left: 30rpx;
  background: #fff;
  height: 80rpx;
  line-height: 80rpx;
}

.show-post {
  padding-left: 30rpx;
  background: #fff;
  height: 80rpx;
  line-height: 80rpx;
}

.create-btn {
  height: 80rpx;
  text-align: center;
  font-size: 32rpx;
  color: #fff;
  text-align: center;
  border-radius: 0rpx;
  background:#7F7AA6 ;
  margin-top: 160rpx;
  width: 100%;
  position: fixed;
  bottom: 0;
  left: 0;
}

.create-btn .btn {
  text-align: center;
  color: #fff;
  font-size: 16px;
  background: none;
}

card.json:

{
  "usingComponents": {},
  "navigationBarTitleText":"模板编辑"
}

因为图片网络上拿来的,需要设置不检验合法域名,纯属周末瞎玩!

源码下载:

https://github.com/Lydever/wx-business-card

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值