Compare commits
4 Commits
dev-hxf
...
9e24edad28
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e24edad28 | |||
| 67b3e63de9 | |||
|
|
056ca965b3 | ||
| 4fd6a21f35 |
28
project.config.json
Normal file
28
project.config.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"appid": "wx24c1b58020a5ce66",
|
||||||
|
"compileType": "miniprogram",
|
||||||
|
"libVersion": "3.3.3",
|
||||||
|
"packOptions": {
|
||||||
|
"ignore": [],
|
||||||
|
"include": []
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"coverView": true,
|
||||||
|
"es6": true,
|
||||||
|
"postcss": true,
|
||||||
|
"minified": true,
|
||||||
|
"enhance": true,
|
||||||
|
"showShadowRootInWxmlPanel": true,
|
||||||
|
"packNpmRelationList": [],
|
||||||
|
"babelSetting": {
|
||||||
|
"ignore": [],
|
||||||
|
"disablePlugins": [],
|
||||||
|
"outputPath": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"condition": {},
|
||||||
|
"editorSetting": {
|
||||||
|
"tabIndent": "insertSpaces",
|
||||||
|
"tabSize": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
7
project.private.config.json
Normal file
7
project.private.config.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
|
||||||
|
"projectname": "jwl-applet",
|
||||||
|
"setting": {
|
||||||
|
"compileHotReLoad": true
|
||||||
|
}
|
||||||
|
}
|
||||||
1404
src/components/yan-qr/qrcode.js
Normal file
1404
src/components/yan-qr/qrcode.js
Normal file
File diff suppressed because it is too large
Load Diff
95
src/components/yan-qr/yan-qr.md
Normal file
95
src/components/yan-qr/yan-qr.md
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
## 使用方式
|
||||||
|
``` javascript
|
||||||
|
<yan-qr />
|
||||||
|
```
|
||||||
|
|
||||||
|
## 属性说明
|
||||||
|
|属性名 |类型 | 默认值 |说明 |
|
||||||
|
|-- |-- |-----------|-- |
|
||||||
|
|canvasId |String | 'qrcode' |canvas-id |
|
||||||
|
|text |String | 'hello' |二维码内容 |
|
||||||
|
|size |Number | 340 |单位是px |
|
||||||
|
|margin |Number | 0 |边距 |
|
||||||
|
|level |String | 'L' |二维码解析度L/M/Q/H |
|
||||||
|
|fColor |String | '#000000' |二维码颜色 |
|
||||||
|
|bColor |String | '#ffffff' |二维码背景颜色 |
|
||||||
|
|fileType |String | 'png' |二维码图片类型 |
|
||||||
|
|
||||||
|
## 示例代码
|
||||||
|
``` javascript
|
||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view>
|
||||||
|
<view>
|
||||||
|
<view>需要转换的文本:</view>
|
||||||
|
<textarea v-model="content" @blur="inputText" placeholder="请在这里输入" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
二维码
|
||||||
|
<view>
|
||||||
|
<yan-qr :filePath.sync="filePath" :text="text" :margin="20" />
|
||||||
|
</view>
|
||||||
|
二维码图片地址
|
||||||
|
<view>
|
||||||
|
<textarea v-model="filePath" disabled />
|
||||||
|
</view>
|
||||||
|
<button @click='btn'>生成二维码</button>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
qrShow: false,
|
||||||
|
content: '',
|
||||||
|
filePath: '',
|
||||||
|
text: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
filePath() {
|
||||||
|
console.log(this.filePath);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
//*获取文本框内容*//
|
||||||
|
inputText: function(e) {
|
||||||
|
this.content = e.detail.value
|
||||||
|
},
|
||||||
|
|
||||||
|
//*按钮*//
|
||||||
|
btn: function() {
|
||||||
|
if (this.content == '') {
|
||||||
|
uni.showToast({ //显示对话框
|
||||||
|
title: "请输入文本",
|
||||||
|
icon: 'none',
|
||||||
|
duration: 1000,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.text = this.content
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
textarea {
|
||||||
|
border: 1px solid #000000;
|
||||||
|
width: 98%;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
width: 80%;
|
||||||
|
margin-top: 180rpx;
|
||||||
|
border-radius: 25px;
|
||||||
|
color: aliceblue;
|
||||||
|
background-color: #55aaff;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
```
|
||||||
115
src/components/yan-qr/yan-qr.vue
Normal file
115
src/components/yan-qr/yan-qr.vue
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<canvas :canvas-id="canvasId" v-show="qrShow" :style="qrShowStyle" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import uQRCode from './qrcode.js'
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
canvasId: {
|
||||||
|
type: String,
|
||||||
|
default: 'qrcode' //canvas-id
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: 'hello' //二维码内容
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 150 //二维码大小
|
||||||
|
},
|
||||||
|
margin: {
|
||||||
|
type: Number,
|
||||||
|
default: 0 //二维码边距
|
||||||
|
},
|
||||||
|
level: {
|
||||||
|
type: String,
|
||||||
|
default: 'L' //二维码质量L/M/Q/H
|
||||||
|
},
|
||||||
|
bColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#ffffff' //二维码背景颜色
|
||||||
|
},
|
||||||
|
fColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#000000' //二维码颜色
|
||||||
|
},
|
||||||
|
fileType: {
|
||||||
|
type: String,
|
||||||
|
default: 'png' //二维码图片类型
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
qrShow: false,
|
||||||
|
qrShowStyle: {
|
||||||
|
"width": "150px",
|
||||||
|
"height": "150px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
text(newVal, oldVal) {
|
||||||
|
this.onQrFun()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.onQrFun()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onQrFun() {
|
||||||
|
this.qrShow = this.text != ''
|
||||||
|
if(this.qrShow){
|
||||||
|
this.qrShowStyle.width = this.size+"px"
|
||||||
|
this.qrShowStyle.height = this.size+"px"
|
||||||
|
let level;
|
||||||
|
switch (this.level) {
|
||||||
|
case "M":
|
||||||
|
case "m":
|
||||||
|
level = uQRCode.errorCorrectLevel.M
|
||||||
|
break;
|
||||||
|
case "Q":
|
||||||
|
case "q":
|
||||||
|
level = uQRCode.errorCorrectLevel.Q
|
||||||
|
break;
|
||||||
|
case "H":
|
||||||
|
case "h":
|
||||||
|
level = uQRCode.errorCorrectLevel.H
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
level = uQRCode.errorCorrectLevel.L
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uQRCode.make({
|
||||||
|
canvasId: this.canvasId,
|
||||||
|
componentInstance: this,
|
||||||
|
text: this.text,
|
||||||
|
size: this.size,
|
||||||
|
margin: this.margin,
|
||||||
|
backgroundColor: this.bColor,
|
||||||
|
foregroundColor: this.fColor,
|
||||||
|
fileType: this.fileType,
|
||||||
|
errorCorrectLevel: level,
|
||||||
|
success: res => {}
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.canvasToTempFilePath({
|
||||||
|
canvasId: this.canvasId,
|
||||||
|
success: (res) => {
|
||||||
|
// 在H5平台下,tempFilePath 为 base64
|
||||||
|
this.$emit("update:filePath", res.tempFilePath);
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
}, 600)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
65
src/jtools/api/activity.js
Normal file
65
src/jtools/api/activity.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import request from '../request/index.js';
|
||||||
|
|
||||||
|
//查询活动列表
|
||||||
|
export function queryActivityList(data) {
|
||||||
|
return request({
|
||||||
|
url: 'activity/applet/activity/list',
|
||||||
|
method: 'get',
|
||||||
|
data,
|
||||||
|
noToken: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//查询活动详情
|
||||||
|
export function queryActivityDetail(data) {
|
||||||
|
return request({
|
||||||
|
url: 'activity/applet/activity/detail',
|
||||||
|
method: 'get',
|
||||||
|
data,
|
||||||
|
noToken: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//查询抽奖次数
|
||||||
|
export function queryLuckyNum(data) {
|
||||||
|
return request({
|
||||||
|
url: 'activity/applet/activity/lucky/num',
|
||||||
|
method: 'get',
|
||||||
|
data,
|
||||||
|
noToken: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//查询中奖结果
|
||||||
|
export function queryLuckyResult(data) {
|
||||||
|
return request({
|
||||||
|
url: 'activity/applet/activity/lucky/result',
|
||||||
|
method: 'get',
|
||||||
|
data,
|
||||||
|
noToken: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//录入中奖结果
|
||||||
|
export function saveWinner(data) {
|
||||||
|
return request({
|
||||||
|
url: 'activity/applet/activity/winner/save',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
noToken: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//核销
|
||||||
|
export function receiveWinner(data) {
|
||||||
|
return request({
|
||||||
|
url: 'activity/applet/activity/winner/receive',
|
||||||
|
method: 'POST',
|
||||||
|
data,
|
||||||
|
noToken: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//查询中奖记录
|
||||||
|
export function getLuckyRecord(data) {
|
||||||
|
return request({
|
||||||
|
url: 'activity/applet/activity/lucky/record',
|
||||||
|
method: 'get',
|
||||||
|
data,
|
||||||
|
noToken: true
|
||||||
|
});
|
||||||
|
}
|
||||||
18
src/package.json
Normal file
18
src/package.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"id": "yan-qr",
|
||||||
|
"name": "动态生成二维码",
|
||||||
|
"displayName": "动态生成二维码",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "动态生成二维码",
|
||||||
|
"keywords": [
|
||||||
|
"二维码",
|
||||||
|
"生成二维码",
|
||||||
|
"动态二维码"
|
||||||
|
],
|
||||||
|
"dcloudext": {
|
||||||
|
"category": [
|
||||||
|
"前端组件",
|
||||||
|
"通用组件"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -173,6 +173,30 @@
|
|||||||
"navigationBarTitleText": "切换车型",
|
"navigationBarTitleText": "切换车型",
|
||||||
"enablePullDownRefresh": false
|
"enablePullDownRefresh": false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path" : "pages/index/activity",
|
||||||
|
"style" :
|
||||||
|
{
|
||||||
|
"navigationBarTitleText" : "活动",
|
||||||
|
"enablePullDownRefresh" : false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path" : "pages/me/myGift",
|
||||||
|
"style" :
|
||||||
|
{
|
||||||
|
"navigationBarTitleText" : "我的奖品",
|
||||||
|
"enablePullDownRefresh" : false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path" : "pages/me/qrCode",
|
||||||
|
"style" :
|
||||||
|
{
|
||||||
|
"navigationBarTitleText" : "核销二维码",
|
||||||
|
"enablePullDownRefresh" : false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
26
src/pages/index/activity.vue
Normal file
26
src/pages/index/activity.vue
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<GGL></GGL>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import GGL from './components/ggl/index'
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
GGL
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
147
src/pages/index/components/ggl/index.vue
Normal file
147
src/pages/index/components/ggl/index.vue
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
<template>
|
||||||
|
<view style="padding-bottom: 50px;background-color: #9e0f00;">
|
||||||
|
<image class="wp100" mode="widthFix" src="https://jwl-jiakao-bq.oss-cn-hangzhou.aliyuncs.com/%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%9B%BE%E7%89%87/ggl_header.png"></image>
|
||||||
|
<view class="tip">您今日还剩1次刮奖机会,共有999人参加活动</view>
|
||||||
|
<view class="scraping">
|
||||||
|
<scraping-card :result="result" watermark="刮一刮" title="刮一刮赢取大奖" ref="reset" ></scraping-card>
|
||||||
|
<view v-if="showBtn" class="gj">
|
||||||
|
<view class="btn" @tap="handleScrap">
|
||||||
|
点我刮奖
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="relative mt30 m20lr">
|
||||||
|
<image class="wp100" mode="widthFix" src="/static/image/index/tip.png"></image>
|
||||||
|
<view class="title">中奖名单</view>
|
||||||
|
<view class="card">
|
||||||
|
<view v-for="(item, index) in winningList" :key="index" class="card-item">
|
||||||
|
<text class="item-text">188****8888</text>
|
||||||
|
<text class="item-text">一等奖</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="relative mt30 m20lr">
|
||||||
|
<image class="wp100" mode="widthFix" src="/static/image/index/tip.png"></image>
|
||||||
|
<view class="title">活动说明</view>
|
||||||
|
<view class="card">
|
||||||
|
<view class="item-text">1. 中奖率100%</view>
|
||||||
|
<view class="item-text">2. 报名后可获得一次抽奖机会</view>
|
||||||
|
<view class="item-text">3. 中奖用户请于"我的-我的奖品"中查看并核销</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ScrapingCard from './scraping.vue'
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ScrapingCard
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
result: '特等奖',
|
||||||
|
showBtn: true,
|
||||||
|
winningList: [1,2,3,4,5,6,7,8]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleScrap() {
|
||||||
|
this.showBtn = !this.showBtn
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.tip {
|
||||||
|
position: relative;
|
||||||
|
margin-top: -80px;
|
||||||
|
margin-left: 40px;
|
||||||
|
margin-right: 40px;
|
||||||
|
height: 52rpx;
|
||||||
|
background: rgba(0,0,0,0.5);
|
||||||
|
border-radius: 26rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 52rpx;
|
||||||
|
}
|
||||||
|
.scraping {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
margin-left: 40px;
|
||||||
|
margin-right: 40px;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 3px solid #9e0f00; /* 实线边框 */
|
||||||
|
border-top: 3px dashed #9e0f00; /* 虚线边框 */
|
||||||
|
border-right: 3px dashed #9e0f00; /* 虚线边框 */
|
||||||
|
border-bottom: 3px dashed #9e0f00; /* 虚线边框 */
|
||||||
|
border-left: 3px dashed #9e0f00; /* 虚线边框 */
|
||||||
|
border-radius: 5px; /* 圆角 */
|
||||||
|
padding: 10px; /* 内容与边框之间的空间 */
|
||||||
|
}
|
||||||
|
.gj {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 21;
|
||||||
|
.btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: calc(50% - 100rpx);
|
||||||
|
width: 200rpx;
|
||||||
|
height: 70rpx;
|
||||||
|
line-height: 70rpx;
|
||||||
|
background-color: #BE1200;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
position: absolute;
|
||||||
|
left: calc(50% - 160rpx);
|
||||||
|
top: -14px;
|
||||||
|
width: 320rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
line-height: 80rpx;
|
||||||
|
text-align: center;
|
||||||
|
background: linear-gradient(0deg, #ECB181, #FFEDD3);
|
||||||
|
border: 6rpx solid #E32D1A;
|
||||||
|
border-radius: 40rpx 40rpx 0 0;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #BE1200;
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
margin-top: -40rpx;
|
||||||
|
padding: 26rpx;
|
||||||
|
min-height: 280rpx;
|
||||||
|
background: #FFEDD3;
|
||||||
|
border: 6rpx solid #E32D1A;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
.card-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 80rpx;
|
||||||
|
line-height: 80rpx;
|
||||||
|
border-bottom: 1px solid #ecd3ae;
|
||||||
|
}
|
||||||
|
.card-item:last-of-type {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.item-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #BE1200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
266
src/pages/index/components/ggl/scraping.vue
Normal file
266
src/pages/index/components/ggl/scraping.vue
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
<template>
|
||||||
|
<view class="scraping-happy" id="container">
|
||||||
|
<canvas
|
||||||
|
canvas-id="scraping-happy"
|
||||||
|
class="scraping__canvas"
|
||||||
|
:disable-scroll="true"
|
||||||
|
@touchstart="touchstart"
|
||||||
|
@touchmove="touchmove"
|
||||||
|
@touchend="touchend"
|
||||||
|
/>
|
||||||
|
<cover-view class="scraping__view">
|
||||||
|
{{ showText }}
|
||||||
|
</cover-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/** @name 水印配置默认值 **/
|
||||||
|
const WATERMARK = {
|
||||||
|
text: '刮一刮',
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#C5C5C5',
|
||||||
|
}
|
||||||
|
/** @name 标题配置默认值 **/
|
||||||
|
const TITLE = {
|
||||||
|
text: '刮一刮',
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#333',
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @name 涂层配置默认值
|
||||||
|
* @property { string } color 涂层颜色
|
||||||
|
* @property { number } drawSize 清除涂层的画笔大小
|
||||||
|
*/
|
||||||
|
const MASK = {
|
||||||
|
color: '#DDDDDD',
|
||||||
|
drawSize: 20,
|
||||||
|
}
|
||||||
|
/** @name 容错值,解决部分机型涂层没有覆盖满的情况,主要原因是由于像素尺寸不同导致的,应尽可能让width与height保持整数 **/
|
||||||
|
const TOLERANT = 3;
|
||||||
|
|
||||||
|
let ctx = null;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
/** @name 涂层设置 **/
|
||||||
|
mask: {
|
||||||
|
type: [String, Object],
|
||||||
|
},
|
||||||
|
/** @name 水印设置 **/
|
||||||
|
watermark: {
|
||||||
|
type: [String, Object],
|
||||||
|
},
|
||||||
|
/** @name 提示文字 **/
|
||||||
|
title: {
|
||||||
|
type: [String, Object],
|
||||||
|
},
|
||||||
|
/** @name 刮开百分之多少直接消除图层,为0的时候不消除 **/
|
||||||
|
percentage: {
|
||||||
|
type: Number,
|
||||||
|
default: 60,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
touchX: 0,
|
||||||
|
touchY: 0,
|
||||||
|
showText: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
maskSetting() {
|
||||||
|
return {
|
||||||
|
...MASK,
|
||||||
|
...(typeof this.mask === 'object' ? this.mask : { text: this.mask }),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watermarkSetting() {
|
||||||
|
return {
|
||||||
|
...WATERMARK,
|
||||||
|
...(typeof this.watermark === 'object' ? this.watermark : { text: this.watermark }),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
titleSetting() {
|
||||||
|
return {
|
||||||
|
...TITLE,
|
||||||
|
...(typeof this.title === 'object' ? this.title : { text: this.title }),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 获取画布实例
|
||||||
|
ctx = uni.createCanvasContext('scraping-happy', this);
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** @name 初始化 **/
|
||||||
|
init() {
|
||||||
|
const query = uni.createSelectorQuery().in(this);
|
||||||
|
query
|
||||||
|
.select('#container')
|
||||||
|
.boundingClientRect(({ width, height }) => {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.initCanvas();
|
||||||
|
this.showText = this.result
|
||||||
|
}, 20)
|
||||||
|
})
|
||||||
|
.exec();
|
||||||
|
},
|
||||||
|
/** @name 初始化canvas状态 **/
|
||||||
|
initCanvas() {
|
||||||
|
const { width, height } = this;
|
||||||
|
// 清空矩形内容
|
||||||
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
// 设置画笔颜色
|
||||||
|
ctx.setFillStyle(this.maskSetting.color);
|
||||||
|
// 绘制矩形
|
||||||
|
ctx.fillRect(0, 0, width, height + TOLERANT);
|
||||||
|
// 绘制水印
|
||||||
|
this.drawWatermark();
|
||||||
|
// 绘制提示文字
|
||||||
|
this.drawTitle();
|
||||||
|
// 绘制到canvas身上
|
||||||
|
ctx.draw();
|
||||||
|
},
|
||||||
|
/** @name 绘制水印 **/
|
||||||
|
drawWatermark() {
|
||||||
|
if (!this.watermarkSetting.text) return;
|
||||||
|
// 保存当前的绘图上下文
|
||||||
|
ctx.save();
|
||||||
|
// 旋转
|
||||||
|
ctx.rotate((-10 * Math.PI) / 180);
|
||||||
|
// 水印具体绘制过程
|
||||||
|
const { width, height } = this;
|
||||||
|
const watermarkWidth = this.watermarkSetting.text.length * this.watermarkSetting.fontSize;
|
||||||
|
let x = 0;
|
||||||
|
let y = 0;
|
||||||
|
let i = 0;
|
||||||
|
while ((x <= width * 5 || y <= height * 5) && i < 300) {
|
||||||
|
ctx.setFillStyle(this.watermarkSetting.color);
|
||||||
|
ctx.setFontSize(this.watermarkSetting.fontSize);
|
||||||
|
ctx.fillText(this.watermarkSetting.text, x, y);
|
||||||
|
x += watermarkWidth + watermarkWidth * 1.6;
|
||||||
|
if (x > width && y <= height) {
|
||||||
|
x = -Math.random() * 100;
|
||||||
|
y += this.watermarkSetting.fontSize * 3;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
|
},
|
||||||
|
/** @name 绘制提示文字 **/
|
||||||
|
drawTitle() {
|
||||||
|
if (!this.titleSetting.text) return;
|
||||||
|
ctx.setTextAlign('center');
|
||||||
|
ctx.setTextBaseline('middle');
|
||||||
|
ctx.setFillStyle(this.titleSetting.color);
|
||||||
|
ctx.setFontSize(this.titleSetting.fontSize);
|
||||||
|
ctx.fillText(this.titleSetting.text, this.width / 2, this.height / 3);
|
||||||
|
},
|
||||||
|
/** @name 触摸事件 **/
|
||||||
|
touchstart(e) {
|
||||||
|
this.touchX = e.touches[0].x;
|
||||||
|
this.touchY = e.touches[0].y;
|
||||||
|
},
|
||||||
|
async touchmove(e) {
|
||||||
|
// 把画笔到画布中的指定点
|
||||||
|
ctx.moveTo(this.touchX, this.touchY);
|
||||||
|
// 清除涂层
|
||||||
|
ctx.clearRect(this.touchX, this.touchY, this.maskSetting.drawSize, this.maskSetting.drawSize);
|
||||||
|
ctx.draw(true);
|
||||||
|
// 记录移动点位
|
||||||
|
this.touchX = e.touches[0].x;
|
||||||
|
this.touchY = e.touches[0].y;
|
||||||
|
|
||||||
|
// if (this.percentage > 0) {
|
||||||
|
// const clearPercent = await this.getClearMaskPercent();
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
async touchend() {
|
||||||
|
if (this.percentage > 0) {
|
||||||
|
const clearPercent = await this.getClearMaskPercent();
|
||||||
|
if (clearPercent >= this.percentage) {
|
||||||
|
ctx.moveTo(0, 0);
|
||||||
|
ctx.clearRect(0, 0, this.width, this.height);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.draw(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** @name 计算被清除的涂层百分比 **/
|
||||||
|
getClearMaskPercent() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
uni.canvasGetImageData({
|
||||||
|
canvasId: 'scraping-happy',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: this.width,
|
||||||
|
height: this.height,
|
||||||
|
success: res => {
|
||||||
|
// 区域内所有点的像素信息,它是一个数组,数组中每 "4" 项表示一个点的 rgba 值
|
||||||
|
const allPointPixels = res.data;
|
||||||
|
// 储存被清除的点-点的透明度
|
||||||
|
const clearPoint = [];
|
||||||
|
// 取透明度来判断,如果透明度值小于一半,则判断为该点已经被清除
|
||||||
|
for (let i = 0; i < allPointPixels.length; i += 4) {
|
||||||
|
if (allPointPixels[i + 3] < 128) {
|
||||||
|
clearPoint.push(allPointPixels[i + 3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 已被清除的百分比 = 清除的点 / 全部的点
|
||||||
|
const percent = (
|
||||||
|
(clearPoint.length / (allPointPixels.length / 4)) *
|
||||||
|
100
|
||||||
|
).toFixed(2);
|
||||||
|
resolve(percent);
|
||||||
|
},
|
||||||
|
fail: e => {
|
||||||
|
console.log('canvasGetImageData', e);
|
||||||
|
},
|
||||||
|
}, this);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** @name 重置 **/
|
||||||
|
reset() {
|
||||||
|
this.initCanvas();
|
||||||
|
this.touchX = 0;
|
||||||
|
this.touchY = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.scraping-happy {
|
||||||
|
width: 100%;
|
||||||
|
height: 200rpx;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.scraping__canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
/* background-color: red; */
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.scraping__view {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
color: #f29100;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -11,6 +11,9 @@
|
|||||||
<u-sticky bgColor="#fff">
|
<u-sticky bgColor="#fff">
|
||||||
<u-tabs :list="categoryList" :current="curTab" :scrollable="false" @change="changeCategory"></u-tabs>
|
<u-tabs :list="categoryList" :current="curTab" :scrollable="false" @change="changeCategory"></u-tabs>
|
||||||
</u-sticky>
|
</u-sticky>
|
||||||
|
<view class="m10tb">
|
||||||
|
<u-swiper :list="activityList" @click="handleToActivity"></u-swiper>
|
||||||
|
</view>
|
||||||
<view style="background-color: rgb(245, 245, 245);">
|
<view style="background-color: rgb(245, 245, 245);">
|
||||||
<template v-if="subject=='1' || subject=='4'">
|
<template v-if="subject=='1' || subject=='4'">
|
||||||
<Subject1 :subject="subject" :rightList="rightList" :wrongList="wrongList" />
|
<Subject1 :subject="subject" :rightList="rightList" :wrongList="wrongList" />
|
||||||
@@ -28,12 +31,16 @@
|
|||||||
mapActions
|
mapActions
|
||||||
} from 'pinia' //引入映射函数
|
} from 'pinia' //引入映射函数
|
||||||
import useQuestionStore from '@/jtools/store/question' //引入store
|
import useQuestionStore from '@/jtools/store/question' //引入store
|
||||||
|
import useUserStore from '@/jtools/store/user'
|
||||||
import storage from '@/jtools/storage';
|
import storage from '@/jtools/storage';
|
||||||
import {
|
import {
|
||||||
querySysConfigList,
|
querySysConfigList,
|
||||||
} from '@/jtools/api/question';
|
} from '@/jtools/api/question';
|
||||||
import Subject1 from "./components/Subject1";
|
import Subject1 from "./components/Subject1";
|
||||||
import Subject2 from "./components/Subject2";
|
import Subject2 from "./components/Subject2";
|
||||||
|
import {
|
||||||
|
queryActivityList,
|
||||||
|
} from '@/jtools/api/activity';
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Subject1,
|
Subject1,
|
||||||
@@ -49,6 +56,7 @@
|
|||||||
categoryList: [],
|
categoryList: [],
|
||||||
rightList: storage.get(`rightList_subject${this.subject}`) || [],
|
rightList: storage.get(`rightList_subject${this.subject}`) || [],
|
||||||
wrongList: storage.get(`wrongList_subject${this.subject}`) || [],
|
wrongList: storage.get(`wrongList_subject${this.subject}`) || [],
|
||||||
|
activityList: ['https://cdn.uviewui.com/uview/swiper/swiper1.png']
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onShow() {
|
onShow() {
|
||||||
@@ -61,6 +69,7 @@
|
|||||||
if(this.subject=='2'||this.subject=='3'){
|
if(this.subject=='2'||this.subject=='3'){
|
||||||
this.$refs.subjectRef.getDiverType()
|
this.$refs.subjectRef.getDiverType()
|
||||||
}
|
}
|
||||||
|
this.queryActivityList();
|
||||||
},
|
},
|
||||||
onHide(){
|
onHide(){
|
||||||
this.show=false
|
this.show=false
|
||||||
@@ -115,6 +124,42 @@
|
|||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
//查询活动列表
|
||||||
|
queryActivityList(){
|
||||||
|
// console.log(this.user)
|
||||||
|
// console.log(useUserStore().userInfo)
|
||||||
|
// this.activityList = null;
|
||||||
|
// uni.request({
|
||||||
|
// url: 'http://localhost:8089/applet/activity/list',
|
||||||
|
// method: 'get',
|
||||||
|
// data: {'schoolId': useUserStore().userInfo.schoolId}
|
||||||
|
// }).then(resp => {
|
||||||
|
// console.log(".....")
|
||||||
|
// console.log(resp)
|
||||||
|
// if(resp.data.code == 200) {
|
||||||
|
// this.activityList = resp.data.data
|
||||||
|
// console.log("*****")
|
||||||
|
// console.log(resp.data)
|
||||||
|
// console.log(resp.data.data)
|
||||||
|
// console.log(this.activityList)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
queryActivityList({schoolId: this.user.schoolId}).then(resp => {
|
||||||
|
this.activityList = resp.data;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 去活动
|
||||||
|
handleToActivity(index) {
|
||||||
|
let detailId;
|
||||||
|
this.activityList.find((item, index1) => {
|
||||||
|
if(index === index1){
|
||||||
|
detailId = item.detailId;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/index/activity?detailId='+detailId,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -75,6 +75,11 @@
|
|||||||
<template #icon>
|
<template #icon>
|
||||||
<img src="/static/image/mine/wdzl.png" style="width: 24px;height: 24px;">
|
<img src="/static/image/mine/wdzl.png" style="width: 24px;height: 24px;">
|
||||||
</template>
|
</template>
|
||||||
|
</u-cell>
|
||||||
|
<u-cell size="large" title="我的奖品" isLink @tap="handleGift">
|
||||||
|
<template #icon>
|
||||||
|
<u-icon size="24" name="gift"></u-icon>
|
||||||
|
</template>
|
||||||
</u-cell>
|
</u-cell>
|
||||||
<u-cell size="large" title="我的体检" isLink @tap="handleTJ">
|
<u-cell size="large" title="我的体检" isLink @tap="handleTJ">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@@ -224,6 +229,11 @@ export default {
|
|||||||
handleLogout() {
|
handleLogout() {
|
||||||
useUserStore().logout()
|
useUserStore().logout()
|
||||||
},
|
},
|
||||||
|
handleGift() {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/me/myGift'
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
67
src/pages/me/myGift.vue
Normal file
67
src/pages/me/myGift.vue
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<view class="p10lr p20tb">
|
||||||
|
<view v-for="(item, index) in list" :key="index" class="item">
|
||||||
|
<view class="relative">
|
||||||
|
<img src="/static/image/mine/giftitem.png" style="width: 100%;" mode="widthFix" alt="" />
|
||||||
|
<view class="ab_full df ai-c jcc">一等奖</view>
|
||||||
|
</view>
|
||||||
|
<view class="df ai-c jcsb p20tb p10lr">
|
||||||
|
<view class="item-label">
|
||||||
|
<view>活动名称:幸运刮刮乐开心赢大奖</view>
|
||||||
|
<view>参与时间:2024-01-01 08:00</view>
|
||||||
|
<view>有效期至:2024-03-01 08:00</view>
|
||||||
|
</view>
|
||||||
|
<view class="ml20" style="width: 120rpx;">
|
||||||
|
<img v-if="index%2==0" src="/static/image/mine/writeoff.png" style="width: 120rpx;height: 120rpx;" />
|
||||||
|
<view v-else class="btn" @tap="handleWriteoff(item)">核销</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
list: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
this.handleSearch()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleSearch() {
|
||||||
|
this.list = [1,2,3,4,5]
|
||||||
|
},
|
||||||
|
handleWriteoff(item) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/me/qrCode?item=${item}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.item {
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
border-radius: 36rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
.item-label {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #666;
|
||||||
|
line-height: 48rpx;
|
||||||
|
}
|
||||||
|
.btn {
|
||||||
|
width: 120rpx;
|
||||||
|
height: 68rpx;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 68rpx;
|
||||||
|
border-radius: 34rpx;
|
||||||
|
background-color: #BE1200;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
29
src/pages/me/qrCode.vue
Normal file
29
src/pages/me/qrCode.vue
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<view class="df jcc" style="padding-top: 100px;">
|
||||||
|
<qrcode value="123" :size="200"/>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import qrcode from '/src/uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.vue'
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
qrcode
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(option) {
|
||||||
|
this.value = option.item
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
BIN
src/static/image/index/tip.png
Normal file
BIN
src/static/image/index/tip.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
src/static/image/mine/giftitem.png
Normal file
BIN
src/static/image/mine/giftitem.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
BIN
src/static/image/mine/writeoff.png
Normal file
BIN
src/static/image/mine/writeoff.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
25
src/uni_modules/lime-qrcode/changelog.md
Normal file
25
src/uni_modules/lime-qrcode/changelog.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
## 0.1.2(2023-12-14)
|
||||||
|
- fix: uvue 引入 API 自定义包出错
|
||||||
|
## 0.1.1(2023-12-11)
|
||||||
|
- chore: uvue的二维码API独立,需要单独下载
|
||||||
|
## 0.1.0(2023-12-07)
|
||||||
|
- fix: 修复因utssdk目录导致无法运行
|
||||||
|
## 0.0.9(2023-12-06)
|
||||||
|
- feat: 支持uvue
|
||||||
|
## 0.0.8(2023-12-06)
|
||||||
|
- feat: 支持uvue
|
||||||
|
## 0.0.7(2023-12-06)
|
||||||
|
- feat: 支持uvue
|
||||||
|
## 0.0.6(2023-12-06)
|
||||||
|
- feat: 支持uvue
|
||||||
|
## 0.0.5(2023-07-30)
|
||||||
|
- fix: 修复再次生成前没有清空,导致图形叠加
|
||||||
|
## 0.0.4(2023-07-27)
|
||||||
|
- fix: 修复相同尺寸无法再次生成
|
||||||
|
## 0.0.3(2023-06-09)
|
||||||
|
- feat: 支持通过`@vue/composition-api`在`vue2`上使用
|
||||||
|
- chore: 更新文档
|
||||||
|
## 0.0.2(2023-06-08)
|
||||||
|
- chore: 更新文档
|
||||||
|
## 0.0.1(2023-06-08)
|
||||||
|
- 首次
|
||||||
179
src/uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.uvue
Normal file
179
src/uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.uvue
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
<template>
|
||||||
|
<view class="l-qrcode" ref="l-qrcode" :style="[styles]">
|
||||||
|
<image class="l-qrcode__icon" v-if="icon !=''" :src="icon" :style="[iconStyle]"></image>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { type PropType } from 'vue'
|
||||||
|
import { QRCodeCanvas, QRCodePropsTypes , ImageSettings } from '@/uni_modules/lime-qrcodegen'
|
||||||
|
// import { addUnit } from '@/uni_modules/lime-shared/addUnit'
|
||||||
|
// import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
|
||||||
|
import { addUnit, unitConvert } from './utils'
|
||||||
|
import { TakeSnapshotFailCallback, TakeSnapshotCompleteCallback, TakeSnapshotSuccessCallback} from './type'
|
||||||
|
|
||||||
|
const name = 'l-qrcode'
|
||||||
|
export default {
|
||||||
|
name,
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: Object,
|
||||||
|
default: 160
|
||||||
|
},
|
||||||
|
iconSize: {
|
||||||
|
type: Object,
|
||||||
|
default: 40
|
||||||
|
},
|
||||||
|
marginSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#000'
|
||||||
|
},
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'transparent'
|
||||||
|
},
|
||||||
|
bordered: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
errorLevel: {
|
||||||
|
type: String as PropType<'L' | 'M' | 'Q' | 'H'>,
|
||||||
|
default: 'M' // 'L' | 'M' | 'Q' | 'H'
|
||||||
|
},
|
||||||
|
useCanvasToTempFilePath: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
// status: {
|
||||||
|
// type: String as PropType<'active'|'expired'|'loading'>,
|
||||||
|
// default: 'active' // active | expired | loading
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
emits: ['success'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
qrcode: null as QRCodeCanvas | null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
styles() : Map<string, any> {
|
||||||
|
const style = new Map<string, any>()
|
||||||
|
const size = addUnit(this.size);
|
||||||
|
style.set('width', size)
|
||||||
|
style.set('height', size)
|
||||||
|
style.set('background', this.bgColor)
|
||||||
|
return style
|
||||||
|
},
|
||||||
|
iconStyle() : Map<string, any> {
|
||||||
|
const style = new Map<string, any>()
|
||||||
|
const size = addUnit(this.iconSize);
|
||||||
|
style.set('width', size)
|
||||||
|
style.set('height', size)
|
||||||
|
return style
|
||||||
|
},
|
||||||
|
qrCodeProps() : QRCodePropsTypes {
|
||||||
|
const param = {
|
||||||
|
value: this.value,
|
||||||
|
size: unitConvert(this.size),
|
||||||
|
fgColor: this.color,
|
||||||
|
level: ['L', 'M', 'Q', 'H'].includes(this.errorLevel) ? this.errorLevel : 'M',
|
||||||
|
marginSize: this.marginSize,
|
||||||
|
imageSettings: null,
|
||||||
|
includeMargin: this.bordered,
|
||||||
|
} as QRCodePropsTypes
|
||||||
|
|
||||||
|
if(this.iconSize != '' && this.icon != ''){
|
||||||
|
const size = unitConvert(this.iconSize)
|
||||||
|
param.imageSettings = {
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
excavate: true
|
||||||
|
} as ImageSettings
|
||||||
|
}
|
||||||
|
return param
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
canvasToTempFilePath(options :UTSJSONObject) : void {
|
||||||
|
const el = (this.$refs['l-qrcode'] as Element);
|
||||||
|
const format = options.getString('format') ?? 'png';
|
||||||
|
const fail = options.get('fail') as TakeSnapshotFailCallback | null;
|
||||||
|
const complete = options.get('complete') as TakeSnapshotCompleteCallback | null;
|
||||||
|
const success = options.get('success') as TakeSnapshotSuccessCallback | null;
|
||||||
|
const newOptions = {
|
||||||
|
format,
|
||||||
|
fail,
|
||||||
|
complete,
|
||||||
|
success,
|
||||||
|
} as TakeSnapshotOptions
|
||||||
|
el.takeSnapshot(newOptions)
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
const el = (this.$refs['l-qrcode'] as Element)
|
||||||
|
const ctx = el.getDrawableContext();
|
||||||
|
if (ctx == null) return
|
||||||
|
this.qrcode = new QRCodeCanvas(ctx)
|
||||||
|
const render = (v : QRCodePropsTypes) => {
|
||||||
|
this.qrcode!.render(v);
|
||||||
|
if (this.useCanvasToTempFilePath) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.canvasToTempFilePath({
|
||||||
|
success: (res: TakeSnapshotSuccess) => {
|
||||||
|
this.$emit('success', res.tempFilePath)
|
||||||
|
},
|
||||||
|
fail: (_: TakeSnapshotFail) => {
|
||||||
|
uni.showToast({
|
||||||
|
icon: 'error',
|
||||||
|
title: '截图失败'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// TakeSnapshotOptions
|
||||||
|
},200)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$watch('qrCodeProps', (v: QRCodePropsTypes) => {
|
||||||
|
render(v)
|
||||||
|
}, {immediate: true})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.l-qrcode {
|
||||||
|
position: relative;
|
||||||
|
background-color: aqua;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&-mask {
|
||||||
|
position: absolute;
|
||||||
|
// inset: 0;
|
||||||
|
// inset-block-start: 0;
|
||||||
|
// inset-inline-start: 0;
|
||||||
|
z-index: 10;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
// width: 100%;
|
||||||
|
// height: 100%;
|
||||||
|
color: rgba(0, 0, 0, 0.88);
|
||||||
|
line-height: 1.5714285714285714;
|
||||||
|
background: rgba(255, 255, 255, 0.96);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
223
src/uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.vue
Normal file
223
src/uni_modules/lime-qrcode/components/l-qrcode/l-qrcode.vue
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
<template>
|
||||||
|
<view class="l-qrcode" :style="[styles]">
|
||||||
|
<!-- #ifndef APP-NVUE -->
|
||||||
|
<canvas :style="styles" type="2d" :canvas-id="canvasId" :id="canvasId"></canvas>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef APP-NVUE -->
|
||||||
|
<web-view
|
||||||
|
ref="qrcodeRef"
|
||||||
|
@pagefinish="onFinished"
|
||||||
|
@error="onError"
|
||||||
|
@onPostMessage="onMessage"
|
||||||
|
:style="styles" src="/uni_modules/lime-qrcode/hybrid/html/index.html?v=1"></web-view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- <view class="l-qrcode-mask" v-if="['loading', 'expired'].includes(props.status)">
|
||||||
|
<l-loading v-if="props.status == 'loading'"></l-loading>
|
||||||
|
<view class="l-qrcode-expired" v-if="props.status == 'expired'">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</view> -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
// @ts-nocheck
|
||||||
|
import { computed, defineComponent, getCurrentInstance, watch, onUnmounted, onMounted } from '@/uni_modules/lime-shared/vue';
|
||||||
|
import QRCodeProps from './props'
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
import { getCanvas, isCanvas2d } from './useCanvas'
|
||||||
|
import { QRCodeCanvas } from './qrcode.js';
|
||||||
|
// #endif
|
||||||
|
import { addUnit } from '@/uni_modules/lime-shared/addUnit'
|
||||||
|
import { createImage } from '@/uni_modules/lime-shared/createImage'
|
||||||
|
import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
|
||||||
|
import { isBase64 } from '@/uni_modules/lime-shared/isBase64'
|
||||||
|
import { pathToBase64 } from '@/uni_modules/lime-shared/pathToBase64'
|
||||||
|
import { debounce } from '@/uni_modules/lime-shared/debounce'
|
||||||
|
const name = 'l-qrcode'
|
||||||
|
export default defineComponent({
|
||||||
|
name,
|
||||||
|
props: QRCodeProps,
|
||||||
|
emits: ['success'],
|
||||||
|
setup(props, {emit}) {
|
||||||
|
const context = getCurrentInstance();
|
||||||
|
const canvasId = `l-qrcode${context.uid}`
|
||||||
|
const styles = computed(() => `width: ${addUnit(props.size)}; height: ${addUnit(props.size)};`)
|
||||||
|
let qrcode = null
|
||||||
|
let canvas = null
|
||||||
|
const qrCodeProps = computed(() => {
|
||||||
|
const { value, icon, size, color, bgColor, bordered, iconSize, errorLevel, marginSize } = props
|
||||||
|
const imageSettings = {
|
||||||
|
src: icon,
|
||||||
|
x: undefined,
|
||||||
|
y: undefined,
|
||||||
|
height: unitConvert(iconSize),
|
||||||
|
width: unitConvert(iconSize),
|
||||||
|
excavate: true,
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
value,
|
||||||
|
size: unitConvert(size),
|
||||||
|
level: errorLevel,
|
||||||
|
bgColor,
|
||||||
|
fgColor: color,
|
||||||
|
imageSettings: icon ? imageSettings : undefined,
|
||||||
|
includeMargin: bordered,
|
||||||
|
marginSize: marginSize ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
const stacks = new Map()
|
||||||
|
// #endif
|
||||||
|
const canvasToTempFilePath = debounce((args: UniNamespace.CanvasToTempFilePathRes) => {
|
||||||
|
if(!canvas) return
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
const copyArgs = Object.assign({
|
||||||
|
canvasId,
|
||||||
|
canvas: null
|
||||||
|
}, args)
|
||||||
|
|
||||||
|
if (isCanvas2d) {
|
||||||
|
copyArgs.canvas = canvas
|
||||||
|
}
|
||||||
|
if ('toTempFilePath' in canvas) {
|
||||||
|
canvas.toTempFilePath(copyArgs)
|
||||||
|
} else {
|
||||||
|
uni.canvasToTempFilePath(copyArgs, context);
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
if(!stacks.size) {
|
||||||
|
const flie = 'file-' + Math.random();
|
||||||
|
const stack = {args, time: +new Date()}
|
||||||
|
stacks.set(`${flie}`, stack)
|
||||||
|
canvas.toDataURL(flie)
|
||||||
|
setTimeout(() => {
|
||||||
|
const stack = stacks.get(flie)
|
||||||
|
if(stack && 'fail' in stack.args) {
|
||||||
|
stack.args.fail({
|
||||||
|
error: '超时'
|
||||||
|
})
|
||||||
|
stacks.delete(flie)
|
||||||
|
}
|
||||||
|
},5000)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
const useCanvasToTempFilePath = () => {
|
||||||
|
if(props.useCanvasToTempFilePath) {
|
||||||
|
canvasToTempFilePath({
|
||||||
|
success(res: UniNamespace.CanvasToTempFilePathRes) {
|
||||||
|
emit('success', res.tempFilePath)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
const onFinished = () => {
|
||||||
|
const { pixelRatio } = uni.getSystemInfoSync()
|
||||||
|
canvas = {
|
||||||
|
toDataURL(flie: string) {
|
||||||
|
const ref: any = context.refs['qrcodeRef'];
|
||||||
|
if(ref) {
|
||||||
|
ref?.evalJS(`toDataURL('${flie}')`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
qrcode = {
|
||||||
|
async render(props: any) {
|
||||||
|
const ref: any = context.refs['qrcodeRef'];
|
||||||
|
const { src } = props.imageSettings || { };
|
||||||
|
if(!ref) return
|
||||||
|
if(src && !isBase64(src) && !/^http/.test(src) && /^\/static/.test(src)) {
|
||||||
|
props.imageSettings.src = await pathToBase64(src)
|
||||||
|
}
|
||||||
|
const _props = JSON.stringify(Object.assign({}, props, {pixelRatio}));
|
||||||
|
ref?.evalJS(`render(${_props})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qrcode.render(qrCodeProps.value)
|
||||||
|
useCanvasToTempFilePath()
|
||||||
|
}
|
||||||
|
const onError = () => {
|
||||||
|
console.warn('lime-qrcode 加载失败')
|
||||||
|
}
|
||||||
|
const onMessage = (e: any) => {
|
||||||
|
const {detail:{data: [res]}} = e
|
||||||
|
if(res.event == 'toDataURL') {
|
||||||
|
const {file, image, msg} = res.data;
|
||||||
|
const stack = stacks.get(file)
|
||||||
|
if(stack && image && 'success' in stack.args) {
|
||||||
|
stack.args.success({tempFilePath: image})
|
||||||
|
stacks.delete(file)
|
||||||
|
} else if(stack && 'fails' in stack.args) {
|
||||||
|
stack.args.fail({error: msg})
|
||||||
|
stacks.delete(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
const propsWatch = watch(props, () => {
|
||||||
|
if (qrcode) {
|
||||||
|
qrcode.render(qrCodeProps.value)
|
||||||
|
useCanvasToTempFilePath()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onMounted(() => {
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
getCanvas(canvasId, { context }).then(res => {
|
||||||
|
canvas = res
|
||||||
|
qrcode = new QRCodeCanvas(res, {
|
||||||
|
// #ifdef H5
|
||||||
|
path2D: false,
|
||||||
|
// #endif
|
||||||
|
pixelRatio: isCanvas2d ? uni.getSystemInfoSync().pixelRatio : 1,
|
||||||
|
createImage
|
||||||
|
})
|
||||||
|
qrcode.render(qrCodeProps.value)
|
||||||
|
useCanvasToTempFilePath()
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
onUnmounted(() => {
|
||||||
|
propsWatch && propsWatch()
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
canvasId,
|
||||||
|
styles,
|
||||||
|
props,
|
||||||
|
canvasToTempFilePath,
|
||||||
|
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
onFinished,
|
||||||
|
onError,
|
||||||
|
onMessage
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.l-qrcode {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&-mask {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
// inset-block-start: 0;
|
||||||
|
// inset-inline-start: 0;
|
||||||
|
z-index: 10;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
// width: 100%;
|
||||||
|
// height: 100%;
|
||||||
|
color: rgba(0, 0, 0, 0.88);
|
||||||
|
line-height: 1.5714285714285714;
|
||||||
|
background: rgba(255, 255, 255, 0.96);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
36
src/uni_modules/lime-qrcode/components/l-qrcode/props.ts
Normal file
36
src/uni_modules/lime-qrcode/components/l-qrcode/props.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
// import type { PropType } from './vue'
|
||||||
|
export default {
|
||||||
|
value: String,
|
||||||
|
icon: String,
|
||||||
|
size: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 160
|
||||||
|
},
|
||||||
|
iconSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 40
|
||||||
|
},
|
||||||
|
marginSize: Number,
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#000'
|
||||||
|
},
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'transparent'
|
||||||
|
},
|
||||||
|
bordered: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
errorLevel: {
|
||||||
|
type: String as PropType<'L'|'M'|'Q'|'H'>,
|
||||||
|
default: 'M' // 'L' | 'M' | 'Q' | 'H'
|
||||||
|
},
|
||||||
|
useCanvasToTempFilePath: Boolean
|
||||||
|
// status: {
|
||||||
|
// type: String as PropType<'active'|'expired'|'loading'>,
|
||||||
|
// default: 'active' // active | expired | loading
|
||||||
|
// }
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
25
src/uni_modules/lime-qrcode/components/l-qrcode/type.ts
Normal file
25
src/uni_modules/lime-qrcode/components/l-qrcode/type.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
export type ImageSettings = {
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
x?: number
|
||||||
|
y?: number
|
||||||
|
excavate: boolean
|
||||||
|
}
|
||||||
|
export type QRCodePropsTypes = {
|
||||||
|
value?: string
|
||||||
|
size?: number
|
||||||
|
fgColor?: string
|
||||||
|
level?: string
|
||||||
|
marginSize: number
|
||||||
|
includeMargin: boolean
|
||||||
|
imageSettings?: ImageSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
export type QRCodeCallback = (cells : boolean[][]) => void
|
||||||
|
|
||||||
|
export type Excavation = {
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
h: number
|
||||||
|
w: number
|
||||||
|
}
|
||||||
78
src/uni_modules/lime-qrcode/components/l-qrcode/useCanvas.ts
Normal file
78
src/uni_modules/lime-qrcode/components/l-qrcode/useCanvas.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
// @ts-nocheck
|
||||||
|
import type { ComponentInternalInstance } from './vue'
|
||||||
|
import { getRect } from '@/uni_modules/lime-shared/getRect'
|
||||||
|
import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
|
||||||
|
export const isCanvas2d = canIUseCanvas2d()
|
||||||
|
|
||||||
|
export async function getCanvas(canvasId: string, options: {context: ComponentInternalInstance}) {
|
||||||
|
let { context } = options
|
||||||
|
// #ifdef MP || VUE2
|
||||||
|
if (context.proxy) context = context.proxy
|
||||||
|
// #endif
|
||||||
|
return getRect('#' + canvasId, {context, type: isCanvas2d ? 'fields': 'boundingClientRect'}).then(res => {
|
||||||
|
if(res.node){
|
||||||
|
return res.node
|
||||||
|
} else {
|
||||||
|
const ctx = uni.createCanvasContext(canvasId, context)
|
||||||
|
return {
|
||||||
|
getContext(type: string) {
|
||||||
|
if(type == '2d') {
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
},
|
||||||
|
width: res.width,
|
||||||
|
height: res.height,
|
||||||
|
}
|
||||||
|
// #ifdef H5
|
||||||
|
// canvas.value = context.proxy.$el.querySelector('#'+ canvasId)
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// #ifndef H5 || APP-NVUE
|
||||||
|
class Image {
|
||||||
|
currentSrc: string | null = null
|
||||||
|
naturalHeight: number = 0
|
||||||
|
naturalWidth: number = 0
|
||||||
|
width: number = 0
|
||||||
|
height: number = 0
|
||||||
|
tagName: string = 'IMG'
|
||||||
|
path: any = ''
|
||||||
|
crossOrigin: any = ''
|
||||||
|
referrerPolicy: any = ''
|
||||||
|
onload: () => void
|
||||||
|
onerror: () => void
|
||||||
|
constructor() {}
|
||||||
|
set src(src) {
|
||||||
|
this.currentSrc = src
|
||||||
|
uni.getImageInfo({
|
||||||
|
src,
|
||||||
|
success: (res) => {
|
||||||
|
this.path = res.path
|
||||||
|
this.naturalWidth = this.width = res.width
|
||||||
|
this.naturalHeight = this.height = res.height
|
||||||
|
this.onload()
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
this.onerror()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
get src() {
|
||||||
|
return this.currentSrc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
export function createImage(canvas: WechatMiniprogram.Canvas) {
|
||||||
|
if(canvas && canvas.createImage) {
|
||||||
|
return canvas.createImage()
|
||||||
|
} else if(typeof window != 'undefined' && window.Image) {
|
||||||
|
return new window.Image()
|
||||||
|
}
|
||||||
|
// #ifndef H5 || APP-NVUE
|
||||||
|
return new Image()
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
35
src/uni_modules/lime-qrcode/components/l-qrcode/utils.uts
Normal file
35
src/uni_modules/lime-qrcode/components/l-qrcode/utils.uts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
export function addUnit(value: any|null):string{
|
||||||
|
if(value == null){
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
value = `${value}`
|
||||||
|
return /^(-)?\d+(\\.\d+)?$/.test(value) ? `${value}px` : value
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unitConvert(value: any|null): number{
|
||||||
|
if(typeof value == 'number'){
|
||||||
|
return value as number
|
||||||
|
}
|
||||||
|
if(typeof value == 'string'){
|
||||||
|
value = `${value}`
|
||||||
|
if(/^(-)?\d+(\\.\d+)?$/.test(value)){
|
||||||
|
return parseFloat(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g;
|
||||||
|
const results = reg.exec(value);
|
||||||
|
if (results == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const unit = results[3];
|
||||||
|
const v = parseFloat(value);
|
||||||
|
if (unit == 'rpx') {
|
||||||
|
const { windowWidth } = uni.getWindowInfo()
|
||||||
|
return windowWidth / 750 * v;
|
||||||
|
}
|
||||||
|
if (unit == 'px') {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
<template>
|
||||||
|
<view class="demo-block">
|
||||||
|
<text class="demo-block__title-text ultra">QRCode</text>
|
||||||
|
<text class="demo-block__desc-text">QRCode</text>
|
||||||
|
<view class="demo-block__body">
|
||||||
|
<view class="demo-block">
|
||||||
|
<text class="demo-block__title-text large">基础</text>
|
||||||
|
<view class="demo-block__body">
|
||||||
|
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx"></l-qrcode>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="demo-block">
|
||||||
|
<text class="demo-block__title-text large">icon</text>
|
||||||
|
<view class="demo-block__body">
|
||||||
|
<image v-if="image !=''" :src="image" style="width: 300rpx;" mode="widthFix"></image>
|
||||||
|
<view style="flex-direction: row; justify-content: space-between">
|
||||||
|
<l-qrcode ref="qrcodeRef" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
|
||||||
|
<l-qrcode :useCanvasToTempFilePath="true" @success="success" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
|
||||||
|
</view>
|
||||||
|
<button @click="onClick">生成图片</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="demo-block">
|
||||||
|
<text class="demo-block__title-text large">颜色</text>
|
||||||
|
<view class="demo-block__body">
|
||||||
|
<view style="flex-direction: row; justify-content: space-between">
|
||||||
|
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(82,196,26)"></l-qrcode>
|
||||||
|
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(22,119,255)" bgColor="rgb(245,245,245)"></l-qrcode>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="demo-block">
|
||||||
|
<text class="demo-block__title-text large">纠错比例</text>
|
||||||
|
<view class="demo-block__body">
|
||||||
|
<l-qrcode value="img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" size="300rpx" :errorLevel="levels[index]"></l-qrcode>
|
||||||
|
<button @click="onToggle">切换纠错等级:{{levels[index]}}</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="demo-block">
|
||||||
|
<text class="demo-block__title-text large">动态</text>
|
||||||
|
<view class="demo-block__body">
|
||||||
|
<l-qrcode :value="text" size="300rpx" :marginSize="1" bgColor="white"></l-qrcode>
|
||||||
|
<button @click="update">更新</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
// import {ComponentPublicInstance} from 'vue'
|
||||||
|
export default {
|
||||||
|
name: 'lime-qrcode',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
text: 'qcoon.com.cn',
|
||||||
|
image: '',
|
||||||
|
index: 0,
|
||||||
|
levels: ['L', 'M', 'Q', 'H']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
success(src: string) {
|
||||||
|
console.log(`src`, src)
|
||||||
|
},
|
||||||
|
update() {
|
||||||
|
this.text = `qcoon.cn?v=${Math.random()}`
|
||||||
|
},
|
||||||
|
onToggle() {
|
||||||
|
this.index++
|
||||||
|
this.index = this.index % this.levels.length
|
||||||
|
},
|
||||||
|
onClick() {
|
||||||
|
const el:LQrcodeComponentPublicInstance = this.$refs['qrcodeRef'] as LQrcodeComponentPublicInstance
|
||||||
|
el.canvasToTempFilePath({
|
||||||
|
success:(res: TakeSnapshotSuccess)=>{
|
||||||
|
this.image = res.tempFilePath
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.demo-block {
|
||||||
|
margin: 32px 20px 0;
|
||||||
|
overflow: visible;
|
||||||
|
&__title {
|
||||||
|
margin: 0;
|
||||||
|
margin-top: 8px;
|
||||||
|
&-text {
|
||||||
|
color: rgba(0, 0, 0, 0.6);
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 16px;
|
||||||
|
|
||||||
|
&.large {
|
||||||
|
color: rgba(0, 0, 0, 0.9);
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 26px;
|
||||||
|
}
|
||||||
|
&.ultra {
|
||||||
|
color: rgba(0, 0, 0, 0.9);
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__desc-text {
|
||||||
|
color: rgba(0, 0, 0, 0.6);
|
||||||
|
margin: 8px 16px 0 0;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
&__body {
|
||||||
|
margin: 16px 0;
|
||||||
|
overflow: visible;
|
||||||
|
.demo-block {
|
||||||
|
// margin-top: 0px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<demo-block title="QRCode" type="ultra">
|
||||||
|
<demo-block title="基础">
|
||||||
|
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx"></l-qrcode>
|
||||||
|
</demo-block>
|
||||||
|
<demo-block title="icon">
|
||||||
|
<view style="display: flex; gap: 10px">
|
||||||
|
<image v-if="image" :src="image" style="width: 300rpx;" mode="widthFix"></image>
|
||||||
|
<l-qrcode ref="qrcodeRef" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
|
||||||
|
<l-qrcode useCanvasToTempFilePath @success="success" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
|
||||||
|
</view>
|
||||||
|
<button @click="onClick">生成图片</button>
|
||||||
|
</demo-block>
|
||||||
|
<demo-block title="颜色">
|
||||||
|
<view style="display: flex; gap: 10px">
|
||||||
|
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(82,196,26)"></l-qrcode>
|
||||||
|
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(22,119,255)" bgColor="rgb(245,245,245)"></l-qrcode>
|
||||||
|
</view>
|
||||||
|
</demo-block>
|
||||||
|
<demo-block title="纠错比例">
|
||||||
|
<l-qrcode value="img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" size="300rpx" :errorLevel="levels[index]"></l-qrcode>
|
||||||
|
<button @click="onToggle">切换纠错等级:{{levels[index]}}</button>
|
||||||
|
</demo-block>
|
||||||
|
<demo-block title="动态">
|
||||||
|
<l-qrcode :value="text" size="300rpx" marginSize="20rpx" bgColor="white"></l-qrcode>
|
||||||
|
<button @click="update">更新</button>
|
||||||
|
</demo-block>
|
||||||
|
</demo-block>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import {ref, defineComponent} from '../l-qrcode/vue'
|
||||||
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
const qrcodeRef = ref(null)
|
||||||
|
const image = ref(null)
|
||||||
|
const text = ref('qcoon.com.cn')
|
||||||
|
const levels = ['L', 'M', 'Q', 'H']
|
||||||
|
let index = ref(0)
|
||||||
|
const onToggle = () => {
|
||||||
|
index.value++
|
||||||
|
index.value = index.value % levels.length
|
||||||
|
}
|
||||||
|
const onClick = () => {
|
||||||
|
if(qrcodeRef.value) {
|
||||||
|
qrcodeRef.value.canvasToTempFilePath({
|
||||||
|
success(res) {
|
||||||
|
image.value = res.tempFilePath
|
||||||
|
console.log('success:::', res)
|
||||||
|
},
|
||||||
|
fail(err) {
|
||||||
|
console.log('err:::', err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const success = (res) => {
|
||||||
|
console.log('res', res)
|
||||||
|
}
|
||||||
|
|
||||||
|
const update = () =>{
|
||||||
|
text.value = `qcoon.cn?v=${Math.random()}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
levels,
|
||||||
|
index,
|
||||||
|
image,
|
||||||
|
text,
|
||||||
|
qrcodeRef,
|
||||||
|
onClick,
|
||||||
|
update,
|
||||||
|
success,
|
||||||
|
onToggle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
77
src/uni_modules/lime-qrcode/hybrid/html/index.html
Normal file
77
src/uni_modules/lime-qrcode/hybrid/html/index.html
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>lime-qrcode</title>
|
||||||
|
<style>
|
||||||
|
html,body,canvas {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
/* background-color: rgba(255,0,0,0.1) */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="lime-qrcode"></canvas>
|
||||||
|
<script type="text/javascript" src="./uni.webview.1.5.3.js"></script>
|
||||||
|
<script type="text/javascript" src="./qrcode.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var canvas = document.querySelector('#lime-qrcode')
|
||||||
|
var pixelRatio = window.devicePixelRatio || 1
|
||||||
|
function appendWatermark(image) {
|
||||||
|
emit('append', mark.toDataURL())
|
||||||
|
}
|
||||||
|
|
||||||
|
var qrcode = new lime.QRCodeCanvas(canvas, {
|
||||||
|
pixelRatio,
|
||||||
|
})
|
||||||
|
function render(props) {
|
||||||
|
if(props.pixelRatio) {
|
||||||
|
pixelRatio = props.pixelRatio
|
||||||
|
}
|
||||||
|
if(qrcode) {
|
||||||
|
qrcode.render(props)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toDataURL(file) {
|
||||||
|
if(qrcode && canvas) {
|
||||||
|
try{
|
||||||
|
const image = canvas.toDataURL()
|
||||||
|
emit('toDataURL', {
|
||||||
|
file,
|
||||||
|
image
|
||||||
|
})
|
||||||
|
}catch(e){
|
||||||
|
emit('toDataURL', {
|
||||||
|
file,
|
||||||
|
msg: e
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function emit(event, data) {
|
||||||
|
postMessage({
|
||||||
|
event,
|
||||||
|
data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
function postMessage(data) {
|
||||||
|
uni.postMessage({
|
||||||
|
data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// render({
|
||||||
|
// content: ['Lime UI'],
|
||||||
|
// // rotate: -22,
|
||||||
|
// // baseSize: 2,
|
||||||
|
// // fontGap: 3
|
||||||
|
// })
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
6
src/uni_modules/lime-qrcode/hybrid/html/qrcode.min.js
vendored
Normal file
6
src/uni_modules/lime-qrcode/hybrid/html/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
89
src/uni_modules/lime-qrcode/package.json
Normal file
89
src/uni_modules/lime-qrcode/package.json
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
{
|
||||||
|
"id": "lime-qrcode",
|
||||||
|
"displayName": "qrcode 二维码生成",
|
||||||
|
"version": "0.1.2",
|
||||||
|
"description": "全端二维码生成插件,draw api绘制。在H5,微信小程序,uvue,nvue上测试过,非uvue为vue3实现vue2需配置@vue/composition-api",
|
||||||
|
"keywords": [
|
||||||
|
"qrcode",
|
||||||
|
"qr",
|
||||||
|
"uvue",
|
||||||
|
"生成图片",
|
||||||
|
"二维码"
|
||||||
|
],
|
||||||
|
"repository": "",
|
||||||
|
"engines": {
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"type": "component-vue",
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": "305716444"
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "无",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": ""
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": [
|
||||||
|
"lime-shared"
|
||||||
|
],
|
||||||
|
"encrypt": [],
|
||||||
|
"platforms": {
|
||||||
|
"cloud": {
|
||||||
|
"tcb": "y",
|
||||||
|
"aliyun": "y"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
},
|
||||||
|
"App": {
|
||||||
|
"app-vue": "y",
|
||||||
|
"app-nvue": "y",
|
||||||
|
"app-android": {
|
||||||
|
"minVersion": "19"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"H5-mobile": {
|
||||||
|
"Safari": "y",
|
||||||
|
"Android Browser": "y",
|
||||||
|
"微信浏览器(Android)": "y",
|
||||||
|
"QQ浏览器(Android)": "y"
|
||||||
|
},
|
||||||
|
"H5-pc": {
|
||||||
|
"Chrome": "y",
|
||||||
|
"IE": "u",
|
||||||
|
"Edge": "u",
|
||||||
|
"Firefox": "u",
|
||||||
|
"Safari": "u"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "y",
|
||||||
|
"阿里": "u",
|
||||||
|
"百度": "u",
|
||||||
|
"字节跳动": "u",
|
||||||
|
"QQ": "u",
|
||||||
|
"钉钉": "u",
|
||||||
|
"快手": "u",
|
||||||
|
"飞书": "u",
|
||||||
|
"京东": "u"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
153
src/uni_modules/lime-qrcode/readme.md
Normal file
153
src/uni_modules/lime-qrcode/readme.md
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
# lime-qrcode 二维码
|
||||||
|
- uniapp vue3 生成二维码插件
|
||||||
|
- 仅在H5、微信小程序、APP-NVUE测试过,如果你在其它端遇到问题或其它端也能跑,请告之
|
||||||
|
- uvue 需要导入[lime-qrcodegen](https://ext.dcloud.net.cn/plugin?id=15838)
|
||||||
|
|
||||||
|
## 使用
|
||||||
|
- 导入插件后直接使用
|
||||||
|
- uvue 需要导入**[lime-qrcodegen](https://ext.dcloud.net.cn/plugin?id=15838)**
|
||||||
|
|
||||||
|
#### 基础使用
|
||||||
|
|
||||||
|
```html
|
||||||
|
<l-qrcode value="http://lime.qcoon.cn" />
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### ICON
|
||||||
|
- 带 Icon 的二维码
|
||||||
|
|
||||||
|
```html
|
||||||
|
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" icon="/static/logo.png" iconSize="70rpx"></l-qrcode>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 颜色
|
||||||
|
- 通过设置 `color` 自定义二维码颜色,通过设置 `bgColor` 自定义背景颜色。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(82,196,26)"></l-qrcode>
|
||||||
|
<l-qrcode value="https://limeui.qcoon.cn" size="300rpx" color="rgb(22,119,255)" bgColor="rgb(245,245,245)"></l-qrcode>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 纠错比例
|
||||||
|
- 通过设置 `errorLevel` 调整不同的容错等级。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<l-qrcode value="img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" size="300rpx" errorLevel="H"></l-qrcode>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 生成图片
|
||||||
|
- 1、通过调用插件的`canvasToTempFilePath`方法生成图片。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<image v-if="image" :src="image" style="width: 300rpx;" mode="widthFix"></image>
|
||||||
|
<l-qrcode ref="qrcodeRef" value="https://limeui.qcoon.cn" size="300rpx" icon="https://img10.360buyimg.com/img/jfs/t1/182127/16/37474/11761/64659c31F0cd84976/21f25b952f03a49a.jpg" iconSize="70rpx"></l-qrcode>
|
||||||
|
<button @click="onClick">生成图片</button>
|
||||||
|
```
|
||||||
|
```js
|
||||||
|
// vue3
|
||||||
|
const qrcodeRef = ref(null)
|
||||||
|
const onClick = () => {
|
||||||
|
if(!qrcodeRef.value) return
|
||||||
|
qrcodeRef.value.canvasToTempFilePath({
|
||||||
|
success(res) {
|
||||||
|
image.value = res.tempFilePath
|
||||||
|
console.log('success:::', res)
|
||||||
|
},
|
||||||
|
fail(err) {
|
||||||
|
console.log('err:::', err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// vue2
|
||||||
|
const el = this.$refs['qrcodeRef']
|
||||||
|
el.canvasToTempFilePath({
|
||||||
|
success:(res)=>{
|
||||||
|
this.image = res.tempFilePath
|
||||||
|
},
|
||||||
|
fail(err) {
|
||||||
|
console.log('err:::', err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// uvue
|
||||||
|
const el:LQrcodeComponentPublicInstance = this.$refs['qrcodeRef'] as LQrcodeComponentPublicInstance
|
||||||
|
el.canvasToTempFilePath({
|
||||||
|
success:(res: TakeSnapshotSuccess)=>{
|
||||||
|
this.image = res.tempFilePath
|
||||||
|
},
|
||||||
|
fail(err: TakeSnapshotFail) {
|
||||||
|
console.log('err:::', err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
- 2、通过设置`useCanvasToTempFilePath`在`success`事件里接收图片地址
|
||||||
|
|
||||||
|
```html
|
||||||
|
<image v-if="image" :src="image" style="width: 300rpx;" mode="widthFix"></image>
|
||||||
|
<l-qrcode useCanvasToTempFilePath @success="success" value="https://limeui.qcoon.cn"></l-qrcode>
|
||||||
|
```
|
||||||
|
```js
|
||||||
|
const image = ref(null)
|
||||||
|
const success = (img) => {
|
||||||
|
image.value = img
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关于vue2的使用方式
|
||||||
|
- 插件使用了`composition-api`, 如果你希望在vue2中使用请按官方的教程[vue-composition-api](https://uniapp.dcloud.net.cn/tutorial/vue-composition-api.html)配置
|
||||||
|
- 关键代码是: 在main.js中 在vue2部分加上这一段即可,官方是把它单独成了一个文件.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// main.js vue2
|
||||||
|
import Vue from 'vue'
|
||||||
|
import VueCompositionAPI from '@vue/composition-api'
|
||||||
|
Vue.use(VueCompositionAPI)
|
||||||
|
```
|
||||||
|
另外插件也用到了TS,vue2可能会遇过官方的TS版本过低的问题,找到HX目录下的`compile-typescript`目录
|
||||||
|
```cmd
|
||||||
|
// \HBuilderX\plugins\compile-typescript
|
||||||
|
yarn add typescript -D
|
||||||
|
- or -
|
||||||
|
npm install typescript -D
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查看示例
|
||||||
|
- 导入后直接使用这个标签查看演示效果
|
||||||
|
|
||||||
|
```html
|
||||||
|
// 代码位于 uni_modules/lime-qrcode/compoents/lime-qrcode
|
||||||
|
<lime-qrcode />
|
||||||
|
```
|
||||||
|
|
||||||
|
### 插件标签
|
||||||
|
- 默认 l-qrcode 为 component
|
||||||
|
- 默认 lime-qrcode 为 demo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
|
| --------------------------| ------------------------------------------------------------ | ---------------- | ------------ |
|
||||||
|
| value | 扫描后的文本 | <em>string</em> | `-` |
|
||||||
|
| icon | 二维码中图片的地址 | <em>string</em> | `-` |
|
||||||
|
| size | 二维码大小 | <em>number,string</em> | `160` |
|
||||||
|
| iconSize | 二维码中图片的大小 | <em>number,string</em> | `40` |
|
||||||
|
| color | 二维码颜色 | <em>string</em> | `-` |
|
||||||
|
| bgColor | 二维码背景颜色 | <em>string</em> | `-` |
|
||||||
|
| errorLevel | 二维码纠错等级 | `'L' | 'M' | 'Q' | 'H' ` | `M` |
|
||||||
|
| marginSize | 边距码大小,默认为0码点 | <em>number</em> | `0` |
|
||||||
|
|
||||||
|
### 常见问题
|
||||||
|
- icon 是网络地址时,H5和Nvue需要解决跨域问题,小程序需要配置download
|
||||||
|
|
||||||
|
## 打赏
|
||||||
|
|
||||||
|
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
|
||||||
|

|
||||||
|

|
||||||
25
src/uni_modules/lime-shared/addUnit/index.ts
Normal file
25
src/uni_modules/lime-shared/addUnit/index.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import {isNumeric} from '../isNumeric'
|
||||||
|
import {isDef} from '../isDef'
|
||||||
|
/**
|
||||||
|
* 给一个值添加单位(像素 px)
|
||||||
|
* @param value 要添加单位的值,可以是字符串或数字
|
||||||
|
* @returns 添加了单位的值,如果值为 undefined 则返回 undefined
|
||||||
|
*/
|
||||||
|
export function addUnit(value?: string | number): string | undefined {
|
||||||
|
if (!isDef(value)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = String(value); // 将值转换为字符串
|
||||||
|
|
||||||
|
// 如果值是数字,则在后面添加单位 "px",否则保持原始值
|
||||||
|
return isNumeric(value) ? `${value}px` : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// console.log(addUnit(100)); // 输出: "100px"
|
||||||
|
// console.log(addUnit("200")); // 输出: "200px"
|
||||||
|
// console.log(addUnit("300px")); // 输出: "300px"(已经包含单位)
|
||||||
|
// console.log(addUnit()); // 输出: undefined(值为 undefined)
|
||||||
|
// console.log(addUnit(null)); // 输出: undefined(值为 null)
|
||||||
63
src/uni_modules/lime-shared/arrayBufferToFile/index.ts
Normal file
63
src/uni_modules/lime-shared/arrayBufferToFile/index.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import {platform} from '../platform'
|
||||||
|
/**
|
||||||
|
* buffer转路径
|
||||||
|
* @param {Object} buffer
|
||||||
|
*/
|
||||||
|
// @ts-nocheck
|
||||||
|
export function arrayBufferToFile(buffer: ArrayBuffer | Blob, name?: string, format?:string):Promise<(File|string)> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// #ifdef MP
|
||||||
|
const fs = uni.getFileSystemManager()
|
||||||
|
//自定义文件名
|
||||||
|
if (!name && !format) {
|
||||||
|
reject(new Error('ERROR_NAME_PARSE'))
|
||||||
|
}
|
||||||
|
const fileName = `${name || new Date().getTime()}.${format.replace(/(.+)?\//,'')}`;
|
||||||
|
let pre = platform()
|
||||||
|
const filePath = `${pre.env.USER_DATA_PATH}/${fileName}`
|
||||||
|
fs.writeFile({
|
||||||
|
filePath,
|
||||||
|
data: buffer,
|
||||||
|
success() {
|
||||||
|
resolve(filePath)
|
||||||
|
},
|
||||||
|
fail(err) {
|
||||||
|
console.error(err)
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
const file = new File([buffer], name, {
|
||||||
|
type: format,
|
||||||
|
});
|
||||||
|
resolve(file)
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
||||||
|
const base64 = uni.arrayBufferToBase64(buffer)
|
||||||
|
bitmap.loadBase64Data(base64, () => {
|
||||||
|
if (!name && !format) {
|
||||||
|
reject(new Error('ERROR_NAME_PARSE'))
|
||||||
|
}
|
||||||
|
const fileNmae = `${name || new Date().getTime()}.${format.replace(/(.+)?\//,'')}`;
|
||||||
|
const filePath = `_doc/uniapp_temp/${fileNmae}`
|
||||||
|
bitmap.save(filePath, {},
|
||||||
|
() => {
|
||||||
|
bitmap.clear()
|
||||||
|
resolve(filePath)
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
bitmap.clear()
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
}, (error) => {
|
||||||
|
bitmap.clear()
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
13
src/uni_modules/lime-shared/base64ToArrayBuffer/index.ts
Normal file
13
src/uni_modules/lime-shared/base64ToArrayBuffer/index.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
// 未完成
|
||||||
|
export function base64ToArrayBuffer(base64 : string) {
|
||||||
|
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
|
||||||
|
if (!format) {
|
||||||
|
new Error('ERROR_BASE64SRC_PARSE')
|
||||||
|
}
|
||||||
|
if(uni.base64ToArrayBuffer) {
|
||||||
|
return uni.base64ToArrayBuffer(bodyData)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
76
src/uni_modules/lime-shared/base64ToPath/index.ts
Normal file
76
src/uni_modules/lime-shared/base64ToPath/index.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import {platform} from '../platform'
|
||||||
|
/**
|
||||||
|
* base64转路径
|
||||||
|
* @param {Object} base64
|
||||||
|
*/
|
||||||
|
export function base64ToPath(base64: string, filename?: string):Promise<string> {
|
||||||
|
const [, format] = /^data:image\/(\w+);base64,/.exec(base64) || [];
|
||||||
|
console.log('format', format)
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// #ifdef MP
|
||||||
|
const fs = uni.getFileSystemManager()
|
||||||
|
//自定义文件名
|
||||||
|
if (!filename && !format) {
|
||||||
|
reject(new Error('ERROR_BASE64SRC_PARSE'))
|
||||||
|
}
|
||||||
|
// const time = new Date().getTime();
|
||||||
|
const name = filename || `${new Date().getTime()}.${format}`;
|
||||||
|
let pre = platform()
|
||||||
|
const filePath = `${pre.env.USER_DATA_PATH}/${name}`
|
||||||
|
fs.writeFile({
|
||||||
|
filePath,
|
||||||
|
data: base64.split(',')[1],
|
||||||
|
encoding: 'base64',
|
||||||
|
success() {
|
||||||
|
resolve(filePath)
|
||||||
|
},
|
||||||
|
fail(err) {
|
||||||
|
console.error(err)
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
// mime类型
|
||||||
|
let mimeString = base64.split(',')[0].split(':')[1].split(';')[0];
|
||||||
|
//base64 解码
|
||||||
|
let byteString = atob(base64.split(',')[1]);
|
||||||
|
//创建缓冲数组
|
||||||
|
let arrayBuffer = new ArrayBuffer(byteString.length);
|
||||||
|
//创建视图
|
||||||
|
let intArray = new Uint8Array(arrayBuffer);
|
||||||
|
for (let i = 0; i < byteString.length; i++) {
|
||||||
|
intArray[i] = byteString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
resolve(URL.createObjectURL(new Blob([intArray], {
|
||||||
|
type: mimeString
|
||||||
|
})))
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
||||||
|
bitmap.loadBase64Data(base64, () => {
|
||||||
|
if (!filename && !format) {
|
||||||
|
reject(new Error('ERROR_BASE64SRC_PARSE'))
|
||||||
|
}
|
||||||
|
// const time = new Date().getTime();
|
||||||
|
const name = filename || `${new Date().getTime()}.${format}`;
|
||||||
|
const filePath = `_doc/uniapp_temp/${name}`
|
||||||
|
bitmap.save(filePath, {},
|
||||||
|
() => {
|
||||||
|
bitmap.clear()
|
||||||
|
resolve(filePath)
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
bitmap.clear()
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
}, (error) => {
|
||||||
|
bitmap.clear()
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
21
src/uni_modules/lime-shared/camelCase/index.ts
Normal file
21
src/uni_modules/lime-shared/camelCase/index.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* 将字符串转换为 camelCase 或 PascalCase 风格的命名约定
|
||||||
|
* @param str 要转换的字符串
|
||||||
|
* @param isPascalCase 指示是否转换为 PascalCase 的布尔值,默认为 false
|
||||||
|
* @returns 转换后的字符串
|
||||||
|
*/
|
||||||
|
export function camelCase(str: string, isPascalCase: boolean = false): string {
|
||||||
|
// 将字符串分割成单词数组
|
||||||
|
let words: string[] = str.split(/[\s_-]+/);
|
||||||
|
|
||||||
|
// 将数组中的每个单词首字母大写(除了第一个单词)
|
||||||
|
let camelCased: string[] = words.map((word, index) => {
|
||||||
|
if (index === 0 && !isPascalCase) {
|
||||||
|
return word.toLowerCase(); // 第一个单词全小写
|
||||||
|
}
|
||||||
|
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 将数组中的单词拼接成一个字符串
|
||||||
|
return camelCased.join('');
|
||||||
|
};
|
||||||
58
src/uni_modules/lime-shared/canIUseCanvas2d/index.ts
Normal file
58
src/uni_modules/lime-shared/canIUseCanvas2d/index.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
interface My {
|
||||||
|
SDKVersion: string
|
||||||
|
}
|
||||||
|
declare var my: My
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
function compareVersion(v1:string, v2:string) {
|
||||||
|
let a1 = v1.split('.');
|
||||||
|
let a2 = v2.split('.');
|
||||||
|
const len = Math.max(a1.length, a2.length);
|
||||||
|
|
||||||
|
while (a1.length < len) {
|
||||||
|
a1.push('0');
|
||||||
|
}
|
||||||
|
while (a2.length < len) {
|
||||||
|
a2.push('0');
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
const num1 = parseInt(a1[i], 10);
|
||||||
|
const num2 = parseInt(a2[i], 10);
|
||||||
|
|
||||||
|
if (num1 > num2) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (num1 < num2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gte(version: string) {
|
||||||
|
let {SDKVersion} = uni.getSystemInfoSync();
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
SDKVersion = my.SDKVersion
|
||||||
|
// #endif
|
||||||
|
return compareVersion(SDKVersion, version) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 环境是否支持canvas 2d */
|
||||||
|
export function canIUseCanvas2d() {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
return gte('2.9.0');
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
return gte('2.7.0');
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
return gte('1.78.0');
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO
|
||||||
|
return false
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
30
src/uni_modules/lime-shared/changelog.md
Normal file
30
src/uni_modules/lime-shared/changelog.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
## 0.1.4(2023-09-05)
|
||||||
|
- feat: 增加 Hooks `useIntersectionObserver`
|
||||||
|
- feat: 增加 `floatAdd`
|
||||||
|
- feat: 因为本人插件兼容 vue2 需要使用 `composition-api`,故增加vue文件代码插件的条件编译
|
||||||
|
## 0.1.3(2023-08-13)
|
||||||
|
- feat: 增加 `camelCase`
|
||||||
|
## 0.1.2(2023-07-17)
|
||||||
|
- feat: 增加 `getClassStr`
|
||||||
|
## 0.1.1(2023-07-06)
|
||||||
|
- feat: 增加 `isNumeric`, 区别于 `isNumber`
|
||||||
|
## 0.1.0(2023-06-30)
|
||||||
|
- fix: `clamp`忘记导出了
|
||||||
|
## 0.0.9(2023-06-27)
|
||||||
|
- feat: 增加`arrayBufferToFile`
|
||||||
|
## 0.0.8(2023-06-19)
|
||||||
|
- feat: 增加`createAnimation`、`clamp`
|
||||||
|
## 0.0.7(2023-06-08)
|
||||||
|
- chore: 更新注释
|
||||||
|
## 0.0.6(2023-06-08)
|
||||||
|
- chore: 增加`createImage`为`lime-watermark`和`lime-qrcode`提供依赖
|
||||||
|
## 0.0.5(2023-06-03)
|
||||||
|
- chore: 更新注释
|
||||||
|
## 0.0.4(2023-05-22)
|
||||||
|
- feat: 增加`range`,`exif`,`selectComponent`
|
||||||
|
## 0.0.3(2023-05-08)
|
||||||
|
- feat: 增加`fillZero`,`debounce`,`throttle`,`random`
|
||||||
|
## 0.0.2(2023-05-05)
|
||||||
|
- chore: 更新文档
|
||||||
|
## 0.0.1(2023-05-05)
|
||||||
|
- 无
|
||||||
16
src/uni_modules/lime-shared/clamp/index.ts
Normal file
16
src/uni_modules/lime-shared/clamp/index.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 将一个值限制在指定的范围内
|
||||||
|
* @param min 最小值
|
||||||
|
* @param max 最大值
|
||||||
|
* @param val 要限制的值
|
||||||
|
* @returns 限制后的值
|
||||||
|
*/
|
||||||
|
export function clamp(min: number, max: number, val: number): number {
|
||||||
|
return Math.max(min, Math.min(max, val));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// console.log(clamp(0, 10, 5)); // 输出: 5(在范围内,不做更改)
|
||||||
|
// console.log(clamp(0, 10, -5)); // 输出: 0(小于最小值,被限制为最小值)
|
||||||
|
// console.log(clamp(0, 10, 15)); // 输出: 10(大于最大值,被限制为最大值)
|
||||||
103
src/uni_modules/lime-shared/cloneDeep/index.ts
Normal file
103
src/uni_modules/lime-shared/cloneDeep/index.ts
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 深度克隆一个对象或数组
|
||||||
|
* @param obj 要克隆的对象或数组
|
||||||
|
* @returns 克隆后的对象或数组
|
||||||
|
*/
|
||||||
|
export function cloneDeep<T>(obj: any): T {
|
||||||
|
// 如果传入的对象为空,返回空
|
||||||
|
if (obj === null) {
|
||||||
|
return null as unknown as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果传入的对象是 Set 类型,则将其转换为数组,并通过新的 Set 构造函数创建一个新的 Set 对象
|
||||||
|
if (obj instanceof Set) {
|
||||||
|
return new Set([...obj]) as unknown as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果传入的对象是 Map 类型,则将其转换为数组,并通过新的 Map 构造函数创建一个新的 Map 对象
|
||||||
|
if (obj instanceof Map) {
|
||||||
|
return new Map([...obj]) as unknown as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果传入的对象是 WeakMap 类型,则直接用传入的 WeakMap 对象进行赋值
|
||||||
|
if (obj instanceof WeakMap) {
|
||||||
|
let weakMap = new WeakMap();
|
||||||
|
weakMap = obj;
|
||||||
|
return weakMap as unknown as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果传入的对象是 WeakSet 类型,则直接用传入的 WeakSet 对象进行赋值
|
||||||
|
if (obj instanceof WeakSet) {
|
||||||
|
let weakSet = new WeakSet();
|
||||||
|
weakSet = obj;
|
||||||
|
return weakSet as unknown as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果传入的对象是 RegExp 类型,则通过新的 RegExp 构造函数创建一个新的 RegExp 对象
|
||||||
|
if (obj instanceof RegExp) {
|
||||||
|
return new RegExp(obj) as unknown as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果传入的对象是 undefined 类型,则返回 undefined
|
||||||
|
if (typeof obj === 'undefined') {
|
||||||
|
return undefined as unknown as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果传入的对象是数组,则递归调用 cloneDeep 函数对数组中的每个元素进行克隆
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
return obj.map(cloneDeep) as unknown as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果传入的对象是 Date 类型,则通过新的 Date 构造函数创建一个新的 Date 对象
|
||||||
|
if (obj instanceof Date) {
|
||||||
|
return new Date(obj.getTime()) as unknown as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果传入的对象是普通对象,则使用递归调用 cloneDeep 函数对对象的每个属性进行克隆
|
||||||
|
if (typeof obj === 'object') {
|
||||||
|
const newObj: any = {};
|
||||||
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
|
newObj[key] = cloneDeep(value);
|
||||||
|
}
|
||||||
|
const symbolKeys = Object.getOwnPropertySymbols(obj);
|
||||||
|
for (const key of symbolKeys) {
|
||||||
|
newObj[key] = cloneDeep(obj[key]);
|
||||||
|
}
|
||||||
|
return newObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果传入的对象是基本数据类型(如字符串、数字等),则直接返回
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 示例使用
|
||||||
|
|
||||||
|
// // 克隆一个对象
|
||||||
|
// const obj = { name: 'John', age: 30 };
|
||||||
|
// const clonedObj = cloneDeep(obj);
|
||||||
|
|
||||||
|
// console.log(clonedObj); // 输出: { name: 'John', age: 30 }
|
||||||
|
// console.log(clonedObj === obj); // 输出: false (副本与原对象是独立的)
|
||||||
|
|
||||||
|
// // 克隆一个数组
|
||||||
|
// const arr = [1, 2, 3];
|
||||||
|
// const clonedArr = cloneDeep(arr);
|
||||||
|
|
||||||
|
// console.log(clonedArr); // 输出: [1, 2, 3]
|
||||||
|
// console.log(clonedArr === arr); // 输出: false (副本与原数组是独立的)
|
||||||
|
|
||||||
|
// // 克隆一个包含嵌套对象的对象
|
||||||
|
// const person = {
|
||||||
|
// name: 'Alice',
|
||||||
|
// age: 25,
|
||||||
|
// address: {
|
||||||
|
// city: 'New York',
|
||||||
|
// country: 'USA',
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
// const clonedPerson = cloneDeep(person);
|
||||||
|
|
||||||
|
// console.log(clonedPerson); // 输出: { name: 'Alice', age: 25, address: { city: 'New York', country: 'USA' } }
|
||||||
|
// console.log(clonedPerson === person); // 输出: false (副本与原对象是独立的)
|
||||||
|
// console.log(clonedPerson.address === person.address); // 输出: false (嵌套对象的副本也是独立的)
|
||||||
22
src/uni_modules/lime-shared/closest/index.ts
Normal file
22
src/uni_modules/lime-shared/closest/index.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在给定数组中找到最接近目标数字的元素。
|
||||||
|
* @param arr 要搜索的数字数组。
|
||||||
|
* @param target 目标数字。
|
||||||
|
* @returns 最接近目标数字的数组元素。
|
||||||
|
*/
|
||||||
|
export function closest(arr: number[], target: number) {
|
||||||
|
return arr.reduce((pre, cur) =>
|
||||||
|
Math.abs(pre - target) < Math.abs(cur - target) ? pre : cur
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
// // 定义一个数字数组
|
||||||
|
// const numbers = [1, 3, 5, 7, 9];
|
||||||
|
|
||||||
|
// // 在数组中找到最接近目标数字 6 的元素
|
||||||
|
// const closestNumber = closest(numbers, 6);
|
||||||
|
|
||||||
|
// console.log(closestNumber); // 输出结果: 5
|
||||||
149
src/uni_modules/lime-shared/createAnimation/index.ts
Normal file
149
src/uni_modules/lime-shared/createAnimation/index.ts
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
// nvue 需要在节点上设置ref或在export里传入
|
||||||
|
// const animation = createAnimation({
|
||||||
|
// ref: this.$refs['xxx'],
|
||||||
|
// duration: 0,
|
||||||
|
// timingFunction: 'linear'
|
||||||
|
// })
|
||||||
|
// animation.opacity(1).translate(x, y).step({duration})
|
||||||
|
// animation.export(ref)
|
||||||
|
|
||||||
|
// 抹平nvue 与 uni.createAnimation的使用差距
|
||||||
|
// 但是nvue动画太慢~~~无语
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
const nvueAnimation = uni.requireNativePlugin('animation')
|
||||||
|
|
||||||
|
type AnimationTypes = 'matrix' | 'matrix3d' | 'rotate' | 'rotate3d' | 'rotateX' | 'rotateY' | 'rotateZ' | 'scale' | 'scale3d' | 'scaleX' | 'scaleY' | 'scaleZ' | 'skew' | 'skewX' | 'skewY' | 'translate' | 'translate3d' | 'translateX' | 'translateY' | 'translateZ'
|
||||||
|
| 'opacity' | 'backgroundColor' | 'width' | 'height' | 'left' | 'right' | 'top' | 'bottom'
|
||||||
|
|
||||||
|
interface Styles {
|
||||||
|
[key : string] : any
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StepConfig {
|
||||||
|
duration?: number
|
||||||
|
timingFunction?: string
|
||||||
|
delay?: number
|
||||||
|
needLayout?: boolean
|
||||||
|
transformOrigin?: string
|
||||||
|
}
|
||||||
|
interface StepAnimate {
|
||||||
|
styles?: Styles
|
||||||
|
config?: StepConfig
|
||||||
|
}
|
||||||
|
interface StepAnimates {
|
||||||
|
[key: number]: StepAnimate
|
||||||
|
}
|
||||||
|
interface CreateAnimationOptions extends UniApp.CreateAnimationOptions {
|
||||||
|
ref?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Callback = (time: number) => void
|
||||||
|
const animateTypes1 : AnimationTypes[] = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d',
|
||||||
|
'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY',
|
||||||
|
'translateZ'
|
||||||
|
]
|
||||||
|
const animateTypes2 : AnimationTypes[] = ['opacity', 'backgroundColor']
|
||||||
|
const animateTypes3 : AnimationTypes[] = ['width', 'height', 'left', 'right', 'top', 'bottom']
|
||||||
|
|
||||||
|
class LimeAnimation {
|
||||||
|
ref : any
|
||||||
|
context : any
|
||||||
|
options : UniApp.CreateAnimationOptions
|
||||||
|
// stack : any[] = []
|
||||||
|
next : number = 0
|
||||||
|
currentStepAnimates : StepAnimates = {}
|
||||||
|
duration : number = 0
|
||||||
|
constructor(options : CreateAnimationOptions) {
|
||||||
|
const {ref} = options
|
||||||
|
this.ref = ref
|
||||||
|
this.options = options
|
||||||
|
}
|
||||||
|
addAnimate(type : AnimationTypes, args: (string | number)[]) {
|
||||||
|
let aniObj = this.currentStepAnimates[this.next]
|
||||||
|
let stepAnimate:StepAnimate = {}
|
||||||
|
if (!aniObj) {
|
||||||
|
stepAnimate = {styles: {}, config: {}}
|
||||||
|
} else {
|
||||||
|
stepAnimate = aniObj
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animateTypes1.includes(type)) {
|
||||||
|
if (!stepAnimate.styles.transform) {
|
||||||
|
stepAnimate.styles.transform = ''
|
||||||
|
}
|
||||||
|
let unit = ''
|
||||||
|
if (type === 'rotate') {
|
||||||
|
unit = 'deg'
|
||||||
|
}
|
||||||
|
stepAnimate.styles.transform += `${type}(${args.map((v: number) => v + unit).join(',')}) `
|
||||||
|
} else {
|
||||||
|
stepAnimate.styles[type] = `${args.join(',')}`
|
||||||
|
}
|
||||||
|
this.currentStepAnimates[this.next] = stepAnimate
|
||||||
|
}
|
||||||
|
animateRun(styles: Styles = {}, config:StepConfig = {}, ref: any) {
|
||||||
|
const el = ref || this.ref
|
||||||
|
if (!el) return
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const time = +new Date()
|
||||||
|
nvueAnimation.transition(el, {
|
||||||
|
styles,
|
||||||
|
...config
|
||||||
|
}, () => {
|
||||||
|
resolve(+new Date() - time)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
nextAnimate(animates: StepAnimates, step: number = 0, ref: any, cb: Callback) {
|
||||||
|
let obj = animates[step]
|
||||||
|
if (obj) {
|
||||||
|
let { styles, config } = obj
|
||||||
|
// this.duration += config.duration
|
||||||
|
this.animateRun(styles, config, ref).then((time: number) => {
|
||||||
|
step += 1
|
||||||
|
this.duration += time
|
||||||
|
this.nextAnimate(animates, step, ref, cb)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.currentStepAnimates = {}
|
||||||
|
cb && cb(this.duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
step(config:StepConfig = {}) {
|
||||||
|
this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config)
|
||||||
|
this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin
|
||||||
|
this.next++
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
export(ref: any, cb?: Callback) {
|
||||||
|
ref = ref || this.ref
|
||||||
|
if(!ref) return
|
||||||
|
this.duration = 0
|
||||||
|
this.next = 0
|
||||||
|
this.nextAnimate(this.currentStepAnimates, 0, ref, cb)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => {
|
||||||
|
LimeAnimation.prototype[type] = function(...args: (string | number)[]) {
|
||||||
|
this.addAnimate(type, args)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
export function createAnimation(options : CreateAnimationOptions) {
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
// 在iOS10+QQ小程序平台下,传给原生的对象一定是个普通对象而不是Proxy对象,否则会报parameter should be Object instead of ProxyObject的错误
|
||||||
|
return uni.createAnimation({ ...options })
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
return new LimeAnimation(options)
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
61
src/uni_modules/lime-shared/createImage/index.ts
Normal file
61
src/uni_modules/lime-shared/createImage/index.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import {isBrowser} from '../isBrowser'
|
||||||
|
class Image {
|
||||||
|
currentSrc: string | null = null
|
||||||
|
naturalHeight: number = 0
|
||||||
|
naturalWidth: number = 0
|
||||||
|
width: number = 0
|
||||||
|
height: number = 0
|
||||||
|
tagName: string = 'IMG'
|
||||||
|
path: string = ''
|
||||||
|
crossOrigin: string = ''
|
||||||
|
referrerPolicy: string = ''
|
||||||
|
onload: () => void = () => {}
|
||||||
|
onerror: () => void = () => {}
|
||||||
|
complete: boolean = false
|
||||||
|
constructor() {}
|
||||||
|
set src(src: string) {
|
||||||
|
console.log('src', src)
|
||||||
|
if(!src) {
|
||||||
|
return this.onerror()
|
||||||
|
}
|
||||||
|
src = src.replace(/^@\//,'/')
|
||||||
|
this.currentSrc = src
|
||||||
|
uni.getImageInfo({
|
||||||
|
src,
|
||||||
|
success: (res) => {
|
||||||
|
const localReg = /^\.|^\/(?=[^\/])/;
|
||||||
|
// #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO
|
||||||
|
res.path = localReg.test(src) ? `/${res.path}` : res.path;
|
||||||
|
// #endif
|
||||||
|
this.complete = true
|
||||||
|
this.path = res.path
|
||||||
|
this.naturalWidth = this.width = res.width
|
||||||
|
this.naturalHeight = this.height = res.height
|
||||||
|
this.onload()
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
this.onerror()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
get src() {
|
||||||
|
return this.currentSrc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interface UniImage extends WechatMiniprogram.Image {
|
||||||
|
complete?: boolean
|
||||||
|
naturalHeight?: number
|
||||||
|
naturalWidth?: number
|
||||||
|
}
|
||||||
|
/** 创建用于 canvas 的 img */
|
||||||
|
export function createImage(canvas?: any): HTMLImageElement | UniImage {
|
||||||
|
if(canvas && canvas.createImage) {
|
||||||
|
return (canvas as WechatMiniprogram.Canvas).createImage()
|
||||||
|
} else if(this.tagName == 'canvas' && !('toBlob' in this) || canvas && !('toBlob' in canvas)){
|
||||||
|
return new Image()
|
||||||
|
} else if(isBrowser) {
|
||||||
|
return new window.Image()
|
||||||
|
}
|
||||||
|
return new Image()
|
||||||
|
}
|
||||||
38
src/uni_modules/lime-shared/debounce/index.ts
Normal file
38
src/uni_modules/lime-shared/debounce/index.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
type Timeout = ReturnType<typeof setTimeout> | null;
|
||||||
|
/**
|
||||||
|
* 防抖函数,通过延迟一定时间来限制函数的执行频率。
|
||||||
|
* @param fn 要防抖的函数。
|
||||||
|
* @param wait 触发防抖的等待时间,单位为毫秒。
|
||||||
|
* @returns 防抖函数。
|
||||||
|
*/
|
||||||
|
export function debounce(fn: (...args: any[]) => void, wait = 300) {
|
||||||
|
let timer: Timeout = null; // 用于存储 setTimeout 的标识符的变量
|
||||||
|
|
||||||
|
return function (this: any, ...args: any[]) {
|
||||||
|
if (timer) clearTimeout(timer); // 如果上一个 setTimeout 存在,则清除它
|
||||||
|
|
||||||
|
// 设置一个新的 setTimeout,在指定的等待时间后调用防抖函数
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
fn.apply(this, args); // 使用提供的参数调用原始函数
|
||||||
|
}, wait);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
// 定义一个函数
|
||||||
|
// function saveData(data: string) {
|
||||||
|
// // 模拟保存数据的操作
|
||||||
|
// console.log(`Saving data: ${data}`);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 创建一个防抖函数,延迟 500 毫秒后调用 saveData 函数
|
||||||
|
// const debouncedSaveData = debounce(saveData, 500);
|
||||||
|
|
||||||
|
// // 连续调用防抖函数
|
||||||
|
// debouncedSaveData('Data 1'); // 不会立即调用 saveData 函数
|
||||||
|
// debouncedSaveData('Data 2'); // 不会立即调用 saveData 函数
|
||||||
|
|
||||||
|
// 在 500 毫秒后,只会调用一次 saveData 函数,输出结果为 "Saving data: Data 2"
|
||||||
1056
src/uni_modules/lime-shared/exif/index.ts
Normal file
1056
src/uni_modules/lime-shared/exif/index.ts
Normal file
File diff suppressed because it is too large
Load Diff
11
src/uni_modules/lime-shared/fillZero/index.ts
Normal file
11
src/uni_modules/lime-shared/fillZero/index.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 在数字前填充零,返回字符串形式的结果
|
||||||
|
* @param number 要填充零的数字
|
||||||
|
* @param length 填充零后的字符串长度,默认为2
|
||||||
|
* @returns 填充零后的字符串
|
||||||
|
*/
|
||||||
|
export function fillZero(number: number, length: number = 2): string {
|
||||||
|
// 将数字转换为字符串,然后使用 padStart 方法填充零到指定长度
|
||||||
|
return `${number}`.padStart(length, '0');
|
||||||
|
}
|
||||||
36
src/uni_modules/lime-shared/floatAdd/index.ts
Normal file
36
src/uni_modules/lime-shared/floatAdd/index.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import {isNumber} from '../isNumber'
|
||||||
|
/**
|
||||||
|
* 返回两个浮点数相加的结果
|
||||||
|
* @param num1 第一个浮点数
|
||||||
|
* @param num2 第二个浮点数
|
||||||
|
* @returns 两个浮点数的相加结果
|
||||||
|
*/
|
||||||
|
export function floatAdd(num1: number, num2: number): number {
|
||||||
|
// 检查 num1 和 num2 是否为数字类型
|
||||||
|
if (!(isNumber(num1) || isNumber(num2))) {
|
||||||
|
console.warn('Please pass in the number type');
|
||||||
|
return NaN;
|
||||||
|
}
|
||||||
|
|
||||||
|
let r1: number, r2: number, m: number;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 获取 num1 小数点后的位数
|
||||||
|
r1 = num1.toString().split('.')[1].length;
|
||||||
|
} catch (error) {
|
||||||
|
r1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 获取 num2 小数点后的位数
|
||||||
|
r2 = num2.toString().split('.')[1].length;
|
||||||
|
} catch (error) {
|
||||||
|
r2 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算需要扩大的倍数
|
||||||
|
m = Math.pow(10, Math.max(r1, r2));
|
||||||
|
|
||||||
|
// 返回相加结果
|
||||||
|
return (num1 * m + num2 * m) / m;
|
||||||
|
}
|
||||||
27
src/uni_modules/lime-shared/getClassStr/index.ts
Normal file
27
src/uni_modules/lime-shared/getClassStr/index.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 获取对象的类名字符串
|
||||||
|
* @param obj - 需要处理的对象
|
||||||
|
* @returns 由对象属性作为类名组成的字符串
|
||||||
|
*/
|
||||||
|
export function getClassStr<T>(obj: T): string {
|
||||||
|
let classNames: string[] = [];
|
||||||
|
|
||||||
|
// 遍历对象的属性
|
||||||
|
for (let key in obj) {
|
||||||
|
// 检查属性确实属于对象自身且其值为true
|
||||||
|
if ((obj as any).hasOwnProperty(key) && obj[key]) {
|
||||||
|
// 将属性名添加到类名数组中
|
||||||
|
classNames.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将类名数组用空格连接成字符串并返回
|
||||||
|
return classNames.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
// const obj = { foo: true, bar: false, baz: true };
|
||||||
|
// const classNameStr = getClassStr(obj);
|
||||||
|
// console.log(classNameStr); // 输出: "foo baz"
|
||||||
6
src/uni_modules/lime-shared/getCurrentPage/index.ts
Normal file
6
src/uni_modules/lime-shared/getCurrentPage/index.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/** 获取当前页 */
|
||||||
|
export const getCurrentPage = () => {
|
||||||
|
const pages = getCurrentPages();
|
||||||
|
return pages[pages.length - 1] //as T & WechatMiniprogram.Page.TrivialInstance;
|
||||||
|
};
|
||||||
14
src/uni_modules/lime-shared/getLocalFilePath/index.ts
Normal file
14
src/uni_modules/lime-shared/getLocalFilePath/index.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
export const getLocalFilePath = (path: string) => {
|
||||||
|
if(typeof plus == 'undefined') return path
|
||||||
|
if(/^(_www|_doc|_documents|_downloads|file:\/\/|\/storage\/emulated\/0\/)/.test(path)) return path
|
||||||
|
if (/^\//.test(path)) {
|
||||||
|
const localFilePath = plus.io.convertAbsoluteFileSystem(path)
|
||||||
|
if (localFilePath !== path) {
|
||||||
|
return localFilePath
|
||||||
|
} else {
|
||||||
|
path = path.slice(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '_www/' + path
|
||||||
|
}
|
||||||
86
src/uni_modules/lime-shared/getRect/index.ts
Normal file
86
src/uni_modules/lime-shared/getRect/index.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
// 当编译环境是 APP-NVUE 时,引入 uni.requireNativePlugin('dom'),具体插件用途未知
|
||||||
|
const dom = uni.requireNativePlugin('dom')
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
interface RectOptions {
|
||||||
|
/**
|
||||||
|
* 上下文
|
||||||
|
*/
|
||||||
|
context ?: any // ComponentInternalInstance 类型,用于指定上下文
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否需要获取所有节点,nvue 环境下不支持
|
||||||
|
*/
|
||||||
|
needAll ?: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点引用对象,类型为 UniNamespace.NodesRef
|
||||||
|
*/
|
||||||
|
nodes ?: UniNamespace.NodesRef
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点引用对象的键,类型为 UniNamespace.NodesRef 中的某个键
|
||||||
|
*/
|
||||||
|
type ?: keyof UniNamespace.NodesRef
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取节点信息
|
||||||
|
* @param selector 选择器字符串
|
||||||
|
* @param options RectOptions 对象,用于配置选项
|
||||||
|
* @returns 包含节点信息的 Promise 对象
|
||||||
|
*/
|
||||||
|
export function getRect(selector : string, options : RectOptions = {}) {
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
const typeDefault = 'boundingClientRect'
|
||||||
|
let { context, needAll, type = typeDefault } = options
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP || VUE2
|
||||||
|
if (context.proxy) context = context.proxy
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
return new Promise<UniNamespace.NodeInfo>((resolve, reject) => {
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
const dom = uni.createSelectorQuery().in(context)[needAll ? 'selectAll' : 'select'](selector);
|
||||||
|
const result = (rect: UniNamespace.NodeInfo) => {
|
||||||
|
if (rect) {
|
||||||
|
resolve(rect)
|
||||||
|
} else {
|
||||||
|
reject('no rect')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type == typeDefault) {
|
||||||
|
dom[type](result).exec()
|
||||||
|
} else {
|
||||||
|
dom[type]({
|
||||||
|
node: true,
|
||||||
|
size: true,
|
||||||
|
rect: true
|
||||||
|
}, result).exec()
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
let { context } = options
|
||||||
|
if (/#|\./.test(selector) && context.refs) {
|
||||||
|
selector = selector.replace(/#|\./, '')
|
||||||
|
if (context.refs[selector]) {
|
||||||
|
selector = context.refs[selector]
|
||||||
|
if(Array.isArray(selector)) {
|
||||||
|
selector = selector[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dom.getComponentRect(selector, (res) => {
|
||||||
|
if (res.size) {
|
||||||
|
resolve(res.size)
|
||||||
|
} else {
|
||||||
|
reject('no rect')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
});
|
||||||
|
};
|
||||||
30
src/uni_modules/lime-shared/getStyleStr/index.ts
Normal file
30
src/uni_modules/lime-shared/getStyleStr/index.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
interface CSSProperties {
|
||||||
|
[key: string]: string | number
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 将字符串转换为带有连字符分隔的小写形式
|
||||||
|
* @param key - 要转换的字符串
|
||||||
|
* @returns 转换后的字符串
|
||||||
|
*/
|
||||||
|
export function toLowercaseSeparator(key: string) {
|
||||||
|
return key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取样式对象对应的样式字符串
|
||||||
|
* @param style - CSS样式对象
|
||||||
|
* @returns 由非空有效样式属性键值对组成的字符串
|
||||||
|
*/
|
||||||
|
export function getStyleStr(style: CSSProperties): string {
|
||||||
|
return Object.keys(style)
|
||||||
|
.filter(key => style[key] !== undefined && style[key] !== null && style[key] !== '')
|
||||||
|
.map((key: string) => `${toLowercaseSeparator(key)}: ${style[key]};`)
|
||||||
|
.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
// const style = { color: 'red', fontSize: '16px', backgroundColor: '', border: null };
|
||||||
|
// const styleStr = getStyleStr(style);
|
||||||
|
// console.log(styleStr);
|
||||||
|
// 输出: "color: red; font-size: 16px;"
|
||||||
30
src/uni_modules/lime-shared/hasOwn/index.ts
Normal file
30
src/uni_modules/lime-shared/hasOwn/index.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
const hasOwnProperty = Object.prototype.hasOwnProperty
|
||||||
|
/**
|
||||||
|
* 检查对象或数组是否具有指定的属性或键
|
||||||
|
* @param obj 要检查的对象或数组
|
||||||
|
* @param key 指定的属性或键
|
||||||
|
* @returns 如果对象或数组具有指定的属性或键,则返回true;否则返回false
|
||||||
|
*/
|
||||||
|
export function hasOwn(obj: Object | Array<any>, key: string): boolean {
|
||||||
|
return hasOwnProperty.call(obj, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
// const obj = { name: 'John', age: 30 };
|
||||||
|
|
||||||
|
// if (hasOwn(obj, 'name')) {
|
||||||
|
// console.log("对象具有 'name' 属性");
|
||||||
|
// } else {
|
||||||
|
// console.log("对象不具有 'name' 属性");
|
||||||
|
// }
|
||||||
|
// // 输出: 对象具有 'name' 属性
|
||||||
|
|
||||||
|
// const arr = [1, 2, 3];
|
||||||
|
|
||||||
|
// if (hasOwn(arr, 'length')) {
|
||||||
|
// console.log("数组具有 'length' 属性");
|
||||||
|
// } else {
|
||||||
|
// console.log("数组不具有 'length' 属性");
|
||||||
|
// }
|
||||||
|
// 输出: 数组具有 'length' 属性
|
||||||
43
src/uni_modules/lime-shared/index.ts
Normal file
43
src/uni_modules/lime-shared/index.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
// validator
|
||||||
|
export * from './isString'
|
||||||
|
export * from './isNumber'
|
||||||
|
export * from './isNumeric'
|
||||||
|
export * from './isDef'
|
||||||
|
export * from './isFunction'
|
||||||
|
export * from './isObject'
|
||||||
|
export * from './isPromise'
|
||||||
|
export * from './isBase64'
|
||||||
|
|
||||||
|
export * from './hasOwn'
|
||||||
|
|
||||||
|
// 单位转换
|
||||||
|
export * from './addUnit'
|
||||||
|
export * from './unitConvert'
|
||||||
|
export * from './toNumber'
|
||||||
|
|
||||||
|
export * from './random'
|
||||||
|
export * from './range'
|
||||||
|
export * from './fillZero'
|
||||||
|
|
||||||
|
// image
|
||||||
|
export * from './base64ToPath'
|
||||||
|
export * from './pathToBase64'
|
||||||
|
export * from './exif'
|
||||||
|
|
||||||
|
// canvas
|
||||||
|
export * from './canIUseCanvas2d'
|
||||||
|
|
||||||
|
// page
|
||||||
|
export * from './getCurrentPage'
|
||||||
|
|
||||||
|
// dom
|
||||||
|
export * from './getRect'
|
||||||
|
export * from './selectComponent'
|
||||||
|
export * from './createAnimation'
|
||||||
|
|
||||||
|
// delay
|
||||||
|
export * from './sleep'
|
||||||
|
export * from './debounce'
|
||||||
|
export * from './throttle'
|
||||||
|
|
||||||
9
src/uni_modules/lime-shared/isBase64/index.ts
Normal file
9
src/uni_modules/lime-shared/isBase64/index.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 判断给定的路径是否为Base64编码的图像路径
|
||||||
|
* @param path 图像路径
|
||||||
|
* @returns 如果路径是Base64编码,则返回true;否则返回false
|
||||||
|
*/
|
||||||
|
export const isBase64 = (path: string): boolean => {
|
||||||
|
return /^data:image\/(\w+);base64/.test(path);
|
||||||
|
};
|
||||||
2
src/uni_modules/lime-shared/isBrowser/index.ts
Normal file
2
src/uni_modules/lime-shared/isBrowser/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
export const isBrowser = typeof window !== 'undefined';
|
||||||
9
src/uni_modules/lime-shared/isDef/index.ts
Normal file
9
src/uni_modules/lime-shared/isDef/index.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 检查一个值是否已定义(不为 undefined)且不为 null
|
||||||
|
* @param value 要检查的值
|
||||||
|
* @returns 如果值已定义且不为 null,则返回 true;否则返回 false
|
||||||
|
*/
|
||||||
|
export function isDef(value: unknown): boolean {
|
||||||
|
return value !== undefined && value !== null;
|
||||||
|
}
|
||||||
8
src/uni_modules/lime-shared/isFunction/index.ts
Normal file
8
src/uni_modules/lime-shared/isFunction/index.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 检查一个值是否为函数类型
|
||||||
|
* @param val 要检查的值
|
||||||
|
* @returns 如果值的类型是函数类型,则返回 true;否则返回 false
|
||||||
|
*/
|
||||||
|
export const isFunction = (val: unknown): val is Function =>
|
||||||
|
typeof val === 'function';
|
||||||
9
src/uni_modules/lime-shared/isNumber/index.ts
Normal file
9
src/uni_modules/lime-shared/isNumber/index.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 检查一个值是否为数字类型
|
||||||
|
* @param value 要检查的值,可以是 number 类型或 string 类型的数字
|
||||||
|
* @returns 如果值是数字类型且不是 NaN,则返回 true;否则返回 false
|
||||||
|
*/
|
||||||
|
export function isNumber(value: number | string): boolean {
|
||||||
|
return typeof value === 'number' && !isNaN(value);
|
||||||
|
}
|
||||||
9
src/uni_modules/lime-shared/isNumeric/index.ts
Normal file
9
src/uni_modules/lime-shared/isNumeric/index.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 检查一个值是否为数字类型或表示数字的字符串
|
||||||
|
* @param value 要检查的值,可以是 string 类型或 number 类型
|
||||||
|
* @returns 如果值是数字类型或表示数字的字符串,则返回 true;否则返回 false
|
||||||
|
*/
|
||||||
|
export function isNumeric(value: string | number): boolean {
|
||||||
|
return /^(-)?\d+(\.\d+)?$/.test(value);
|
||||||
|
}
|
||||||
8
src/uni_modules/lime-shared/isObject/index.ts
Normal file
8
src/uni_modules/lime-shared/isObject/index.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 检查一个值是否为对象类型
|
||||||
|
* @param val 要检查的值
|
||||||
|
* @returns 如果值的类型是对象类型,则返回 true;否则返回 false
|
||||||
|
*/
|
||||||
|
export const isObject = (val : unknown) : val is Record<any, any> =>
|
||||||
|
val !== null && typeof val === 'object';
|
||||||
13
src/uni_modules/lime-shared/isPromise/index.ts
Normal file
13
src/uni_modules/lime-shared/isPromise/index.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import {isFunction} from '../isFunction'
|
||||||
|
import {isObject} from '../isObject'
|
||||||
|
/**
|
||||||
|
* 检查一个值是否为 Promise 类型
|
||||||
|
* @param val 要检查的值
|
||||||
|
* @returns 如果值的类型是 Promise 类型,则返回 true;否则返回 false
|
||||||
|
*/
|
||||||
|
export const isPromise = <T = any>(val: unknown): val is Promise<T> => {
|
||||||
|
// 使用 isObject 函数判断值是否为对象类型
|
||||||
|
// 使用 isFunction 函数判断值是否具有 then 方法和 catch 方法
|
||||||
|
return isObject(val) && isFunction(val.then) && isFunction(val.catch);
|
||||||
|
};
|
||||||
7
src/uni_modules/lime-shared/isString/index.ts
Normal file
7
src/uni_modules/lime-shared/isString/index.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 检查一个值是否为字符串类型
|
||||||
|
* @param str 要检查的值
|
||||||
|
* @returns 如果值的类型是字符串类型,则返回 true;否则返回 false
|
||||||
|
*/
|
||||||
|
export const isString = (str: unknown): str is string => typeof str === 'string';
|
||||||
17
src/uni_modules/lime-shared/kebabCase/index.ts
Normal file
17
src/uni_modules/lime-shared/kebabCase/index.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// export function toLowercaseSeparator(key: string) {
|
||||||
|
// return key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串转换为指定连接符的命名约定
|
||||||
|
* @param str 要转换的字符串
|
||||||
|
* @param separator 指定的连接符,默认为 "-"
|
||||||
|
* @returns 转换后的字符串
|
||||||
|
*/
|
||||||
|
export function kebabCase(str: string, separator: string = "-"): string {
|
||||||
|
return str
|
||||||
|
.replace(/[A-Z]/g, match => `${separator}${match.toLowerCase()}`) // 将大写字母替换为连接符加小写字母
|
||||||
|
.replace(/[\s_-]+/g, separator) // 将空格、下划线和短横线替换为指定连接符
|
||||||
|
.replace(new RegExp(`^${separator}|${separator}$`, "g"), "") // 删除开头和结尾的连接符
|
||||||
|
.toLowerCase(); // 将结果转换为全小写
|
||||||
|
}
|
||||||
83
src/uni_modules/lime-shared/package.json
Normal file
83
src/uni_modules/lime-shared/package.json
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"id": "lime-shared",
|
||||||
|
"displayName": "lime-shared",
|
||||||
|
"version": "0.1.4",
|
||||||
|
"description": "本人插件的几个公共函数,获取当前页,图片的base64转临时路径,图片的exif信息等",
|
||||||
|
"keywords": [
|
||||||
|
"lime-shared",
|
||||||
|
"exif",
|
||||||
|
"selectComponent"
|
||||||
|
],
|
||||||
|
"repository": "",
|
||||||
|
"engines": {
|
||||||
|
"HBuilderX": "^3.1.0"
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"type": "sdk-js",
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": ""
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "无",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": ""
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": [],
|
||||||
|
"encrypt": [],
|
||||||
|
"platforms": {
|
||||||
|
"cloud": {
|
||||||
|
"tcb": "y",
|
||||||
|
"aliyun": "y"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
},
|
||||||
|
"App": {
|
||||||
|
"app-vue": "y",
|
||||||
|
"app-nvue": "y"
|
||||||
|
},
|
||||||
|
"H5-mobile": {
|
||||||
|
"Safari": "y",
|
||||||
|
"Android Browser": "y",
|
||||||
|
"微信浏览器(Android)": "y",
|
||||||
|
"QQ浏览器(Android)": "y"
|
||||||
|
},
|
||||||
|
"H5-pc": {
|
||||||
|
"Chrome": "y",
|
||||||
|
"IE": "u",
|
||||||
|
"Edge": "u",
|
||||||
|
"Firefox": "u",
|
||||||
|
"Safari": "u"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "y",
|
||||||
|
"阿里": "y",
|
||||||
|
"百度": "y",
|
||||||
|
"字节跳动": "y",
|
||||||
|
"QQ": "y",
|
||||||
|
"钉钉": "y",
|
||||||
|
"快手": "y",
|
||||||
|
"飞书": "y",
|
||||||
|
"京东": "u"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
121
src/uni_modules/lime-shared/pathToBase64/index.ts
Normal file
121
src/uni_modules/lime-shared/pathToBase64/index.ts
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
import { getLocalFilePath } from '../getLocalFilePath'
|
||||||
|
// #endif
|
||||||
|
function isImage(extension : string) {
|
||||||
|
const imageExtensions = ["jpg", "jpeg", "png", "gif", "bmp", "svg"];
|
||||||
|
return imageExtensions.includes(extension.toLowerCase());
|
||||||
|
}
|
||||||
|
// #ifdef H5
|
||||||
|
function getSVGFromURL(url: string) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', url, true);
|
||||||
|
xhr.responseType = 'text';
|
||||||
|
|
||||||
|
xhr.onload = function () {
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
const svg = xhr.responseText;
|
||||||
|
resolve(svg);
|
||||||
|
} else {
|
||||||
|
reject(new Error(xhr.statusText));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = function () {
|
||||||
|
reject(new Error('Network error'));
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.send();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
/**
|
||||||
|
* 路径转base64
|
||||||
|
* @param {Object} string
|
||||||
|
*/
|
||||||
|
export function pathToBase64(path : string) : Promise<string> {
|
||||||
|
if (/^data:/.test(path)) return path
|
||||||
|
let extension = path.substring(path.lastIndexOf('.') + 1);
|
||||||
|
const isImageFile = isImage(extension)
|
||||||
|
let prefix = ''
|
||||||
|
if (isImageFile) {
|
||||||
|
prefix = 'image/';
|
||||||
|
if(extension == 'svg') {
|
||||||
|
extension += '+xml'
|
||||||
|
}
|
||||||
|
} else if (extension === 'pdf') {
|
||||||
|
prefix = 'application/pdf';
|
||||||
|
} else if (extension === 'txt') {
|
||||||
|
prefix = 'text/plain';
|
||||||
|
} else {
|
||||||
|
// 添加更多文件类型的判断
|
||||||
|
// 如果不是图片、PDF、文本等类型,可以设定默认的前缀或采取其他处理
|
||||||
|
prefix = 'application/octet-stream';
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// #ifdef H5
|
||||||
|
if (isImageFile) {
|
||||||
|
if(extension == 'svg') {
|
||||||
|
getSVGFromURL(path).then(svg => {
|
||||||
|
const base64 = btoa(svg);
|
||||||
|
resolve(`data:image/svg+xml;base64,${base64}`);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let image = new Image();
|
||||||
|
image.setAttribute("crossOrigin", 'Anonymous');
|
||||||
|
image.onload = function () {
|
||||||
|
let canvas = document.createElement('canvas');
|
||||||
|
canvas.width = this.naturalWidth;
|
||||||
|
canvas.height = this.naturalHeight;
|
||||||
|
canvas.getContext('2d').drawImage(image, 0, 0);
|
||||||
|
let result = canvas.toDataURL(`${prefix}${extension}`)
|
||||||
|
resolve(result);
|
||||||
|
canvas.height = canvas.width = 0
|
||||||
|
}
|
||||||
|
image.src = path + '?v=' + Math.random()
|
||||||
|
image.onerror = (error) => {
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
reject('not image');
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef MP
|
||||||
|
if (uni.canIUse('getFileSystemManager')) {
|
||||||
|
uni.getFileSystemManager().readFile({
|
||||||
|
filePath: path,
|
||||||
|
encoding: 'base64',
|
||||||
|
success: (res) => {
|
||||||
|
resolve(`data:${prefix}${extension};base64,${res.data}`)
|
||||||
|
},
|
||||||
|
fail: (error) => {
|
||||||
|
console.error({ error, path })
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), (entry) => {
|
||||||
|
entry.file((file : any) => {
|
||||||
|
const fileReader = new plus.io.FileReader()
|
||||||
|
fileReader.onload = (data) => {
|
||||||
|
resolve(data.target.result)
|
||||||
|
}
|
||||||
|
fileReader.onerror = (error) => {
|
||||||
|
console.error({ error, path })
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
fileReader.readAsDataURL(file)
|
||||||
|
}, reject)
|
||||||
|
}, reject)
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
2320
src/uni_modules/lime-shared/piexif/index.ts
Normal file
2320
src/uni_modules/lime-shared/piexif/index.ts
Normal file
File diff suppressed because it is too large
Load Diff
27
src/uni_modules/lime-shared/platform/index.ts
Normal file
27
src/uni_modules/lime-shared/platform/index.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
declare var tt: Uni
|
||||||
|
declare var swan: Uni
|
||||||
|
declare var my: Uni
|
||||||
|
declare var dd: Uni
|
||||||
|
declare var ks: Uni
|
||||||
|
declare var jd: Uni
|
||||||
|
declare var qa: Uni
|
||||||
|
declare var qq: Uni
|
||||||
|
declare var qh: Uni
|
||||||
|
declare var qq: Uni
|
||||||
|
|
||||||
|
export function platform(): Uni | WechatMiniprogram.Wx {
|
||||||
|
const UNDEFINED = 'undefined'
|
||||||
|
if(typeof wx !== UNDEFINED) return wx // 微信
|
||||||
|
if(typeof tt !== UNDEFINED) return tt // 字节 飞书
|
||||||
|
if(typeof swan !== UNDEFINED) return swan // 百度
|
||||||
|
if(typeof my !== UNDEFINED) return my // 支付宝
|
||||||
|
if(typeof dd !== UNDEFINED) return dd // 钉钉
|
||||||
|
if(typeof ks !== UNDEFINED) return ks // 快手
|
||||||
|
if(typeof jd !== UNDEFINED) return jd // 京东
|
||||||
|
if(typeof qa !== UNDEFINED) return qa // 快应用
|
||||||
|
if(typeof qq !== UNDEFINED) return qq // qq
|
||||||
|
if(typeof qh !== UNDEFINED) return qh // 360
|
||||||
|
if(typeof uni !== UNDEFINED) return uni
|
||||||
|
return null
|
||||||
|
}
|
||||||
30
src/uni_modules/lime-shared/raf/index.ts
Normal file
30
src/uni_modules/lime-shared/raf/index.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import {isBrowser} from '../isBrowser'
|
||||||
|
|
||||||
|
// 是否支持被动事件监听
|
||||||
|
export const supportsPassive = true;
|
||||||
|
|
||||||
|
// 请求动画帧
|
||||||
|
export function raf(fn: FrameRequestCallback): number {
|
||||||
|
// 如果是在浏览器环境下,使用 requestAnimationFrame 方法
|
||||||
|
if (isBrowser) {
|
||||||
|
return requestAnimationFrame(fn); // 请求动画帧
|
||||||
|
} else { // 在非浏览器环境下,使用 setTimeout 模拟
|
||||||
|
return setTimeout(fn, 1000 / 30); // 使用 setTimeout 模拟动画帧,每秒钟执行 30 次
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消动画帧
|
||||||
|
export function cancelRaf(id: number) {
|
||||||
|
// 如果是在浏览器环境下,使用 cancelAnimationFrame 方法
|
||||||
|
if (isBrowser) {
|
||||||
|
cancelAnimationFrame(id); // 取消动画帧
|
||||||
|
} else { // 在非浏览器环境下,使用 clearTimeout 模拟
|
||||||
|
clearTimeout(id); // 使用 clearTimeout 模拟取消动画帧
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 双倍动画帧
|
||||||
|
export function doubleRaf(fn: FrameRequestCallback): void {
|
||||||
|
raf(() => raf(fn)); // 在下一帧回调中再次请求动画帧,实现双倍动画帧效果
|
||||||
|
}
|
||||||
22
src/uni_modules/lime-shared/random/index.ts
Normal file
22
src/uni_modules/lime-shared/random/index.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 生成一个指定范围内的随机数
|
||||||
|
* @param min 随机数的最小值
|
||||||
|
* @param max 随机数的最大值
|
||||||
|
* @param fixed 随机数的小数位数,默认为 0
|
||||||
|
* @returns 生成的随机数
|
||||||
|
*/
|
||||||
|
export function random(min: number, max: number, fixed: number = 0) {
|
||||||
|
// 将 min 和 max 转换为数字类型
|
||||||
|
min = +min || 0;
|
||||||
|
max = +max || 0;
|
||||||
|
// 计算随机数范围内的一个随机数
|
||||||
|
const num = Math.random() * (max - min) + min;
|
||||||
|
// 如果 fixed 参数为 0,则返回四舍五入的整数随机数;否则保留固定小数位数
|
||||||
|
return fixed == 0 ? Math.round(num) : Number(num.toFixed(fixed));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
// console.log(random(0, 10)); // 输出:在 0 和 10 之间的一个整数随机数
|
||||||
|
// console.log(random(0, 1, 2)); // 输出:在 0 和 1 之间的一个保留两位小数的随机数
|
||||||
|
// console.log(random(1, 100, 3)); // 输出:在 1 和 100 之间的一个保留三位小数的随机数
|
||||||
31
src/uni_modules/lime-shared/range/index.ts
Normal file
31
src/uni_modules/lime-shared/range/index.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 生成一个数字范围的数组
|
||||||
|
* @param start 范围的起始值
|
||||||
|
* @param end 范围的结束值
|
||||||
|
* @param step 步长,默认为 1
|
||||||
|
* @param fromRight 是否从右侧开始生成,默认为 false
|
||||||
|
* @returns 生成的数字范围数组
|
||||||
|
*/
|
||||||
|
export function range(start: number, end: number, step: number = 1, fromRight: boolean = false): number[] {
|
||||||
|
let index = -1;
|
||||||
|
// 计算范围的长度
|
||||||
|
let length = Math.max(Math.ceil((end - start) / (step || 1)), 0);
|
||||||
|
// 创建一个长度为 length 的数组
|
||||||
|
const result = new Array(length);
|
||||||
|
|
||||||
|
// 使用循环生成数字范围数组
|
||||||
|
while (length--) {
|
||||||
|
// 根据 fromRight 参数决定从左侧还是右侧开始填充数组
|
||||||
|
result[fromRight ? length : ++index] = start;
|
||||||
|
start += step;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
// console.log(range(0, 5)); // 输出: [0, 1, 2, 3, 4]
|
||||||
|
// console.log(range(1, 10, 2, true)); // 输出: [9, 7, 5, 3, 1]
|
||||||
|
// console.log(range(5, 0, -1)); // 输出: [5, 4, 3, 2, 1]
|
||||||
251
src/uni_modules/lime-shared/readme.md
Normal file
251
src/uni_modules/lime-shared/readme.md
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# lime-shared 工具库
|
||||||
|
- 本人插件的几个公共函数
|
||||||
|
|
||||||
|
## 引入
|
||||||
|
```js
|
||||||
|
// 按需引入
|
||||||
|
// 这种只会引入相关的方法
|
||||||
|
import {getRect} from '@/uni_modules/lime-shared/getRect'
|
||||||
|
|
||||||
|
// 全量引入
|
||||||
|
// 这种引入方式,会全量打包
|
||||||
|
import {getRect} from '@/uni_modules/lime-shared'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Utils
|
||||||
|
|
||||||
|
#### getRect
|
||||||
|
- 返回节点尺寸信息
|
||||||
|
|
||||||
|
```js
|
||||||
|
// 组件内需要传入上下文
|
||||||
|
// 如果是nvue 则需要在节点上加与id或class同名的ref
|
||||||
|
getRect('#id',{context: this}).then(res => {})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### addUnit
|
||||||
|
- 将未带单位的数值添加px,如果有单位则返回原值
|
||||||
|
|
||||||
|
```js
|
||||||
|
addUnit(10)
|
||||||
|
// 10px
|
||||||
|
```
|
||||||
|
|
||||||
|
#### unitConvert
|
||||||
|
- 将带有rpx|px的字符转成number,若本身是number则直接返回
|
||||||
|
|
||||||
|
```js
|
||||||
|
unitConvert('10rpx')
|
||||||
|
// 5 设备不同 返回的值也不同
|
||||||
|
unitConvert('10px')
|
||||||
|
// 10
|
||||||
|
unitConvert(10)
|
||||||
|
// 10
|
||||||
|
```
|
||||||
|
|
||||||
|
#### canIUseCanvas2d
|
||||||
|
- 环境是否支持使用 canvas 2d
|
||||||
|
|
||||||
|
```js
|
||||||
|
canIUseCanvas2d()
|
||||||
|
// 若支持返回 true 否则 false
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### getCurrentPage
|
||||||
|
- 获取当前页
|
||||||
|
|
||||||
|
```js
|
||||||
|
const page = getCurrentPage()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### base64ToPath
|
||||||
|
- 把base64的图片转成临时路径
|
||||||
|
|
||||||
|
```js
|
||||||
|
base64ToPath(`xxxxx`).then(res => {})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### pathToBase64
|
||||||
|
- 把图片的临时路径转成base64
|
||||||
|
|
||||||
|
```js
|
||||||
|
pathToBase64(`xxxxx/xxx.png`).then(res => {})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### sleep
|
||||||
|
- 睡眠,让 async 内部程序等待一定时间后再执行
|
||||||
|
|
||||||
|
```js
|
||||||
|
async next () => {
|
||||||
|
await sleep(300)
|
||||||
|
console.log('limeui');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### isBase64
|
||||||
|
- 判断字符串是否为base64
|
||||||
|
|
||||||
|
```js
|
||||||
|
isBase64('xxxxx')
|
||||||
|
```
|
||||||
|
|
||||||
|
#### throttle
|
||||||
|
- 节流
|
||||||
|
|
||||||
|
```js
|
||||||
|
throttle((nama) => {console.log(nama)}, 200)('limeui');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### debounce
|
||||||
|
- 防抖
|
||||||
|
|
||||||
|
```js
|
||||||
|
debounce((nama) => {console.log(nama)}, 200)('limeui');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### random
|
||||||
|
- 返回指定范围的随机数
|
||||||
|
|
||||||
|
```js
|
||||||
|
random(1, 5);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### range
|
||||||
|
- 生成区间数组
|
||||||
|
|
||||||
|
```js
|
||||||
|
range(0, 5)
|
||||||
|
// [0,1,2,3,4,5]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### clamp
|
||||||
|
- 夹在min和max之间的数值,如小于min,返回min, 如大于max,返回max,否侧原值返回
|
||||||
|
|
||||||
|
```js
|
||||||
|
clamp(0, 10, -1)
|
||||||
|
// 0
|
||||||
|
clamp(0, 10, 11)
|
||||||
|
// 10
|
||||||
|
clamp(0, 10, 9)
|
||||||
|
// 9
|
||||||
|
```
|
||||||
|
|
||||||
|
#### floatAdd
|
||||||
|
- 返回两个浮点数相加的结果
|
||||||
|
|
||||||
|
```js
|
||||||
|
floatAdd(0.1, 0.2) // 0.3
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### fillZero
|
||||||
|
- 补零,如果传入的是`个位数`则在前面补0
|
||||||
|
|
||||||
|
```js
|
||||||
|
fillZero(9);
|
||||||
|
// 09
|
||||||
|
```
|
||||||
|
|
||||||
|
#### exif
|
||||||
|
- 获取图片exif
|
||||||
|
- 支持临时路径、base64
|
||||||
|
|
||||||
|
```js
|
||||||
|
uni.chooseImage({
|
||||||
|
count: 1, //最多可以选择的图片张数
|
||||||
|
sizeType: "original",
|
||||||
|
success: (res) => {
|
||||||
|
exif.getData(res.tempFiles[0], function() {
|
||||||
|
let tagj = exif.getTag(this, "GPSLongitude");
|
||||||
|
let Orientation = exif.getTag(this, 'Orientation');
|
||||||
|
console.log(tagj, Orientation)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### selectComponent
|
||||||
|
- 获取页面或当前实例的指定组件,会在页面或实例向所有的节点查找(包括子组件或子子组件)
|
||||||
|
- 仅vue3,vue2没有测试过
|
||||||
|
|
||||||
|
```js
|
||||||
|
// 当前页面
|
||||||
|
const page = getCurrentPage()
|
||||||
|
selectComponent('.custom', {context: page}).then(res => {
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### createAnimation
|
||||||
|
- 创建动画,与uni.createAnimation使用方法一致,只为了抹平nvue
|
||||||
|
|
||||||
|
```html
|
||||||
|
<view ref="ball" :animation="animationData"></view>
|
||||||
|
```
|
||||||
|
```js
|
||||||
|
const ball = ref(null)
|
||||||
|
const animation = createAnimation({
|
||||||
|
transformOrigin: "50% 50%",
|
||||||
|
duration: 1000,
|
||||||
|
timingFunction: "ease",
|
||||||
|
delay: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
animation.scale(2,2).rotate(45).step()
|
||||||
|
// nvue 无导出数据,这样写只为了平台一致,
|
||||||
|
// nvue 需要把 ref 传入,其它平台不需要
|
||||||
|
const animationData = animation.export(ball.value)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## composition-api
|
||||||
|
- 因本人插件需要兼容vue2/vue3,故增加一个vue文件,代替条件编译
|
||||||
|
- vue2需要在main.js加上这一段
|
||||||
|
```js
|
||||||
|
// vue2
|
||||||
|
import Vue from 'vue'
|
||||||
|
import VueCompositionAPI from '@vue/composition-api'
|
||||||
|
Vue.use(VueCompositionAPI)
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
//使用
|
||||||
|
import {computed, onMounted, watch, reactive} from '@/uni_modules/lime-shared/vue'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Hooks
|
||||||
|
#### useIntersectionObserver
|
||||||
|
- 使用 Intersection Observer 观察元素可见性的钩子函数
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="target">
|
||||||
|
<h1>Hello world</h1>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
// options 接口可传的参数,若在插件里context为必传
|
||||||
|
interface UseIntersectionObserverOptions {
|
||||||
|
root ?: string; // 观察器的根元素选择器字符串
|
||||||
|
rootMargin ?: {
|
||||||
|
top ?: number; // 根元素顶部边距
|
||||||
|
bottom ?: number; // 根元素底部边距
|
||||||
|
left ?: number; // 根元素左侧边距
|
||||||
|
right ?: number; // 根元素右侧边距
|
||||||
|
}; // 根元素的边距
|
||||||
|
thresholds ?: any[]; // 交叉比例数组,用于指定何时触发回调函数
|
||||||
|
context ?: any; // 上下文对象,用于指定观察器的上下文
|
||||||
|
initialRatio ?: number; // 初始的交叉比例
|
||||||
|
observeAll ?: boolean; // 是否同时观察所有交叉对象
|
||||||
|
}
|
||||||
|
const options: UseIntersectionObserverOptions = {
|
||||||
|
rootMargin: {top: 44},
|
||||||
|
context: this
|
||||||
|
}
|
||||||
|
const {stop} = useIntersectionObserver('.target', (result) => {
|
||||||
|
|
||||||
|
}, options)
|
||||||
|
```
|
||||||
152
src/uni_modules/lime-shared/selectComponent/index.ts
Normal file
152
src/uni_modules/lime-shared/selectComponent/index.ts
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
interface SelectOptions {
|
||||||
|
context?: any
|
||||||
|
needAll?: boolean
|
||||||
|
node?: boolean
|
||||||
|
}
|
||||||
|
// #ifdef MP
|
||||||
|
function selectMPComponent(key: string, name: string, context: any, needAll: boolean) {
|
||||||
|
const {proxy, $vm} = context
|
||||||
|
context = $vm || proxy
|
||||||
|
if(!['ref','component'].includes(key)) {
|
||||||
|
const queue = [context]
|
||||||
|
let result = null
|
||||||
|
const selector = (key == 'id' ? '#': '.') + name;
|
||||||
|
while(queue.length > 0) {
|
||||||
|
const child = queue.shift();
|
||||||
|
const flag = child?.selectComponent(selector)
|
||||||
|
if(flag) {
|
||||||
|
if(!needAll) {return result = flag.$vm}
|
||||||
|
return result = child.selectAllComponents(selector).map(item => item.$vm)
|
||||||
|
} else {
|
||||||
|
child.$children && (queue.push(...child.$children));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
const {$templateRefs} = context.$
|
||||||
|
const nameMap = {}
|
||||||
|
for (var i = 0; i < $templateRefs.length; i++) {
|
||||||
|
const item = $templateRefs[i]
|
||||||
|
nameMap[item.i] = item.r
|
||||||
|
}
|
||||||
|
let result = []
|
||||||
|
if(context.$children.length) {
|
||||||
|
const queue = [...context.$children]
|
||||||
|
while(queue.length > 0) {
|
||||||
|
const child = queue.shift();
|
||||||
|
if(key == 'component' && (child.type?.name === name || child.$?.type?.name === name)) {
|
||||||
|
result.push(child)
|
||||||
|
} else if(child.$refs && child.$refs[name]) {
|
||||||
|
result = child.$refs[name]
|
||||||
|
} else if(nameMap[child.id] === name){
|
||||||
|
result.push(child)
|
||||||
|
} else {
|
||||||
|
child.$children && (queue.push(...child.$children));
|
||||||
|
}
|
||||||
|
if(result.length && !needAll) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return needAll ? result : result[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
function selectH5Component(key: string, name: string, context: any, needAll: boolean) {
|
||||||
|
const {_, component } = context
|
||||||
|
const child = {component: _ || component || context, children: null , subTree: null, props: null}
|
||||||
|
let result = []
|
||||||
|
let queue = [child]
|
||||||
|
while(queue.length > 0 ) {
|
||||||
|
const child = queue.shift()
|
||||||
|
const {component, children , props, subTree} = child
|
||||||
|
if(key === 'component' && component?.type?.name == name) {
|
||||||
|
result.push(component)
|
||||||
|
} else if(key === 'ref' && component && (props?.ref == name || component[key][name])) {
|
||||||
|
if(props?.ref == name) {
|
||||||
|
//exposed
|
||||||
|
result.push(component)
|
||||||
|
} else if(component[key][name]) {
|
||||||
|
result.push(component[key][name])
|
||||||
|
}
|
||||||
|
} else if(key !== 'ref' && component?.exposed && new RegExp(`\\b${name}\\b`).test(component.attrs[key])) {
|
||||||
|
// exposed
|
||||||
|
result.push(component)
|
||||||
|
} else if(children && Array.isArray(children)) {
|
||||||
|
queue.push(...children)
|
||||||
|
} else if(!component && subTree) {
|
||||||
|
queue.push(subTree)
|
||||||
|
} else if(component?.subTree) {
|
||||||
|
queue.push(component.subTree)
|
||||||
|
}
|
||||||
|
if(result.length && !needAll) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return needAll ? result : result[0]
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP
|
||||||
|
function selectAPPComponent(key: string, name: string, context: any, needAll: boolean, node: boolean) {
|
||||||
|
let result = []
|
||||||
|
// const {_, component} = context
|
||||||
|
// const child = {component: _ || component || context, children: null, props: null, subTree: null}
|
||||||
|
const queue = [context]
|
||||||
|
while(queue.length > 0) {
|
||||||
|
const child = queue.shift()
|
||||||
|
const {component, children, props, subTree} = child
|
||||||
|
const isComp = component && props && component.exposed && !node
|
||||||
|
if(key == 'component' && child.type && child.type.name === name) {
|
||||||
|
result.push(component)
|
||||||
|
} else if(props?.[key] === name && node) {
|
||||||
|
result.push(child)
|
||||||
|
} else if(key === 'ref' && isComp && (props.ref === name || props.ref_key === name)) {
|
||||||
|
// exposed
|
||||||
|
result.push(component)
|
||||||
|
} else if(key !== 'ref' && isComp && new RegExp(`\\b${name}\\b`).test(props[key])) {
|
||||||
|
// exposed
|
||||||
|
result.push(component)
|
||||||
|
}
|
||||||
|
// else if(component && component.subTree && Array.isArray(component.subTree.children)){
|
||||||
|
// queue.push(...component.subTree.children)
|
||||||
|
// }
|
||||||
|
else if(subTree) {
|
||||||
|
queue.push(subTree)
|
||||||
|
} else if(component && component.subTree){
|
||||||
|
queue.push(component.subTree)
|
||||||
|
}
|
||||||
|
else if(children && Array.isArray(children)) {
|
||||||
|
queue.push(...children)
|
||||||
|
}
|
||||||
|
if(result.length && !needAll) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return needAll ? result : result[0]
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
export function selectComponent(selector: string, options: SelectOptions = {}) {
|
||||||
|
// . class
|
||||||
|
// # id
|
||||||
|
// $ ref
|
||||||
|
// @ component name
|
||||||
|
const reg = /^(\.|#|@|\$)([a-zA-Z_0-9\-]+)$/;
|
||||||
|
if(!reg.test(selector)) return null
|
||||||
|
let { context, needAll, node} = options
|
||||||
|
const [,prefix, name] = selector.match(reg)
|
||||||
|
const symbolMappings = {'.': 'class', '#': 'id', '$':'ref', '@':'component'}
|
||||||
|
|
||||||
|
const key = symbolMappings [prefix] //prefix === '.' ? 'class' : prefix === '#' ? 'id' : 'ref';
|
||||||
|
console.log('key', key)
|
||||||
|
// #ifdef MP
|
||||||
|
return selectMPComponent(key, name, context, needAll)
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
return selectH5Component(key, name, context, needAll)
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP
|
||||||
|
return selectAPPComponent(key, name, context, needAll, node)
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
30
src/uni_modules/lime-shared/sleep/index.ts
Normal file
30
src/uni_modules/lime-shared/sleep/index.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 延迟指定时间后解析的 Promise
|
||||||
|
* @param delay 延迟的时间(以毫秒为单位),默认为 300 毫秒
|
||||||
|
* @returns 一个 Promise,在延迟结束后解析
|
||||||
|
*/
|
||||||
|
export const sleep = (delay: number = 300) =>
|
||||||
|
new Promise(resolve => setTimeout(resolve, delay));
|
||||||
|
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
// async function example() {
|
||||||
|
// console.log("Start");
|
||||||
|
|
||||||
|
// // 延迟 1 秒后执行
|
||||||
|
// await sleep(1000);
|
||||||
|
// console.log("1 second later");
|
||||||
|
|
||||||
|
// // 延迟 500 毫秒后执行
|
||||||
|
// await sleep(500);
|
||||||
|
// console.log("500 milliseconds later");
|
||||||
|
|
||||||
|
// // 延迟 2 秒后执行
|
||||||
|
// await sleep(2000);
|
||||||
|
// console.log("2 seconds later");
|
||||||
|
|
||||||
|
// console.log("End");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// example();
|
||||||
41
src/uni_modules/lime-shared/throttle/index.ts
Normal file
41
src/uni_modules/lime-shared/throttle/index.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 节流函数,用于限制函数的调用频率
|
||||||
|
* @param fn 要进行节流的函数
|
||||||
|
* @param delay 两次调用之间的最小间隔时间
|
||||||
|
* @returns 节流后的函数
|
||||||
|
*/
|
||||||
|
export function throttle(fn: (...args: any[]) => void, delay: number) {
|
||||||
|
let flag = true; // 标记是否可以执行函数
|
||||||
|
|
||||||
|
return (...args: any[]) => {
|
||||||
|
if (flag) {
|
||||||
|
flag = false; // 设置为不可执行状态
|
||||||
|
fn(...args); // 执行传入的函数
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
flag = true; // 经过指定时间后,设置为可执行状态
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// // 示例
|
||||||
|
// // 定义一个被节流的函数
|
||||||
|
// function handleScroll() {
|
||||||
|
// console.log("Scroll event handled!");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 使用节流函数对 handleScroll 进行节流,间隔时间为 500 毫秒
|
||||||
|
// const throttledScroll = throttle(handleScroll, 500);
|
||||||
|
|
||||||
|
// // 模拟多次调用 handleScroll
|
||||||
|
// throttledScroll(); // 输出 "Scroll event handled!"
|
||||||
|
// throttledScroll(); // 不会输出
|
||||||
|
// throttledScroll(); // 不会输出
|
||||||
|
|
||||||
|
// // 经过 500 毫秒后,再次调用 handleScroll
|
||||||
|
// setTimeout(() => {
|
||||||
|
// throttledScroll(); // 输出 "Scroll event handled!"
|
||||||
|
// }, 500);
|
||||||
13
src/uni_modules/lime-shared/toArray/index.ts
Normal file
13
src/uni_modules/lime-shared/toArray/index.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 将一个或多个元素转换为数组
|
||||||
|
* @param item 要转换为数组的元素
|
||||||
|
* @returns 转换后的数组
|
||||||
|
*/
|
||||||
|
export const toArray = <T>(item: T | T[]): T[] => Array.isArray(item) ? item : [item];
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
// console.log(toArray(5)); // 输出: [5]
|
||||||
|
// console.log(toArray("hello")); // 输出: ["hello"]
|
||||||
|
// console.log(toArray([1, 2, 3])); // 输出: [1, 2, 3]
|
||||||
|
// console.log(toArray(["apple", "banana"])); // 输出: ["apple", "banana"]
|
||||||
15
src/uni_modules/lime-shared/toNumber/index.ts
Normal file
15
src/uni_modules/lime-shared/toNumber/index.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
/**
|
||||||
|
* 将字符串转换为数字
|
||||||
|
* @param val 要转换的字符串
|
||||||
|
* @returns 转换后的数字或原始字符串
|
||||||
|
*/
|
||||||
|
export function toNumber(val: string): number | string {
|
||||||
|
const n = parseFloat(val); // 使用 parseFloat 函数将字符串转换为浮点数
|
||||||
|
return isNaN(n) ? val : n; // 使用 isNaN 函数判断是否为非数字,返回转换后的数字或原始字符串
|
||||||
|
}
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
// console.log(toNumber("123")); // 输出: 123
|
||||||
|
// console.log(toNumber("3.14")); // 输出: 3.14
|
||||||
|
// console.log(toNumber("hello")); // 输出: "hello"
|
||||||
39
src/uni_modules/lime-shared/unitConvert/index.ts
Normal file
39
src/uni_modules/lime-shared/unitConvert/index.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import {isString} from '../isString'
|
||||||
|
import {isNumeric} from '../isNumeric'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单位转换函数,将字符串数字或带有单位的字符串转换为数字
|
||||||
|
* @param value 要转换的值,可以是字符串数字或带有单位的字符串
|
||||||
|
* @returns 转换后的数字,如果无法转换则返回0
|
||||||
|
*/
|
||||||
|
export function unitConvert(value: string | number): number {
|
||||||
|
// 如果是字符串数字
|
||||||
|
if (isNumeric(value)) {
|
||||||
|
return Number(value);
|
||||||
|
}
|
||||||
|
// 如果有单位
|
||||||
|
if (isString(value)) {
|
||||||
|
const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g;
|
||||||
|
const results = reg.exec(value);
|
||||||
|
if (!value || !results) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const unit = results[3];
|
||||||
|
value = parseFloat(value);
|
||||||
|
if (unit === 'rpx') {
|
||||||
|
return uni.upx2px(value);
|
||||||
|
}
|
||||||
|
if (unit === 'px') {
|
||||||
|
return value * 1;
|
||||||
|
}
|
||||||
|
// 如果是其他单位,可以继续添加对应的转换逻辑
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
// console.log(unitConvert("123")); // 输出: 123 (字符串数字转换为数字)
|
||||||
|
// console.log(unitConvert("3.14em")); // 输出: 0 (无法识别的单位)
|
||||||
|
// console.log(unitConvert("20rpx")); // 输出: 根据具体情况而定 (根据单位进行转换)
|
||||||
|
// console.log(unitConvert(10)); // 输出: 10 (数字不需要转换)
|
||||||
81
src/uni_modules/lime-shared/useIntersectionObserver/index.ts
Normal file
81
src/uni_modules/lime-shared/useIntersectionObserver/index.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import { watch, unref, Ref } from "../vue"
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
// const dom = weex.requireModule('dom')
|
||||||
|
// const dom = uni.requireNativePlugin('dom')
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
interface UseIntersectionObserverOptions {
|
||||||
|
root ?: string; // 观察器的根元素选择器字符串
|
||||||
|
rootMargin ?: {
|
||||||
|
top ?: number; // 根元素顶部边距
|
||||||
|
bottom ?: number; // 根元素底部边距
|
||||||
|
left ?: number; // 根元素左侧边距
|
||||||
|
right ?: number; // 根元素右侧边距
|
||||||
|
}; // 根元素的边距
|
||||||
|
thresholds ?: any[]; // 交叉比例数组,用于指定何时触发回调函数
|
||||||
|
context ?: any; // 上下文对象,用于指定观察器的上下文
|
||||||
|
initialRatio ?: number; // 初始的交叉比例
|
||||||
|
observeAll ?: boolean; // 是否同时观察所有交叉对象
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 Intersection Observer 观察元素可见性的自定义钩子函数
|
||||||
|
* @param {Ref<string> | string} target - 目标元素,可以是一个字符串或 ref 对象
|
||||||
|
* @param {(result: UniNamespace.ObserveResult) => void} callback - 回调函数,当目标元素的可见性发生变化时调用
|
||||||
|
* @param {UseIntersectionObserverOptions} options - 可选的配置参数
|
||||||
|
* @returns {Object} - 包含 stop 方法的对象,用于停止观察
|
||||||
|
*/
|
||||||
|
export function useIntersectionObserver(
|
||||||
|
target : Ref<string> | string,
|
||||||
|
callback : (result : UniNamespace.ObserveResult) => void,
|
||||||
|
options : UseIntersectionObserverOptions = {}) {
|
||||||
|
const {
|
||||||
|
root, // 观察器的根元素选择器
|
||||||
|
rootMargin = { top: 0, bottom: 0 }, // 根元素的边距,默认为顶部和底部都为0
|
||||||
|
thresholds = [0], // 交叉比例数组,默认为[0]
|
||||||
|
initialRatio = 0, // 初始交叉比例,默认为0
|
||||||
|
observeAll = false, // 是否同时观察所有交叉对象,默认为false
|
||||||
|
context // 上下文对象,用于指定观察器的上下文
|
||||||
|
} = options
|
||||||
|
const noop = () => { }; // 空函数,用于初始化 cleanup
|
||||||
|
let cleanup = noop; // 清理函数,用于停止 Intersection Observer 的观察
|
||||||
|
|
||||||
|
const stopWatch = watch(() => ({ el: unref(target), root: unref(root) }), ({ el, root }) => {
|
||||||
|
if (!el) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
// 创建 Intersection Observer 实例
|
||||||
|
const observer = uni.createIntersectionObserver(context, { thresholds, initialRatio, observeAll })
|
||||||
|
if (root) {
|
||||||
|
// 相对于根元素设置边界
|
||||||
|
observer.relativeTo(root, rootMargin)
|
||||||
|
} else {
|
||||||
|
// 相对于视口设置边界
|
||||||
|
observer.relativeToViewport(rootMargin)
|
||||||
|
}
|
||||||
|
// 观察目标元素的可见性变化
|
||||||
|
observer.observe(el, callback)
|
||||||
|
cleanup = () => {
|
||||||
|
// 停止观察
|
||||||
|
observer.disconnect()
|
||||||
|
// 将 cleanup 函数重置为空函数
|
||||||
|
cleanup = noop
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
// dom.getComponentRect(el, (res) => {
|
||||||
|
// console.log('res', res)
|
||||||
|
// })
|
||||||
|
// #endif
|
||||||
|
}, { immediate: true, flush: 'post' })
|
||||||
|
|
||||||
|
const stop = () => {
|
||||||
|
// 调用 cleanup 函数停止观察
|
||||||
|
cleanup && cleanup()
|
||||||
|
// 停止 watch
|
||||||
|
stopWatch && stopWatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
return { stop }
|
||||||
|
}
|
||||||
8
src/uni_modules/lime-shared/vue/index.ts
Normal file
8
src/uni_modules/lime-shared/vue/index.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
// #ifdef VUE3
|
||||||
|
export * from 'vue';
|
||||||
|
// #endif
|
||||||
|
// #ifndef VUE3
|
||||||
|
export * from '@vue/composition-api';
|
||||||
|
// #endif
|
||||||
Reference in New Issue
Block a user