最近接到一个小程序的业务,好久都没有写过了,想着让自己练练手;经过决定用uniapp开发,以前没有用过nuiapp+vue2.0,所以这算是我的第一次uniapp实践项目。好了废话不多说了,现在说说我在用uniapp开发小程序过程中遇到的问题,有不对的地方或者好的建议,欢迎各位大神指教.....
1.实现动态水波图
由于项目中会统计实时充电效果,所以会用的水波图。我自己在网上找了相关的一些实现方法,但是有的不满足实时变化;其中有几种方案,可以给大家看看;如下:
-
css实现水波图(由于不满足使用需求) [可以参考](https://zhuanlan.zhihu.com/p/266588341) [可以参考](https://blog.csdn.net/YourNikee/article/details/120265438) -
ECharts(由于Echart比较大,小程序引入进去会出现问题,不建议使用) [可以参考](https://blog.csdn.net/IVanLyf/article/details/107247616) [可以参考](https://www.freesion.com/article/75701075423/) -
纯canvas 手写实现(采用方案) [可以参考](http://106.14.220.139/dfv2g/admin/upload/hongdaomall/20220923/902c92a910f84b8ea152e1c80a08d066.html)
这边直接上代码
//html
<canvas type="2d" id="canvas" style="width: 180px; height: 180px;"></canvas>
//js
onLoad(option) {
await this.getByConnectorId() //业务数据接口
this.getTime() // canvas 画水波图
this.timer = setInterval(() => {
if (this.setTimer) {
clearTimeout(this.setTimer)
}
this.getByConnectorId()
this.getTime()
}, 1000 * 10)
},
methods:{
getTime() {
const query = wx.createSelectorQuery();
// 获取canvas dom
query.select('#canvas').fields({ node: true, size: true }).exec(res => {
const canvas = res[0].node;
const ctx = canvas.getContext("2d");
//canvas 画图
this.renderCanvas(canvas, ctx)
})
},
renderCanvas(canvas, ctx) {
let nowRange = this.orderInfo.soc; //用于做一个临时的range
//画布属性
let mW = (canvas.width = 180);
let mH = (canvas.height = 180);
let lineWidth = 1;
let r = mH / 2; //中心
//Sin 曲线属性
let sX = 0;
let axisLength = mW; //轴长
let waveWidth = 0.01; //波浪宽度,数越小越宽
let waveHeight = 20; //波浪高度,数越大越高
let speed = 0.04; //波浪速度,数越大速度越快
let xOffset = 0; //波浪x偏移量
ctx.lineWidth = lineWidth;
//画矩形函数
let IsdrawCircled = false;
let drawCircle = function () {
ctx.strokeStyle = "#eb4d4c";
ctx.stroke();
IsdrawCircled = true;
};
//画sin 曲线函数
let drawSin = function (xOffset, color, waveHeight) {
ctx.save();
let points = []; //用于存放绘制Sin曲线的点
//画圆
ctx.beginPath();
ctx.linewidth = 21;
ctx.strokeStyle = '#8b9df7';
ctx.arc(90, 90, 90, 0, 2 * Math.PI);
ctx.fillStyle = "#eff2fc";
ctx.fill();
// 只显示重叠部分
ctx.globalCompositeOperation = 'source-in'
ctx.beginPath();
//在整个轴长上取点
for (let x = sX; x < sX + axisLength; x += 20 / axisLength) {
//此处坐标(x,y)的取点,依靠公式 “振幅高*sin(x*振幅宽 + 振幅偏移量)”
let y = Math.sin((-sX - x) * waveWidth + xOffset) * 0.8 + 0.1;
let dY = mH * (1 - nowRange / 100);
points.push([x, dY + y * waveHeight]);
ctx.lineTo(x, dY + y * waveHeight);
}
//封闭路径
ctx.lineTo(axisLength, mH);
ctx.lineTo(sX, mH);
ctx.lineTo(points[0][0], points[0][1]);
ctx.fillStyle = color;
ctx.fill();
// 只显示重叠部分(小程序真机不支持该属性)
//canvas globalCompositeOperation可以参考(http://t.zoukankan.com/qiuzhimutou-p-4722823.html)
// ctx.globalCompositeOperation = 'destination-atop'
//画圆
// ctx.beginPath();
// ctx.linewidth = 21;
// ctx.strokeStyle = '#8b9df7';
// ctx.arc(90, 90, 90, 0, 2 * Math.PI);
// ctx.fillStyle = "#eff2fc";
// ctx.fill();
ctx.restore();
};
const that = this
let render = function () {
console.log('+++++++++')
ctx.clearRect(0, 0, mW, mH);
ctx.strokeRect(0, 0, mW, mH);
ctx.strokeStyle = "#8e9cf900";
if (IsdrawCircled == false) {
drawCircle();
}
drawSin(xOffset + Math.PI * 0.7, "#c3d0fe", 18);
// drawSin(xOffset, "#8e9cf9", 18);
drawText();
ctx.stroke();
ctx.closePath();
xOffset += speed;
that.setTimer = setTimeout(() => {
render()
}, 1000 / 60)
};
// 写百分比文本函数
let drawText = function () {
ctx.save();
let size = 36;
ctx.font = size + "px PingFang SC-Regular";
ctx.textAlign = "center";
ctx.fillStyle = "#F69F53";
ctx.fillText(~~nowRange + "%", r, r);
ctx.restore();
ctx.font = "20px PingFang SC-Regular";
ctx.textAlign = "center";
ctx.fillStyle = "#000000"
let orderStatus = that.orderInfo.orderStatus
switch (orderStatus) {
case orderStatus = 1:
ctx.fillText('启动中', r, r + 36);
break;
case orderStatus = 2:
ctx.fillText('充电中', r, r + 36);
break;
case orderStatus = 3:
ctx.fillText('停止中', r, r + 36);
break;
case orderStatus = 4:
ctx.fillText('已结束', r, r + 36);
break;
case orderStatus = 7:
ctx.fillText('放电启动中', r, r + 36);
break;
case orderStatus = 8:
ctx.fillText('放电中', r, r + 36);
break;
case orderStatus = 9:
ctx.fillText('等待中', r, r + 36);
break;
default:
ctx.fillText('未知', r, r + 36);
}
// ctx.fillText('充电中', r, r + 36);
ctx.restore();
ctx.font = "14px PingFang SC-Regular";
ctx.textAlign = "center";
ctx.fillStyle = "#000000"
if (that.orderInfo.orderType == 1) {
ctx.fillText('按需充电', r, r + 56);
} else if (that.orderInfo.orderType == 2) {
ctx.fillText('有序充电', r, r + 56);
} else if (that.orderInfo.orderType == 3) {
ctx.fillText('V2G模式 ', r, r + 56);
} else {
ctx.fillText('即插即充模式', r, r + 56);
}
ctx.restore();
};
render();
// // })
}
}
2.对接企业微信
首先要在微信开发者工具中增加一个企业微信小程序模拟器(设置>扩展设置>模拟器插件>企业微信小程序模拟器),然后就可以选择切换小程序或是企业微信小程序。在对接去企业微信可能会有多个企业对接,可以在选择切换机行那一行有一个手机一样的图标,点击可以选择企业。
-
调用wx.qy.login的问题 在模拟器端调用wx.qy.login 返回的数据是{code:'......',errMsg:'qy.login:ok'},而真机调用的时候返回的是{code:'......',errMsg:'qy__login:ok'},就是这个errMsg要注意。
-
调用wx.qy.login,然后调用后台登录接口一直报(invlid code 无效code)
解决方案: 1.先调用wx.qy.login,拿到code
- 然后调用后台接口传入code(后台这个接口是调用腾讯企业微信的接口,如下图)
3.拿到2返回的userid和session_key存起来,然后依次调用wx.qy.getAvatar(用户头像),wx.qy.getMobile(手机号),wx.qy.getQrCode(个人二维码),然后调用后台登录接口;如图
第一次写文章,写的不好希望大家理解,记录我在实际项目开发中遇到的问题,希望对大家有一点点帮助,有不大好的地方希望大佬们批评指正.....