dlsjs 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dlsjs.cjs.js +2 -0
- package/dist/dlsjs.cjs.js.map +1 -0
- package/dist/dlsjs.es.js +8332 -0
- package/dist/dlsjs.es.js.map +1 -0
- package/dist/dlsjs.umd.js +2 -0
- package/dist/dlsjs.umd.js.map +1 -0
- package/package.json +9 -5
- package/src/Browser/Dom.js +0 -127
- package/src/Browser/File.js +0 -174
- package/src/Browser/Local.js +0 -61
- package/src/Browser/Nav.js +0 -208
- package/src/Browser/Screen.js +0 -175
- package/src/Browser/Timer.js +0 -99
- package/src/ES/Chain.js +0 -62
- package/src/ES/Const.js +0 -24
- package/src/ES/Judgment.js +0 -184
- package/src/ES/QRW.js +0 -287
- package/src/ES/Singleton.js +0 -73
- package/src/ES/Trans.js +0 -390
- package/src/ES/Tree.js +0 -916
- package/src/Instance/transCore.js +0 -108
- package/src/Instance/transFunc.js +0 -84
- package/src/Instance/transRule.js +0 -32
- package/src/index.js +0 -19
package/package.json
CHANGED
|
@@ -3,18 +3,17 @@
|
|
|
3
3
|
"author": "林川",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"private": false,
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.6",
|
|
7
7
|
"description": "domain-language for js",
|
|
8
8
|
"main": "dist/dlsjs.umd.js",
|
|
9
|
-
"module": "dist/dlsjs.
|
|
10
|
-
"type": "module",
|
|
9
|
+
"module": "dist/dlsjs.esm.js",
|
|
11
10
|
"exports": {
|
|
12
11
|
".": {
|
|
13
12
|
"require": {
|
|
14
|
-
"default": "./dist/dlsjs.
|
|
13
|
+
"default": "./dist/dlsjs.cjs.js"
|
|
15
14
|
},
|
|
16
15
|
"import": {
|
|
17
|
-
"default": "./dist/dlsjs.
|
|
16
|
+
"default": "./dist/dlsjs.esm.js"
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
19
|
},
|
|
@@ -33,6 +32,11 @@
|
|
|
33
32
|
"qs": "^6.12.0",
|
|
34
33
|
"ramda": "^0.29.1"
|
|
35
34
|
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"package.json",
|
|
38
|
+
"README.md"
|
|
39
|
+
],
|
|
36
40
|
"overrides": {
|
|
37
41
|
"vite": "npm:rolldown-vite@7.2.5"
|
|
38
42
|
}
|
package/src/Browser/Dom.js
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 移动弹窗[用于拖动绝对定位的元素]
|
|
3
|
-
* @param eventDown 鼠标按下事件对象
|
|
4
|
-
* @param selector 弹窗选择器
|
|
5
|
-
* @param restrictionType 限制类型:'none'(无限制)/'full'(限制整个弹窗)/'drag-point'(限制拖动点,默认)
|
|
6
|
-
*/
|
|
7
|
-
export const movePanel = (eventDown, selector, restrictionType = 'drag-point') => {
|
|
8
|
-
eventDown.preventDefault();
|
|
9
|
-
const disX = eventDown.layerX;
|
|
10
|
-
const disY = eventDown.layerY;
|
|
11
|
-
|
|
12
|
-
const panel = document.querySelector(selector);
|
|
13
|
-
// 获取弹窗的宽高
|
|
14
|
-
const panelWidth = panel.offsetWidth;
|
|
15
|
-
const panelHeight = panel.offsetHeight;
|
|
16
|
-
|
|
17
|
-
document.onmousemove = (eventMove) => {
|
|
18
|
-
moveOption(eventMove);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
document.onmouseup = () => {
|
|
22
|
-
document.onmousemove = null;
|
|
23
|
-
document.onmouseup = null;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const moveOption = (eventMove) => {
|
|
27
|
-
// 获取浏览器可视区域尺寸
|
|
28
|
-
const clientWidth = document.documentElement.clientWidth;
|
|
29
|
-
const clientHeight = document.documentElement.clientHeight;
|
|
30
|
-
|
|
31
|
-
// 计算无边界限制时的位置
|
|
32
|
-
let left = eventMove.clientX - disX;
|
|
33
|
-
let top = eventMove.clientY - disY;
|
|
34
|
-
|
|
35
|
-
// 根据限制类型应用不同的边界检查
|
|
36
|
-
switch (restrictionType) {
|
|
37
|
-
case 'full': // 限制整个弹窗在屏幕内
|
|
38
|
-
left = Math.max(0, Math.min(left, clientWidth - panelWidth));
|
|
39
|
-
top = Math.max(0, Math.min(top, clientHeight - panelHeight));
|
|
40
|
-
break;
|
|
41
|
-
|
|
42
|
-
case 'drag-point': // 限制拖动点在屏幕内(默认)
|
|
43
|
-
// 计算拖动点(鼠标按下的位置)的屏幕坐标
|
|
44
|
-
const dragPointX = left + disX;
|
|
45
|
-
const dragPointY = top + disY;
|
|
46
|
-
|
|
47
|
-
// 确保拖动点不超出屏幕边界
|
|
48
|
-
if (dragPointX < 0) left = -disX;
|
|
49
|
-
if (dragPointY < 0) top = -disY;
|
|
50
|
-
if (dragPointX > clientWidth) left = clientWidth - disX;
|
|
51
|
-
if (dragPointY > clientHeight) top = clientHeight - disY;
|
|
52
|
-
break;
|
|
53
|
-
|
|
54
|
-
case 'none': // 无限制
|
|
55
|
-
default:
|
|
56
|
-
// 不需要边界检查
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// 应用位置
|
|
61
|
-
panel.style.top = top + 'px';
|
|
62
|
-
panel.style.left = left + 'px';
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* 移动弹窗[用于拖动相对定位的元素]
|
|
67
|
-
* @param eventDown
|
|
68
|
-
* @param selector
|
|
69
|
-
*/
|
|
70
|
-
export const moveRelate = (eventDown, selector) => {
|
|
71
|
-
eventDown.preventDefault()
|
|
72
|
-
let disX = eventDown.pageX;
|
|
73
|
-
let disY = eventDown.pageY;
|
|
74
|
-
let startX = parseInt(document.querySelector(selector).style.left || '0')
|
|
75
|
-
let startY = parseInt(document.querySelector(selector).style.top || '0')
|
|
76
|
-
document.onmousemove = (eventMove) => {
|
|
77
|
-
moveOption(eventMove)
|
|
78
|
-
};
|
|
79
|
-
document.onmouseup = () => {
|
|
80
|
-
document.onmousemove = null;
|
|
81
|
-
document.onmouseup = null;
|
|
82
|
-
};
|
|
83
|
-
const moveOption = (eventMove) => {
|
|
84
|
-
let left = eventMove.pageX - disX;
|
|
85
|
-
let top = eventMove.pageY - disY;
|
|
86
|
-
document.querySelector(selector).style.top = top + startY + 'px'
|
|
87
|
-
document.querySelector(selector).style.left = left + startX+ 'px'
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* 计算文本宽度
|
|
93
|
-
* @param str
|
|
94
|
-
* @param fontSize
|
|
95
|
-
* @return {number}
|
|
96
|
-
*/
|
|
97
|
-
export function getTextWidth(str, fontSize = '14px') {
|
|
98
|
-
let result;
|
|
99
|
-
let ele = document.createElement('span')
|
|
100
|
-
ele.innerText = str;
|
|
101
|
-
ele.style.fontSize = fontSize;
|
|
102
|
-
document.documentElement.append(ele);
|
|
103
|
-
result = ele.offsetWidth;
|
|
104
|
-
document.documentElement.removeChild(ele);
|
|
105
|
-
return result;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* 计算图片真实尺寸
|
|
110
|
-
* @param url
|
|
111
|
-
* @return {Promise<unknown>}
|
|
112
|
-
*/
|
|
113
|
-
function getImageSizeByUrl(url) {
|
|
114
|
-
return new Promise(function (resolve, reject) {
|
|
115
|
-
let image = new Image();
|
|
116
|
-
image.onload = function () {
|
|
117
|
-
resolve({
|
|
118
|
-
width: image.width,
|
|
119
|
-
height: image.height
|
|
120
|
-
});
|
|
121
|
-
};
|
|
122
|
-
image.onerror = function () {
|
|
123
|
-
reject(new Error('error'));
|
|
124
|
-
};
|
|
125
|
-
image.src = url;
|
|
126
|
-
});
|
|
127
|
-
}
|
package/src/Browser/File.js
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import axios from "axios"
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 通过文件资源管理器选择本地文件
|
|
5
|
-
* @param [acceptType] 接受的文件类型,例:‘image/*’
|
|
6
|
-
* @param multiple 是否可选多个文件
|
|
7
|
-
* @return {Promise<FileList>}
|
|
8
|
-
*/
|
|
9
|
-
export function chooseFile(acceptType, multiple) {
|
|
10
|
-
return new Promise((resolve) => {
|
|
11
|
-
let input = document.querySelector("#lcf-choose-file-input")
|
|
12
|
-
if(!input) {
|
|
13
|
-
input = document.createElement("input")
|
|
14
|
-
input.type = 'file'
|
|
15
|
-
input.id = 'lcf-choose-file-input'
|
|
16
|
-
input.style.display = 'none'
|
|
17
|
-
if(acceptType) input.accept = acceptType
|
|
18
|
-
if(multiple) input.multiple = true
|
|
19
|
-
input.onchange = function () {
|
|
20
|
-
resolve(input.files)
|
|
21
|
-
input.remove()
|
|
22
|
-
}
|
|
23
|
-
document.body.append(input) // 兼容ios,ios下input必须挂载到页面上才可以使用拍照功能
|
|
24
|
-
}
|
|
25
|
-
input.click()
|
|
26
|
-
})
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* 选择本地json文件后直接返回json对象/数组
|
|
31
|
-
*/
|
|
32
|
-
export async function chooseJsonObj() {
|
|
33
|
-
let files = await chooseFile()
|
|
34
|
-
let jsonStr = await file2Json(files[0])
|
|
35
|
-
return JSON.parse(jsonStr)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* 通过请求从服务器读取文件(亦可读取项目内文件)
|
|
40
|
-
* @param url 文件路径
|
|
41
|
-
* @param [fileName] 文件名,默认取url参数末位单元,'/'为分隔符
|
|
42
|
-
* @return {Promise<File>}
|
|
43
|
-
*/
|
|
44
|
-
export function requestFile(url, fileName) {
|
|
45
|
-
if(!fileName) {
|
|
46
|
-
const urlList = url.split('/')
|
|
47
|
-
fileName = urlList[urlList.length - 1]
|
|
48
|
-
}
|
|
49
|
-
return new Promise((resolve, reject) => {
|
|
50
|
-
axios({
|
|
51
|
-
method:'get',
|
|
52
|
-
url,
|
|
53
|
-
responseType: 'arraybuffer'
|
|
54
|
-
}).then(res => {
|
|
55
|
-
resolve(new File([res.data], fileName))
|
|
56
|
-
}).catch(error => {
|
|
57
|
-
reject(error.toString())
|
|
58
|
-
})
|
|
59
|
-
})
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 从服务器读取json(亦可读取项目内文件)
|
|
64
|
-
* @param url 文件路径
|
|
65
|
-
* @return {Promise<File>}
|
|
66
|
-
*/
|
|
67
|
-
export function requestJSON(url) {
|
|
68
|
-
return new Promise((resolve, reject) => {
|
|
69
|
-
axios({
|
|
70
|
-
method:'get',
|
|
71
|
-
url,
|
|
72
|
-
responseType: 'json'
|
|
73
|
-
}).then(res => {
|
|
74
|
-
resolve(res.data)
|
|
75
|
-
}).catch(error => {
|
|
76
|
-
reject(error.toString())
|
|
77
|
-
})
|
|
78
|
-
})
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* 下载blob格式文件
|
|
83
|
-
*/
|
|
84
|
-
export function downloadBlob(blob, name) {
|
|
85
|
-
// 创建下载链接
|
|
86
|
-
const save_link = document.createElement("a");
|
|
87
|
-
|
|
88
|
-
// 使用标准的 URL.createObjectURL 方法
|
|
89
|
-
save_link.href = URL.createObjectURL(blob);
|
|
90
|
-
save_link.download = name;
|
|
91
|
-
|
|
92
|
-
// 添加到文档中(某些浏览器需要此步骤)
|
|
93
|
-
save_link.style.display = 'none';
|
|
94
|
-
document.body.appendChild(save_link);
|
|
95
|
-
|
|
96
|
-
// 触发下载
|
|
97
|
-
save_link.click();
|
|
98
|
-
|
|
99
|
-
// 清理资源
|
|
100
|
-
setTimeout(() => {
|
|
101
|
-
document.body.removeChild(save_link);
|
|
102
|
-
URL.revokeObjectURL(save_link.href);
|
|
103
|
-
}, 100);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* 下载文本
|
|
108
|
-
* @param text - 要下载的文本内容
|
|
109
|
-
* @param name - 下载的文件名(包括扩展名)
|
|
110
|
-
*/
|
|
111
|
-
export function downloadText(text, name) {
|
|
112
|
-
// 创建文本内容的 Blob 对象
|
|
113
|
-
const blob = new Blob([text], { type: 'text/plain' });
|
|
114
|
-
|
|
115
|
-
// 创建下载链接
|
|
116
|
-
const link = document.createElement('a');
|
|
117
|
-
link.href = URL.createObjectURL(blob);
|
|
118
|
-
link.download = name;
|
|
119
|
-
link.style.position = 'fixed';
|
|
120
|
-
link.style.top = '-1000px'; // 移出可视区域
|
|
121
|
-
|
|
122
|
-
// 添加到文档
|
|
123
|
-
document.body.appendChild(link);
|
|
124
|
-
|
|
125
|
-
// 触发下载
|
|
126
|
-
link.click();
|
|
127
|
-
|
|
128
|
-
// 清理资源
|
|
129
|
-
const cleanup = () => {
|
|
130
|
-
if (link.parentNode) {
|
|
131
|
-
link.parentNode.removeChild(link);
|
|
132
|
-
}
|
|
133
|
-
URL.revokeObjectURL(link.href);
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
// 延迟清理确保下载开始
|
|
137
|
-
setTimeout(cleanup, 100);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* 下载remote地址文件,使用html标签直接下载在微前端等情况下可能无法约束下载格式。所以应使用此种方式。
|
|
142
|
-
*/
|
|
143
|
-
export async function downloadByUrl(url, name) {
|
|
144
|
-
const f = await requestFile(url, name)
|
|
145
|
-
downloadBlob(f, name)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* file转json字符
|
|
150
|
-
*/
|
|
151
|
-
export async function file2Json(file) {
|
|
152
|
-
return new Promise(resolve => {
|
|
153
|
-
const FR = new FileReader()
|
|
154
|
-
FR.readAsText(file)
|
|
155
|
-
FR.onload = function (e) {
|
|
156
|
-
resolve(e.target.result)
|
|
157
|
-
}
|
|
158
|
-
})
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* json字符转blob对象
|
|
163
|
-
*/
|
|
164
|
-
export function json2Blob(jsonObject) {
|
|
165
|
-
return new Blob([jsonObject])
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* base64转换
|
|
170
|
-
*/
|
|
171
|
-
export function toBase64(str){
|
|
172
|
-
let encode = encodeURI(str);
|
|
173
|
-
return btoa(encode);
|
|
174
|
-
}
|
package/src/Browser/Local.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 获取localStorage缓存值
|
|
3
|
-
* @param {string} key 存储在localstorage的键名
|
|
4
|
-
* @returns {string|{}} 如果能通过json转化则返回对象,否则返回原字符串
|
|
5
|
-
*/
|
|
6
|
-
export function localGet (key) {
|
|
7
|
-
const value = window.localStorage.getItem(key)
|
|
8
|
-
try {
|
|
9
|
-
return JSON.parse(window.localStorage.getItem(key))
|
|
10
|
-
} catch (error) {
|
|
11
|
-
return value
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* 设定localStorage缓存值
|
|
17
|
-
* @param {string} key 存储在localstorage的键名
|
|
18
|
-
* @param {{}|any} value 可以存储简单对象或者简单类型
|
|
19
|
-
*/
|
|
20
|
-
export function localSet (key, value) {
|
|
21
|
-
window.localStorage.setItem(key, JSON.stringify(value))
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 删除localStorage缓存值
|
|
26
|
-
* @param {string} key 存储在localstorage的键名
|
|
27
|
-
*/
|
|
28
|
-
export function localRemove (key) {
|
|
29
|
-
window.localStorage.removeItem(key)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* 获取sessionStorage缓存值
|
|
34
|
-
* @param {string} key 存储在sessionStorage的键名
|
|
35
|
-
* @returns {string|{}} 如果能通过json转化则返回对象,否则返回原字符串
|
|
36
|
-
*/
|
|
37
|
-
export function sessionGet (key) {
|
|
38
|
-
const value = window.sessionStorage.getItem(key)
|
|
39
|
-
try {
|
|
40
|
-
return JSON.parse(window.sessionStorage.getItem(key))
|
|
41
|
-
} catch (error) {
|
|
42
|
-
return value
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* 设定sessionStorage缓存值
|
|
48
|
-
* @param {string} key 存储在sessionStorage的键名
|
|
49
|
-
* @param value 可以存储简单对象或者简单类型
|
|
50
|
-
*/
|
|
51
|
-
export function sessionSet (key, value) {
|
|
52
|
-
window.sessionStorage.setItem(key, JSON.stringify(value))
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* 删除sessionStorage缓存值
|
|
57
|
-
* @param {string} key 存储在sessionStorage的键名
|
|
58
|
-
*/
|
|
59
|
-
export function sessionRemove (key) {
|
|
60
|
-
window.sessionStorage.removeItem(key)
|
|
61
|
-
}
|
package/src/Browser/Nav.js
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 检测是否为移动设备
|
|
3
|
-
* 综合使用User-Agent、屏幕尺寸和触摸支持进行判断
|
|
4
|
-
* 时间复杂度O(1):直接访问浏览器属性和正则匹配
|
|
5
|
-
*
|
|
6
|
-
* @returns {boolean} 是否为移动设备
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* if (isMobileDevice()) {
|
|
10
|
-
* console.log('当前在移动设备上');
|
|
11
|
-
* // 加载移动端优化样式
|
|
12
|
-
* }
|
|
13
|
-
*/
|
|
14
|
-
export function isMobileDevice() {
|
|
15
|
-
// 1. 检查User-Agent
|
|
16
|
-
const mobileUserAgent = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
|
|
17
|
-
const isMobileUA = mobileUserAgent.test(navigator.userAgent);
|
|
18
|
-
|
|
19
|
-
// 2. 检查屏幕尺寸(移动设备通常宽度小于768px)
|
|
20
|
-
const isSmallScreen = window.innerWidth <= 768;
|
|
21
|
-
|
|
22
|
-
// 3. 检查触摸支持
|
|
23
|
-
const hasTouchSupport = 'ontouchstart' in window ||
|
|
24
|
-
navigator.maxTouchPoints > 0 ||
|
|
25
|
-
navigator.msMaxTouchPoints > 0;
|
|
26
|
-
|
|
27
|
-
// 4. 检查设备像素比(移动设备通常有较高的DPI)
|
|
28
|
-
const isHighDPI = window.devicePixelRatio >= 1.5;
|
|
29
|
-
|
|
30
|
-
// 综合判断:User-Agent匹配或(小屏幕且支持触摸)
|
|
31
|
-
return isMobileUA || (isSmallScreen && hasTouchSupport);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* 获取设备类型详细信息
|
|
36
|
-
* 时间复杂度O(1):直接访问浏览器属性和正则匹配
|
|
37
|
-
*
|
|
38
|
-
* @returns {Object} 设备信息对象,包含类型、屏幕尺寸等
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* const deviceInfo = getDeviceInfo();
|
|
42
|
-
* console.log(deviceInfo.type); // 'mobile', 'tablet', 'desktop'
|
|
43
|
-
* console.log(deviceInfo.screenWidth); // 屏幕宽度
|
|
44
|
-
*/
|
|
45
|
-
export function getDeviceInfo() {
|
|
46
|
-
const userAgent = navigator.userAgent.toLowerCase();
|
|
47
|
-
const screenWidth = window.innerWidth;
|
|
48
|
-
|
|
49
|
-
let type = 'desktop';
|
|
50
|
-
let subType = 'unknown';
|
|
51
|
-
|
|
52
|
-
// 检测设备类型
|
|
53
|
-
if (/mobile|android|iphone|ipod/.test(userAgent)) {
|
|
54
|
-
type = 'mobile';
|
|
55
|
-
if (/iphone|ipod/.test(userAgent)) subType = 'iphone';
|
|
56
|
-
else if (/android/.test(userAgent)) subType = 'android';
|
|
57
|
-
} else if (/ipad/.test(userAgent) || (screenWidth <= 1024 && screenWidth > 768)) {
|
|
58
|
-
type = 'tablet';
|
|
59
|
-
if (/ipad/.test(userAgent)) subType = 'ipad';
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// 根据屏幕尺寸进一步调整
|
|
63
|
-
if (type === 'desktop' && screenWidth <= 768) {
|
|
64
|
-
type = 'mobile';
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return {
|
|
68
|
-
type,
|
|
69
|
-
subType,
|
|
70
|
-
screenWidth,
|
|
71
|
-
screenHeight: window.innerHeight,
|
|
72
|
-
pixelRatio: window.devicePixelRatio,
|
|
73
|
-
userAgent: navigator.userAgent
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* 复制文本到剪贴板
|
|
79
|
-
* 优先使用现代Clipboard API,降级到传统execCommand方法
|
|
80
|
-
* 时间复杂度O(1):直接调用浏览器API
|
|
81
|
-
*
|
|
82
|
-
* @param {string} text - 要复制的文本内容
|
|
83
|
-
* @returns {Promise<boolean>} 复制是否成功
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* // 使用async/await
|
|
87
|
-
* const success = await copyText('Hello World');
|
|
88
|
-
* if (success) {
|
|
89
|
-
* console.log('复制成功');
|
|
90
|
-
* }
|
|
91
|
-
*
|
|
92
|
-
* // 使用Promise
|
|
93
|
-
* copyText('Hello World').then(success => {
|
|
94
|
-
* if (success) {
|
|
95
|
-
* console.log('复制成功');
|
|
96
|
-
* }
|
|
97
|
-
* });
|
|
98
|
-
*/
|
|
99
|
-
export function copyText(text) {
|
|
100
|
-
// 输入验证
|
|
101
|
-
if (typeof text !== 'string') {
|
|
102
|
-
console.warn('dlsjs: copyText 参数必须是字符串');
|
|
103
|
-
return Promise.resolve(false);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (text === '') {
|
|
107
|
-
console.warn('dlsjs: copyText 不能复制空字符串');
|
|
108
|
-
return Promise.resolve(false);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// 优先使用现代Clipboard API(需要安全上下文)
|
|
112
|
-
if (navigator.clipboard && window.isSecureContext) {
|
|
113
|
-
return navigator.clipboard.writeText(text)
|
|
114
|
-
.then(() => true)
|
|
115
|
-
.catch(error => {
|
|
116
|
-
console.error('dlsjs: 使用Clipboard API复制失败:', error);
|
|
117
|
-
return fallbackCopyText(text);
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// 降级到传统方法
|
|
122
|
-
return Promise.resolve(fallbackCopyText(text));
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* 传统复制文本方法(降级方案)
|
|
127
|
-
* 时间复杂度O(1):DOM操作和execCommand调用
|
|
128
|
-
*
|
|
129
|
-
* @param {string} text - 要复制的文本
|
|
130
|
-
* @returns {boolean} 复制是否成功
|
|
131
|
-
*/
|
|
132
|
-
function fallbackCopyText(text) {
|
|
133
|
-
try {
|
|
134
|
-
// 创建临时textarea元素(比input更适合多行文本)
|
|
135
|
-
const textarea = document.createElement('textarea');
|
|
136
|
-
textarea.value = text;
|
|
137
|
-
textarea.style.position = 'fixed';
|
|
138
|
-
textarea.style.left = '-9999px';
|
|
139
|
-
textarea.style.top = '0';
|
|
140
|
-
textarea.setAttribute('readonly', '');
|
|
141
|
-
|
|
142
|
-
document.body.appendChild(textarea);
|
|
143
|
-
|
|
144
|
-
// 选择文本(兼容不同浏览器)
|
|
145
|
-
if (textarea.select) {
|
|
146
|
-
textarea.select();
|
|
147
|
-
} else if (textarea.setSelectionRange) {
|
|
148
|
-
textarea.setSelectionRange(0, textarea.value.length);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// 尝试复制
|
|
152
|
-
const successful = document.execCommand('copy');
|
|
153
|
-
document.body.removeChild(textarea);
|
|
154
|
-
|
|
155
|
-
if (!successful) {
|
|
156
|
-
console.warn('dlsjs: 传统复制方法执行失败');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return successful;
|
|
160
|
-
} catch (error) {
|
|
161
|
-
console.error('dlsjs: 传统复制方法出错:', error);
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* 检查剪贴板API是否可用
|
|
168
|
-
* 时间复杂度O(1):直接检查浏览器API支持
|
|
169
|
-
*
|
|
170
|
-
* @returns {boolean} 剪贴板API是否可用
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
* if (isClipboardSupported()) {
|
|
174
|
-
* // 可以使用现代剪贴板API
|
|
175
|
-
* } else {
|
|
176
|
-
* // 需要使用传统方法
|
|
177
|
-
* }
|
|
178
|
-
*/
|
|
179
|
-
export function isClipboardSupported() {
|
|
180
|
-
return !!(navigator.clipboard && window.isSecureContext);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* 读取剪贴板文本内容
|
|
185
|
-
* 需要用户授权,只能在安全上下文(HTTPS)中使用
|
|
186
|
-
* 时间复杂度O(1):直接调用浏览器API
|
|
187
|
-
*
|
|
188
|
-
* @returns {Promise<string>} 剪贴板中的文本内容
|
|
189
|
-
*
|
|
190
|
-
* @example
|
|
191
|
-
* try {
|
|
192
|
-
* const text = await readClipboardText();
|
|
193
|
-
* console.log('剪贴板内容:', text);
|
|
194
|
-
* } catch (error) {
|
|
195
|
-
* console.error('读取剪贴板失败:', error);
|
|
196
|
-
* }
|
|
197
|
-
*/
|
|
198
|
-
export function readClipboardText() {
|
|
199
|
-
if (!isClipboardSupported()) {
|
|
200
|
-
return Promise.reject(new Error('dlsjs: 当前环境不支持剪贴板读取'));
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return navigator.clipboard.readText()
|
|
204
|
-
.catch(error => {
|
|
205
|
-
console.error('dlsjs: 读取剪贴板失败:', error);
|
|
206
|
-
throw error;
|
|
207
|
-
});
|
|
208
|
-
}
|