国庆头像,从开发到发布的所遇到的问题以及解决思路,史上最全的开发思路

153 阅读2分钟

蹭一波国庆热度,国庆头像小程序搞起来,这里是使用uniapp开发的小程序,自己封装一个组件,一天时间了解以及上手实现。

先说遇到的问题吧~~

  1. 实现的思路是什么?

    实现的思路就是使用canvas画布去生成图片,渲染效果图,获取微信头像,将素材添加到头像上面,使用uniapp的api去保存图片到本地\

  2. 使用什么技术实现?

    canvas+uniapp+wx.downloadFile\

  3. canvas的api怎么使用?

    将获取到图片以及素材放到canvas里面\

this.ctx.drawImage(this.avatarUrl, 0, 0, this.canvasSide, this.canvasSide)
this.ctx.drawImage(img, 00this.canvasSide, 
this.canvasSide)this.ctx.draw()

4.小程序上线后,服务器的图片怎么解决渲染问题?

由于素材太大,导致小程序无法上传,所以借助服务器,由接口获取素材数据,遇到的问题是canvas需要将其下载到本地之后才能渲染,由于本地编译的时候开启不校验合法域名,所以一切正常,但是上线体验服真机测试的时候发现,canvas无法渲染,将其不勾选也发现有同样的问题,一开始的想法是将其图片的域名加上就可以了,然后发现并没有效果,找了一段时间发现将其不校验取消即可报错,这个时候将其漏掉的域名加上就可以了\

5.canvas渲染的图片模糊怎么办呢?

这个问题目前还在解决中,思路是将其画布放大,是因为获取图片的时候像素太低导致图片模糊,具体的解决方案,后续跟进解决,后面会加入uniapp截取图片尺寸上传,\

话不多说,上代码吧,\

<template>
	<view class="wrapper" :style="{height: windowHeight + 'px'}">
		<view class="title">
			<text class="animation" :key="index" :style="'--t:' + index" v-for="(word,index) in title">{{ word }}</text>
		</view>
		<view class="box">
			<view class="img-wrap">
				<canvas class="canvas" canvas-id="canvas"></canvas>
			</view>
			<view class="save-btn">
				<span class="btn" type="default" @tap="getUserInfo">获取头像</span>
				<span class="btn" type="default" @tap="upload">上传图片</span>
				<span class="btn" type="default" @tap="save">保存头像</span>
			</view>
		</view>
		<view class="select">
			<view class="select-text">
				<span :class="{select_textActive: item.id == index}" v-for="item in imgList"
					@tap="handleCategore(item.id)">{{item.name}}</span>
			</view>
			<view class="select-list">
				<view class="select-pic" :class="{select_active: id == index}" v-for="(source,index) in sources"
					:key="index" @tap="handle(source.src,index)">
					<image class="avatar" :src="avatarUrl"></image>
					<image class="avatar" :src="source.src"></image>
				</view>

			</view>
		</view>

		<view class="preview-wrap" :style="{display: newAvatar ? 'block' : 'none'}" @tap="newAvatar = ''">
			<view class="preview" @tap.stop="(()=>{return false})">
				<view class="new-avatar">
					<image :src="newAvatar"></image>
				</view>
				<view class="hint">长按头像保存图片</view>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		props: {
			imgList: {
				type: Array,
				required: true
			},
			title: {
				type: String
			},
		},
		data() {
			return {
				avatarUrl: '',
				target: '',
				windowHeight: 0,
				//画笔
				ctx: null,
				canvasSide: 0,
				id: 0,
				// #ifdef H5
				newAvatar: '',
				// #endif
				canvas: '',
				index: 1
			}
		},
		computed: {
			sources(picList = []) {
				picList = this.imgList.find(item => {
					console.log(item);
					return item.id == this.index
				}).picList
				return picList.map((item, index) => {
					return {
						id: index,
						src: item
					}
				})
			}
		},
		created() {
			uni.getSystemInfo({
				success: (res) => {
					this.windowHeight = res.windowHeight;
				}
			})
		},
		mounted() {
			uni.createSelectorQuery().in(this).select('.canvas').boundingClientRect(data => {
				console.log(data.width,'chushihua ')
				this.canvasSide = data.width;
				this.ctx = uni.createCanvasContext('canvas', this);
				// #ifdef MP
				uni.getUserInfo({
					provider: 'weixin',
					success: (res) => {
						uni.getImageInfo({
							src: res.userInfo.avatarUrl,
							success: (image) => {
								var that = this
								wx.downloadFile({ //下载
									url: that.sources[0].src, //服务器上的pdf地址
									success: function(res1) {
										console.log('初始化', res1)
										//将其下载后赋值给canvas
										that.avatarUrl = image.path
										// 绘制canvas
										that.target = res1.tempFilePath
										that.ctx = uni.createCanvasContext(
											'canvas', that);
										that.drawImage(that.target)
									}
								})
							}
						})
					}
				})
				// #endif
			}).exec();
		},
		methods: {
			handle(src, index) {
				// this.target = src;
				this.id = index;
				this.drawImage(src)
				this.downloadFile(src)
				console.log(this.target, '切换')
			},
			handleCategore(id) {
				this.index = id
				let src = ''
				if (this.id > this.sources.length) {
					//如果切换的分类时,index>数组的长度就默认选最后一张图片
					this.id = this.sources.length - 1
					src = this.sources[this.id].src
				} else {
					src = this.sources.find(item => {
						//切换分类时实时响应
						return item.id == this.id
					}).src
				}
				this.downloadFile(src)
			},
			downloadFile(src){
				var that = this
				wx.downloadFile({ //下载
					url: src, //服务器上的pdf地址
					success: function(res1) {
						console.log('初始化', res1)
						//将其下载后赋值给canvas
						that.target = res1.tempFilePath
						that.ctx = uni.createCanvasContext(
							'canvas', that);
						that.drawImage(that.target)
					}
				})
			},
			drawImage(img) {
				this.ctx.drawImage(this.avatarUrl, 0, 0, this.canvasSide, this.canvasSide)
				this.ctx.drawImage(img, 0, 0, this.canvasSide, this.canvasSide)
				this.ctx.draw()
				
			},
			save() {
				uni.canvasToTempFilePath({
					width: this.canvasSide,
					height: this.canvasSide,
					canvasId: 'canvas',
					success: (res) => {
						// #ifndef H5
						uni.saveImageToPhotosAlbum({
							filePath: res.tempFilePath,
							success: function() {
								uni.showToast({
									title: '保存成功'
								});
							},
							fail: (err) => {
								console.log(err)
								uni.showToast({
									title: '保存失败'
								});
							}
						});
						// #endif
						// #ifdef H5
						this.newAvatar = res.tempFilePath;
						// #endif
					}
				}, this)
			},
			upload() {
				uni.chooseImage({
					count: 1,
					success: (res) => {
						this.avatarUrl = res.tempFilePaths[0];
						this.ctx = uni.createCanvasContext('canvas', this);
						this.drawImage(this.target)
					}
				})
			},
			getUserInfo() {
				uni.showModal({
					title: '温馨提示',
					content: '亲,授权微信登录后才能正常使用小程序功能',
					success: (res) => {
						if (res.confirm) {
							uni.getUserProfile({
								desc: "获取个人信息",
								success: (res) => {
									this.userList = res.userInfo;
									var that = this
									wx.downloadFile({ //下载
										url: res.userInfo.avatarUrl, //服务器上的pdf地址
										success: function(res1) {
											//将其下载后赋值给canvas
											that.avatarUrl = res1.tempFilePath
											// 绘制canvas
											that.ctx = uni.createCanvasContext(
												'canvas', that);
											that.drawImage(that.target)
										}
									})
								}
							})
						}
					}
				})
			},
		},
	}
</script>

<style>
	.wrapper {
		display: flex;
		flex-direction: column;
		background-image: linear-gradient(#50D0BC, #35b8e9);
		padding: 20rpx;
	}

	.box {
		display: flex;
		justify-content: center;
		margin: 100rpx 0;
	}

	.title {
		font-size: 40rpx;
		margin: 30px 0;
		color: #d90003;
		text-align: center;
	}

	.img-wrap {
		width: 150px;
		height: 150px;
		margin-right: 60rpx;
	}

	.canvas {
		width: 150px;
		height: 150px;
	}

	.avatar {
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
	}

	.select {
		display: flex;
		flex-direction: column;
		padding: 40rpx;
		background-color: #fff;
		border-radius: 16rpx;
	}

	.select-text span {
		padding: 0 10px 10px 10px;
		margin-bottom: 10px;
	}

	.select_textActive {
		border-bottom: 1px solid #35d4d0;
	}

	.select-list,
	.select-text {
		display: flex;
		overflow-x: auto;
	}

	.select-pic {
		flex-shrink: 0;
		position: relative;
		width: 140rpx;
		height: 140rpx;
		border: 4rpx solid transparent;
	}

	.select_active {
		border-color: #35d4d0;
	}

	.save-btn {
		color: #ffffff;
		display: flex;
		flex-direction: column;
		justify-content: space-between;
	}

	.btn {
		background-color: #35d4d0;
		margin: 0 20rpx;
		padding: 20rpx;
		border-radius: 20px;
	}

	.preview-wrap {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background-color: rgba(0, 0, 0, .8);
	}

	.preview {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		margin: auto;
		width: 80%;
		height: 60%;
		border-radius: 12px;
		background-color: #fff;
	}

	.new-avatar {
		width: 500rpx;
		height: 500rpx;
		margin: 40rpx auto 0;
		border: 1px solid #b3e6e6;
		border-radius: 4px;
		overflow: hidden;
	}

	.new-avatar image {
		width: 100%;
		height: 100%;
	}

	.hint {
		font-size: 40rpx;
		text-align: center;
		margin: 30rpx auto 0;
	}

	.animation {
		animation: tiaodong 0.75s cubic-bezier(0.05, 0, 0.2, 1) infinite alternate;
		display: inline-block;
		transform: translate3d(0, 0, 0);
		animation-delay: calc(0.1s * var(--t));
		animation-play-state: running;
	}

	@keyframes tiaodong {

		0%,
		40%,
		100% {
			transform: translate3d(0, 0, 0);
		}

		20% {
			transform: translate3d(0, -10px, 0);
		}
	}
</style>

使用方法\

### 微信国庆修改头像
使用方法
//直接引入
<avatar :imgList="sources"></avatar>

|  参数   | 类型  | 是否必填 |
|  ----  | ----  | ---- |
| imgList | Array | 必填 |
| title | String | 选填 |
数据格式
sources: [{
            id: 1,
            name: '热门',
            picList: [
              '图片路径g',
              '图片路径',
              '图片路径', 
              '图片路径'
            ]
          },
          {
            id: 2,
            name: '国庆节',
            picList: [
              '图片路径',
              '图片路径',
              '图片路径',
            ]
          }
        ],
        title: '领取您的专属头像'


实现的效果\

源码已同步uniapp插件市场\

ext.dcloud.net.cn/plugin?id=9…