uni-app
uni-app 中 css 关于 calc()函数计算无效问题
原本以为uni-app不支持calc计算,后来发现:
计算符:+ - * /
计算符前后都需要空格,否则计算无效
.tets{
height: calc(var(--status-bar-height) + 10px);
}
获取系统状态栏的高度
let systemInfo = uni.getSystemInfoSync();
(systemInfo.statusBarHeight) + (systemInfo.platform == "ios" ? 44 : 48)
uni.upx2px(this.titleWidth))
- swiper组件 如果有轮播图的组件名叫swiper.vue 或者 Swiper.vue 的时候,那么在使用swiper组件的时候会报 “找不到事件处理程序”,因此组件名不能叫swiper/Swiper。
<swiper>
一定要给高度才会生效,一般是动态获取里面的元素或列表高度再赋值给<swiper>
- 出现遮罩后阻止页面滚动,可以在遮罩的touchmove事件中阻止默认事件。
@touchmove.prevent=""
- 在使用picker的时候 值只能使用 - 的形式隔开 不然在ios上会从第一年第一月开始 ,事件是绑定在{{data}}上的,具体可查看uniapp文档
- 阻止事件,冒泡时要在外层加一层标签
<view @tap.stop="xx"></view>
,直接在需要使用的方法上加.stop
无效
- 在{{}}中使用toFixed会报错,可以单独写个变量进行处理后再赋值
- H5 io操作文件 获取不到信息
注意异步方法
- 通过路径获取操作目录或文件对象 resolveLocalFileSystemURL()
- 获取当前目录中的所有文件和子目录 readEntries()
canvas绘制问题
setTimeout(function(){ //延迟执行 否则H5不显示
ctx.stroke();
ctx.draw()
},500)
- 进入页面调用方法生命周期用mounted
- map组件添加callout属性在模拟器可以展示,但在真机属性失效,比如边框颜色,样式 取消callout属性,目前只能使用title方法 没有什么很好的办法
uniapp在ios端每个页面都可以上下拉,阻止方法
pages.json内设置:
{
"path": "pages/personal/index",
"style": {
"app-plus": {
"bounce": "none"
}
}
}
修改input的值v-model不生效
this.$nextTick(() => {
this.value= val;
});
- rpx不支持动态横竖屏切换计算,使用rpx时建议锁定屏幕方向
- uni-app官方不支持动态组件,目前用v-if判断
uni-app实现在小程序和h5中在线预览pdf功能
在小程序中预览
先调用
downloadFile
获取到本地文件路径tempFilePath 再调用openDocument
就可以在新页面中预览文件,这个API还可以给参数fileType赋值,比如pdf,就会指定类型打开pdf文件uni.downloadFile({
url: 'https://xxx.com/abc.pdf',
success: function (res) {
var filePath = res.tempFilePath;
uni.openDocument({
filePath: filePath,
success: function (res) {
console.log('打开文档成功');
}
});
}
});在h5中预览
按照正常的逻辑,说到浏览器预览文件,可能首先想到的就是嵌一个a链接,但是这个对于苹果的手机浏览器来说是可以用的,然而安卓手机点击a链接之后则是会将文件直接下载下来,但是用户肯定不满意,这时候就可以把pdf.js插件安排上了,可以去官网下载zip文件,或者上网百度一下,参考解决方案
<template>
<view>
<web-view :src="pdfUrl"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
pdfUrl:'',
from:''
}
},
onLoad() {
this.pdfUrl = '/hybrid/html/web/viewer.html?file='+encodeURIComponent(pdfUrl)
},
}
</script>
wepy
- npm install -g wepy-cli@1.7.0
- wepy小程序的scroll-view 需要加高度,scroll-top和scroll才会生效,而且高度不能大于内容高度,否则不起效!
<scroll-view style="height: 1000px;" scroll-top="{{scrollTop}}" @scroll="scroll" scroll-with-animation="true" scroll-y="true"
</scroll-view>
- 数据修改,需要调用this.$apply() ,视图才会更新
操作方法用
@tap=function
的形式进行绑定。基本上所有微信原生的方法bindFn=fn
都可以直接写成@Fn=fn
.// Template
// 原生的 bindtap=fn
<view @tap="fn"></view>
// Script
class Foo extends wepy.page {
methods = {
fn: () => {},
}
}
模板事件提供了“方法后缀”作为语法糖以代替原生写法,有
.default
,.stop
和.user
后缀,比较常用的是.stop
// .default 可不写
<view @tap="fn"></view>
// .stop 相当于 catch, 点击事件到此结束,不会向上层组件冒泡
<view @tap.stop="fn"></view>
- mixin 可以将通用方法提供给不同地方使用。在这里它能直接读取共有的数据(比如说从Redux 里读取的内容等)但使用时要注意当mixin 中用到了来自Redux 中的数据时,数据本身的connect 要在其具体引用到的页面里面定义,貌似Mixin 本身并不能将Redux 中的数据connect 进来。
- mixin 中的methods 中不能直接使用
this.foo = bar
去设置页面中的值,因为上下文不一致了不会生效。
对于原生及非原生组件,它的模板逻辑也总是“看上去不那么固定”的
// 正确 - 省略为 true
<scroll-view scroll-y></scroll-view>
// 错误 - 布尔值不能带括号
<scroll-view scroll-y="{{true}}"></scroll-view>
// 正确 - 估计这里实际上可能 "true" 是被忽略了的
<scroll-view scroll-y="true"></scroll-view>
// 正确 - 但此时这个方法接受到的第一个参数为当前Class的实例,坑爹啊
<view @tap="toggleSomeThing"></view>
// 错误 - 布尔值要带括号
<view @tap="toggleSomeThing(true)"></view>
// 正确
<view @tap="toggleSomeThing({{true}})"></view>
canvas 签名
<template>
<div class="wrapper">
<div class="left-btn-area">
<button @tap="clearClick" class="clean-btn">清除</button>
<button @tap="saveClick" class="save-btn">完成</button>
<span class="left-tips"></span>
</div>
<div class="center-sign-area">
<canvas class='firstCanvas'
canvas-id="firstCanvas"
@touchmove='move'
@touchend='end'
@error="error"
disable-scroll='true'>
</canvas>
<canvas class='twoCanvas'
canvas-id="twoCanvas"
disable-scroll='true'>
</canvas>
</div>
<div class="right-title-area">
<div class="right-title">签字板</div>
</div>
</div>
</template>
<script lang="typescript">
import wepy from 'wepy';
import Global from '@U/tools';
import ajax from '@U/ajax';
import API from '@S/api';
import http from '@U/ajax';
var content = null;
var contentCopy = null;
export default class Register extends wepy.page {
config = {
navigationBarTitleText: '电子签名',
enablePullDownRefresh: false,
};
props = {
show: {
type: Boolean,
twoWay: true,
},
};
onunload() {
this.heartTimer && clearInterval(this.heartTimer);
this.methods.closePendingInquiryWS();
clearInterval(this.listTimer);
this.listTimer = null;
}
data = {
touchs: [],
signImage: '',
windowWidth: wx.getSystemInfoSync().windowWidth,
windowHeight: wx.getSystemInfoSync().windowHeight,
};
methods = {
move(e) {
let point = { x: e.touches[0].x, y: e.touches[0].y };
this.touchs.push(point);
if (this.touchs.length >= 2) {
this.methods.draw(this.touchs);
}
},
end(e) {
for (let i = 0; i < this.touchs.length; i++) {
this.touchs.pop();
}
},
clearClick() {
console.log(999)
content.clearRect(0, 0, this.windowWidth, this.windowHeight);
content.draw(true);
if(contentCopy){
contentCopy.clearRect(0, 0, this.windowHeight, this.windowWidth);
contentCopy.draw(true);
}
},
close() {
this.$emit('closeRegister');
},
saveClick() {
let _this = this;
wx.canvasToTempFilePath(
{
canvasId: 'firstCanvas',
success: (res) => {
let temp_path = res.tempFilePath;
// 小程序读取文件管理器 api
let fileSystemManager = wx.getFileSystemManager();
fileSystemManager.readFile({
filePath: temp_path,
encoding: 'base64',
success: (data) => {
let base64 = 'data:image/png;base64,' + data.data;
if (base64.length / wx.getSystemInfoSync().pixelRatio < 6000) {
wx.showModal({
showCancel: false,
title: '签名不完整,请重签',
});
_this.methods.clearClick();
} else {
_this.methods.drowImage(temp_path);
}
},
});
},
},
this
);
},
drowImage(path) {
//这个path是第一个canvas的临时路径,带过来
contentCopy = wx.createCanvasContext('twoCanvas'); //第二个canvas的唯一标识
contentCopy.scale(0.5, 0.5); //把第一个canvas的缩小一倍,因为我的第一个比较大,可以自己调整,太大显示不全
contentCopy.translate(0, 300); //这个是原点偏移(第二个canvas的高度是300,宽度是600)
contentCopy.rotate((-90 * Math.PI) / 180); //逆时针旋转90°,拿到横向的签名
contentCopy.drawImage(path, 0, 0, 300, 600); //把第一个画在第二个上
contentCopy.draw(true); ////注意这地方绘制需要时间,需要把下面获取临时图片延迟一下,不然有可能获取到的是空白就因为draw()方法没有执行完成
wx.showLoading({
title: '加载中...',
icon: 'none',
});
setTimeout(() => {
wx.canvasToTempFilePath(
{
canvasId: 'twoCanvas',
success: (res) => {
let temp_path = res.tempFilePath;
console.log(res.tempFilePath);
this.upLoad(res.tempFilePath);
// 小程序读取文件管理器 api
},
},
this
);
}, 500);
},
async upLoad(img) {
let res = await http.POST(`${prefix}/***/agencyLogin/xxx`, {});
if (!res.err) {
this.ossInfo = res.data;
let key = this.ossInfo.dir + '/' + this.UUID();
wx.uploadFile({
url: this.ossInfo.host,
filePath: img,
name: 'file',
formData: {
name: img,
key: key,
policy: this.ossInfo.policy,
OSSAccessKeyId: this.ossInfo.accessId,
success_action_status: '200',
signature: this.ossInfo.signature,
},
success: (res) => {
wx.setStorageSync('regImg', this.ossInfo.host + '/' + key);
wx.navigateBack();
},
fail: (res) => {
wx.showModal({
title: '提示',
content: '上传失败,请重试',
showCancel: false,
});
},
complete: () => {
wx.hideToast();
},
});
}
},
UUID() {
let s = [];
let hexDigits = '0123456789abcdef';
for (let i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = '4';
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
s[8] = s[13] = s[18] = s[23] = '-';
let uuid = s.join('');
return uuid;
},
draw(touchs) {
let point1 = touchs[0];
let point2 = touchs[1];
touchs.shift();
content.moveTo(point1.x, point1.y);
content.lineTo(point2.x, point2.y);
content.stroke();
content.draw(true);
},
};
onLoad() {
content = wx.createCanvasContext('firstCanvas', this);
content.setStrokeStyle('#000000');
content.lineWidth = 3;
content.setLineCap('round');
content.setLineJoin('round');
}
}
</script>
<style lang="scss">
.wrapper {
width: 100%;
height: 94vh;
margin-top: 1.5vh;
display: flex;
align-content: center;
flex-direction: row;
justify-content: center;
font-size: 28rpx;
}
.right-title-area {
display: inline-flex;
align-items: center;
}
.center-sign-area {
border: 4rpx dashed #e9e9e9;
flex: 5;
overflow: hidden;
box-sizing: border-box;
}
.firstCanvas {
background-color: #fff;
width: 100%;
height: 100%;
}
.right-title {
transform: rotate(90deg);
flex: 1;
color: #666;
}
.left-btn-area button {
font-size: 28rpx;
}
.left-btn-area {
height: 95vh;
display: inline-flex;
flex-direction: column;
justify-content: space-between;
align-content: space-between;
flex: 1;
}
.clean-btn {
position: absolute;
top: 50rpx;
left: 0rpx;
transform: rotate(90deg);
color: #fff;
background-color: rgb(255, 103, 103);
}
.left-tips {
position: absolute;
align-items: center;
color: red;
display: inline-flex;
transform: rotate(90deg);
left: -320rpx;
width: 100%;
top: 55%;
}
.clean-btn image {
position: absolute;
top: 13rpx;
left: 25rpx;
}
.save-btn {
position: absolute;
bottom: 52rpx;
display: inline-flex;
transform: rotate(90deg);
background: #008ef6;
color: #fff;
margin-bottom: 30rpx;
text-align: center;
justify-content: center;
}
</style>