文章废话比较多,主要是想讲一下做这个功能所经历的一些事情,先上代码吧:
由于需要借助canvas生成图片,这里的代码是在应用的首页index.vue执行的,在App.vue无法实现,需要在index.vue中定义
代码写的比较乱,先将就着看,之后再整理
<!-- #ifdef APP-PLUS -->
<block v-if="showWatermark">
<canvas class="watermarkCans" canvas-id="watermarkCanvas"></canvas>
</block>
<!-- #endif -->
下面是js
initWatermark(msg) {
// #ifdef APP-PLUS
let _self = this;
let id = '1.23452384164.123412415';
if (plus.nativeObj.View.getViewById(id) !== null) {
plus.nativeObj.View.getViewById(id).close();
}
let canvasInAppPlusContext = uni.createCanvasContext('watermarkCanvas');
canvasInAppPlusContext.rotate(-30 * Math.PI / 180);
canvasInAppPlusContext.setFontSize(uni.upx2px(28));
canvasInAppPlusContext.setFillStyle('rgba(200, 200, 200, 0.50)');
canvasInAppPlusContext.setTextAlign('left');
canvasInAppPlusContext.setTextBaseline('middle');
canvasInAppPlusContext.fillText(msg, -25, uni.upx2px(170));
canvasInAppPlusContext.draw(false, function() {
uni.canvasToTempFilePath({
canvasId: "watermarkCanvas",
success: function(res) {
_self.showWatermark = false;
let path = res.tempFilePath;
uni.getSystemInfo({
success: function (res) {
//水印排列行数
let row = Math.floor(res.windowHeight / uni.upx2px(250));
let tarArr = [];
for(let i = 0; i < row; i++) {
for(let j = 0; j < 3; j++){
tarArr.push({
tag: 'img',
src: path,
position: {
top: (uni.upx2px(255) * i) + 'px',
left: (uni.upx2px(255) * j) + 'px',
width: uni.upx2px(255) + 'px',
height: uni.upx2px(255) + 'px'
}
});
}
}
var watermarkView = new plus.nativeObj.View(id, {
top:'70px',
left:'0px',
right: '0px',
bottom: '50px'
}, tarArr);
//拦截View控件的触屏事件,将事件穿透给下一层view
watermarkView.interceptTouchEvent(false);
watermarkView.show();
}
});
}
});
});
// #endif
// #ifdef H5
let id = '1.23452384164.123412415';
if (document.getElementById(id) !== null) {
document.body.removeChild(document.getElementById(id));
}
let can = document.createElement('canvas');
can.width = uni.upx2px(250);
can.height = uni.upx2px(250);
let cans = can.getContext('2d');
cans.rotate(-30 * Math.PI / 180);
cans.font = uni.upx2px(28) + 'px';
cans.fillStyle = 'rgba(200, 200, 200, 0.50)';
cans.textAlign = 'left';
cans.textBaseline = 'Middle';
cans.fillText(msg, -25, uni.upx2px(170));
let div = document.createElement('div');
div.id = id;
div.style.pointerEvents = 'none';
div.style.top = '44px';
div.style.left = '-40px';
div.style.bottom = '50px';
div.style.right = '0px';
div.style.position = 'fixed';
div.style.zIndex = '100000';
// div.style.width = document.documentElement.clientWidth + 'px'
// div.style.height = document.documentElement.clientHeight + 'px'
div.style.background = 'url(' + can.toDataURL('image/png') + ') left top repeat';
document.body.appendChild(div);
return id;
// #endif
}
前两天在研究一个全局水印的功能,需要达到以下的效果:
1、根据给出的文字生成水印
2、水印需要在全局生效,不能跳转页面后消失
3、H5端和APP端都要兼容
根据以上的需求,我研究了以下几种方案:
1、封装水印组件。
做一个漂浮的div,定义z-index层级和pointer-event属性和背景平铺重复,在需要的页面中使用组件。这个实现起来很简单,兼容H5和APP,但是有一个问题需要在每一个页面中去单独引入,不符合全局水印的定义,而且项目要提供给项目组使用,很明显不是一个完美的方案。
2、往页面中插入一个div
实现方式和第一点类似,优点是只能在H5端生效,APP端没有body,这个方案直接被pass了
3、用native.js分别实现安卓和IOS端的效果
但是由于对原生开发不了解,这个方案直接就实现不了了
4、直接丢给原生开发做,再去引入插件
这明显不是个好点子,而且研究了这么久不能半半途而废
尝试了很多方法之后我就思考:有没有这样一个顶层的视图容器的东西,可以让我去插入内容,还不会影响事件的穿透,基于这个想法,我又做了一下尝试
1、应用生命周期
由于对移动开发和vue都不熟,尝试了很多vue的方法,生命周期钩子,createElement,render等等,都失败了。
2、webview
我了解到uni-app在APP端实质上也是一个webview,每一个页面其实是这个webview的子webview,我想在应用的onLaunch里边去获取到顶层的webview,往webview中添加子窗口的方式实现,因为各种原因,实现了一半,但是感觉好像有了苗头
3、plus.nativeObj.View
也就是我最终的实现方式,研究了好久,发现了这个宝藏对象。
plus.nativeObj:可以管理系统原生对象。
plus.nativeObj.View:原生控件对象可用于在屏幕上绘制图片或文本内容,当控件不再使用时需要调用close方法销毁控件。
链接:http://www.html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View
尝试了之后发现可以在屏幕上绘制内容,并且在整个应用生效,开心到爆炸,但是!!又遇到了一个问题,这些内容会形成类似遮罩层的东西,导致事件无法穿透。研究了一番,找到了这样一个方法:view.interceptTouchEvent(false),它可以拦截View控件的触屏事件。
接下来,就是文字生成水印图片的问题了,我用的canvas绘制了一个水印,转换成图片实现。期间遇到了一个问题,APP端的uni.canvasToTempFilePath事件需要放在cans.draw()的回调里去实现。
13 个评论
要回复文章请先登录或注册
语文数学天才
8***@qq.com (作者)
3***@qq.com