在项目中nvue页面调用刮刮卡组件wed端没问题,移动端遮盖涂层不显示。vue页面就没任何问题,怎么调整能让他再移动端正常显示。
<template>
<!-- #ifdef APP-PLUS-NVUE -->
<view class="base-cloud">
<view class="father">
<view class="container-wrapper">
<view :class="{op0 : !ready}" class="prize-container">
<slot></slot>
</view>
<canvas :style="{width: width+'px', height: height+'px'}" class="abs" :disable-scroll="true" @touchstart="touchstart" @touchend="touchend" @touchmove="touchmove" canvas-id="scratch-card"></canvas>
</view>
</view>
</view>
<!-- #endif -->
<!-- #ifndef APP-PLUS-NVUE -->
<view class="base-cloud">
<view class="father" id="canvas">
<view :class="{op0 : !ready}">
<slot></slot>
</view>
<canvas :style="{width: width+'px', height : height+'px'}" class="abs" :disable-scroll="true" @touchstart="touchstart" @touchend="touchend" @touchmove="touchmove" canvas-id="scratch-card"></canvas>
</view>
</view>
<!-- #endif -->
</template>
<script>
export default {
name : "scratch-card" ,
props:{
percentage : { //刮开百分之多少的时候开奖
type : Number ,
default : 20
},
touchSize : { //触摸画笔大小
type : Number ,
default : 20
},
fillColor : { //未刮开图层时的填充色
type : String ,
default : '#ddd'
},
watermark : { //水印文字
type : String ,
default : '刮一刮'
},
watermarkColor : { //水印文字颜色
type : String ,
default : '#c5c5c5'
},
watermarkSize : { //水印文字大小
type : Number ,
default : 14
},
title : { //提示文字
type : String ,
default : '刮一刮开奖'
},
titleColor : { //提示文字颜色
type : String ,
default : '#888'
},
titleSize : { //提示文字大小
type : Number ,
default : 24
},
disabled : { //是否禁止刮卡
type : Boolean ,
default : false
}
},
data() {
return {
width : 0 ,
height : 0 ,
startX : null ,
startY : null ,
computing : false ,
complete : false ,
reset : false ,
ready : false ,
storePoints:[],
touchCount: 0, // 触摸次数计数器,用于nvue平台估算刮开百分比
ctx: null // 将ctx移到组件实例内部
};
},
mounted() {
// 根据平台使用不同的canvas上下文创建方式
// #ifdef APP-PLUS-NVUE
// nvue平台使用getContext获取canvas上下文
this.ctx = uni.createCanvasContext("scratch-card" , this) ;
// #endif
// #ifndef APP-PLUS-NVUE
// 其他平台使用原方式
this.ctx = uni.createCanvasContext("scratch-card" , this) ;
// #endif
this.getRect();
},
methods:{
getRect:function(e){
// 针对 nvue 平台,使用更兼容的方式获取尺寸
// #ifdef APP-PLUS-NVUE
// nvue平台获取设备像素比,将rpx转换为像素
const sysInfo = uni.getSystemInfoSync();
const pixelRatio = sysInfo.pixelRatio;
const screenWidth = sysInfo.screenWidth;
// 页面容器尺寸为600rpx x 300rpx
// 将rpx转换为像素:1rpx = screenWidth / 750 px
this.width = Math.round((600 / 750) * screenWidth);
this.height = Math.round((300 / 750) * screenWidth);
setTimeout(() => {
this.init();
}, 20);
// #endif
// 针对其他平台使用原方法
// #ifndef APP-PLUS-NVUE
const query = uni.createSelectorQuery().in(this);
query.select('#canvas').boundingClientRect(data => {
this.width = data.width;
this.height = data.height;
setTimeout(e => {
this.init();
},20);
}).exec();
// #endif
},
init : function(e){
this.computing = false ;
this.complete = false ;
this.reset = false ;
this.ready = false ;
this.touchCount = 0; // 重置触摸次数计数器
// #ifdef APP-PLUS-NVUE
// nvue 平台的绘制方式
// 清除画布
this.ctx.clearRect(0, 0, this.width, this.height);
// 重置绘制状态
this.ctx.setFillStyle(this.fillColor);
this.ctx.fillRect(0, 0, this.width, this.height);
//绘制文字水印
this.fillWatermark();
//绘制标题
this.fillTitle();
// nvue平台需要立即绘制
this.ctx.draw();
// #endif
// #ifndef APP-PLUS-NVUE
// 其他平台的绘制方式
this.ctx.clearRect(0, 0, this.width, this.height);
this.ctx.setFillStyle(this.fillColor);
this.ctx.fillRect(0, 0, this.width, this.height);
//绘制文字水印
this.fillWatermark();
//绘制标题
this.fillTitle();
this.ctx.draw();
// #endif
this.ready = true ;
},
/**
* 绘制文字水印
*/
fillWatermark : function(e){
if (!this.watermark) {
return ;
}
var width = this.watermark.length * this.watermarkSize ;
this.ctx.save() ;
this.ctx.rotate(-10 * Math.PI / 180);
let x = 0 ;
let y = 0 ;
let i = 0 ;
while( (x <= this.width * 5 || y <= this.height*5) && i < 300){
this.ctx.setFillStyle(this.watermarkColor);
this.ctx.setFontSize(this.watermarkSize);
this.ctx.fillText(this.watermark, x , y );
x += width + width * 1.6 ;
if (x > this.width && y <= this.height ) {
x = -Math.random()*100 ;
y += this.watermarkSize * 3 ;
}
i++ ;
}
this.ctx.restore();
},
/**
* 绘制标题
*/
fillTitle : function(e){
if (!this.title) {
return ;
}
this.ctx.setTextAlign("center");
this.ctx.setTextBaseline("middle");
this.ctx.setFillStyle(this.titleColor);
this.ctx.setFontSize(this.titleSize);
this.ctx.fillText(this.title, this.width/2 , this.height/2 );
},
touchstart : function(e){
if (this.disabled) {
return ;
}
this.startX = e.touches[0].x;
this.startY = e.touches[0].y;
},
touchend : function(e){
this.getFilledPercentage();
},
touchmove : function(e){
if(this.complete || this.disabled ){
return ;
}
// 获取当前触摸点相对于canvas的坐标
const currentX = e.touches[0].x;
const currentY = e.touches[0].y;
// #ifdef APP-PLUS-NVUE
// nvue 平台的处理方式
this.ctx.save();
this.ctx.beginPath();
// 使用圆形刮开效果,与其他平台保持一致
this.ctx.arc(currentX, currentY, this.touchSize / 2, 0, Math.PI * 2);
this.ctx.clip();
this.ctx.clearRect(
currentX - this.touchSize / 2,
currentY - this.touchSize / 2,
this.touchSize,
this.touchSize
);
this.ctx.restore();
this.ctx.draw(true);
// #endif
// #ifndef APP-PLUS-NVUE
// 其他平台的处理方式
this.ctx.beginPath();
this.ctx.globalCompositeOperation = 'destination-out';
this.ctx.arc(this.startX, this.startY, this.touchSize / 2, 0, Math.PI * 2);
this.ctx.fill();
this.ctx.globalCompositeOperation = 'source-over';
this.ctx.draw(true);
// #endif
//记录移动点位
this.startX = currentX;
this.startY = currentY;
},
getFilledPercentage:function(e){
if (this.computing) {
return ;
}
this.computing = true ;
// #ifdef APP-PLUS-NVUE
// nvue 平台不支持 canvasGetImageData,使用触摸次数来估算刮开百分比
// 初始化触摸次数计数器
if (!this.touchCount) {
this.touchCount = 0;
}
// 每次触摸增加计数
this.touchCount++;
// 根据触摸次数和画布大小估算刮开百分比
// 假设每次触摸刮开约1%的面积
const estimatedPercent = Math.min((this.touchCount / (this.width * this.height / (this.touchSize * this.touchSize))) * 100, 100);
if (estimatedPercent >= this.percentage) {
this.success();
}
this.computing = false;
// #endif
// #ifndef APP-PLUS-NVUE
// 其他平台使用原方法
uni.canvasGetImageData({
canvasId: 'scratch-card' ,
x: 0,
y: 0,
width: this.width ,
height: this.height ,
success: (res) => {
let pixels = res.data;
let transPixels = 0;
let totalPixels = pixels.length / 4;
for (let i = 0; i < pixels.length; i += 4) {
// 检查像素是否透明
if (pixels[i + 3] < 128) {
transPixels++;
}
}
var percent = (transPixels / totalPixels * 100).toFixed(2);
if( percent >= this.percentage ){
this.success();
}
this.computing = false ;
console.log(percent)
},
fail : function(e){
console.log(e);
// 如果 canvasGetImageData 失败(例如在某些平台上),尝试其他方法
this.computing = false ;
},
}, this);
// #endif
},
success : function(e){
this.complete = true ;
if (this.reset) {
return ;
}
this.reset = true ;
this.ctx.moveTo(0, 0);
this.ctx.clearRect(0,0, this.width, this.height);
this.ctx.stroke() ;
this.ctx.draw(true);
this.$emit("complete",{});
},
}
}
</script>
<style>
/ 基础样式,适用于所有平台 /
.base-cloud {
position: relative;
display: flex;
width: 100%;
height: 100%;
}
.father {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.abs {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
}
.op0 {
opacity: 0;
}
.prize-container {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 1;
}
/ #ifdef APP-PLUS-NVUE /
/ nvue平台特定样式 /
.base-cloud {
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.father {
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
width: 100%;
height: 100%;
}
.container-wrapper {
position: relative;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
}
.abs {
position: absolute;
top: 0;
left: 0;
z-index: 10;
}
.prize-container {
position: relative;
display: flex;
justify-content: center;
align-items: center;
z-index: 1;
}
/ #endif /
</style>
1***@qq.com (作者)
上传了,麻烦看一下
2025-12-23 15:16