修改h5
This commit is contained in:
parent
4c1f42de56
commit
ecc98b14a2
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1 @@
|
||||
/uni_modules
|
||||
/unpackage/dist
|
||||
|
||||
|
33
uni_modules/lime-drag/changelog.md
Normal file
33
uni_modules/lime-drag/changelog.md
Normal file
@ -0,0 +1,33 @@
|
||||
## 0.1.3(2023-08-19)
|
||||
- fix: 修复使用remove导致样式错乱
|
||||
## 0.1.2(2023-08-09)
|
||||
- fix: 修复nvue没有获取节点的问题
|
||||
- fix: 修复因延时导致卡在中途
|
||||
- fix: 修复change事件有时失效的问题
|
||||
## 0.1.1(2023-07-03)
|
||||
- chore: 更新文档
|
||||
## 0.1.0(2023-07-03)
|
||||
- fix: 外面的事件冒泡导致点击调动内部移动方法错乱
|
||||
## 0.0.9(2023-05-30)
|
||||
- fix: 修复因手机事件为`onLongpress`导致,在手机上无法长按
|
||||
- fix: 无法因css导致滚动
|
||||
## 0.0.8(2023-04-23)
|
||||
- feat: 更新文档
|
||||
## 0.0.7(2023-04-23)
|
||||
- feat: 由于删除是一个危险的动作,故把方法暴露出来,而不在内部处理。如果之前有使用删除的,需要注意
|
||||
- feat: 原来的`add`变更为`push`,增加`unshift`
|
||||
## 0.0.6(2023-04-12)
|
||||
- fix: 修复`handle`不生效问题
|
||||
- feat: 增加 `to`方法
|
||||
## 0.0.5(2023-04-11)
|
||||
- chore: `grid` 插槽增加 `nindex`、`oindex`
|
||||
## 0.0.4(2023-04-04)
|
||||
- chore: 去掉 script-setup 语法糖
|
||||
- chore: 文档增加 vue2 使用方法
|
||||
## 0.0.3(2023-03-30)
|
||||
- feat: 重要说明 更新 list 只会再次初始化
|
||||
- feat: 更新文档
|
||||
## 0.0.2(2023-03-29)
|
||||
- 修改文档
|
||||
## 0.0.1(2023-03-29)
|
||||
- 初次提交
|
93
uni_modules/lime-drag/components/l-drag/index.scss
Normal file
93
uni_modules/lime-drag/components/l-drag/index.scss
Normal file
@ -0,0 +1,93 @@
|
||||
$drag-handle-size: var(--l-drag-handle-size, 50rpx);
|
||||
$drag-delete-size: var(--l-drag-delete-size, 32rpx);
|
||||
.l-drag {
|
||||
// min-height: 100rpx;
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
margin: 24rpx 30rpx 0 30rpx;
|
||||
// padding: 30rpx 0;
|
||||
|
||||
|
||||
/* #ifdef APP-NVUE */
|
||||
// flex: 1;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
// width: 100%;
|
||||
/* #endif */
|
||||
}
|
||||
.l-drag__inner {
|
||||
/* #ifdef APP-NVUE */
|
||||
flex: 1;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 100%;
|
||||
/* #endif */
|
||||
min-height: 100rpx;
|
||||
}
|
||||
.l-drag__view {
|
||||
// touch-action: none;
|
||||
// user-select: none;
|
||||
// -webkit-user-select: auto;
|
||||
z-index: 2;
|
||||
transition: opacity 300ms ease;
|
||||
.mask {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-color: transparent;
|
||||
z-index: 9;
|
||||
}
|
||||
/* #ifndef APP-NVUE */
|
||||
> view {
|
||||
&:last-child {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
|
||||
}
|
||||
.l-drag-enter {
|
||||
opacity: 0;
|
||||
}
|
||||
.l-drag__ghost {
|
||||
/* #ifndef APP-NVUE */
|
||||
> view {
|
||||
&:last-child {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
}
|
||||
.l-is-active {
|
||||
z-index: 3;
|
||||
}
|
||||
.l-is-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
.l-drag__delete {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
width: $drag-delete-size;
|
||||
height: $drag-delete-size;
|
||||
}
|
||||
.l-drag__handle {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
width: $drag-handle-size;
|
||||
height: $drag-handle-size;
|
||||
}
|
||||
/* #ifndef APP-NVUE */
|
||||
.l-drag__delete::before,.l-drag__handle::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
/* #endif */
|
532
uni_modules/lime-drag/components/l-drag/l-drag.vue
Normal file
532
uni_modules/lime-drag/components/l-drag/l-drag.vue
Normal file
@ -0,0 +1,532 @@
|
||||
<template>
|
||||
<view class="l-drag l-class" :style="[areaStyles]" ref="dragRef" @touchstart="setDisabled">
|
||||
<movable-area class="l-drag__inner" v-if="isReset" :style="[innerStyles]">
|
||||
<slot></slot>
|
||||
<movable-view class="l-drag__ghost" v-if="isDrag && props.ghost" :animation="true" :style="[viewStyles]" direction="all" :x="ghostEl.x" :y="ghostEl.y" key="l-drag-clone">
|
||||
<slot name="ghost"></slot>
|
||||
</movable-view>
|
||||
<movable-view v-if="props.before" class="l-drag__before" disabled :animation="false" :style="[viewStyles]" :x="beforeEl.x" :y="beforeEl.y">
|
||||
<slot name="before"></slot>
|
||||
</movable-view>
|
||||
<movable-view
|
||||
v-for="(item, oindex) in cloneList" :key="item.id"
|
||||
direction="all"
|
||||
:data-oindex="oindex"
|
||||
:style="[viewStyles]"
|
||||
class="l-drag__view"
|
||||
:class="[{'l-is-active': oindex == active, 'l-is-hidden': !item.show}, item.class]"
|
||||
:x="item.x"
|
||||
:y="item.y"
|
||||
:friction="friction"
|
||||
:damping="damping"
|
||||
:animation="animation"
|
||||
:disabled="isDisabled || props.disabled"
|
||||
@touchstart="touchStart"
|
||||
@change="touchMove"
|
||||
@touchend="touchEnd"
|
||||
@touchcancel="touchEnd"
|
||||
@longpress="setDisabled"
|
||||
>
|
||||
<!-- <view v-if="props.remove" class="l-drag__remove" :style="removeStyle" data-remove="true">
|
||||
<slot name="remove" :oindex="oindex" data-remove="true" />
|
||||
</view> -->
|
||||
<!-- <view v-if="props.handle" class="l-drag__handle" :style="handleStyle" data-handle="true">
|
||||
<slot name="handle" :oindex="oindex" :active="!isDisabled && !isDisabled && oindex == active" />
|
||||
</view> -->
|
||||
<slot name="grid" :oindex="oindex" :index="item.index" :oldindex="item.oldindex" :content="item.content" :active="!isDisabled && !isDisabled && oindex == active" />
|
||||
<view class="mask" v-if="!(isDisabled || props.disabled) && props.longpress"></view>
|
||||
</movable-view>
|
||||
|
||||
|
||||
<movable-view v-if="props.after" class="l-drag__after" disabled :animation="true" direction="all" :style="[viewStyles]" :x="afterEl.x" :y="afterEl.y">
|
||||
<slot name="after"></slot>
|
||||
</movable-view>
|
||||
</movable-area>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
import { computed, onMounted, ref, getCurrentInstance, watch, nextTick, reactive , triggerRef, onUnmounted, defineComponent} from "./vue";
|
||||
import DragProps from './props';
|
||||
import type {GridRect, Grid, Position} from './type'
|
||||
// #ifdef APP-NVUE
|
||||
const dom = weex.requireModule('dom')
|
||||
// #endif
|
||||
|
||||
export default defineComponent({
|
||||
name: 'l-drag',
|
||||
externalClasses: ['l-class'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
},
|
||||
props: DragProps,
|
||||
emits: ['change'],
|
||||
setup(props, {emit, expose}) {
|
||||
const res = wx.getSystemInfoSync();
|
||||
const statusHeight = res.statusBarHeight; //状态栏高度
|
||||
const cusnavbarheight = (statusHeight + 44) + "px";
|
||||
// #ifdef APP-NVUE
|
||||
const dragRef = ref(null)
|
||||
// #endif
|
||||
const app = getCurrentInstance()
|
||||
const isDrag = ref(false)
|
||||
const isInit = ref(false)
|
||||
const isReset = ref(true)
|
||||
const colmunId = ref(-1)
|
||||
/** 选中项原始下标 */
|
||||
const active = ref(-1)
|
||||
const maxIndex = ref(-1)
|
||||
const animation = ref(true)
|
||||
const isDisabled = ref(props.handle || props.longpress ? true: false)
|
||||
|
||||
const dragEl = reactive({
|
||||
content: null,
|
||||
/** 当前视图下标*/
|
||||
index: 0,
|
||||
/** 旧视图下标 */
|
||||
oldindex: -1,
|
||||
/** 上次原始下标 */
|
||||
lastindex: -1
|
||||
})
|
||||
|
||||
const ghostEl = reactive({
|
||||
content: null,
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
const beforeEl = reactive({
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
const afterEl = reactive({
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
|
||||
let gridRects = [] //ref<GridRect[]>([])
|
||||
const areaWidth = ref(0)
|
||||
const cloneList = ref<Grid[]>([])
|
||||
// 删除项时可能会减少行数影响到删除过渡动画,故增加此值在删除时保持高度不变,等动画完成后再归零
|
||||
const leaveRow = ref(0)
|
||||
const extra = computed(() => (props.before ? 1 :0) + (props.after ? 1 : 0))
|
||||
const rows = computed(() => Math.ceil( ((isInit.value ? cloneList.value.length : props.list.length) + extra.value) / props.column ))
|
||||
const gridHeight = computed(() => props.aspectRatio ? girdWidth.value / props.aspectRatio : (/rpx$/.test(`${props.gridHeight}`) ? uni.upx2px(parseInt(`${props.gridHeight}`)) : parseInt(`${props.gridHeight}`)))
|
||||
const girdWidth = computed(() => areaWidth.value / props.column)
|
||||
const viewStyles = computed(() => ({width: girdWidth.value + 'px',height: gridHeight.value + 'px'}))
|
||||
const areaStyles = computed(() => ({height: (rows.value + leaveRow.value ) * gridHeight.value + 'px'}))
|
||||
const innerStyles = computed(() => ({
|
||||
// #ifdef APP-NVUE
|
||||
width: areaWidth.value + 'px',
|
||||
// #endif
|
||||
height: (rows.value + props.extraRow + leaveRow.value) * gridHeight.value + 'px'}))
|
||||
|
||||
const sleep = (cb: Function, time = 1000/60) => setTimeout(cb, time)
|
||||
const createGrid = (content: any, position?:Position|null): Grid => {
|
||||
colmunId.value++
|
||||
maxIndex.value++
|
||||
const index = maxIndex.value
|
||||
const colmun = gridRects[index]
|
||||
|
||||
let x = 0
|
||||
let y = 0
|
||||
if(colmun) {
|
||||
if(props.after) {
|
||||
let nxet = gridRects[index + 1]
|
||||
if(!nxet) {
|
||||
nxet = createGridRect(gridRects.length + (props.before ? 1 : 0))
|
||||
gridRects.push(nxet)
|
||||
}
|
||||
setReset(() => setAfter(nxet))
|
||||
} else {
|
||||
setReset()
|
||||
}
|
||||
x = colmun.x
|
||||
y = colmun.y
|
||||
} else {
|
||||
const nxet = createGridRect(gridRects.length + (props.before ? 1 : 0))
|
||||
gridRects.push(nxet)
|
||||
setReset()
|
||||
x = nxet.x
|
||||
y = nxet.y
|
||||
}
|
||||
if(position) {
|
||||
x = position.x
|
||||
y = position.y
|
||||
}
|
||||
return {id: `l-drag-item-${colmunId.value}`, index, oldindex: index, content, x, y, class: '', show: true}
|
||||
}
|
||||
const setReset = (cb?: any) => {
|
||||
// const newRow = (cloneList.value.length + extra.value) % (props.column)
|
||||
if(isInit.value) {
|
||||
cb&&sleep(cb)
|
||||
}
|
||||
}
|
||||
const setAfter = ({x, y} = {x: 0, y: 0}) => {
|
||||
if(props.after) {
|
||||
afterEl.x = x
|
||||
afterEl.y = y
|
||||
}
|
||||
}
|
||||
const setDisabled = (e: any, flag?: boolean= false) => {
|
||||
// e?.preventDefault()
|
||||
const type = `${e.type}`.toLowerCase()
|
||||
const {handle = props.touchHandle} = e.target.dataset
|
||||
if(props.handle && !handle) {
|
||||
isDisabled.value = true
|
||||
} else if(props.handle && handle && !props.longpress) {
|
||||
isDisabled.value = flag
|
||||
} else if(props.handle && handle && props.longpress && type.includes('longpress')) {
|
||||
isDisabled.value = false
|
||||
} else if(props.longpress && type.includes('longpress') && !props.handle) {
|
||||
isDisabled.value = false
|
||||
}
|
||||
if(type.includes('touchend') && props.longpress) {
|
||||
isDisabled.value = true
|
||||
}
|
||||
}
|
||||
const createGridRect = (i: number, last?: GridRect): GridRect => {
|
||||
let { row } = last || gridRects[gridRects.length - 1] || { row: 0 }
|
||||
const col = i % (props.column)
|
||||
const grid = (row: number, x: number, y: number):GridRect => {
|
||||
return {row, x, y, x1: x + girdWidth.value, y1: y + gridHeight.value}
|
||||
}
|
||||
if(col == 0 && i != 0) {row++}
|
||||
return grid(row, col * girdWidth.value, row * gridHeight.value)
|
||||
}
|
||||
const createGridRects = () => {
|
||||
let rects: GridRect[] = []
|
||||
const length = rows.value * props.column + extra.value
|
||||
gridRects = []
|
||||
for (var i = 0; i < length; i++) {
|
||||
const item = createGridRect(i, rects[rects.length - 1])
|
||||
rects.push(item)
|
||||
}
|
||||
if(props.before) {
|
||||
const {x, y} = rects.shift()
|
||||
beforeEl.x = x
|
||||
beforeEl.y = y
|
||||
}
|
||||
setAfter(rects[props.list.length])
|
||||
gridRects = rects as GridRect[]
|
||||
}
|
||||
const updateList = (v: any[]) => {
|
||||
cloneList.value = v.map((content) => createGrid(content))
|
||||
}
|
||||
|
||||
const touchStart = (e: any) => {
|
||||
if(e.target.dataset.remove) return
|
||||
// 选中项原始下标
|
||||
const {oindex} = e.currentTarget?.dataset || e.target?.dataset || {}
|
||||
if(typeof oindex !== 'number') return
|
||||
const target = cloneList.value[oindex]
|
||||
isDrag.value = true
|
||||
// 选中项原始下标
|
||||
active.value = oindex
|
||||
// 选中项的当前下标
|
||||
dragEl.index = dragEl.oldindex = target.index
|
||||
ghostEl.x = target.x||0
|
||||
ghostEl.y = target.y||0
|
||||
dragEl.content = ghostEl.content = target.content
|
||||
}
|
||||
|
||||
const touchEnd = (e: any) => {
|
||||
setTimeout(() => {
|
||||
if(e.target.dataset.remove || active.value==-1) return
|
||||
setDisabled(e, true)
|
||||
isDrag.value = false
|
||||
const isEmit = dragEl.index !== dragEl.oldindex && dragEl.oldindex > -1 // active.value !== dragEl.index
|
||||
dragEl.lastindex = active.value
|
||||
dragEl.oldindex = active.value = -1
|
||||
const last = cloneList.value[dragEl.lastindex]
|
||||
const position = gridRects[dragEl.index]
|
||||
nextTick(() => {
|
||||
last.x = position.x + 0.001
|
||||
last.y = position.y + 0.001
|
||||
sleep(() => {
|
||||
last.x = position.x
|
||||
last.y = position.y
|
||||
isEmit && emitting()
|
||||
})
|
||||
})
|
||||
},80)
|
||||
|
||||
}
|
||||
const emitting = () => {
|
||||
const clone = [...cloneList.value].sort((a, b) => a.index - b.index)//.map(item => ref(item.content))
|
||||
emit('change', clone)
|
||||
}
|
||||
|
||||
const touchMove = (e: any) => {
|
||||
if(!isDrag.value) return
|
||||
// #ifndef APP-NVUE
|
||||
let {oindex} = e.currentTarget.dataset
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
oindex = e.currentTarget.dataset['-oindex']
|
||||
// #endif
|
||||
if(oindex != active.value) return
|
||||
const {x, y} = e.detail
|
||||
const centerX = x + girdWidth.value / 2
|
||||
const centerY = y + gridHeight.value / 2
|
||||
for (let i = 0; i < cloneList.value.length; i++) {
|
||||
const item = gridRects[i]
|
||||
if(centerX > item.x && centerX < item.x1 && centerY > item.y && centerY < item.y1) {
|
||||
ghostEl.x = item.x
|
||||
ghostEl.y = item.y
|
||||
if(dragEl.index != i) {
|
||||
_move(active.value, i)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const getDragEl = (oindex: number) => {
|
||||
if(isDrag.value) {return dragEl}
|
||||
return cloneList.value[oindex]
|
||||
}
|
||||
|
||||
/**
|
||||
* 把原始数据中排序为index的项 移动到 toIndex
|
||||
* @param oindex 原始数据的下标
|
||||
* @param toIndex 视图中的下标
|
||||
* @param position 指定坐标
|
||||
*/
|
||||
const _move = (oindex: number, toIndex: number, position?: Position|null, emit: boolean = true) => {
|
||||
const length = cloneList.value.length - 1
|
||||
if(toIndex > length || toIndex < 0) return
|
||||
// 获取oIdnex在视图中的项目
|
||||
const dragEl = getDragEl(oindex)
|
||||
let speed = 0
|
||||
let start = dragEl.index
|
||||
// 比较开始index和终点index,设置方向
|
||||
if(start < toIndex) {speed = 1}
|
||||
if(start > toIndex) {speed = -1}
|
||||
if(!speed) return
|
||||
// 距离
|
||||
let distance = start - toIndex
|
||||
// 找到区间所有的项
|
||||
while(distance) {
|
||||
distance += speed
|
||||
// 目标
|
||||
const target = isDrag.value ? (dragEl.index += speed) : (start += speed)
|
||||
let targetOindex = cloneList.value.findIndex(item => item.index == target && item.content != dragEl.content)
|
||||
if (targetOindex == oindex) return
|
||||
if (targetOindex < 0) {targetOindex = cloneList.value.length - 1}
|
||||
let targetEl = cloneList.value[targetOindex]
|
||||
if(!targetEl) return;
|
||||
// 上一个index
|
||||
const lastIndex = target - speed
|
||||
const activeEl = cloneList.value[oindex]
|
||||
const rect = gridRects[lastIndex]
|
||||
targetEl.x = rect.x
|
||||
targetEl.y = rect.y
|
||||
targetEl.oldindex = targetEl.index
|
||||
targetEl.index = lastIndex
|
||||
activeEl.oldindex = activeEl.index //oIndex
|
||||
activeEl.index = toIndex
|
||||
// 到达终点,如果是拖拽则不处理
|
||||
if(!distance && !isDrag.value) {
|
||||
const rect = gridRects[toIndex]
|
||||
const {x, y} = position||rect
|
||||
activeEl.x = dragEl.x = x
|
||||
activeEl.y = dragEl.y = y
|
||||
// triggerRef(cloneList)
|
||||
if(emit) {
|
||||
emitting()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 为区分是主动调用还是内部方法
|
||||
*/
|
||||
const move = (oindex: number, toIndex: number) => {
|
||||
active.value = -1
|
||||
isDrag.value = false
|
||||
_move(oindex, toIndex)
|
||||
}
|
||||
// 临时处理 待有空再完善
|
||||
const REMOVE_TIME = 400
|
||||
let removeTimer = null
|
||||
const remove = (oindex: number) => {
|
||||
active.value = -1
|
||||
isDrag.value = false
|
||||
|
||||
clearTimeout(removeTimer)
|
||||
const item = cloneList.value[oindex]
|
||||
if(props.disabled || !item) return
|
||||
item.show = false
|
||||
const after = cloneList.value.length - 1
|
||||
_move(oindex, after, item, false)
|
||||
setAfter(gridRects[after])
|
||||
maxIndex.value--
|
||||
const _remove = (_index = oindex) => {
|
||||
// 小程序 删除会闪一下 所以先关闭动画再开启
|
||||
// animation.value = false
|
||||
const row = Math.ceil((cloneList.value.length - 1 + extra.value) / props.column)
|
||||
if( row < rows.value) {
|
||||
leaveRow.value = (rows.value - row)
|
||||
}
|
||||
cloneList.value.splice(_index, 1)[0]
|
||||
emitting()
|
||||
removeTimer = setTimeout(() => {
|
||||
leaveRow.value = 0
|
||||
}, REMOVE_TIME)
|
||||
}
|
||||
_remove()
|
||||
}
|
||||
const push = (...args: any) => {
|
||||
if(props.disabled) return
|
||||
if(Array.isArray(args)) {
|
||||
Promise.all(args.map(async item => await add(item, true))).then(emitting)
|
||||
}
|
||||
}
|
||||
const add = (content: any, after: boolean) => {
|
||||
return new Promise((resolve) => {
|
||||
const item = createGrid(content, after ? null : {x: -100, y:0})
|
||||
item.class = 'l-drag-enter'
|
||||
cloneList.value.push(item)
|
||||
const length = cloneList.value.length - 1
|
||||
nextTick(() => {
|
||||
sleep(() => {
|
||||
item.class = 'l-drag-leave'
|
||||
_move(length, (after ? length : 0), null, false)
|
||||
triggerRef(cloneList)
|
||||
resolve(true)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
const unshift = (...args: any) => {
|
||||
if(props.disabled) return
|
||||
if(Array.isArray(args)) {
|
||||
Promise.all(args.map(async (item) => await add(item))).then(emitting)
|
||||
}
|
||||
}
|
||||
|
||||
// 暂时先简单处理,待有空再完善
|
||||
const shift = () => {
|
||||
if(!cloneList.value.length) return
|
||||
remove(cloneList.value.findIndex(item => item.index == 0) || 0)
|
||||
}
|
||||
const pop = () => {
|
||||
const length = cloneList.value.length-1
|
||||
if(length < 0 ) return
|
||||
remove(cloneList.value.findIndex(item => item.index == length) || length)
|
||||
}
|
||||
// const splice = (start, count, ...context) => {
|
||||
// // 暂未实现
|
||||
// }
|
||||
const clear = () => {
|
||||
isInit.value = isDrag.value = false
|
||||
maxIndex.value = colmunId.value = active.value = -1
|
||||
cloneList.value = []
|
||||
gridRects = []
|
||||
}
|
||||
const init = () => {
|
||||
clear()
|
||||
createGridRects()
|
||||
nextTick(() => {
|
||||
updateList(props.list)
|
||||
isInit.value = true
|
||||
})
|
||||
}
|
||||
let count = 0
|
||||
const getRect = () => {
|
||||
count++
|
||||
// #ifndef APP-NVUE
|
||||
uni.createSelectorQuery().in(app.proxy).select('.l-drag').boundingClientRect((res: UniNamespace.NodeInfo) => {
|
||||
if(res) {
|
||||
areaWidth.value = res.width || 0
|
||||
// 小程序居然无法响应式?
|
||||
init()
|
||||
}
|
||||
}).exec()
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
sleep(() => {
|
||||
nextTick(() => {
|
||||
dom.getComponentRect(dragRef.value, (res) => {
|
||||
if(!res.size.width && count < 5) {
|
||||
getRect()
|
||||
} else {
|
||||
areaWidth.value = res.size.width || 0
|
||||
init()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
onMounted(getRect)
|
||||
onUnmounted(clear)
|
||||
watch(() => props.list, init)
|
||||
|
||||
// #ifdef VUE3
|
||||
expose({
|
||||
remove,
|
||||
// add,
|
||||
move,
|
||||
push,
|
||||
unshift,
|
||||
shift,
|
||||
pop
|
||||
})
|
||||
// #endif
|
||||
return {
|
||||
// #ifdef APP-NVUE
|
||||
dragRef,
|
||||
// #endif
|
||||
cloneList,
|
||||
|
||||
areaStyles,
|
||||
innerStyles,
|
||||
viewStyles,
|
||||
|
||||
setDisabled,
|
||||
isDisabled,
|
||||
isReset,
|
||||
isDrag,
|
||||
|
||||
active,
|
||||
animation,
|
||||
|
||||
afterEl,
|
||||
ghostEl,
|
||||
beforeEl,
|
||||
|
||||
touchStart,
|
||||
touchMove,
|
||||
touchEnd,
|
||||
|
||||
remove,
|
||||
// add,
|
||||
move,
|
||||
push,
|
||||
unshift,
|
||||
// shift,
|
||||
// pop,
|
||||
props
|
||||
// isDelete: props.delete,
|
||||
// ...toRefs(props)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.l-drag{
|
||||
margin-top: v-bind(cusnavbarheight);
|
||||
|
||||
}
|
||||
@import './index';
|
||||
|
||||
</style>
|
47
uni_modules/lime-drag/components/l-drag/props.ts
Normal file
47
uni_modules/lime-drag/components/l-drag/props.ts
Normal file
@ -0,0 +1,47 @@
|
||||
// @ts-nocheck
|
||||
export default {
|
||||
list: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
column: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
/**宽高比 填写这项, gridHeight 失效*/
|
||||
aspectRatio: Number,
|
||||
gridHeight: {
|
||||
type: [Number, String],
|
||||
default: '120rpx'
|
||||
},
|
||||
// removeStyle: String,
|
||||
// handleStyle: String,
|
||||
damping: {
|
||||
type: Number,
|
||||
default: 40
|
||||
},
|
||||
friction: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
/**
|
||||
* 由于 movable-area 无法动态设置高度,故增加额外的行数。用于增加动态项时,高度不够无法正确显示
|
||||
*/
|
||||
extraRow: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
/**
|
||||
* 由于 movable-area 无法动态设置高度,但vif 重染可以,另一种实现动态高度的方式, 这BUG uni官方好像修复了。
|
||||
*/
|
||||
// reset: Boolean,
|
||||
// sort: Boolean,
|
||||
// remove: Boolean,
|
||||
ghost: Boolean,
|
||||
handle: Boolean,
|
||||
touchHandle: Boolean,
|
||||
before: Boolean,
|
||||
after: Boolean,
|
||||
disabled: Boolean,
|
||||
longpress: Boolean,
|
||||
}
|
21
uni_modules/lime-drag/components/l-drag/type.ts
Normal file
21
uni_modules/lime-drag/components/l-drag/type.ts
Normal file
@ -0,0 +1,21 @@
|
||||
export interface Position {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
export interface GridRect extends Position{
|
||||
row : number
|
||||
// x : number
|
||||
// y : number
|
||||
x1 : number
|
||||
y1 : number
|
||||
}
|
||||
export interface Grid extends Position{
|
||||
id : string
|
||||
index : number
|
||||
oldindex : number
|
||||
content : any
|
||||
// x : number
|
||||
// y : number
|
||||
class : string
|
||||
show: boolean
|
||||
}
|
9
uni_modules/lime-drag/components/l-drag/vue.ts
Normal file
9
uni_modules/lime-drag/components/l-drag/vue.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// export * from '@/uni_modules/lime-vue'
|
||||
|
||||
// #ifdef VUE3
|
||||
export * from 'vue';
|
||||
// #endif
|
||||
// #ifndef VUE3
|
||||
export * from '@vue/composition-api';
|
||||
// #endif
|
268
uni_modules/lime-drag/components/lime-drag/lime-drag.vue
Normal file
268
uni_modules/lime-drag/components/lime-drag/lime-drag.vue
Normal file
@ -0,0 +1,268 @@
|
||||
<template>
|
||||
<demo-block type="ultra" title="拖拽">
|
||||
<demo-block title="基础">
|
||||
<l-drag :list="list">
|
||||
<template #grid="{active, index}">
|
||||
<view class="inner" :class="{active}">
|
||||
<text class="text" :class="{'text-active': active}">{{index}}</text>
|
||||
</view>
|
||||
</template>
|
||||
</l-drag>
|
||||
</demo-block>
|
||||
<demo-block title="多列 长按">
|
||||
<!-- 列后 删除 幽灵 长按 -->
|
||||
<l-drag ref="dragRef2" :list="list" @change="change2" :aspectRatio="1" :column="4" after ghost longpress>
|
||||
<template #grid="{oindex, content, active}">
|
||||
<view class="grid">
|
||||
<view class="remove" @click="onRemove2(oindex)"></view>
|
||||
<view class="inner" :class="{active}">
|
||||
<text class="text" :class="{'text-active': active}">{{content}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<template #ghost>
|
||||
<view class="grid">
|
||||
<!-- 幽灵样式 -->
|
||||
<view class="inner ghost"></view>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 示例未设置 before -->
|
||||
<template #before>
|
||||
<view class="grid">
|
||||
<view class="inner extra" @click="onAdd2">
|
||||
增加
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template #after>
|
||||
<view class="grid">
|
||||
<view class="inner extra" @click="onAdd2">
|
||||
增加
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</l-drag>
|
||||
<button @click="refresh2">更新列表</button>
|
||||
<button @click="onUnshift2">向前增加</button>
|
||||
<button @click="onPush2">向后增加</button>
|
||||
<button @click="onShift2">shift</button>
|
||||
<button @click="onPop2">pop</button>
|
||||
</demo-block>
|
||||
<demo-block title="单列 按手柄">
|
||||
<!-- 幽灵 手柄 -->
|
||||
<view class="inputs">
|
||||
<text>把原始下标为</text>
|
||||
<input type="text" v-model="move3.index">
|
||||
<text>的项移动到</text>
|
||||
<input type="text" v-model="move3.nindex">
|
||||
</view>
|
||||
<view style="height: 600rpx; overflow: auto;">
|
||||
<l-drag ref="dragRef3" :list="list3" @change="change3" grid-height="200rpx" :column="1" :touchHandle="touchHandle3" ghost handle>
|
||||
<template #grid="{active, content, index, oindex}">
|
||||
<view class="grid">
|
||||
<view class="mover" @touchstart="touchHandle3 = true" @touchend="touchHandle3 = false" style="left: 100rpx; top: 50%; transform: translateY(-50%); position: absolute; z-index: 1;"></view>
|
||||
<view class="inner" :class="{active}">
|
||||
<text class="text" :class="{'text-active': active}">{{content}}</text>
|
||||
<view @click.stop.prevent="to(oindex, index - 1)">上移</view>
|
||||
<view @click.stop.prevent="to(oindex, index + 1)">下移</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template #ghost>
|
||||
<view class="grid">
|
||||
<!-- 幽灵样式 -->
|
||||
<view class="inner ghost"></view>
|
||||
</view>
|
||||
</template>
|
||||
</l-drag>
|
||||
</view>
|
||||
</demo-block>
|
||||
</demo-block>
|
||||
</template>
|
||||
<script>
|
||||
import {ref, watch, defineComponent, reactive} from '../l-drag/vue'
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
// 示例1和2共用list
|
||||
const list = ref(new Array(7).fill(0).map((v,i) => i));
|
||||
// 示例2 多列 长按
|
||||
const dragRef2 = ref(null)
|
||||
const newList2 = ref([])
|
||||
const change2 = v => {
|
||||
console.log('示例2数据发生变化::', v)
|
||||
newList2.value = [...v]
|
||||
}
|
||||
const onRemove2 = (index) => {
|
||||
if(dragRef2.value && index >= 0) {
|
||||
dragRef2.value.remove(index)
|
||||
}
|
||||
}
|
||||
const onAdd2 = () => {
|
||||
dragRef2.value.push(Math.round(Math.random() * 1000))
|
||||
}
|
||||
const onShift2 = () => {
|
||||
dragRef2.value.shift()
|
||||
}
|
||||
const onPop2 = () => {
|
||||
dragRef2.value.pop()
|
||||
}
|
||||
const onUnshift2 = () => {
|
||||
dragRef2.value.unshift(Math.round(Math.random() * 1000), Math.round(Math.random() * 1000))
|
||||
}
|
||||
const onPush2 = () => {
|
||||
dragRef2.value.push(Math.round(Math.random() * 1000), Math.round(Math.random() * 1000))
|
||||
}
|
||||
const refresh2 = () => {
|
||||
list.value = new Array(10).fill(0).map((v,i) => i);
|
||||
}
|
||||
|
||||
|
||||
// 示例3
|
||||
const list3 = new Array(5).fill(0).map((v,i) => i);
|
||||
const dragRef3 = ref(null)
|
||||
const newList3 = ref([])
|
||||
const touchHandle3 = ref(false)
|
||||
|
||||
const change3 = v => {
|
||||
newList3.value = v
|
||||
}
|
||||
const move3 = reactive({
|
||||
index: 0,
|
||||
nindex: 0
|
||||
})
|
||||
watch(() => move3.nindex, (v, o) => {
|
||||
dragRef3.value.move(move3.index*1, move3.nindex*1)
|
||||
})
|
||||
|
||||
const to = (oindex, index) => {
|
||||
dragRef3.value.move(oindex, index)
|
||||
}
|
||||
|
||||
return {
|
||||
list,
|
||||
// 示例2
|
||||
dragRef2,
|
||||
change2,
|
||||
onRemove2,
|
||||
onAdd2,
|
||||
refresh2,
|
||||
onUnshift2,
|
||||
onPush2,
|
||||
onShift2,
|
||||
onPop2,
|
||||
// 示例3
|
||||
list3,
|
||||
dragRef3,
|
||||
change3,
|
||||
move3,
|
||||
touchHandle3,
|
||||
to
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
.grid {
|
||||
height: 100%;
|
||||
/* #ifdef APP-NVUE */
|
||||
flex: 1;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 100%;
|
||||
/* #endif */
|
||||
padding: 16rpx;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
.remove {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
background-color: red;
|
||||
border-radius: 50%;
|
||||
font-size: 16rpx;
|
||||
color: white;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
.inner {
|
||||
/* #ifdef APP-NVUE */
|
||||
flex: 1;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
/* #endif */
|
||||
|
||||
border: 1rpx solid #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: white;
|
||||
font-size: 50rpx;
|
||||
font-weight: bold;
|
||||
color: blue;
|
||||
transition: all 300ms ease;
|
||||
position: relative;
|
||||
}
|
||||
.extra {
|
||||
color: #ddd
|
||||
}
|
||||
.mover {
|
||||
position: relative;
|
||||
width: 50rpx;
|
||||
margin-top: 10rpx;
|
||||
height: 30rpx;
|
||||
border: 2px solid #ddd;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
/* background-color: #ddd; */
|
||||
}
|
||||
.mover::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 50rpx;
|
||||
top: 15rpx;
|
||||
border-top: 2px solid #ddd;
|
||||
}
|
||||
.active {
|
||||
box-shadow: 0 2rpx 16rpx rgba(0, 0, 0, 0.1);
|
||||
background-color: blue;
|
||||
color: white;
|
||||
border: 1rpx solid blue;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
/* #ifdef APP-NVUE */
|
||||
.text {
|
||||
font-size: 50rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
.text-active {
|
||||
font-size: 50rpx;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
/* #endif */
|
||||
.ghost {
|
||||
background-color: rgba(0, 0, 255, 0.1);
|
||||
}
|
||||
.inputs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
input {
|
||||
background-color: #fff;
|
||||
width: 80rpx;
|
||||
border: 1rpx solid #ddd;
|
||||
padding: 5rpx 10rpx;
|
||||
margin: 0 8rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
87
uni_modules/lime-drag/package.json
Normal file
87
uni_modules/lime-drag/package.json
Normal file
@ -0,0 +1,87 @@
|
||||
{
|
||||
"id": "lime-drag",
|
||||
"displayName": "拖拽排序-拖动排序-LimeUI",
|
||||
"version": "0.1.3",
|
||||
"description": "uniapp vue3 拖拽排序插件,用于图片或列表的拖动排序,可设置列数、增加删除等功能, vue2只要配置@vue/composition-api",
|
||||
"keywords": [
|
||||
"拖拽",
|
||||
"拖拽排序",
|
||||
"排序",
|
||||
"拖动",
|
||||
"拖动排序"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.7.12"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"lime-shared"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "n",
|
||||
"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",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
170
uni_modules/lime-drag/readme.md
Normal file
170
uni_modules/lime-drag/readme.md
Normal file
@ -0,0 +1,170 @@
|
||||
# lime-drag 拖拽排序
|
||||
- 当前为初版 可能会有BUG
|
||||
- 基于uniapp vue3
|
||||
- Q群 1169785031
|
||||
|
||||
|
||||
### 安装
|
||||
- 在市场导入插件即可在任意页面使用,无须再`import`
|
||||
|
||||
|
||||
### 使用
|
||||
- 提供简单的使用示例,更多请查看下方的demo
|
||||
|
||||
```html
|
||||
<l-drag :list="list" @change="change">
|
||||
<!-- // 每一项的插槽 grid 的 content 您传入的数据 -->
|
||||
<template #grid="{active, content}">
|
||||
<!-- // grid.active 是否为当前拖拽项目 根据自己需要写样式 -->
|
||||
<view class="inner" :class="{active: active}">
|
||||
<text class="text" :class="{'text-active': active}">{{grid.content}}</text>
|
||||
</view>
|
||||
</template>
|
||||
</l-drag>
|
||||
```
|
||||
|
||||
```js
|
||||
const list = new Array(7).fill(0).map((v,i) => i);
|
||||
// 拖拽后新的数据
|
||||
const newList = ref([])
|
||||
const change = v => newList.value = v
|
||||
```
|
||||
#### 增删
|
||||
- 不要给list赋值,这样只会重新初始化
|
||||
- 增加数据 调用暴露的`push`
|
||||
- 删除某条数据调用暴露的`remove`方法,需要传入`oindex`
|
||||
|
||||
```html
|
||||
<l-drag :list="list" @change="change" ref="dragRef" after remove>
|
||||
<!-- 每一项插槽 grid 的 content 是您传入的数据 -->
|
||||
<template #grid="{active, index, oldindex, oindex}">
|
||||
<!-- active 是否为当前拖拽项目 根据自己需要写样式 -->
|
||||
<!-- index 排序后列表下标 -->
|
||||
<!-- oldindex 排序后列表旧下标 -->
|
||||
<!-- oindex 列表原始下标,输入的数据排位不会因为排序而改变 -->
|
||||
<view class="remove" @click="onRemove(oindex)"></view>
|
||||
<view class="inner" :class="{active}">
|
||||
<text class="text" :class="{'text-active': active}">{{content}}</text>
|
||||
</view>
|
||||
</template>
|
||||
<template #after>
|
||||
<view class="grid">
|
||||
<view class="inner extra" @click="onAdd">
|
||||
增加
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</l-drag>
|
||||
```
|
||||
```js
|
||||
const dragRef = ref(null)
|
||||
const list = new Array(7).fill(0).map((v,i) => i);
|
||||
const onAdd = () => {
|
||||
dragRef.value.push(Math.round(Math.random() * 1000))
|
||||
}
|
||||
const onRemove = (oindex) => {
|
||||
if(dragRef.value && oindex >= 0) {
|
||||
// 记得oindex为数组的原始index
|
||||
dragRef.value.remove(oindex)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### 插槽
|
||||
```html
|
||||
<l-drag :list="list">
|
||||
<!-- 每一项的插槽 -->
|
||||
<template #grid="{active, index, oldindex, oindex, content}"></template>
|
||||
<!-- 当前拖拽项幽灵插槽 设置`ghost`后使用 主要为实现拖拽时 有个影子跟着 -->
|
||||
<template #ghots></template>
|
||||
|
||||
<!-- 前后方插槽为固定在列表前方和后方,不能拖动 -->
|
||||
<!-- 列表前方的插槽 设置`before`后使用 -->
|
||||
<template #before></template>
|
||||
<!-- 列表后方的插槽 设置`after`后使用 -->
|
||||
<template #after></template>
|
||||
</l-drag>
|
||||
```
|
||||
|
||||
|
||||
### 查看示例
|
||||
- 导入后直接使用这个标签查看演示效果
|
||||
|
||||
```html
|
||||
<!-- // 代码位于 uni_modules/lime-drag/compoents/lime-drag -->
|
||||
<lime-drag />
|
||||
```
|
||||
|
||||
|
||||
### 插件标签
|
||||
- 默认 l-drag 为 component
|
||||
- 默认 lime-drag 为 demo
|
||||
|
||||
### 关于vue2的使用方式
|
||||
- 插件使用了`composition-api`, 如果你希望在vue2中使用请按官方的教程[vue-composition-api](https://uniapp.dcloud.net.cn/tutorial/vue-composition-api.html)配置
|
||||
- 关键代码是: 在main.js中 在vue2部分加上这一段即可,官方是把它单独成了一个文件.
|
||||
```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
|
||||
```
|
||||
|
||||
- 小程序需要在`manifest.json`启用`slotMultipleInstance`
|
||||
```json
|
||||
"mp-weixin" : {
|
||||
"slotMultipleInstance" : true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --------------------------| ------------------------------------------------------------ | ---------------- | ------------ |
|
||||
| list | 列表数组,不可变化,变化后会重新初始化 | <em>array</em> | `[]` |
|
||||
| column | 列数 | <em>number</em> | `2` |
|
||||
| gridHeight | 行高,宫格高度 | <em>string</em> | `120rpx` |
|
||||
| damping | 阻尼系数,用于控制x或y改变时的动画和过界回弹的动画,值越大移动越快 | <em>string</em> | `-` |
|
||||
| friction | 摩擦系数,用于控制惯性滑动的动画,值越大摩擦力越大,滑动越快停止;必须大于0,否则会被设置成默认值 | <em>number</em> | `2` |
|
||||
| extraRow | 额外行数 | <em>number</em> | `0` |
|
||||
| ghost | 开启幽灵插槽 | <em>boolean</em> | `false` |
|
||||
| before | 开启列前插槽 | <em>boolean</em> | `false` |
|
||||
| after | 开启列后插槽 | <em>boolean</em> | `false` |
|
||||
| disabled | 是否禁用 | <em>boolean</em> | `false` |
|
||||
| longpress | 是否长按 | <em>boolean</em> | `false` |
|
||||
|
||||
### Events
|
||||
| 参数 | 说明 | 参数 |
|
||||
| --------------------------| ------------------------------------------------------------ | ---------------- |
|
||||
| change | 返回新数据 | list |
|
||||
|
||||
### Expose
|
||||
| 参数 | 说明 | 参数 |
|
||||
| --------------------------| ------------------------------------------------------------ | ---------------- |
|
||||
| remove | 删除, 传入`oindex`,即数据列表原始的index | |
|
||||
| push | 向后增加,可以是数组或单数据 | |
|
||||
| unshift | 向前增加,可以是数组或单数据 | |
|
||||
| move | 移动, 传入(`oindex`, `toindex`),将数据列表原始的index项移到视图中的目标位置 | |
|
||||
|
||||
|
||||
### TODO
|
||||
将来实现的功能
|
||||
- splice
|
||||
|
||||
## 打赏
|
||||
|
||||
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
|
||||

|
||||

|
42
uni_modules/lime-shared/addUnit/index.ts
Normal file
42
uni_modules/lime-shared/addUnit/index.ts
Normal file
@ -0,0 +1,42 @@
|
||||
// @ts-nocheck
|
||||
import {isNumeric} from '../isNumeric'
|
||||
import {isDef} from '../isDef'
|
||||
/**
|
||||
* 给一个值添加单位(像素 px)
|
||||
* @param value 要添加单位的值,可以是字符串或数字
|
||||
* @returns 添加了单位的值,如果值为 null 则返回 null
|
||||
*/
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export function addUnit(value?: string | number): string | null {
|
||||
if (!isDef(value)) {
|
||||
return null;
|
||||
}
|
||||
value = String(value); // 将值转换为字符串
|
||||
// 如果值是数字,则在后面添加单位 "px",否则保持原始值
|
||||
return isNumeric(value) ? `${value}px` : value;
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
function addUnit(value: string): string
|
||||
function addUnit(value: number): string
|
||||
function addUnit(value: any|null): string|null {
|
||||
if (!isDef(value)) {
|
||||
return null;
|
||||
}
|
||||
value = `${value}` //value.toString(); // 将值转换为字符串
|
||||
|
||||
// 如果值是数字,则在后面添加单位 "px",否则保持原始值
|
||||
return isNumeric(value) ? `${value}px` : value;
|
||||
}
|
||||
export {addUnit}
|
||||
// #endif
|
||||
|
||||
|
||||
// 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)
|
82
uni_modules/lime-shared/animation/bezier.ts
Normal file
82
uni_modules/lime-shared/animation/bezier.ts
Normal file
@ -0,0 +1,82 @@
|
||||
export function cubicBezier(p1x : number, p1y : number, p2x : number, p2y : number):(x: number)=> number {
|
||||
const ZERO_LIMIT = 1e-6;
|
||||
// Calculate the polynomial coefficients,
|
||||
// implicit first and last control points are (0,0) and (1,1).
|
||||
const ax = 3 * p1x - 3 * p2x + 1;
|
||||
const bx = 3 * p2x - 6 * p1x;
|
||||
const cx = 3 * p1x;
|
||||
|
||||
const ay = 3 * p1y - 3 * p2y + 1;
|
||||
const by = 3 * p2y - 6 * p1y;
|
||||
const cy = 3 * p1y;
|
||||
|
||||
function sampleCurveDerivativeX(t : number) : number {
|
||||
// `ax t^3 + bx t^2 + cx t` expanded using Horner's rule
|
||||
return (3 * ax * t + 2 * bx) * t + cx;
|
||||
}
|
||||
|
||||
function sampleCurveX(t : number) : number {
|
||||
return ((ax * t + bx) * t + cx) * t;
|
||||
}
|
||||
|
||||
function sampleCurveY(t : number) : number {
|
||||
return ((ay * t + by) * t + cy) * t;
|
||||
}
|
||||
|
||||
// Given an x value, find a parametric value it came from.
|
||||
function solveCurveX(x : number) : number {
|
||||
let t2 = x;
|
||||
let derivative : number;
|
||||
let x2 : number;
|
||||
|
||||
// https://trac.webkit.org/browser/trunk/Source/WebCore/platform/animation
|
||||
// first try a few iterations of Newton's method -- normally very fast.
|
||||
// http://en.wikipedia.org/wikiNewton's_method
|
||||
for (let i = 0; i < 8; i++) {
|
||||
// f(t) - x = 0
|
||||
x2 = sampleCurveX(t2) - x;
|
||||
if (Math.abs(x2) < ZERO_LIMIT) {
|
||||
return t2;
|
||||
}
|
||||
derivative = sampleCurveDerivativeX(t2);
|
||||
// == 0, failure
|
||||
/* istanbul ignore if */
|
||||
if (Math.abs(derivative) < ZERO_LIMIT) {
|
||||
break;
|
||||
}
|
||||
t2 -= x2 / derivative;
|
||||
}
|
||||
|
||||
// Fall back to the bisection method for reliability.
|
||||
// bisection
|
||||
// http://en.wikipedia.org/wiki/Bisection_method
|
||||
let t1 = 1;
|
||||
/* istanbul ignore next */
|
||||
let t0 = 0;
|
||||
|
||||
/* istanbul ignore next */
|
||||
t2 = x;
|
||||
/* istanbul ignore next */
|
||||
while (t1 > t0) {
|
||||
x2 = sampleCurveX(t2) - x;
|
||||
if (Math.abs(x2) < ZERO_LIMIT) {
|
||||
return t2;
|
||||
}
|
||||
if (x2 > 0) {
|
||||
t1 = t2;
|
||||
} else {
|
||||
t0 = t2;
|
||||
}
|
||||
t2 = (t1 + t0) / 2;
|
||||
}
|
||||
|
||||
// Failure
|
||||
return t2;
|
||||
}
|
||||
|
||||
return function (x : number) : number {
|
||||
return sampleCurveY(solveCurveX(x));
|
||||
}
|
||||
|
||||
// return solve;
|
||||
}
|
2
uni_modules/lime-shared/animation/ease.ts
Normal file
2
uni_modules/lime-shared/animation/ease.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import {cubicBezier} from './bezier';
|
||||
export let ease = cubicBezier(0.25, 0.1, 0.25, 1);
|
10
uni_modules/lime-shared/animation/index.ts
Normal file
10
uni_modules/lime-shared/animation/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export * from './uvue.uts'
|
||||
// #endif
|
||||
|
||||
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export * from './vue.ts'
|
||||
// #endif
|
97
uni_modules/lime-shared/animation/useTransition.ts
Normal file
97
uni_modules/lime-shared/animation/useTransition.ts
Normal file
@ -0,0 +1,97 @@
|
||||
// @ts-nocheck
|
||||
import { ComponentPublicInstance } from 'vue'
|
||||
import { ease } from './ease';
|
||||
import { Timeline, Animation } from './';
|
||||
export type UseTransitionOptions = {
|
||||
duration ?: number
|
||||
immediate ?: boolean
|
||||
context ?: ComponentPublicInstance
|
||||
}
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
import { ref, watch, Ref } from '@/uni_modules/lime-shared/vue'
|
||||
|
||||
export function useTransition(percent : Ref<number>|(() => number), options : UseTransitionOptions) : Ref<number> {
|
||||
const current = ref(0)
|
||||
const { immediate, duration = 300 } = options
|
||||
let tl:Timeline|null = null;
|
||||
let timer = -1
|
||||
const isFunction = typeof percent === 'function'
|
||||
watch(isFunction ? percent : () => percent.value, (v) => {
|
||||
if(tl == null){
|
||||
tl = new Timeline()
|
||||
}
|
||||
tl.start();
|
||||
tl.add(
|
||||
new Animation(
|
||||
current.value,
|
||||
v,
|
||||
duration,
|
||||
0,
|
||||
ease,
|
||||
nowValue => {
|
||||
current.value = nowValue
|
||||
clearTimeout(timer)
|
||||
if(current.value == v){
|
||||
timer = setTimeout(()=>{
|
||||
tl?.pause();
|
||||
tl = null
|
||||
}, duration)
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}, { immediate })
|
||||
|
||||
return current
|
||||
}
|
||||
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
type UseTransitionReturnType = Ref<number>
|
||||
export function useTransition(source : any, options : UseTransitionOptions) : UseTransitionReturnType {
|
||||
const outputRef : Ref<number> = ref(0)
|
||||
const immediate = options.immediate ?? false
|
||||
const duration = options.duration ?? 300
|
||||
const context = options.context //as ComponentPublicInstance | null
|
||||
let tl:Timeline|null = null;
|
||||
let timer = -1
|
||||
const watchFunc = (v : number) => {
|
||||
if(tl == null){
|
||||
tl = new Timeline()
|
||||
}
|
||||
tl!.start();
|
||||
tl!.add(
|
||||
new Animation(
|
||||
outputRef.value,
|
||||
v,
|
||||
duration,
|
||||
0,
|
||||
ease,
|
||||
nowValue => {
|
||||
outputRef.value = nowValue //nowValue < 0.0001 ? 0 : Math.abs(v - nowValue) < 0.00001 ? v : nowValue;
|
||||
clearTimeout(timer)
|
||||
if(outputRef.value == v){
|
||||
timer = setTimeout(()=>{
|
||||
tl?.pause();
|
||||
tl = null
|
||||
}, duration)
|
||||
}
|
||||
}
|
||||
), null
|
||||
);
|
||||
}
|
||||
|
||||
if (context != null && typeof source == 'string') {
|
||||
context.$watch(source, watchFunc, { immediate } as WatchOptions)
|
||||
} else {
|
||||
watch(source, watchFunc, { immediate } as WatchOptions)
|
||||
}
|
||||
|
||||
const stop = ()=>{
|
||||
|
||||
}
|
||||
return outputRef //as UseTransitionReturnType
|
||||
}
|
||||
|
||||
// #endif
|
112
uni_modules/lime-shared/animation/uvue.uts
Normal file
112
uni_modules/lime-shared/animation/uvue.uts
Normal file
@ -0,0 +1,112 @@
|
||||
// @ts-nocheck
|
||||
export class Timeline {
|
||||
state : string
|
||||
animations : Set<Animation> = new Set<Animation>()
|
||||
delAnimations : Animation[] = []
|
||||
startTimes : Map<Animation, number> = new Map<Animation, number>()
|
||||
pauseTime : number = 0
|
||||
pauseStart : number = Date.now()
|
||||
tickHandler : number = 0
|
||||
tickHandlers : number[] = []
|
||||
tick : (() => void) | null = null
|
||||
constructor() {
|
||||
this.state = 'Initiated';
|
||||
}
|
||||
start() {
|
||||
if (!(this.state === 'Initiated')) return;
|
||||
this.state = 'Started';
|
||||
|
||||
let startTime = Date.now();
|
||||
this.pauseTime = 0;
|
||||
this.tick = () => {
|
||||
let now = Date.now();
|
||||
this.animations.forEach((animation : Animation) => {
|
||||
let t:number;
|
||||
const ani = this.startTimes.get(animation)
|
||||
if (ani == null) return
|
||||
if (ani < startTime) {
|
||||
t = now - startTime - animation.delay - this.pauseTime;
|
||||
} else {
|
||||
t = now - ani - animation.delay - this.pauseTime;
|
||||
}
|
||||
if (t > animation.duration) {
|
||||
this.delAnimations.push(animation)
|
||||
// 不能在 foreach 里面 对 集合进行删除操作
|
||||
// this.animations.delete(animation);
|
||||
t = animation.duration;
|
||||
}
|
||||
if (t > 0) animation.run(t);
|
||||
})
|
||||
// 不能在 foreach 里面 对 集合进行删除操作
|
||||
while (this.delAnimations.length > 0) {
|
||||
const animation = this.delAnimations.pop();
|
||||
if (animation == null) return
|
||||
this.animations.delete(animation);
|
||||
}
|
||||
clearTimeout(this.tickHandler);
|
||||
if (this.state != 'Started') return
|
||||
this.tickHandler = setTimeout(() => {
|
||||
this.tick!()
|
||||
}, 1000 / 60)
|
||||
// this.tickHandlers.push(this.tickHandler)
|
||||
}
|
||||
this.tick!()
|
||||
}
|
||||
pause() {
|
||||
if (!(this.state === 'Started')) return;
|
||||
this.state = 'Paused';
|
||||
this.pauseStart = Date.now();
|
||||
clearTimeout(this.tickHandler);
|
||||
}
|
||||
resume() {
|
||||
if (!(this.state === 'Paused')) return;
|
||||
this.state = 'Started';
|
||||
this.pauseTime += Date.now() - this.pauseStart;
|
||||
this.tick!();
|
||||
}
|
||||
reset() {
|
||||
this.pause();
|
||||
this.state = 'Initiated';
|
||||
this.pauseTime = 0;
|
||||
this.pauseStart = 0;
|
||||
this.animations.clear()
|
||||
this.delAnimations.clear()
|
||||
this.startTimes.clear()
|
||||
this.tickHandler = 0;
|
||||
}
|
||||
add(animation : Animation, startTime ?: number | null) {
|
||||
if (startTime == null) startTime = Date.now();
|
||||
this.animations.add(animation);
|
||||
this.startTimes.set(animation, startTime);
|
||||
}
|
||||
}
|
||||
|
||||
export class Animation {
|
||||
startValue : number
|
||||
endValue : number
|
||||
duration : number
|
||||
timingFunction : (t : number) => number
|
||||
delay : number
|
||||
template : (t : number) => void
|
||||
constructor(
|
||||
startValue : number,
|
||||
endValue : number,
|
||||
duration : number,
|
||||
delay : number,
|
||||
timingFunction : (t : number) => number,
|
||||
template : (v : number) => void) {
|
||||
this.startValue = startValue;
|
||||
this.endValue = endValue;
|
||||
this.duration = duration;
|
||||
this.timingFunction = timingFunction;
|
||||
this.delay = delay;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
run(time : number) {
|
||||
let range = this.endValue - this.startValue;
|
||||
let progress = time / this.duration
|
||||
if(progress != 1) progress = this.timingFunction(progress)
|
||||
this.template(this.startValue + range * progress)
|
||||
}
|
||||
}
|
123
uni_modules/lime-shared/animation/vue.ts
Normal file
123
uni_modules/lime-shared/animation/vue.ts
Normal file
@ -0,0 +1,123 @@
|
||||
// @ts-nocheck
|
||||
const TICK = Symbol('tick');
|
||||
const TICK_HANDLER = Symbol('tick-handler');
|
||||
const ANIMATIONS = Symbol('animations');
|
||||
const START_TIMES = Symbol('start-times');
|
||||
const PAUSE_START = Symbol('pause-start');
|
||||
const PAUSE_TIME = Symbol('pause-time');
|
||||
const _raf = typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame : function(cb: Function) {return setTimeout(cb, 1000/60)}
|
||||
const _caf = typeof cancelAnimationFrame !== 'undefined' ? cancelAnimationFrame: function(id: any) {clearTimeout(id)}
|
||||
|
||||
// const TICK = 'tick';
|
||||
// const TICK_HANDLER = 'tick-handler';
|
||||
// const ANIMATIONS = 'animations';
|
||||
// const START_TIMES = 'start-times';
|
||||
// const PAUSE_START = 'pause-start';
|
||||
// const PAUSE_TIME = 'pause-time';
|
||||
// const _raf = function(callback):number|null {return setTimeout(callback, 1000/60)}
|
||||
// const _caf = function(id: number):void {clearTimeout(id)}
|
||||
|
||||
export class Timeline {
|
||||
state: string
|
||||
constructor() {
|
||||
this.state = 'Initiated';
|
||||
this[ANIMATIONS] = new Set();
|
||||
this[START_TIMES] = new Map();
|
||||
}
|
||||
start() {
|
||||
if (!(this.state === 'Initiated')) return;
|
||||
this.state = 'Started';
|
||||
|
||||
let startTime = Date.now();
|
||||
this[PAUSE_TIME] = 0;
|
||||
this[TICK] = () => {
|
||||
let now = Date.now();
|
||||
this[ANIMATIONS].forEach((animation) => {
|
||||
let t: number;
|
||||
if (this[START_TIMES].get(animation) < startTime) {
|
||||
t = now - startTime - animation.delay - this[PAUSE_TIME];
|
||||
} else {
|
||||
t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME];
|
||||
}
|
||||
|
||||
if (t > animation.duration) {
|
||||
this[ANIMATIONS].delete(animation);
|
||||
t = animation.duration;
|
||||
}
|
||||
if (t > 0) animation.run(t);
|
||||
})
|
||||
// for (let animation of this[ANIMATIONS]) {
|
||||
// let t: number;
|
||||
// console.log('animation', animation)
|
||||
// if (this[START_TIMES].get(animation) < startTime) {
|
||||
// t = now - startTime - animation.delay - this[PAUSE_TIME];
|
||||
// } else {
|
||||
// t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME];
|
||||
// }
|
||||
|
||||
// if (t > animation.duration) {
|
||||
// this[ANIMATIONS].delete(animation);
|
||||
// t = animation.duration;
|
||||
// }
|
||||
// if (t > 0) animation.run(t);
|
||||
// }
|
||||
this[TICK_HANDLER] = _raf(this[TICK]);
|
||||
};
|
||||
this[TICK]();
|
||||
}
|
||||
pause() {
|
||||
if (!(this.state === 'Started')) return;
|
||||
this.state = 'Paused';
|
||||
|
||||
this[PAUSE_START] = Date.now();
|
||||
_caf(this[TICK_HANDLER]);
|
||||
}
|
||||
resume() {
|
||||
if (!(this.state === 'Paused')) return;
|
||||
this.state = 'Started';
|
||||
|
||||
this[PAUSE_TIME] += Date.now() - this[PAUSE_START];
|
||||
this[TICK]();
|
||||
}
|
||||
reset() {
|
||||
this.pause();
|
||||
this.state = 'Initiated';
|
||||
this[PAUSE_TIME] = 0;
|
||||
this[PAUSE_START] = 0;
|
||||
this[ANIMATIONS] = new Set();
|
||||
this[START_TIMES] = new Map();
|
||||
this[TICK_HANDLER] = null;
|
||||
}
|
||||
add(animation: any, startTime?: number) {
|
||||
if (arguments.length < 2) startTime = Date.now();
|
||||
this[ANIMATIONS].add(animation);
|
||||
this[START_TIMES].set(animation, startTime);
|
||||
}
|
||||
}
|
||||
|
||||
export class Animation {
|
||||
startValue: number
|
||||
endValue: number
|
||||
duration: number
|
||||
timingFunction: (t: number) => number
|
||||
delay: number
|
||||
template: (t: number) => void
|
||||
constructor(startValue: number, endValue: number, duration: number, delay: number, timingFunction: (t: number) => number, template: (v: number) => void) {
|
||||
timingFunction = timingFunction || (v => v);
|
||||
template = template || (v => v);
|
||||
|
||||
this.startValue = startValue;
|
||||
this.endValue = endValue;
|
||||
this.duration = duration;
|
||||
this.timingFunction = timingFunction;
|
||||
this.delay = delay;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
run(time: number) {
|
||||
let range = this.endValue - this.startValue;
|
||||
let progress = time / this.duration
|
||||
if(progress != 1) progress = this.timingFunction(progress)
|
||||
this.template(this.startValue + range * progress)
|
||||
}
|
||||
}
|
10
uni_modules/lime-shared/arrayBufferToFile/index.ts
Normal file
10
uni_modules/lime-shared/arrayBufferToFile/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
|
||||
// #ifdef UNI-APP-X
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export * from './uvue.uts'
|
||||
// #endif
|
||||
// #endif
|
10
uni_modules/lime-shared/arrayBufferToFile/uvue.uts
Normal file
10
uni_modules/lime-shared/arrayBufferToFile/uvue.uts
Normal file
@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
// import {platform} from '../platform'
|
||||
/**
|
||||
* buffer转路径
|
||||
* @param {Object} buffer
|
||||
*/
|
||||
// @ts-nocheck
|
||||
export function arrayBufferToFile(buffer: ArrayBuffer, name?: string, format?:string):Promise<(File|string)> {
|
||||
console.error('[arrayBufferToFile] 当前环境不支持')
|
||||
}
|
63
uni_modules/lime-shared/arrayBufferToFile/vue.ts
Normal file
63
uni_modules/lime-shared/arrayBufferToFile/vue.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
uni_modules/lime-shared/base64ToArrayBuffer/index.ts
Normal file
13
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 {
|
||||
|
||||
}
|
||||
}
|
9
uni_modules/lime-shared/base64ToPath/index.ts
Normal file
9
uni_modules/lime-shared/base64ToPath/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export * from './uvue.uts'
|
||||
// #endif
|
22
uni_modules/lime-shared/base64ToPath/uvue.uts
Normal file
22
uni_modules/lime-shared/base64ToPath/uvue.uts
Normal file
@ -0,0 +1,22 @@
|
||||
// @ts-nocheck
|
||||
import { processFile, ProcessFileOptions } from '@/uni_modules/lime-file-utils'
|
||||
|
||||
/**
|
||||
* base64转路径
|
||||
* @param {Object} base64
|
||||
*/
|
||||
export function base64ToPath(base64: string, filename: string | null = null):Promise<string> {
|
||||
return new Promise((resolve,reject) => {
|
||||
processFile({
|
||||
type: 'toDataURL',
|
||||
path: base64,
|
||||
filename,
|
||||
success(res: string){
|
||||
resolve(res)
|
||||
},
|
||||
fail(err){
|
||||
reject(err)
|
||||
}
|
||||
} as ProcessFileOptions)
|
||||
})
|
||||
}
|
75
uni_modules/lime-shared/base64ToPath/vue.ts
Normal file
75
uni_modules/lime-shared/base64ToPath/vue.ts
Normal file
@ -0,0 +1,75 @@
|
||||
// @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) || [];
|
||||
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
uni_modules/lime-shared/camelCase/index.ts
Normal file
21
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):string => {
|
||||
if (index == 0 && !isPascalCase) {
|
||||
return word.toLowerCase(); // 第一个单词全小写
|
||||
}
|
||||
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
||||
});
|
||||
|
||||
// 将数组中的单词拼接成一个字符串
|
||||
return camelCased.join('');
|
||||
};
|
67
uni_modules/lime-shared/canIUseCanvas2d/index.ts
Normal file
67
uni_modules/lime-shared/canIUseCanvas2d/index.ts
Normal file
@ -0,0 +1,67 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
|
||||
// #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;
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
/** 环境是否支持canvas 2d */
|
||||
export function canIUseCanvas2d(): boolean {
|
||||
// #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
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID || APP-NVUE || APP-VUE
|
||||
return false;
|
||||
// #endif
|
||||
}
|
36
uni_modules/lime-shared/changelog.md
Normal file
36
uni_modules/lime-shared/changelog.md
Normal file
@ -0,0 +1,36 @@
|
||||
## 0.1.6(2024-07-24)
|
||||
- fix: vue2 app ts需要明确的后缀,所有补全
|
||||
- chore: 减少依赖
|
||||
## 0.1.5(2024-07-21)
|
||||
- feat: 删除 Hooks
|
||||
- feat: 兼容uniappx
|
||||
## 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
uni_modules/lime-shared/clamp/index.ts
Normal file
16
uni_modules/lime-shared/clamp/index.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 将一个值限制在指定的范围内
|
||||
* @param val 要限制的值
|
||||
* @param min 最小值
|
||||
* @param max 最大值
|
||||
* @returns 限制后的值
|
||||
*/
|
||||
export function clamp(val: number, min: number, max: number): number {
|
||||
return Math.max(min, Math.min(max, val));
|
||||
}
|
||||
|
||||
|
||||
// console.log(clamp(5 ,0, 10)); // 输出: 5(在范围内,不做更改)
|
||||
// console.log(clamp(-5 ,0, 10)); // 输出: 0(小于最小值,被限制为最小值)
|
||||
// console.log(clamp(15 ,0, 10)); // 输出: 10(大于最大值,被限制为最大值)
|
10
uni_modules/lime-shared/cloneDeep/index.ts
Normal file
10
uni_modules/lime-shared/cloneDeep/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export * from './uvue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export * from './vue.ts'
|
||||
// #endif
|
17
uni_modules/lime-shared/cloneDeep/uvue.ts
Normal file
17
uni_modules/lime-shared/cloneDeep/uvue.ts
Normal file
@ -0,0 +1,17 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 深度克隆一个对象或数组
|
||||
* @param obj 要克隆的对象或数组
|
||||
* @returns 克隆后的对象或数组
|
||||
*/
|
||||
export function cloneDeep<T>(obj: any): T {
|
||||
// 如果传入的对象是基本数据类型(如字符串、数字等),则直接返回
|
||||
// if(['number', 'string'].includes(typeof obj) || Array.isArray(obj)){
|
||||
// return obj as T
|
||||
// }
|
||||
if(typeof obj == 'object'){
|
||||
return JSON.parse(JSON.stringify(obj as T)) as T;
|
||||
}
|
||||
return obj as T
|
||||
}
|
||||
|
103
uni_modules/lime-shared/cloneDeep/vue.ts
Normal file
103
uni_modules/lime-shared/cloneDeep/vue.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
uni_modules/lime-shared/closest/index.ts
Normal file
22
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):number {
|
||||
return arr.reduce((pre: number, cur: number):number =>
|
||||
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
|
139
uni_modules/lime-shared/components/lime-shared/lime-shared.vue
Normal file
139
uni_modules/lime-shared/components/lime-shared/lime-shared.vue
Normal file
@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<view id="shared" style="height: 500px; width: 300px; background-color: aqua;">
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { getRect, getAllRect } from '@/uni_modules/lime-shared/getRect'
|
||||
|
||||
import { camelCase } from '@/uni_modules/lime-shared/camelCase'
|
||||
import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
|
||||
import { clamp } from '@/uni_modules/lime-shared/clamp'
|
||||
import { cloneDeep } from '@/uni_modules/lime-shared/cloneDeep'
|
||||
import { closest } from '@/uni_modules/lime-shared/closest'
|
||||
import { debounce } from '@/uni_modules/lime-shared/debounce'
|
||||
import { fillZero } from '@/uni_modules/lime-shared/fillZero'
|
||||
import { floatAdd } from '@/uni_modules/lime-shared/floatAdd'
|
||||
import { getClassStr } from '@/uni_modules/lime-shared/getClassStr'
|
||||
import { getCurrentPage } from '@/uni_modules/lime-shared/getCurrentPage'
|
||||
import { getStyleStr } from '@/uni_modules/lime-shared/getStyleStr'
|
||||
import { hasOwn } from '@/uni_modules/lime-shared/hasOwn'
|
||||
import { isBase64 } from '@/uni_modules/lime-shared/isBase64'
|
||||
import { isBrowser } from '@/uni_modules/lime-shared/isBrowser'
|
||||
import { isDef } from '@/uni_modules/lime-shared/isDef'
|
||||
import { isEmpty } from '@/uni_modules/lime-shared/isEmpty'
|
||||
import { isFunction } from '@/uni_modules/lime-shared/isFunction'
|
||||
import { isNumber } from '@/uni_modules/lime-shared/isNumber'
|
||||
import { isNumeric } from '@/uni_modules/lime-shared/isNumeric'
|
||||
import { isObject } from '@/uni_modules/lime-shared/isObject'
|
||||
import { isPromise } from '@/uni_modules/lime-shared/isPromise'
|
||||
import { isString } from '@/uni_modules/lime-shared/isString'
|
||||
import { kebabCase } from '@/uni_modules/lime-shared/kebabCase'
|
||||
import { raf, doubleRaf } from '@/uni_modules/lime-shared/raf'
|
||||
import { random } from '@/uni_modules/lime-shared/random'
|
||||
import { range } from '@/uni_modules/lime-shared/range'
|
||||
import { sleep } from '@/uni_modules/lime-shared/sleep'
|
||||
import { throttle } from '@/uni_modules/lime-shared/throttle'
|
||||
import { toArray } from '@/uni_modules/lime-shared/toArray'
|
||||
import { toBoolean } from '@/uni_modules/lime-shared/toBoolean'
|
||||
import { toNumber } from '@/uni_modules/lime-shared/toNumber'
|
||||
import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
|
||||
import { getCurrentInstance } from '@/uni_modules/lime-shared/vue'
|
||||
|
||||
// #ifdef VUE2
|
||||
type UTSJSONObject = any
|
||||
// #endif
|
||||
|
||||
const context = getCurrentInstance()
|
||||
getRect('#shared', context!).then(res =>{
|
||||
console.log('res', res.bottom)
|
||||
})
|
||||
getAllRect('#shared', context).then(res =>{
|
||||
console.log('res', res)
|
||||
})
|
||||
|
||||
|
||||
console.log('camelCase::', camelCase("hello world"));
|
||||
console.log('camelCase::', camelCase("my_name_is_john", true));
|
||||
console.log('canIUseCanvas2d::', canIUseCanvas2d());
|
||||
console.log('clamp::', clamp(5 ,0, 10));
|
||||
console.log('cloneDeep::', cloneDeep<UTSJSONObject>({a:5}));
|
||||
console.log('closest::', closest([1, 3, 5, 7, 9], 6));
|
||||
|
||||
|
||||
|
||||
|
||||
const saveData = (data: any) => {
|
||||
// 模拟保存数据的操作
|
||||
console.log(`Saving data: ${data}`);
|
||||
}
|
||||
|
||||
const debouncedSaveData = debounce(saveData, 500);
|
||||
debouncedSaveData('Data 1');
|
||||
debouncedSaveData('Data 2');
|
||||
|
||||
console.log('fillZero', fillZero(1))
|
||||
console.log('floatAdd', floatAdd(0.1, 0.2))
|
||||
console.log('getClassStr', getClassStr({hover: true}))
|
||||
console.log('getStyleStr', getStyleStr({ color: 'red', fontSize: '16px', backgroundColor: '', border: null }))
|
||||
console.log('hasOwn', hasOwn({a: true}, 'key'))
|
||||
console.log('isBase64::', isBase64("SGVsbG8sIFdvcmxkIQ=="));
|
||||
console.log('isBrowser::', isBrowser);
|
||||
console.log('isDef::', isDef('6'));
|
||||
console.log('isEmpty::', isEmpty({a: true}));
|
||||
|
||||
const b = () =>{}
|
||||
console.log('isFunction::', isFunction(b));
|
||||
console.log('isNumber::', isNumber('6'));
|
||||
console.log('isNumeric::', isNumeric('6'));
|
||||
console.log('isObject::', isObject({}));
|
||||
|
||||
const promise = ():Promise<boolean> => {
|
||||
return new Promise((resolve) => {
|
||||
resolve(true)
|
||||
})
|
||||
}
|
||||
const a = promise()
|
||||
console.log('isPromise::', isPromise(a));
|
||||
console.log('isString::', isString('null'));
|
||||
console.log('kebabCase::', kebabCase('my love'));
|
||||
console.log('raf::', raf(()=>{
|
||||
console.log('raf:::1')
|
||||
}));
|
||||
console.log('doubleRaf::', doubleRaf(()=>{
|
||||
console.log('doubleRaf:::1')
|
||||
}));
|
||||
console.log('random', random(0, 10))
|
||||
console.log('random', random(0, 1, 2))
|
||||
console.log('range', range(0, 10, 2))
|
||||
console.log('sleep', sleep(300).then(res => {
|
||||
console.log('log')
|
||||
}))
|
||||
|
||||
const handleScroll = (a: string) => {
|
||||
console.log("Scroll event handled!", a);
|
||||
}
|
||||
|
||||
// // 使用节流函数对 handleScroll 进行节流,间隔时间为 500 毫秒
|
||||
const throttledScroll = throttle(handleScroll, 500);
|
||||
throttledScroll('5');
|
||||
const page = getCurrentPage()
|
||||
console.log('getCurrentPage::', page)
|
||||
|
||||
console.log('toArray', toArray<number>(5))
|
||||
console.log('toBoolean', toBoolean(5))
|
||||
console.log('toNumber', toNumber('5'))
|
||||
console.log('unitConvert', unitConvert('5'))
|
||||
|
||||
// uni.getImageInfo({
|
||||
// src: '/static/logo.png',
|
||||
// success(res) {
|
||||
// console.log('res', res)
|
||||
// }
|
||||
// })
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
9
uni_modules/lime-shared/createAnimation/index.ts
Normal file
9
uni_modules/lime-shared/createAnimation/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X
|
||||
export * from './type.ts'
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
|
||||
// #ifdef UNI-APP-X
|
||||
export * from './uvue.ts'
|
||||
// #endif
|
25
uni_modules/lime-shared/createAnimation/type.ts
Normal file
25
uni_modules/lime-shared/createAnimation/type.ts
Normal file
@ -0,0 +1,25 @@
|
||||
export type CreateAnimationOptions = {
|
||||
/**
|
||||
* 动画持续时间,单位ms
|
||||
*/
|
||||
duration ?: number;
|
||||
/**
|
||||
* 定义动画的效果
|
||||
* - linear: 动画从头到尾的速度是相同的
|
||||
* - ease: 动画以低速开始,然后加快,在结束前变慢
|
||||
* - ease-in: 动画以低速开始
|
||||
* - ease-in-out: 动画以低速开始和结束
|
||||
* - ease-out: 动画以低速结束
|
||||
* - step-start: 动画第一帧就跳至结束状态直到结束
|
||||
* - step-end: 动画一直保持开始状态,最后一帧跳到结束状态
|
||||
*/
|
||||
timingFunction ?: string //'linear' | 'ease' | 'ease-in' | 'ease-in-out' | 'ease-out' | 'step-start' | 'step-end';
|
||||
/**
|
||||
* 动画延迟时间,单位 ms
|
||||
*/
|
||||
delay ?: number;
|
||||
/**
|
||||
* 设置transform-origin
|
||||
*/
|
||||
transformOrigin ?: string;
|
||||
}
|
5
uni_modules/lime-shared/createAnimation/uvue.ts
Normal file
5
uni_modules/lime-shared/createAnimation/uvue.ts
Normal file
@ -0,0 +1,5 @@
|
||||
// @ts-nocheck
|
||||
// export * from '@/uni_modules/lime-animateIt'
|
||||
export function createAnimation() {
|
||||
console.error('当前环境不支持,请使用:lime-animateIt')
|
||||
}
|
148
uni_modules/lime-shared/createAnimation/vue.ts
Normal file
148
uni_modules/lime-shared/createAnimation/vue.ts
Normal file
@ -0,0 +1,148 @@
|
||||
// @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动画太慢
|
||||
|
||||
|
||||
|
||||
import { CreateAnimationOptions } from './type'
|
||||
// #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
|
||||
}
|
||||
// export 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
|
||||
return uni.createAnimation({ ...options })
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
return new LimeAnimation(options)
|
||||
// #endif
|
||||
}
|
70
uni_modules/lime-shared/createImage/index.ts
Normal file
70
uni_modules/lime-shared/createImage/index.ts
Normal file
@ -0,0 +1,70 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
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 && this['tagName'] == 'canvas' && !('toBlob' in this) || canvas && !('toBlob' in canvas)){
|
||||
return new Image()
|
||||
} else if(isBrowser) {
|
||||
return new window.Image()
|
||||
}
|
||||
return new Image()
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export function createImage(){
|
||||
console.error('当前环境不支持')
|
||||
}
|
||||
// #endif
|
10
uni_modules/lime-shared/debounce/index.ts
Normal file
10
uni_modules/lime-shared/debounce/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export * from './uvue.ts'
|
||||
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export * from './vue.ts'
|
||||
// #endif
|
36
uni_modules/lime-shared/debounce/uvue.ts
Normal file
36
uni_modules/lime-shared/debounce/uvue.ts
Normal file
@ -0,0 +1,36 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 防抖函数,通过延迟一定时间来限制函数的执行频率。
|
||||
* @param fn 要防抖的函数。
|
||||
* @param wait 触发防抖的等待时间,单位为毫秒。
|
||||
* @returns 防抖函数。
|
||||
*/
|
||||
export function debounce<A extends any>(fn : (args: A)=> void, wait = 300): (args: A)=> void {
|
||||
let timer = -1
|
||||
|
||||
return (args: A) => {
|
||||
if (timer >-1) {clearTimeout(timer)};
|
||||
|
||||
timer = setTimeout(()=>{
|
||||
fn(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"
|
40
uni_modules/lime-shared/debounce/vue.ts
Normal file
40
uni_modules/lime-shared/debounce/vue.ts
Normal file
@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
type Timeout = ReturnType<typeof setTimeout> | null;
|
||||
/**
|
||||
* 防抖函数,通过延迟一定时间来限制函数的执行频率。
|
||||
* @param fn 要防抖的函数。
|
||||
* @param wait 触发防抖的等待时间,单位为毫秒。
|
||||
* @returns 防抖函数。
|
||||
*/
|
||||
export function debounce<A extends any, R>(
|
||||
fn : (...args : A) => R,
|
||||
wait : number = 300) : (...args : A) => void {
|
||||
let timer : Timeout = null;
|
||||
|
||||
return function (...args : A) {
|
||||
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"
|
9
uni_modules/lime-shared/exif/index.ts
Normal file
9
uni_modules/lime-shared/exif/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export * from './uvue.ts'
|
||||
// #endif
|
7
uni_modules/lime-shared/exif/uvue.ts
Normal file
7
uni_modules/lime-shared/exif/uvue.ts
Normal file
@ -0,0 +1,7 @@
|
||||
class EXIF {
|
||||
constructor(){
|
||||
console.error('当前环境不支持')
|
||||
}
|
||||
}
|
||||
|
||||
export const exif = new EXIF()
|
1057
uni_modules/lime-shared/exif/vue.ts
Normal file
1057
uni_modules/lime-shared/exif/vue.ts
Normal file
File diff suppressed because it is too large
Load Diff
11
uni_modules/lime-shared/fillZero/index.ts
Normal file
11
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
uni_modules/lime-shared/floatAdd/index.ts
Normal file
36
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;
|
||||
}
|
53
uni_modules/lime-shared/getClassStr/index.ts
Normal file
53
uni_modules/lime-shared/getClassStr/index.ts
Normal file
@ -0,0 +1,53 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
import { isNumber } from '../isNumber'
|
||||
import { isString } from '../isString'
|
||||
import { isDef } from '../isDef'
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* 获取对象的类名字符串
|
||||
* @param obj - 需要处理的对象
|
||||
* @returns 由对象属性作为类名组成的字符串
|
||||
*/
|
||||
export function getClassStr<T>(obj : T) : string {
|
||||
let classNames : string[] = [];
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
if (obj instanceof UTSJSONObject) {
|
||||
(obj as UTSJSONObject).toMap().forEach((value, key) => {
|
||||
if (isDef(value)) {
|
||||
if (isNumber(value)) {
|
||||
classNames.push(key);
|
||||
}
|
||||
if (isString(value) && value !== '') {
|
||||
classNames.push(key);
|
||||
}
|
||||
if (typeof value == 'boolean' && (value as boolean)) {
|
||||
classNames.push(key);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
// 遍历对象的属性
|
||||
for (let key in obj) {
|
||||
// 检查属性确实属于对象自身且其值为true
|
||||
if ((obj as any).hasOwnProperty(key) && obj[key]) {
|
||||
// 将属性名添加到类名数组中
|
||||
classNames.push(key);
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// 将类名数组用空格连接成字符串并返回
|
||||
return classNames.join(' ');
|
||||
}
|
||||
|
||||
|
||||
// 示例
|
||||
// const obj = { foo: true, bar: false, baz: true };
|
||||
// const classNameStr = getClassStr(obj);
|
||||
// console.log(classNameStr); // 输出: "foo baz"
|
9
uni_modules/lime-shared/getCurrentPage/index.ts
Normal file
9
uni_modules/lime-shared/getCurrentPage/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export * from './uvue.uts'
|
||||
// #endif
|
5
uni_modules/lime-shared/getCurrentPage/uvue.uts
Normal file
5
uni_modules/lime-shared/getCurrentPage/uvue.uts
Normal file
@ -0,0 +1,5 @@
|
||||
// @ts-nocheck
|
||||
export const getCurrentPage = ():Page => {
|
||||
const pages = getCurrentPages();
|
||||
return pages[pages.length - 1]
|
||||
};
|
6
uni_modules/lime-shared/getCurrentPage/vue.ts
Normal file
6
uni_modules/lime-shared/getCurrentPage/vue.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;
|
||||
};
|
62
uni_modules/lime-shared/getLocalFilePath/index.ts
Normal file
62
uni_modules/lime-shared/getLocalFilePath/index.ts
Normal file
@ -0,0 +1,62 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef APP-NVUE || APP-VUE
|
||||
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
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-ANDROID || APP-IOS
|
||||
export { getResourcePath as getLocalFilePath } from '@/uni_modules/lime-file-utils'
|
||||
// export const getLocalFilePath = (path : string) : string => {
|
||||
// let uri = path
|
||||
// if (uri.startsWith("http") || uri.startsWith("<svg") || uri.startsWith("data:image/svg+xml")) {
|
||||
// return uri
|
||||
// }
|
||||
// if (uri.startsWith("file://")) {
|
||||
// uri = uri.substring("file://".length)
|
||||
// } else if (uri.startsWith("unifile://")) {
|
||||
// uri = UTSAndroid.convert2AbsFullPath(uri)
|
||||
// } else {
|
||||
// uri = UTSAndroid.convert2AbsFullPath(uri)
|
||||
// if (uri.startsWith("/android_asset/")) {
|
||||
// uri = uri.replace("/android_asset/", "")
|
||||
// }
|
||||
// }
|
||||
// if (new File(uri).exists()) {
|
||||
// return uri
|
||||
// } else {
|
||||
// return null
|
||||
// }
|
||||
// // return UTSAndroid.convert2AbsFullPath(path)
|
||||
// }
|
||||
// #endif
|
||||
// #ifdef APP-IOS
|
||||
// export const getLocalFilePath = (path : string) : string => {
|
||||
// try {
|
||||
// let uri = path
|
||||
// if (uri.startsWith("http") || uri.startsWith("<svg") || uri.startsWith("data:image/svg+xml")) {
|
||||
// return uri
|
||||
// }
|
||||
// if (uri.startsWith("file://")) {
|
||||
// return uri.substring("file://".length)
|
||||
// } else if (path.startsWith("/var/")) {
|
||||
// return path
|
||||
// }
|
||||
// return UTSiOS.getResourcePath(path)
|
||||
// } catch (e) {
|
||||
// return null
|
||||
// }
|
||||
// // return UTSiOS.getResourcePath(path)
|
||||
// }
|
||||
// #endif
|
9
uni_modules/lime-shared/getRect/index.ts
Normal file
9
uni_modules/lime-shared/getRect/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export * from './uvue.uts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export * from './vue.ts'
|
||||
// #endif
|
16
uni_modules/lime-shared/getRect/uvue.uts
Normal file
16
uni_modules/lime-shared/getRect/uvue.uts
Normal file
@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
export function getRect(selector : string, context: ComponentInternalInstance):Promise<NodeInfo> {
|
||||
return new Promise((resolve)=>{
|
||||
uni.createSelectorQuery().in(context).select(selector).boundingClientRect(res =>{
|
||||
resolve(res as NodeInfo)
|
||||
}).exec();
|
||||
})
|
||||
}
|
||||
|
||||
export function getAllRect(selector : string, context: ComponentInternalInstance):Promise<NodeInfo[]> {
|
||||
return new Promise((resolve)=>{
|
||||
uni.createSelectorQuery().in(context).selectAll(selector).boundingClientRect(res =>{
|
||||
resolve(res as NodeInfo[])
|
||||
}).exec();
|
||||
})
|
||||
}
|
117
uni_modules/lime-shared/getRect/vue.ts
Normal file
117
uni_modules/lime-shared/getRect/vue.ts
Normal file
@ -0,0 +1,117 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef APP-NVUE
|
||||
// 当编译环境是 APP-NVUE 时,引入 uni.requireNativePlugin('dom'),具体插件用途未知
|
||||
const dom = uni.requireNativePlugin('dom')
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* 获取节点信息
|
||||
* @param selector 选择器字符串
|
||||
* @param context ComponentInternalInstance 对象
|
||||
* @param node 是否获取node
|
||||
* @returns 包含节点信息的 Promise 对象
|
||||
*/
|
||||
export function getRect(selector : string, context : ComponentInternalInstance, node: boolean = false) {
|
||||
// 之前是个对象,现在改成实例,防止旧版会报错
|
||||
if(context== null) {
|
||||
return Promise.reject('context is null')
|
||||
}
|
||||
if(context.context){
|
||||
context = context.context
|
||||
}
|
||||
// #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).select(selector);
|
||||
const result = (rect: UniNamespace.NodeInfo) => {
|
||||
if (rect) {
|
||||
resolve(rect)
|
||||
} else {
|
||||
reject('no rect')
|
||||
}
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
dom.boundingClientRect(result).exec()
|
||||
} else {
|
||||
dom.fields({
|
||||
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
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
export function getAllRect(selector : string, context: ComponentInternalInstance, node:boolean = false) {
|
||||
if(context== null) {
|
||||
return Promise.reject('context is null')
|
||||
}
|
||||
// #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).selectAll(selector);
|
||||
const result = (rect: UniNamespace.NodeInfo[]) => {
|
||||
if (rect) {
|
||||
resolve(rect)
|
||||
} else {
|
||||
reject('no rect')
|
||||
}
|
||||
}
|
||||
if (!node) {
|
||||
dom.boundingClientRect(result).exec()
|
||||
} else {
|
||||
dom.fields({
|
||||
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
|
||||
});
|
||||
};
|
54
uni_modules/lime-shared/getStyleStr/index.ts
Normal file
54
uni_modules/lime-shared/getStyleStr/index.ts
Normal file
@ -0,0 +1,54 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
interface CSSProperties {
|
||||
[key : string] : string | number | null
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef VUE3
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
type CSSProperties = UTSJSONObject
|
||||
// #endif
|
||||
// #endif
|
||||
/**
|
||||
* 将字符串转换为带有连字符分隔的小写形式
|
||||
* @param key - 要转换的字符串
|
||||
* @returns 转换后的字符串
|
||||
*/
|
||||
export function toLowercaseSeparator(key : string):string {
|
||||
return key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取样式对象对应的样式字符串
|
||||
* @param style - CSS样式对象
|
||||
* @returns 由非空有效样式属性键值对组成的字符串
|
||||
*/
|
||||
export function getStyleStr(style : CSSProperties) : string {
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
let styleStr = '';
|
||||
style.toMap().forEach((value, key) => {
|
||||
if(value !== null && value != '') {
|
||||
styleStr += `${toLowercaseSeparator(key as string)}: ${value};`
|
||||
}
|
||||
})
|
||||
return styleStr
|
||||
// #endif
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
return Object.keys(style)
|
||||
.filter(
|
||||
(key) =>
|
||||
style[key] !== undefined &&
|
||||
style[key] !== null &&
|
||||
style[key] !== '')
|
||||
.map((key : string) => `${toLowercaseSeparator(key)}: ${style[key]};`)
|
||||
.join(' ');
|
||||
// #endif
|
||||
}
|
||||
|
||||
// 示例
|
||||
// const style = { color: 'red', fontSize: '16px', backgroundColor: '', border: null };
|
||||
// const styleStr = getStyleStr(style);
|
||||
// console.log(styleStr);
|
||||
// 输出: "color: red; font-size: 16px;"
|
39
uni_modules/lime-shared/getStyleStr/index_.uts
Normal file
39
uni_modules/lime-shared/getStyleStr/index_.uts
Normal file
@ -0,0 +1,39 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X
|
||||
interface CSSProperties {
|
||||
[key : string] : string | number
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef UNI-APP-X
|
||||
type CSSProperties = UTSJSONObject
|
||||
// #endif
|
||||
/**
|
||||
* 将字符串转换为带有连字符分隔的小写形式
|
||||
* @param key - 要转换的字符串
|
||||
* @returns 转换后的字符串
|
||||
*/
|
||||
export function toLowercaseSeparator(key : string) : string {
|
||||
return key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取样式对象对应的样式字符串
|
||||
* @param style - CSS样式对象
|
||||
* @returns 由非空有效样式属性键值对组成的字符串
|
||||
*/
|
||||
export function getStyleStr(style : CSSProperties) : string {
|
||||
let styleStr = '';
|
||||
style.toMap().forEach((value, key) => {
|
||||
if(value !== null && value != '') {
|
||||
styleStr += `${toLowercaseSeparator(key as string)}: ${value};`
|
||||
}
|
||||
})
|
||||
return styleStr
|
||||
}
|
||||
|
||||
// 示例
|
||||
// const style = { color: 'red', fontSize: '16px', backgroundColor: '', border: null };
|
||||
// const styleStr = getStyleStr(style);
|
||||
// console.log(styleStr);
|
||||
// 输出: "color: red; font-size: 16px;"
|
9
uni_modules/lime-shared/hasOwn/index.ts
Normal file
9
uni_modules/lime-shared/hasOwn/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export * from './uvue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export * from './vue.ts'
|
||||
// #endif
|
39
uni_modules/lime-shared/hasOwn/uvue.ts
Normal file
39
uni_modules/lime-shared/hasOwn/uvue.ts
Normal file
@ -0,0 +1,39 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 检查对象或数组是否具有指定的属性或键
|
||||
* @param obj 要检查的对象或数组
|
||||
* @param key 指定的属性或键
|
||||
* @returns 如果对象或数组具有指定的属性或键,则返回true;否则返回false
|
||||
*/
|
||||
function hasOwn(obj: UTSJSONObject, key: string): boolean
|
||||
function hasOwn(obj: Map<string, unknown>, key: string): boolean
|
||||
function hasOwn(obj: any, key: string): boolean {
|
||||
if(obj instanceof UTSJSONObject){
|
||||
return obj[key] != null
|
||||
}
|
||||
if(obj instanceof Map<string, unknown>){
|
||||
return (obj as Map<string, unknown>).has(key)
|
||||
}
|
||||
return false
|
||||
}
|
||||
export {
|
||||
hasOwn
|
||||
}
|
||||
// 示例
|
||||
// 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' 属性
|
30
uni_modules/lime-shared/hasOwn/vue.ts
Normal file
30
uni_modules/lime-shared/hasOwn/vue.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
uni_modules/lime-shared/index.ts
Normal file
43
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'
|
||||
|
23
uni_modules/lime-shared/isBase64/index.ts
Normal file
23
uni_modules/lime-shared/isBase64/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
* 判断一个字符串是否为Base64编码。
|
||||
* Base64编码的字符串只包含A-Z、a-z、0-9、+、/ 和 = 这些字符。
|
||||
* @param {string} str - 要检查的字符串。
|
||||
* @returns {boolean} 如果字符串是Base64编码,返回true,否则返回false。
|
||||
*/
|
||||
export function isBase64(str: string): boolean {
|
||||
const base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
||||
return base64Regex.test(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断一个字符串是否为Base64编码的data URI。
|
||||
* Base64编码的data URI通常以"data:"开头,后面跟着MIME类型和编码信息,然后是Base64编码的数据。
|
||||
* @param {string} str - 要检查的字符串。
|
||||
* @returns {boolean} 如果字符串是Base64编码的data URI,返回true,否则返回false。
|
||||
*/
|
||||
export function isBase64DataUri(str: string): boolean {
|
||||
const dataUriRegex = /^data:([a-zA-Z]+\/[a-zA-Z0-9-+.]+)(;base64)?,([a-zA-Z0-9+/]+={0,2})$/;
|
||||
return dataUriRegex.test(str);
|
||||
}
|
8
uni_modules/lime-shared/isBrowser/index.ts
Normal file
8
uni_modules/lime-shared/isBrowser/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef WEB
|
||||
export const isBrowser = typeof window !== 'undefined';
|
||||
// #endif
|
||||
|
||||
// #ifndef WEB
|
||||
export const isBrowser = false;
|
||||
// #endif
|
23
uni_modules/lime-shared/isDef/index.ts
Normal file
23
uni_modules/lime-shared/isDef/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 检查一个值是否已定义(不为 undefined)且不为 null
|
||||
* @param value 要检查的值
|
||||
* @returns 如果值已定义且不为 null,则返回 true;否则返回 false
|
||||
*/
|
||||
// #ifndef UNI-APP-X
|
||||
export function isDef(value: unknown): boolean {
|
||||
return value !== undefined && value !== null;
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef UNI-APP-X
|
||||
export function isDef(value : any|null) : boolean {
|
||||
// #ifdef APP-ANDROID || APP-IOS
|
||||
return value != null;
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID || APP-IOS
|
||||
return value != null && value != undefined;
|
||||
// #endif
|
||||
}
|
||||
// #endif
|
83
uni_modules/lime-shared/isEmpty/index.ts
Normal file
83
uni_modules/lime-shared/isEmpty/index.ts
Normal file
@ -0,0 +1,83 @@
|
||||
// @ts-nocheck
|
||||
import {isDef} from '../isDef'
|
||||
import {isString} from '../isString'
|
||||
import {isNumber} from '../isNumber'
|
||||
/**
|
||||
* 判断一个值是否为空。
|
||||
*
|
||||
* 对于字符串,去除首尾空格后判断长度是否为0。
|
||||
* 对于数组,判断长度是否为0。
|
||||
* 对于对象,判断键的数量是否为0。
|
||||
* 对于null或undefined,直接返回true。
|
||||
* 其他类型(如数字、布尔值等)默认不为空。
|
||||
*
|
||||
* @param {any} value - 要检查的值。
|
||||
* @returns {boolean} 如果值为空,返回true,否则返回false。
|
||||
*/
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export function isEmpty(value : any | null) : boolean {
|
||||
// 为null
|
||||
if(!isDef(value)){
|
||||
return true
|
||||
}
|
||||
// 为空字符
|
||||
if(isString(value)){
|
||||
return value.toString().trim().length == 0
|
||||
}
|
||||
// 为数值
|
||||
if(isNumber(value)){
|
||||
return false
|
||||
}
|
||||
|
||||
if(typeof value == 'object'){
|
||||
// 数组
|
||||
if(Array.isArray(value)){
|
||||
return (value as Array<unknown>).length == 0
|
||||
}
|
||||
// Map
|
||||
if(value instanceof Map<unknown, unknown>) {
|
||||
return value.size == 0
|
||||
}
|
||||
// Set
|
||||
if(value instanceof Set<unknown>) {
|
||||
return value.size == 0
|
||||
}
|
||||
if(value instanceof UTSJSONObject) {
|
||||
return value.toMap().size == 0
|
||||
}
|
||||
return JSON.stringify(value) == '{}'
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export function isEmpty(value: any): boolean {
|
||||
// 检查是否为null或undefined
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查字符串是否为空
|
||||
if (typeof value === 'string') {
|
||||
return value.trim().length === 0;
|
||||
}
|
||||
|
||||
// 检查数组是否为空
|
||||
if (Array.isArray(value)) {
|
||||
return value.length === 0;
|
||||
}
|
||||
|
||||
// 检查对象是否为空
|
||||
if (typeof value === 'object') {
|
||||
return Object.keys(value).length === 0;
|
||||
}
|
||||
|
||||
// 其他类型(如数字、布尔值等)不为空
|
||||
return false;
|
||||
}
|
||||
// #endif
|
16
uni_modules/lime-shared/isFunction/index.ts
Normal file
16
uni_modules/lime-shared/isFunction/index.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 检查一个值是否为函数类型
|
||||
* @param val 要检查的值
|
||||
* @returns 如果值的类型是函数类型,则返回 true;否则返回 false
|
||||
*/
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export const isFunction = (val: any):boolean => typeof val == 'function';
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export const isFunction = (val: unknown): val is Function =>
|
||||
typeof val === 'function';
|
||||
// #endif
|
26
uni_modules/lime-shared/isNumber/index.ts
Normal file
26
uni_modules/lime-shared/isNumber/index.ts
Normal file
@ -0,0 +1,26 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 检查一个值是否为数字类型
|
||||
* @param value 要检查的值,可以是 number 类型或 string 类型的数字
|
||||
* @returns 如果值是数字类型且不是 NaN,则返回 true;否则返回 false
|
||||
*/
|
||||
|
||||
// #ifndef UNI-APP-X
|
||||
export function isNumber(value: number | string | null): boolean {
|
||||
return typeof value === 'number' && !isNaN(value);
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef UNI-APP-X
|
||||
export function isNumber(value: any|null): boolean {
|
||||
// #ifdef APP-ANDROID
|
||||
return ['Byte', 'UByte','Short','UShort','Int','UInt','Long','ULong','Float','Double','number'].includes(typeof value)
|
||||
// #endif
|
||||
// #ifdef APP-IOS
|
||||
return ['Int8', 'UInt8','Int16','UInt16','Int32','UInt32','Int64','UInt64','Int','UInt','Float','Float16','Float32','Float64','Double', 'number'].includes(typeof value)
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID || APP-IOS
|
||||
return typeof value === 'number' && !isNaN(value);
|
||||
// #endif
|
||||
}
|
||||
// #endif
|
33
uni_modules/lime-shared/isNumeric/index.ts
Normal file
33
uni_modules/lime-shared/isNumeric/index.ts
Normal file
@ -0,0 +1,33 @@
|
||||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
* 检查一个值是否为数字类型或表示数字的字符串
|
||||
* @param value 要检查的值,可以是 string 类型或 number 类型
|
||||
* @returns 如果值是数字类型或表示数字的字符串,则返回 true;否则返回 false
|
||||
*/
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export function isNumeric(value: string | number | undefined | null): boolean {
|
||||
return /^(-)?\d+(\.\d+)?$/.test(value);
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
import {isNumber} from '../isNumber';
|
||||
import {isString} from '../isString';
|
||||
export function isNumeric(value : any|null) : boolean {
|
||||
if(value == null) {
|
||||
return false
|
||||
}
|
||||
if(isNumber(value)) {
|
||||
return true
|
||||
} else if(isString(value)) {
|
||||
// const regex = "-?\\d+(\\.\\d+)?".toRegex()
|
||||
const regex = new RegExp("^(-)?\\d+(\\.\\d+)?$")
|
||||
return regex.test(value as string) //regex.matches(value as string)
|
||||
}
|
||||
return false
|
||||
// return /^(-)?\d+(\.\d+)?$/.test(value);
|
||||
}
|
||||
// #endif
|
19
uni_modules/lime-shared/isObject/index.ts
Normal file
19
uni_modules/lime-shared/isObject/index.ts
Normal file
@ -0,0 +1,19 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 检查一个值是否为对象类型
|
||||
* @param val 要检查的值
|
||||
* @returns 如果值的类型是对象类型,则返回 true;否则返回 false
|
||||
*/
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export const isObject = (val : unknown) : val is Record<any, any> =>
|
||||
val !== null && typeof val === 'object';
|
||||
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export const isObject = (val : any | null) : boolean =>{
|
||||
return val !== null && typeof val === 'object';
|
||||
}
|
||||
// #endif
|
22
uni_modules/lime-shared/isPromise/index.ts
Normal file
22
uni_modules/lime-shared/isPromise/index.ts
Normal file
@ -0,0 +1,22 @@
|
||||
// @ts-nocheck
|
||||
import {isFunction} from '../isFunction'
|
||||
import {isObject} from '../isObject'
|
||||
/**
|
||||
* 检查一个值是否为 Promise 类型
|
||||
* @param val 要检查的值
|
||||
* @returns 如果值的类型是 Promise 类型,则返回 true;否则返回 false
|
||||
*/
|
||||
// #ifndef APP-ANDROID
|
||||
export const isPromise = <T = any>(val: unknown): val is Promise<T> => {
|
||||
// 使用 isObject 函数判断值是否为对象类型
|
||||
// 使用 isFunction 函数判断值是否具有 then 方法和 catch 方法
|
||||
return isObject(val) && isFunction(val.then) && isFunction(val.catch);
|
||||
};
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-ANDROID
|
||||
export const isPromise = (val: any): boolean => {
|
||||
return val instanceof Promise<unknown>
|
||||
};
|
||||
// #endif
|
19
uni_modules/lime-shared/isString/index.ts
Normal file
19
uni_modules/lime-shared/isString/index.ts
Normal file
@ -0,0 +1,19 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 检查一个值是否为字符串类型
|
||||
* @param str 要检查的值
|
||||
* @returns 如果值的类型是字符串类型,则返回 true;否则返回 false
|
||||
*/
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
// export const isString = (str: unknown): str is string => typeof str === 'string';
|
||||
export function isString (str: unknown): str is string {
|
||||
return typeof str == 'string'
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export function isString (str: any): boolean {
|
||||
return typeof str == 'string'
|
||||
}
|
||||
// #endif
|
24
uni_modules/lime-shared/kebabCase/index.ts
Normal file
24
uni_modules/lime-shared/kebabCase/index.ts
Normal file
@ -0,0 +1,24 @@
|
||||
// @ts-nocheck
|
||||
// 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
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
.replace(/[A-Z]/g, (match : string, _ : number, _ : string) : string => `${separator}${match.toLowerCase()}`) // 将大写字母替换为连接符加小写字母
|
||||
// #endif
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
.replace(/[A-Z]/g, (match : string) : string => `${separator}${match.toLowerCase()}`) // 将大写字母替换为连接符加小写字母
|
||||
// #endif
|
||||
.replace(/[\s_-]+/g, separator) // 将空格、下划线和短横线替换为指定连接符
|
||||
.replace(new RegExp(`^${separator}|${separator}$`, "g"), "") // 删除开头和结尾的连接符
|
||||
.toLowerCase(); // 将结果转换为全小写
|
||||
}
|
86
uni_modules/lime-shared/package.json
Normal file
86
uni_modules/lime-shared/package.json
Normal file
@ -0,0 +1,86 @@
|
||||
{
|
||||
"id": "lime-shared",
|
||||
"displayName": "lime-shared",
|
||||
"version": "0.1.6",
|
||||
"description": "本人插件的几个公共函数,获取当前页,图片的base64转临时路径,图片的exif信息等",
|
||||
"keywords": [
|
||||
"lime-shared",
|
||||
"exif"
|
||||
],
|
||||
"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",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-uvue": "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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
uni_modules/lime-shared/pathToBase64/index.ts
Normal file
9
uni_modules/lime-shared/pathToBase64/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export * from './uvue.uts'
|
||||
// #endif
|
17
uni_modules/lime-shared/pathToBase64/uvue.uts
Normal file
17
uni_modules/lime-shared/pathToBase64/uvue.uts
Normal file
@ -0,0 +1,17 @@
|
||||
// @ts-nocheck
|
||||
// import { processFile, ProcessFileOptions } from '@/uni_modules/lime-file-utils'
|
||||
export function pathToBase64(path : string) : Promise<string> {
|
||||
console.error('pathToBase64: 当前环境不支持,请使用 【lime-file-utils】')
|
||||
// return new Promise((resolve, reject) => {
|
||||
// processFile({
|
||||
// type: 'toDataURL',
|
||||
// path,
|
||||
// success(res : string) {
|
||||
// resolve(res)
|
||||
// },
|
||||
// fail(err: any){
|
||||
// reject(err)
|
||||
// }
|
||||
// } as ProcessFileOptions)
|
||||
// })
|
||||
}
|
121
uni_modules/lime-shared/pathToBase64/vue.ts
Normal file
121
uni_modules/lime-shared/pathToBase64/vue.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
|
||||
})
|
||||
}
|
34
uni_modules/lime-shared/platform/index.ts
Normal file
34
uni_modules/lime-shared/platform/index.ts
Normal file
@ -0,0 +1,34 @@
|
||||
// @ts-nocheck
|
||||
export function getPlatform():Uni {
|
||||
// #ifdef MP-WEIXIN
|
||||
return wx
|
||||
// #endif
|
||||
// #ifdef MP-BAIDU
|
||||
return swan
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY
|
||||
return my
|
||||
// #endif
|
||||
// #ifdef MP-JD
|
||||
return jd
|
||||
// #endif
|
||||
// #ifdef MP-QQ
|
||||
return qq
|
||||
// #endif
|
||||
// #ifdef MP-360
|
||||
return qh
|
||||
// #endif
|
||||
// #ifdef MP-KUAISHOU
|
||||
return ks
|
||||
// #endif
|
||||
// #ifdef MP-LARK||MP-TOUTIAO
|
||||
return tt
|
||||
// #endif
|
||||
// #ifdef MP-DINGTALK
|
||||
return dd
|
||||
// #endif
|
||||
// #ifdef QUICKAPP-WEBVIEW || QUICKAPP-WEBVIEW-UNION || QUICKAPP-WEBVIEW-HUAWEI
|
||||
return qa
|
||||
// #endif
|
||||
return uni
|
||||
}
|
10
uni_modules/lime-shared/raf/index.ts
Normal file
10
uni_modules/lime-shared/raf/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export * from './uvue.ts'
|
||||
// #endif
|
20
uni_modules/lime-shared/raf/uvue.ts
Normal file
20
uni_modules/lime-shared/raf/uvue.ts
Normal file
@ -0,0 +1,20 @@
|
||||
// @ts-nocheck
|
||||
// import {isBrowser} from '../isBrowser'
|
||||
|
||||
// 是否支持被动事件监听
|
||||
export const supportsPassive = true;
|
||||
|
||||
// 请求动画帧
|
||||
export function raf(fn: TimerCallback): number {
|
||||
return setTimeout(fn, 1000 / 30);
|
||||
}
|
||||
|
||||
// 取消动画帧
|
||||
export function cancelRaf(id: number) {
|
||||
clearTimeout(id);
|
||||
}
|
||||
|
||||
// 双倍动画帧
|
||||
export function doubleRaf(fn: TimerCallback): void {
|
||||
raf(() => raf(fn)); // 在下一帧回调中再次请求动画帧,实现双倍动画帧效果
|
||||
}
|
33
uni_modules/lime-shared/raf/vue.ts
Normal file
33
uni_modules/lime-shared/raf/vue.ts
Normal file
@ -0,0 +1,33 @@
|
||||
// @ts-nocheck
|
||||
// import { isBrowser } from '../isBrowser'
|
||||
type Callback = () => void//Function
|
||||
// 是否支持被动事件监听
|
||||
export const supportsPassive = true;
|
||||
|
||||
// 请求动画帧
|
||||
export function raf(fn : Callback) : number {
|
||||
// #ifndef WEB
|
||||
return setTimeout(fn, 1000 / 30); // 请求动画帧
|
||||
// #endif
|
||||
// #ifdef WEB
|
||||
return requestAnimationFrame(fn); // 请求动画帧
|
||||
// #endif
|
||||
}
|
||||
|
||||
// 取消动画帧
|
||||
export function cancelRaf(id : number) {
|
||||
// 如果是在浏览器环境下,使用 cancelAnimationFrame 方法
|
||||
// #ifdef WEB
|
||||
cancelAnimationFrame(id); // 取消动画帧
|
||||
// #endif
|
||||
// #ifndef WEB
|
||||
clearTimeout(id); // 取消动画帧
|
||||
// #endif
|
||||
}
|
||||
|
||||
// 双倍动画帧
|
||||
export function doubleRaf(fn : Callback) : void {
|
||||
raf(() => {
|
||||
raf(fn)
|
||||
}); // 在下一帧回调中再次请求动画帧,实现双倍动画帧效果
|
||||
}
|
24
uni_modules/lime-shared/random/index.ts
Normal file
24
uni_modules/lime-shared/random/index.ts
Normal file
@ -0,0 +1,24 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 生成一个指定范围内的随机数
|
||||
* @param min 随机数的最小值
|
||||
* @param max 随机数的最大值
|
||||
* @param fixed 随机数的小数位数,默认为 0
|
||||
* @returns 生成的随机数
|
||||
*/
|
||||
|
||||
export function random(min: number, max: number, fixed: number = 0):number {
|
||||
// 将 min 和 max 转换为数字类型
|
||||
// min = +min || 0;
|
||||
// max = +max || 0;
|
||||
// 计算随机数范围内的一个随机数
|
||||
const num = Math.random() * (max - min) + min;
|
||||
// 如果 fixed 参数为 0,则返回四舍五入的整数随机数;否则保留固定小数位数
|
||||
// Number
|
||||
return fixed == 0 ? Math.round(num) : parseFloat(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 之间的一个保留三位小数的随机数
|
36
uni_modules/lime-shared/range/index.ts
Normal file
36
uni_modules/lime-shared/range/index.ts
Normal file
@ -0,0 +1,36 @@
|
||||
// @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), 0);
|
||||
// 创建一个长度为 length 的数组
|
||||
// #ifdef APP-ANDROID
|
||||
const result = Array.fromNative(new IntArray(length.toInt()));
|
||||
// #endif
|
||||
// #ifndef APP-ANDROID
|
||||
const result = new Array(length);
|
||||
// #endif
|
||||
|
||||
// 使用循环生成数字范围数组
|
||||
let _start = start
|
||||
while (length-- > 0) {
|
||||
// 根据 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]
|
445
uni_modules/lime-shared/readme.md
Normal file
445
uni_modules/lime-shared/readme.md
Normal file
@ -0,0 +1,445 @@
|
||||
# lime-shared 工具库
|
||||
- 本人插件的几个公共函数
|
||||
- 按需引入
|
||||
|
||||
|
||||
## 引入
|
||||
按需引入只会引入相关的方法,不要看着 插件函数列表多 而占空间,只要不引用不会被打包
|
||||
```js
|
||||
import {getRect} from '@/uni_modules/lime-shared/getRect'
|
||||
```
|
||||
|
||||
## 目录
|
||||
+ [getRect](#api_getRect): 获取节点尺寸信息
|
||||
+ [addUnit](#api_addUnit): 将未带单位的数值添加px,如果有单位则返回原值
|
||||
+ [unitConvert](#api_unitConvert): 将带有rpx|px的字符转成number,若本身是number则直接返回
|
||||
+ [canIUseCanvas2d](#api_canIUseCanvas2d): 环境是否支持使用 canvas 2d
|
||||
+ [getCurrentPage](#api_getCurrentPage): 获取当前页
|
||||
+ [base64ToPath](#api_base64ToPath): 把base64的图片转成临时路径
|
||||
+ [pathToBase64](#api_pathToBase64): 把图片的临时路径转成base64
|
||||
+ [sleep](#api_sleep): async 内部程序等待一定时间后再执行
|
||||
+ [throttle](#api_throttle): 节流
|
||||
+ [debounce](#api_debounce): 防抖
|
||||
+ [random](#api_random): 返回指定范围的随机数
|
||||
+ [range](#api_range): 生成区间数组
|
||||
+ [clamp](#api_clamp): 夹在min和max之间的数值
|
||||
+ [floatAdd](#api_floatAdd): 返回两个浮点数相加的结果
|
||||
+ [fillZero](#api_fillZero): 补零,如果传入的是个位数则在前面补0
|
||||
+ [exif](#api_exif): 获取图片exif
|
||||
+ [selectComponent](#api_selectComponent): 获取页面或当前实例的指定组件
|
||||
+ [createAnimation](#api_createAnimation): uni.createAnimation
|
||||
+ [animation](#api_animation): 数值从一个值到另一个值的过渡
|
||||
+ [camelCase](#api_camelCase): 字符串转换为 camelCase 或 PascalCase 风格的命名约定
|
||||
+ [kebabCase](#api_kebabCase): 将字符串转换为指定连接符的命名约定
|
||||
+ [closest](#api_closest): 在给定数组中找到最接近目标数字的元素
|
||||
+ [isBase64](#api_isBase64): 判断字符串是否为base64
|
||||
+ [isNumber](#api_isNumber): 检查一个值是否为数字类型
|
||||
+ [isNumeric](#api_isNumeric): 检查一个值是否为数字类型或表示数字的字符串
|
||||
+ [isString](#api_isString): 检查一个值是否为字符串类型
|
||||
+ [composition-api](#api_composition-api): 为兼容vue2
|
||||
|
||||
## Utils
|
||||
|
||||
|
||||
### getRect <a id="api_getRect"></a>
|
||||
- 返回节点尺寸信息
|
||||
|
||||
```js
|
||||
// 组件内需要传入上下文
|
||||
// 如果是nvue 则需要在节点上加与id或class同名的ref
|
||||
getRect('#id',{context: this}).then(res => {})
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
|
||||
### addUnit <a id="api_addUnit"></a>
|
||||
- 将未带单位的数值添加px,如果有单位则返回原值
|
||||
|
||||
```js
|
||||
addUnit(10)
|
||||
// 10px
|
||||
```
|
||||
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
|
||||
### unitConvert <a id="api_unitConvert"></a>
|
||||
- 将带有rpx|px的字符转成number,若本身是number则直接返回
|
||||
|
||||
```js
|
||||
unitConvert('10rpx')
|
||||
// 5 设备不同 返回的值也不同
|
||||
unitConvert('10px')
|
||||
// 10
|
||||
unitConvert(10)
|
||||
// 10
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
### canIUseCanvas2d <a id="api_canIUseCanvas2d"></a>
|
||||
- 环境是否支持使用 canvas 2d
|
||||
|
||||
```js
|
||||
canIUseCanvas2d()
|
||||
// 若支持返回 true 否则 false
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
### getCurrentPage <a id="api_getCurrentPage"></a>
|
||||
- 获取当前页
|
||||
|
||||
```js
|
||||
const page = getCurrentPage()
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
### base64ToPath <a id="api_base64ToPath"></a>
|
||||
- 把base64的图片转成临时路径
|
||||
|
||||
```js
|
||||
base64ToPath(`xxxxx`).then(res => {})
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
### pathToBase64 <a id="api_pathToBase64"></a>
|
||||
- 把图片的临时路径转成base64
|
||||
|
||||
```js
|
||||
pathToBase64(`xxxxx/xxx.png`).then(res => {})
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
### sleep <a id="api_sleep"></a>
|
||||
- 睡眠,让 async 内部程序等待一定时间后再执行
|
||||
|
||||
```js
|
||||
async next () => {
|
||||
await sleep(300)
|
||||
console.log('limeui');
|
||||
}
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
### throttle <a id="api_throttle"></a>
|
||||
- 节流
|
||||
|
||||
```js
|
||||
throttle((nama) => {console.log(nama)}, 200)('limeui');
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
### debounce <a id="api_debounce"></a>
|
||||
- 防抖
|
||||
|
||||
```js
|
||||
debounce((nama) => {console.log(nama)}, 200)('limeui');
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
### random <a id="api_random"></a>
|
||||
- 返回指定范围的随机数
|
||||
|
||||
```js
|
||||
random(1, 5);
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
### range <a id="api_range"></a>
|
||||
- 生成区间数组
|
||||
|
||||
```js
|
||||
range(0, 5)
|
||||
// [0,1,2,3,4,5]
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
### clamp <a id="api_clamp"></a>
|
||||
- 夹在min和max之间的数值,如小于min,返回min, 如大于max,返回max,否侧原值返回
|
||||
|
||||
```js
|
||||
clamp(0, 10, -1)
|
||||
// 0
|
||||
clamp(0, 10, 11)
|
||||
// 10
|
||||
clamp(0, 10, 9)
|
||||
// 9
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
### floatAdd <a id="api_floatAdd"></a>
|
||||
- 返回两个浮点数相加的结果
|
||||
|
||||
```js
|
||||
floatAdd(0.1, 0.2) // 0.3
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
### fillZero <a id="api_fillZero"></a>
|
||||
- 补零,如果传入的是`个位数`则在前面补0
|
||||
|
||||
```js
|
||||
fillZero(9);
|
||||
// 09
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
### exif <a id="api_exif"></a>
|
||||
- 获取图片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)
|
||||
})
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | x |
|
||||
|
||||
|
||||
### selectComponent <a id="api_selectComponent"></a>
|
||||
- 获取页面或当前实例的指定组件,会在页面或实例向所有的节点查找(包括子组件或子子组件)
|
||||
- 仅vue3,vue2没有测试过
|
||||
|
||||
```js
|
||||
// 当前页面
|
||||
const page = getCurrentPage()
|
||||
selectComponent('.custom', {context: page}).then(res => {
|
||||
})
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | x |
|
||||
|
||||
|
||||
|
||||
### createAnimation <a id="api_createAnimation"></a>
|
||||
- 创建动画,与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)
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
### camelCase <a id="api_camelCase"></a>
|
||||
- 将字符串转换为 camelCase 或 PascalCase 风格的命名约定
|
||||
|
||||
```js
|
||||
camelCase("hello world") // helloWorld
|
||||
camelCase("hello world", true) // HelloWorld
|
||||
```
|
||||
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
### kebabCase <a id="api_kebabCase"></a>
|
||||
- 将字符串转换为指定连接符的命名约定
|
||||
|
||||
```js
|
||||
kebabCase("helloWorld") // hello-world
|
||||
kebabCase("hello world_example") // hello-world-example
|
||||
kebabCase("helloWorld", "_") // hello_world
|
||||
```
|
||||
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
|
||||
### closest <a id="api_closest"></a>
|
||||
- 在给定数组中找到最接近目标数字的元素
|
||||
|
||||
```js
|
||||
closest([1, 3, 5, 7, 9], 6) // 5
|
||||
```
|
||||
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
### isBase64 <a id="api_isBase64"></a>
|
||||
- 判断字符串是否为base64
|
||||
|
||||
```js
|
||||
isBase64('xxxxx')
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
### isNumber <a id="api_isNumber"></a>
|
||||
- 检查一个值是否为数字类型
|
||||
|
||||
```js
|
||||
isNumber('0') // false
|
||||
isNumber(0) // true
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
### isNumeric <a id="api_isNumeric"></a>
|
||||
- 检查一个值是否为数字类型或表示数字的字符串
|
||||
|
||||
```js
|
||||
isNumeric('0') // true
|
||||
isNumeric(0) // true
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
### isString <a id="api_isString"></a>
|
||||
- 检查一个值是否为数字类型或表示数字的字符串
|
||||
|
||||
```js
|
||||
isString('0') // true
|
||||
isString(0) // false
|
||||
```
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | √ |
|
||||
|
||||
|
||||
|
||||
|
||||
## composition-api <a id="api_composition-api"></a>
|
||||
- 因本人插件需要兼容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'
|
||||
```
|
||||
|
||||
##### 兼容性
|
||||
| uni-app | uni-app x |
|
||||
|------------|----------------------------------|
|
||||
| √ | x |
|
8
uni_modules/lime-shared/selectAllComponent/index.ts
Normal file
8
uni_modules/lime-shared/selectAllComponent/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef UNI-APP-X
|
||||
export * from './uvue.uts'
|
||||
// #endif
|
||||
|
||||
// #ifndef UNI-APP-X
|
||||
export * from './vue.ts'
|
||||
// #endif
|
39
uni_modules/lime-shared/selectAllComponent/uvue.uts
Normal file
39
uni_modules/lime-shared/selectAllComponent/uvue.uts
Normal file
@ -0,0 +1,39 @@
|
||||
// @ts-nocheck
|
||||
import { type ComponentPublicInstance } from 'vue';
|
||||
|
||||
type SelectOptions = {
|
||||
context : ComponentPublicInstance,
|
||||
needAll : boolean | null,
|
||||
|
||||
}
|
||||
|
||||
export function selectAllComponent(selector : string, options : UTSJSONObject) : ComponentPublicInstance[]|null {
|
||||
const context = options.get('context')! as ComponentPublicInstance;
|
||||
let needAll = options.get('needAll') as boolean;
|
||||
let result:ComponentPublicInstance[] = []
|
||||
|
||||
if(needAll == null) { needAll = true };
|
||||
|
||||
if(context.$children.length > 0) {
|
||||
const queue:ComponentPublicInstance[] = [...context.$children];
|
||||
while(queue.length > 0) {
|
||||
const child = queue.shift();
|
||||
const name = child?.$options?.name;
|
||||
if(name == selector) {
|
||||
result.push(child as ComponentPublicInstance)
|
||||
} else {
|
||||
const children = child?.$children
|
||||
if(children !== null) {
|
||||
queue.push(...children)
|
||||
}
|
||||
}
|
||||
if(result.length > 0 && !needAll) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(result.length > 0) {
|
||||
return result
|
||||
}
|
||||
return null
|
||||
}
|
151
uni_modules/lime-shared/selectAllComponent/vue.ts
Normal file
151
uni_modules/lime-shared/selectAllComponent/vue.ts
Normal file
@ -0,0 +1,151 @@
|
||||
// @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 selectAllComponent(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 = true, node} = options
|
||||
const [,prefix, name] = selector.match(reg)
|
||||
const symbolMappings = {'.': 'class', '#': 'id', '$':'ref', '@':'component'}
|
||||
|
||||
const key = symbolMappings [prefix] //prefix === '.' ? 'class' : prefix === '#' ? 'id' : 'ref';
|
||||
// #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
|
||||
}
|
7
uni_modules/lime-shared/selectComponent/index.ts
Normal file
7
uni_modules/lime-shared/selectComponent/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X
|
||||
export * from './vue.ts'
|
||||
// #endif
|
||||
// #ifdef UNI-APP-X
|
||||
export * from './uvue.uts'
|
||||
// #endif
|
75
uni_modules/lime-shared/selectComponent/uvue.uts
Normal file
75
uni_modules/lime-shared/selectComponent/uvue.uts
Normal file
@ -0,0 +1,75 @@
|
||||
// @ts-nocheck
|
||||
import { type ComponentPublicInstance } from 'vue';
|
||||
// #ifdef APP
|
||||
function findChildren(selector: string, context: ComponentPublicInstance, needAll: boolean): ComponentPublicInstance [] | null{
|
||||
let result:ComponentPublicInstance[] = []
|
||||
|
||||
if(context !== null && context.$children.length > 0) {
|
||||
const queue:ComponentPublicInstance[] = [...context.$children];
|
||||
while(queue.length > 0) {
|
||||
const child = queue.shift();
|
||||
const name = child?.$options?.name;
|
||||
if(name == selector) {
|
||||
result.push(child as ComponentPublicInstance)
|
||||
} else {
|
||||
const children = child?.$children
|
||||
if(children !== null) {
|
||||
queue.push(...children)
|
||||
}
|
||||
}
|
||||
if(result.length > 0 && !needAll) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(result.length > 0) {
|
||||
return result
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
class Query {
|
||||
context : ComponentPublicInstance | null = null
|
||||
selector : string = ''
|
||||
// components : ComponentPublicInstance[] = []
|
||||
constructor(selector : string, context : ComponentPublicInstance | null) {
|
||||
this.selector = selector
|
||||
this.context = context
|
||||
}
|
||||
in(context : ComponentPublicInstance) : Query {
|
||||
return new Query(this.selector, context)
|
||||
}
|
||||
find(): ComponentPublicInstance | null {
|
||||
const selector = this.selector
|
||||
if(selector == '') return null
|
||||
const component = findChildren(selector, this.context!, false)
|
||||
return component != null ? component[0]: null
|
||||
}
|
||||
findAll():ComponentPublicInstance[] | null {
|
||||
const selector = this.selector
|
||||
if(selector == '') return null
|
||||
return findChildren(selector, this.context!, true)
|
||||
}
|
||||
closest(): ComponentPublicInstance | null {
|
||||
const selector = this.selector
|
||||
if(selector == '') return null
|
||||
let parent = this.context!.$parent
|
||||
let name = parent?.$options?.name;
|
||||
while (parent != null && (name == null || selector != name)) {
|
||||
parent = parent.$parent
|
||||
if (parent != null) {
|
||||
name = parent.$options.name
|
||||
}
|
||||
}
|
||||
return parent
|
||||
}
|
||||
}
|
||||
|
||||
export function selectComponent(selector: string): Query{
|
||||
return new Query(selector, null)
|
||||
}
|
||||
// #endif
|
||||
|
||||
// selectComponent('selector').in(this).find()
|
||||
// selectComponent('selector').in(this).findAll()
|
||||
// selectComponent('selector').in(this).closest()
|
149
uni_modules/lime-shared/selectComponent/vue.ts
Normal file
149
uni_modules/lime-shared/selectComponent/vue.ts
Normal file
@ -0,0 +1,149 @@
|
||||
// @ts-nocheck
|
||||
// #ifdef MP
|
||||
function findChildren(selector : string, context : ComponentPublicInstance, needAll : boolean) {
|
||||
const { proxy, $vm } = context
|
||||
context = $vm || proxy
|
||||
if ((selector.startsWith('.') || selector.startsWith('#'))) {
|
||||
const queue = [context]
|
||||
let result = null
|
||||
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 selectorValue = /#|\.|@|$/.test(selector) ? selector.substring(1) : selector
|
||||
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 (child.type?.name === selectorValue || child.$?.type?.name === selectorValue) {
|
||||
result.push(child)
|
||||
} else if (child.$refs && child.$refs[selectorValue]) {
|
||||
result = child.$refs[selectorValue]
|
||||
} else if (nameMap[child.id] === selectorValue) {
|
||||
result.push(child)
|
||||
} else {
|
||||
child.$children && (queue.push(...child.$children));
|
||||
}
|
||||
if (result.length && !needAll) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return needAll ? result : result[0]
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
function findChildren(selector : string, context : ComponentPublicInstance, needAll : boolean){
|
||||
const {_, component } = context
|
||||
const child = {component: _ || component || context, children: null , subTree: null, props: null}
|
||||
let result = []
|
||||
let queue = [child]
|
||||
const selectorValue = /#|\.|@|$/.test(selector) ? selector.substring(1) : selector
|
||||
while(queue.length > 0 ) {
|
||||
const child = queue.shift()
|
||||
const {component, children , props, subTree} = child
|
||||
if(component?.type?.name == selectorValue) {
|
||||
result.push(component)
|
||||
} else if(selector.startsWith('$') && component && (props?.ref == selectorValue || component[key][selectorValue])) {
|
||||
if(props?.ref == selectorValue) {
|
||||
//exposed
|
||||
result.push(component)
|
||||
} else if(component[key][selectorValue]) {
|
||||
result.push(component[key][selectorValue])
|
||||
}
|
||||
} else if(!selector.startsWith('$') && component?.exposed && new RegExp(`\\b${selectorValue}\\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 findChildren(selector : string, context : ComponentPublicInstance, needAll : boolean){
|
||||
let result = []
|
||||
const selectorValue = /#|\.|@|$/.test(selector) ? selector.substring(1) : selector
|
||||
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(child.type && child.type.name === selectorValue) {
|
||||
result.push(component)
|
||||
} else if(props?.[key] === selectorValue && node) {
|
||||
result.push(child)
|
||||
} else if(selector.startsWith('$') && isComp && (props.ref === selectorValue || props.ref_key === selectorValue)) {
|
||||
// exposed
|
||||
result.push(component)
|
||||
} else if(!selector.startsWith('$') && isComp && new RegExp(`\\b${selectorValue}\\b`).test(props[key])) {
|
||||
// exposed
|
||||
result.push(component)
|
||||
}
|
||||
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
|
||||
|
||||
class Query {
|
||||
context : ComponentPublicInstance | null = null
|
||||
selector : string = ''
|
||||
// components : ComponentPublicInstance[] = []
|
||||
constructor(selector : string, context : ComponentPublicInstance | null) {
|
||||
this.selector = selector
|
||||
this.context = context
|
||||
}
|
||||
in(context : ComponentPublicInstance) : Query {
|
||||
return new Query(this.selector, context)
|
||||
}
|
||||
find() : ComponentPublicInstance | null {
|
||||
return findChildren(this.selector, this.context, false)
|
||||
}
|
||||
findAll() : ComponentPublicInstance[] | null {
|
||||
return findChildren(this.selector, this.context, true)
|
||||
}
|
||||
closest() : ComponentPublicInstance | null {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function selectComponent(selector: string) {
|
||||
return new Query(selector)
|
||||
}
|
275
uni_modules/lime-shared/selectElement/index.uts
Normal file
275
uni_modules/lime-shared/selectElement/index.uts
Normal file
@ -0,0 +1,275 @@
|
||||
// @ts-nocheck
|
||||
import {isDef} from '../isDef'
|
||||
import {ComponentPublicInstance} from 'vue'
|
||||
|
||||
type HasSelectorFunc = (selector : string, element : UniElement) => boolean
|
||||
|
||||
const hasSelectorClassName : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
|
||||
return element.classList.includes(selector)
|
||||
}
|
||||
const hasSelectorId : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
|
||||
return element.getAttribute("id") == selector
|
||||
}
|
||||
const hasSelectorTagName : HasSelectorFunc = (selector : string, element : UniElement) : boolean => {
|
||||
return element.tagName!.toLowerCase() == selector.toLowerCase()
|
||||
}
|
||||
|
||||
type ProcessSelectorResult = {
|
||||
selectorValue : string
|
||||
hasSelector : HasSelectorFunc
|
||||
}
|
||||
const processSelector = (selector : string) : ProcessSelectorResult => {
|
||||
|
||||
const selectorValue = /#|\./.test(selector) ? selector.substring(1) : selector
|
||||
let hasSelector : HasSelectorFunc
|
||||
|
||||
if (selector.startsWith('.')) {
|
||||
hasSelector = hasSelectorClassName
|
||||
} else if (selector.startsWith('#')) {
|
||||
hasSelector = hasSelectorId
|
||||
} else {
|
||||
hasSelector = hasSelectorTagName
|
||||
}
|
||||
|
||||
return {
|
||||
selectorValue,
|
||||
hasSelector
|
||||
} as ProcessSelectorResult
|
||||
}
|
||||
|
||||
|
||||
function isNotEmptyString(str:string): boolean {
|
||||
return str.length > 0;
|
||||
}
|
||||
|
||||
function isElement(element:UniElement|null):boolean {
|
||||
return isDef(element) && element?.tagName != 'COMMENT';
|
||||
}
|
||||
|
||||
type ElementArray = Array<UniElement|null>
|
||||
class Query {
|
||||
context : ComponentPublicInstance | null = null
|
||||
selector : string = ''
|
||||
elements : ElementArray = []
|
||||
constructor(selector : string | null, context : ComponentPublicInstance | null) {
|
||||
this.context = context
|
||||
if(selector != null){
|
||||
this.selector = selector
|
||||
}
|
||||
this.find(this.selector)
|
||||
}
|
||||
in(context : ComponentPublicInstance) : Query {
|
||||
return new Query(this.selector, context)
|
||||
}
|
||||
findAll(selector : string): Query {
|
||||
if (isDef(this.context)) {
|
||||
const root = this.context?.$el //as Element | null;
|
||||
if (isDef(root)) {
|
||||
this.elements = [root!] //as ElementArray
|
||||
}
|
||||
const { selectorValue, hasSelector } = processSelector(selector)
|
||||
const foundElements : ElementArray = [];
|
||||
|
||||
function findChildren(element : UniElement) {
|
||||
element.children.forEach((child : UniElement) => {
|
||||
if (hasSelector(selectorValue, child)) {
|
||||
foundElements.push(child)
|
||||
}
|
||||
})
|
||||
}
|
||||
this.elements.forEach(el => {
|
||||
findChildren(el!);
|
||||
});
|
||||
this.elements = foundElements
|
||||
} else if (selector.startsWith('#')) {
|
||||
const element = uni.getElementById(selector)
|
||||
if (isElement(element!)) {
|
||||
this.elements = [element]
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 在当前元素集合中查找匹配的元素
|
||||
*/
|
||||
find(selector : string) : Query {
|
||||
if (isDef(this.context)) {
|
||||
const root = this.context?.$el //as Element | null;
|
||||
if (isElement(root)) {
|
||||
this.elements = [root] //as ElementArray
|
||||
}
|
||||
if(isNotEmptyString(selector) && this.elements.length > 0){
|
||||
const { selectorValue, hasSelector } = processSelector(selector)
|
||||
const foundElements : ElementArray = [];
|
||||
function findChildren(element : UniElement) {
|
||||
element.children.forEach((child : UniElement) => {
|
||||
if (hasSelector(selectorValue, child) && foundElements.length < 1) {
|
||||
foundElements.push(child)
|
||||
}
|
||||
if (foundElements.length < 1) {
|
||||
findChildren(child);
|
||||
}
|
||||
})
|
||||
}
|
||||
this.elements.forEach(el => {
|
||||
findChildren(el!);
|
||||
});
|
||||
this.elements = foundElements
|
||||
}
|
||||
|
||||
} else if (selector.startsWith('#')) {
|
||||
const element = uni.getElementById(selector)
|
||||
if (isElement(element!)) {
|
||||
this.elements = [element]
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 获取当前元素集合的直接子元素
|
||||
*/
|
||||
children() : Query {
|
||||
// if (this.elements.length > 0) {
|
||||
// const children = this.elements.reduce((acc, el) => [...acc, ...Array.from(el.children)], []);
|
||||
// this.elements = children;
|
||||
// }
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 获取当前元素集合的父元素
|
||||
*/
|
||||
parent() : Query {
|
||||
// if (this.elements.length > 0) {
|
||||
// const parents = this.elements.map(el => el.parentElement).filter(parent => parent !== null) as ElementArray;
|
||||
// this.elements = parents
|
||||
// // this.elements = Array.from(new Set(parents));
|
||||
// }
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 获取当前元素集合的兄弟元素
|
||||
*/
|
||||
siblings() : Query {
|
||||
// if (this.elements.length > 0) {
|
||||
// const siblings = this.elements.reduce((acc, el) => [...acc, ...Array.from(el.parentElement?.children || [])], []);
|
||||
// this.elements = siblings.filter(sibling => sibling !== null && !this.elements?.includes(sibling));
|
||||
// }
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 获取当前元素集合的下一个兄弟元素
|
||||
*/
|
||||
next() : Query {
|
||||
// if (this.elements.length > 0) {
|
||||
// const nextElements = this.elements.map(el => el.nextElementSibling).filter(next => next !== null) as ElementArray;
|
||||
// this.elements = nextElements;
|
||||
// }
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 获取当前元素集合的上一个兄弟元素
|
||||
*/
|
||||
prev() : Query {
|
||||
// if (this.elements.length > 0) {
|
||||
// const prevElements = this.elements.map(el => el.previousElementSibling).filter(prev => prev !== null) as ElementArray;
|
||||
// this.elements = prevElements;
|
||||
// }
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 从当前元素开始向上查找匹配的元素
|
||||
*/
|
||||
closest(selector : string) : Query {
|
||||
if (isDef(this.context)) {
|
||||
// && this.context.$parent != null && this.context.$parent.$el !== null
|
||||
if(this.elements.length == 0 && isDef(this.context?.$parent) && isElement(this.context!.$parent?.$el)){
|
||||
this.elements = [this.context!.$parent?.$el!]
|
||||
}
|
||||
|
||||
const selectorsArray = selector.split(',')
|
||||
// const { selectorValue, hasSelector } = processSelector(selector)
|
||||
const processedSelectors = selectorsArray.map((selector: string):ProcessSelectorResult => processSelector(selector))
|
||||
const closestElements = this.elements.map((el) : UniElement | null => {
|
||||
let closestElement : UniElement | null = el
|
||||
while (closestElement !== null) {
|
||||
// if (hasSelector(selectorValue, closestElement)) {
|
||||
// break;
|
||||
// }
|
||||
const isMatchingSelector = processedSelectors.some(({selectorValue, hasSelector}):boolean => {
|
||||
return hasSelector(selectorValue, closestElement!)
|
||||
})
|
||||
if(isMatchingSelector){
|
||||
break;
|
||||
}
|
||||
closestElement = closestElement.parentElement;
|
||||
}
|
||||
return closestElement
|
||||
})
|
||||
this.elements = closestElements.filter((closest : UniElement | null) : boolean => isDef(closest))// as ElementArray
|
||||
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从当前元素集合中过滤出匹配的元素
|
||||
*/
|
||||
filter() : Query {
|
||||
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 从当前元素集合中排除匹配的元素
|
||||
*/
|
||||
not() { }
|
||||
/**
|
||||
* 从当前元素集合中查找包含匹配元素的元素
|
||||
*/
|
||||
has() { }
|
||||
/**
|
||||
* 获取当前元素集合的第一个
|
||||
*/
|
||||
first() : Query {
|
||||
if (this.elements.length > 0) {
|
||||
// this.elements = [this.elements[0]];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 最后一个元素
|
||||
*/
|
||||
last() : Query {
|
||||
if (this.elements.length > 0) {
|
||||
// this.elements = [this.elements[this.elements.length - 1]];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 获取当前元素在其兄弟元素中的索引
|
||||
*/
|
||||
index() : number | null {
|
||||
// if (this.elements.length > 0 && this.elements.length > 0 && this.elements[0].parentElement !== null) {
|
||||
// return Array.from(this.elements[0].parentElement.children).indexOf(this.elements[0]);
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
get(index : number) : UniElement | null {
|
||||
if (this.elements.length > index) {
|
||||
return this.elements[index] //as Element
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function selectElement(selector : string | null = null) : Query {
|
||||
// if(typeof selector == 'string' || selector == null){
|
||||
// return new Query(selector as string | null, null)
|
||||
// }
|
||||
// else if(selector instanceof ComponentPublicInstance){
|
||||
// return new Query(null, selector)
|
||||
// }
|
||||
return new Query(selector, null)
|
||||
}
|
||||
|
||||
// $('xxx').in(this).find('xxx')
|
||||
// $('xxx').in(this).get()
|
44
uni_modules/lime-shared/sleep/index.ts
Normal file
44
uni_modules/lime-shared/sleep/index.ts
Normal file
@ -0,0 +1,44 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 延迟指定时间后解析的 Promise
|
||||
* @param delay 延迟的时间(以毫秒为单位),默认为 300 毫秒
|
||||
* @returns 一个 Promise,在延迟结束后解析
|
||||
*/
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
function sleep(delay: number = 300):Promise<boolean> {
|
||||
return new Promise((resolve):void => {setTimeout(() => {resolve(true)}, delay)});
|
||||
}
|
||||
export {
|
||||
sleep
|
||||
}
|
||||
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export const sleep = (delay: number = 300) =>
|
||||
new Promise(resolve => setTimeout(resolve, delay));
|
||||
|
||||
// #endif
|
||||
|
||||
// 示例
|
||||
// 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();
|
77
uni_modules/lime-shared/throttle/index.ts
Normal file
77
uni_modules/lime-shared/throttle/index.ts
Normal file
@ -0,0 +1,77 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 节流函数,用于限制函数的调用频率
|
||||
* @param fn 要进行节流的函数
|
||||
* @param delay 两次调用之间的最小间隔时间
|
||||
* @returns 节流后的函数
|
||||
*/
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
// type Rfun = (...args: any[]) => void
|
||||
// type Rfun = (...args: any[]) => void
|
||||
|
||||
export function throttle<T extends any|null>(
|
||||
fn: (args : T) => void,
|
||||
delay: number):(args : T) => void {
|
||||
let flag = true; // 标记是否可以执行函数
|
||||
|
||||
return (args : T) =>{
|
||||
if(flag){
|
||||
flag = false;
|
||||
fn(args);
|
||||
|
||||
setTimeout(()=>{
|
||||
flag = true;
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
// return (...args: any[]) => {
|
||||
// // if (flag) {
|
||||
// // flag = false; // 设置为不可执行状态
|
||||
// // fn(...args); // 执行传入的函数
|
||||
|
||||
// // setTimeout(() => {
|
||||
// // flag = true; // 经过指定时间后,设置为可执行状态
|
||||
// // }, delay);
|
||||
// // }
|
||||
// };
|
||||
}
|
||||
|
||||
// #endif
|
||||
|
||||
// // 示例
|
||||
// // 定义一个被节流的函数
|
||||
// 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);
|
21
uni_modules/lime-shared/toArray/index.ts
Normal file
21
uni_modules/lime-shared/toArray/index.ts
Normal file
@ -0,0 +1,21 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 将一个或多个元素转换为数组
|
||||
* @param item 要转换为数组的元素
|
||||
* @returns 转换后的数组
|
||||
*/
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export const toArray = <T>(item: T | T[]): T[] => Array.isArray(item) ? item : [item];
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
export function toArray<T extends any>(item: any): T[] {
|
||||
return Array.isArray(item) ? item as T[] : [item as T]// as T[]
|
||||
};
|
||||
// #endif
|
||||
// 示例
|
||||
// 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"]
|
40
uni_modules/lime-shared/toBoolean/index.ts
Normal file
40
uni_modules/lime-shared/toBoolean/index.ts
Normal file
@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
import { isNumber } from '../isNumber'
|
||||
import { isString } from '../isString'
|
||||
// 函数重载,定义多个函数签名
|
||||
// function toBoolean(value : any) : boolean;
|
||||
// function toBoolean(value : string) : boolean;
|
||||
// function toBoolean(value : number) : boolean;
|
||||
// function toBoolean(value : boolean) : boolean;
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
function toBoolean(value : any | null) : boolean {
|
||||
// 根据输入值的类型,返回相应的布尔值
|
||||
// if (isNumber(value)) {
|
||||
// return (value as number) != 0;
|
||||
// }
|
||||
// if (isString(value)) {
|
||||
// return `${value}`.length > 0;
|
||||
// }
|
||||
// if (typeof value == 'boolean') {
|
||||
// return value as boolean;
|
||||
// }
|
||||
// #ifdef APP-IOS
|
||||
return value != null && value != undefined
|
||||
// #endif
|
||||
// #ifdef APP-ANDROID
|
||||
return value != null
|
||||
// #endif
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
function toBoolean(value : any | null) : value is NonNullable<typeof value> {
|
||||
return !!value//value !== null && value !== undefined;
|
||||
}
|
||||
// #endif
|
||||
|
||||
export {
|
||||
toBoolean
|
||||
}
|
28
uni_modules/lime-shared/toNumber/index.ts
Normal file
28
uni_modules/lime-shared/toNumber/index.ts
Normal file
@ -0,0 +1,28 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* 将字符串转换为数字
|
||||
* @param val 要转换的字符串
|
||||
* @returns 转换后的数字或原始字符串
|
||||
*/
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
// function toNumber(val: string): number
|
||||
// function toNumber(val: string): string
|
||||
function toNumber(val: string): number|null {
|
||||
const n = parseFloat(val); // 使用 parseFloat 函数将字符串转换为浮点数
|
||||
return isNaN(n) ? null : n; // 使用 isNaN 函数判断是否为非数字,返回转换后的数字或原始字符串
|
||||
}
|
||||
export {toNumber}
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
export function toNumber(val: string): number | string {
|
||||
const n = parseFloat(val); // 使用 parseFloat 函数将字符串转换为浮点数
|
||||
return isNaN(n) ? val : n; // 使用 isNaN 函数判断是否为非数字,返回转换后的数字或原始字符串
|
||||
}
|
||||
// #endif
|
||||
|
||||
// 示例
|
||||
// console.log(toNumber("123")); // 输出: 123
|
||||
// console.log(toNumber("3.14")); // 输出: 3.14
|
||||
// console.log(toNumber("hello")); // 输出: "hello"
|
73
uni_modules/lime-shared/unitConvert/index.ts
Normal file
73
uni_modules/lime-shared/unitConvert/index.ts
Normal file
@ -0,0 +1,73 @@
|
||||
// @ts-nocheck
|
||||
import { isString } from '../isString'
|
||||
import { isNumeric } from '../isNumeric'
|
||||
|
||||
/**
|
||||
* 单位转换函数,将字符串数字或带有单位的字符串转换为数字
|
||||
* @param value 要转换的值,可以是字符串数字或带有单位的字符串
|
||||
* @returns 转换后的数字,如果无法转换则返回0
|
||||
*/
|
||||
// #ifndef APP-IOS || APP-ANDROID
|
||||
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;
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
// #ifdef APP-IOS || APP-ANDROID
|
||||
import { isNumber } from '../isNumber'
|
||||
export function unitConvert(value : any | null) : number {
|
||||
if (isNumber(value)) {
|
||||
return value as number
|
||||
}
|
||||
// 如果是字符串数字
|
||||
if (isNumeric(value)) {
|
||||
return parseFloat(value as string);
|
||||
}
|
||||
// 如果有单位
|
||||
if (isString(value)) {
|
||||
const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g;
|
||||
const results = reg.exec(value as string);
|
||||
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;
|
||||
}
|
||||
// #endif
|
||||
// 示例
|
||||
// console.log(unitConvert("123")); // 输出: 123 (字符串数字转换为数字)
|
||||
// console.log(unitConvert("3.14em")); // 输出: 0 (无法识别的单位)
|
||||
// console.log(unitConvert("20rpx")); // 输出: 根据具体情况而定 (根据单位进行转换)
|
||||
// console.log(unitConvert(10)); // 输出: 10 (数字不需要转换)
|
16
uni_modules/lime-shared/vue/index.ts
Normal file
16
uni_modules/lime-shared/vue/index.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef VUE3
|
||||
export * from 'vue';
|
||||
// #endif
|
||||
|
||||
// #ifndef VUE3
|
||||
export * from '@vue/composition-api';
|
||||
|
||||
// #ifdef APP-NVUE
|
||||
import Vue from 'vue'
|
||||
import VueCompositionAPI from '@vue/composition-api'
|
||||
Vue.use(VueCompositionAPI)
|
||||
// #endif
|
||||
|
||||
// #endif
|
6
uni_modules/uni-config-center/changelog.md
Normal file
6
uni_modules/uni-config-center/changelog.md
Normal file
@ -0,0 +1,6 @@
|
||||
## 0.0.3(2022-11-11)
|
||||
- 修复 config 方法获取根节点为数组格式配置时错误的转化为了对象的Bug
|
||||
## 0.0.2(2021-04-16)
|
||||
- 修改插件package信息
|
||||
## 0.0.1(2021-03-15)
|
||||
- 初始化项目
|
81
uni_modules/uni-config-center/package.json
Normal file
81
uni_modules/uni-config-center/package.json
Normal file
@ -0,0 +1,81 @@
|
||||
{
|
||||
"id": "uni-config-center",
|
||||
"displayName": "uni-config-center",
|
||||
"version": "0.0.3",
|
||||
"description": "uniCloud 配置中心",
|
||||
"keywords": [
|
||||
"配置",
|
||||
"配置中心"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "",
|
||||
"type": "unicloud-template-function"
|
||||
},
|
||||
"directories": {
|
||||
"example": "../../../scripts/dist"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "u",
|
||||
"app-nvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "u",
|
||||
"Android Browser": "u",
|
||||
"微信浏览器(Android)": "u",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "u",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "u",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
93
uni_modules/uni-config-center/readme.md
Normal file
93
uni_modules/uni-config-center/readme.md
Normal file
@ -0,0 +1,93 @@
|
||||
# 为什么使用uni-config-center
|
||||
|
||||
实际开发中很多插件需要配置文件才可以正常运行,如果每个插件都单独进行配置的话就会产生下面这样的目录结构
|
||||
|
||||
```bash
|
||||
cloudfunctions
|
||||
└─────common 公共模块
|
||||
├─plugin-a // 插件A对应的目录
|
||||
│ ├─index.js
|
||||
│ ├─config.json // plugin-a对应的配置文件
|
||||
│ └─other-file.cert // plugin-a依赖的其他文件
|
||||
└─plugin-b // plugin-b对应的目录
|
||||
├─index.js
|
||||
└─config.json // plugin-b对应的配置文件
|
||||
```
|
||||
|
||||
假设插件作者要发布一个项目模板,里面使用了很多需要配置的插件,无论是作者发布还是用户使用都是一个大麻烦。
|
||||
|
||||
uni-config-center就是用了统一管理这些配置文件的,使用uni-config-center后的目录结构如下
|
||||
|
||||
```bash
|
||||
cloudfunctions
|
||||
└─────common 公共模块
|
||||
├─plugin-a // 插件A对应的目录
|
||||
│ └─index.js
|
||||
├─plugin-b // plugin-b对应的目录
|
||||
│ └─index.js
|
||||
└─uni-config-center
|
||||
├─index.js // config-center入口文件
|
||||
├─plugin-a
|
||||
│ ├─config.json // plugin-a对应的配置文件
|
||||
│ └─other-file.cert // plugin-a依赖的其他文件
|
||||
└─plugin-b
|
||||
└─config.json // plugin-b对应的配置文件
|
||||
```
|
||||
|
||||
使用uni-config-center后的优势
|
||||
|
||||
- 配置文件统一管理,分离插件主体和配置信息,更新插件更方便
|
||||
- 支持对config.json设置schema,插件使用者在HBuilderX内编写config.json文件时会有更好的提示(后续HBuilderX会提供支持)
|
||||
|
||||
# 用法
|
||||
|
||||
在要使用uni-config-center的公共模块或云函数内引入uni-config-center依赖,请参考:[使用公共模块](https://uniapp.dcloud.net.cn/uniCloud/cf-common)
|
||||
|
||||
```js
|
||||
const createConfig = require('uni-config-center')
|
||||
|
||||
const uniIdConfig = createConfig({
|
||||
pluginId: 'uni-id', // 插件id
|
||||
defaultConfig: { // 默认配置
|
||||
tokenExpiresIn: 7200,
|
||||
tokenExpiresThreshold: 600,
|
||||
},
|
||||
customMerge: function(defaultConfig, userConfig) { // 自定义默认配置和用户配置的合并规则,不设置的情况侠会对默认配置和用户配置进行深度合并
|
||||
// defaudltConfig 默认配置
|
||||
// userConfig 用户配置
|
||||
return Object.assign(defaultConfig, userConfig)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// 以如下配置为例
|
||||
// {
|
||||
// "tokenExpiresIn": 7200,
|
||||
// "passwordErrorLimit": 6,
|
||||
// "bindTokenToDevice": false,
|
||||
// "passwordErrorRetryTime": 3600,
|
||||
// "app-plus": {
|
||||
// "tokenExpiresIn": 2592000
|
||||
// },
|
||||
// "service": {
|
||||
// "sms": {
|
||||
// "codeExpiresIn": 300
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// 获取配置
|
||||
uniIdConfig.config() // 获取全部配置,注意:uni-config-center内不存在对应插件目录时会返回空对象
|
||||
uniIdConfig.config('tokenExpiresIn') // 指定键值获取配置,返回:7200
|
||||
uniIdConfig.config('service.sms.codeExpiresIn') // 指定键值获取配置,返回:300
|
||||
uniIdConfig.config('tokenExpiresThreshold', 600) // 指定键值获取配置,如果不存在则取传入的默认值,返回:600
|
||||
|
||||
// 获取文件绝对路径
|
||||
uniIdConfig.resolve('custom-token.js') // 获取uni-config-center/uni-id/custom-token.js文件的路径
|
||||
|
||||
// 引用文件(require)
|
||||
uniIDConfig.requireFile('custom-token.js') // 使用require方式引用uni-config-center/uni-id/custom-token.js文件。文件不存在时返回undefined,文件内有其他错误导致require失败时会抛出错误。
|
||||
|
||||
// 判断是否包含某文件
|
||||
uniIDConfig.hasFile('custom-token.js') // 配置目录是否包含某文件,true: 文件存在,false: 文件不存在
|
||||
```
|
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user