@whitesev/utils 1.0.2 → 1.0.3
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/index.amd.js +518 -503
- package/dist/index.amd.js.map +1 -1
- package/dist/index.cjs.js +518 -503
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +518 -503
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +518 -503
- package/dist/index.iife.js.map +1 -1
- package/dist/index.system.js +518 -503
- package/dist/index.system.js.map +1 -1
- package/dist/index.umd.js +518 -503
- package/dist/index.umd.js.map +1 -1
- package/dist/src/ajaxHooker.d.ts +6 -6
- package/package.json +1 -1
- package/rollup.config.js +1 -0
- package/src/Utils.ts +3 -3
- package/src/ajaxHooker.js +518 -503
package/dist/index.esm.js
CHANGED
|
@@ -373,181 +373,183 @@ class UtilsGMCookie {
|
|
|
373
373
|
// @version 1.4.1
|
|
374
374
|
// @supportURL https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
|
|
375
375
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
function catchError(fn, ...args) {
|
|
415
|
-
try {
|
|
416
|
-
const result = fn(...args);
|
|
417
|
-
if (isThenable(result)) return result.then(null, errorFn);
|
|
418
|
-
return result;
|
|
419
|
-
} catch (err) {
|
|
420
|
-
console.error(err);
|
|
376
|
+
const AjaxHooker = function () {
|
|
377
|
+
return (function () {
|
|
378
|
+
const version = "1.4.1";
|
|
379
|
+
const hookInst = {
|
|
380
|
+
hookFns: [],
|
|
381
|
+
filters: [],
|
|
382
|
+
};
|
|
383
|
+
const win = window.unsafeWindow || document.defaultView || window;
|
|
384
|
+
let winAh = win.__ajaxHooker;
|
|
385
|
+
const resProto = win.Response.prototype;
|
|
386
|
+
const xhrResponses = ["response", "responseText", "responseXML"];
|
|
387
|
+
const fetchResponses = ["arrayBuffer", "blob", "formData", "json", "text"];
|
|
388
|
+
const fetchInitProps = [
|
|
389
|
+
"method",
|
|
390
|
+
"headers",
|
|
391
|
+
"body",
|
|
392
|
+
"mode",
|
|
393
|
+
"credentials",
|
|
394
|
+
"cache",
|
|
395
|
+
"redirect",
|
|
396
|
+
"referrer",
|
|
397
|
+
"referrerPolicy",
|
|
398
|
+
"integrity",
|
|
399
|
+
"keepalive",
|
|
400
|
+
"signal",
|
|
401
|
+
"priority",
|
|
402
|
+
];
|
|
403
|
+
const xhrAsyncEvents = ["readystatechange", "load", "loadend"];
|
|
404
|
+
const getType = {}.toString.call.bind({}.toString);
|
|
405
|
+
const getDescriptor = Object.getOwnPropertyDescriptor.bind(Object);
|
|
406
|
+
const emptyFn = () => {};
|
|
407
|
+
const errorFn = (e) => console.error(e);
|
|
408
|
+
function isThenable(obj) {
|
|
409
|
+
return (
|
|
410
|
+
obj &&
|
|
411
|
+
["object", "function"].includes(typeof obj) &&
|
|
412
|
+
typeof obj.then === "function"
|
|
413
|
+
);
|
|
421
414
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
function readonly(obj, prop, value = obj[prop]) {
|
|
432
|
-
defineProp(obj, prop, () => value, emptyFn);
|
|
433
|
-
}
|
|
434
|
-
function writable(obj, prop, value = obj[prop]) {
|
|
435
|
-
Object.defineProperty(obj, prop, {
|
|
436
|
-
configurable: true,
|
|
437
|
-
enumerable: true,
|
|
438
|
-
writable: true,
|
|
439
|
-
value: value,
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
function parseHeaders(obj) {
|
|
443
|
-
const headers = {};
|
|
444
|
-
switch (getType(obj)) {
|
|
445
|
-
case "[object String]":
|
|
446
|
-
for (const line of obj.trim().split(/[\r\n]+/)) {
|
|
447
|
-
const [header, value] = line.split(/\s*:\s*/);
|
|
448
|
-
if (!header) break;
|
|
449
|
-
const lheader = header.toLowerCase();
|
|
450
|
-
headers[lheader] =
|
|
451
|
-
lheader in headers ? `${headers[lheader]}, ${value}` : value;
|
|
452
|
-
}
|
|
453
|
-
break;
|
|
454
|
-
case "[object Headers]":
|
|
455
|
-
for (const [key, val] of obj) {
|
|
456
|
-
headers[key] = val;
|
|
457
|
-
}
|
|
458
|
-
break;
|
|
459
|
-
case "[object Object]":
|
|
460
|
-
return { ...obj };
|
|
415
|
+
function catchError(fn, ...args) {
|
|
416
|
+
try {
|
|
417
|
+
const result = fn(...args);
|
|
418
|
+
if (isThenable(result)) return result.then(null, errorFn);
|
|
419
|
+
return result;
|
|
420
|
+
} catch (err) {
|
|
421
|
+
console.error(err);
|
|
422
|
+
}
|
|
461
423
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
fn && fn();
|
|
470
|
-
return new SyncThenable();
|
|
424
|
+
function defineProp(obj, prop, getter, setter) {
|
|
425
|
+
Object.defineProperty(obj, prop, {
|
|
426
|
+
configurable: true,
|
|
427
|
+
enumerable: true,
|
|
428
|
+
get: getter,
|
|
429
|
+
set: setter,
|
|
430
|
+
});
|
|
471
431
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
constructor(request) {
|
|
475
|
-
this.request = request;
|
|
476
|
-
this.requestClone = { ...this.request };
|
|
432
|
+
function readonly(obj, prop, value = obj[prop]) {
|
|
433
|
+
defineProp(obj, prop, () => value, emptyFn);
|
|
477
434
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
435
|
+
function writable(obj, prop, value = obj[prop]) {
|
|
436
|
+
Object.defineProperty(obj, prop, {
|
|
437
|
+
configurable: true,
|
|
438
|
+
enumerable: true,
|
|
439
|
+
writable: true,
|
|
440
|
+
value: value,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
function parseHeaders(obj) {
|
|
444
|
+
const headers = {};
|
|
445
|
+
switch (getType(obj)) {
|
|
446
|
+
case "[object String]":
|
|
447
|
+
for (const line of obj.trim().split(/[\r\n]+/)) {
|
|
448
|
+
const [header, value] = line.split(/\s*:\s*/);
|
|
449
|
+
if (!header) break;
|
|
450
|
+
const lheader = header.toLowerCase();
|
|
451
|
+
headers[lheader] =
|
|
452
|
+
lheader in headers ? `${headers[lheader]}, ${value}` : value;
|
|
492
453
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
454
|
+
break;
|
|
455
|
+
case "[object Headers]":
|
|
456
|
+
for (const [key, val] of obj) {
|
|
457
|
+
headers[key] = val;
|
|
458
|
+
}
|
|
459
|
+
break;
|
|
460
|
+
case "[object Object]":
|
|
461
|
+
return { ...obj };
|
|
462
|
+
}
|
|
463
|
+
return headers;
|
|
496
464
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if (getType(fn) === "[object Function]")
|
|
504
|
-
catchError(fn, this.request);
|
|
505
|
-
});
|
|
506
|
-
requestKeys.forEach((key) => {
|
|
507
|
-
if (isThenable(this.request[key]))
|
|
508
|
-
this.request[key] = this.requestClone[key];
|
|
509
|
-
});
|
|
510
|
-
});
|
|
465
|
+
function stopImmediatePropagation() {
|
|
466
|
+
this.ajaxHooker_isStopped = true;
|
|
467
|
+
}
|
|
468
|
+
class SyncThenable {
|
|
469
|
+
then(fn) {
|
|
470
|
+
fn && fn();
|
|
511
471
|
return new SyncThenable();
|
|
512
472
|
}
|
|
513
|
-
const promises = [];
|
|
514
|
-
win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
|
|
515
|
-
if (this.shouldFilter(filters)) return;
|
|
516
|
-
promises.push(
|
|
517
|
-
Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(
|
|
518
|
-
() =>
|
|
519
|
-
Promise.all(
|
|
520
|
-
requestKeys.map((key) =>
|
|
521
|
-
Promise.resolve(this.request[key]).then(
|
|
522
|
-
(val) => (this.request[key] = val),
|
|
523
|
-
() => (this.request[key] = this.requestClone[key])
|
|
524
|
-
)
|
|
525
|
-
)
|
|
526
|
-
)
|
|
527
|
-
)
|
|
528
|
-
);
|
|
529
|
-
});
|
|
530
|
-
return Promise.all(promises);
|
|
531
473
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
this.request
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
) {
|
|
543
|
-
|
|
474
|
+
class AHRequest {
|
|
475
|
+
constructor(request) {
|
|
476
|
+
this.request = request;
|
|
477
|
+
this.requestClone = { ...this.request };
|
|
478
|
+
}
|
|
479
|
+
shouldFilter(filters) {
|
|
480
|
+
const { type, url, method, async } = this.request;
|
|
481
|
+
return (
|
|
482
|
+
filters.length &&
|
|
483
|
+
!filters.find((obj) => {
|
|
484
|
+
switch (true) {
|
|
485
|
+
case obj.type && obj.type !== type:
|
|
486
|
+
case getType(obj.url) === "[object String]" &&
|
|
487
|
+
!url.includes(obj.url):
|
|
488
|
+
case getType(obj.url) === "[object RegExp]" && !obj.url.test(url):
|
|
489
|
+
case obj.method &&
|
|
490
|
+
obj.method.toUpperCase() !== method.toUpperCase():
|
|
491
|
+
case "async" in obj && obj.async !== async:
|
|
492
|
+
return false;
|
|
544
493
|
}
|
|
494
|
+
return true;
|
|
495
|
+
})
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
waitForRequestKeys() {
|
|
499
|
+
const requestKeys = ["url", "method", "abort", "headers", "data"];
|
|
500
|
+
if (!this.request.async) {
|
|
501
|
+
win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
|
|
502
|
+
if (this.shouldFilter(filters)) return;
|
|
503
|
+
hookFns.forEach((fn) => {
|
|
504
|
+
if (getType(fn) === "[object Function]")
|
|
505
|
+
catchError(fn, this.request);
|
|
506
|
+
});
|
|
507
|
+
requestKeys.forEach((key) => {
|
|
508
|
+
if (isThenable(this.request[key]))
|
|
509
|
+
this.request[key] = this.requestClone[key];
|
|
510
|
+
});
|
|
545
511
|
});
|
|
512
|
+
return new SyncThenable();
|
|
546
513
|
}
|
|
547
|
-
|
|
514
|
+
const promises = [];
|
|
515
|
+
win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
|
|
516
|
+
if (this.shouldFilter(filters)) return;
|
|
517
|
+
promises.push(
|
|
518
|
+
Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(
|
|
519
|
+
() =>
|
|
520
|
+
Promise.all(
|
|
521
|
+
requestKeys.map((key) =>
|
|
522
|
+
Promise.resolve(this.request[key]).then(
|
|
523
|
+
(val) => (this.request[key] = val),
|
|
524
|
+
() => (this.request[key] = this.requestClone[key])
|
|
525
|
+
)
|
|
526
|
+
)
|
|
527
|
+
)
|
|
528
|
+
)
|
|
529
|
+
);
|
|
530
|
+
});
|
|
531
|
+
return Promise.all(promises);
|
|
548
532
|
}
|
|
549
|
-
|
|
550
|
-
|
|
533
|
+
waitForResponseKeys(response) {
|
|
534
|
+
const responseKeys =
|
|
535
|
+
this.request.type === "xhr" ? xhrResponses : fetchResponses;
|
|
536
|
+
if (!this.request.async) {
|
|
537
|
+
if (getType(this.request.response) === "[object Function]") {
|
|
538
|
+
catchError(this.request.response, response);
|
|
539
|
+
responseKeys.forEach((key) => {
|
|
540
|
+
if (
|
|
541
|
+
"get" in getDescriptor(response, key) ||
|
|
542
|
+
isThenable(response[key])
|
|
543
|
+
) {
|
|
544
|
+
delete response[key];
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
return new SyncThenable();
|
|
549
|
+
}
|
|
550
|
+
return Promise.resolve(
|
|
551
|
+
catchError(this.request.response, response)
|
|
552
|
+
).then(() =>
|
|
551
553
|
Promise.all(
|
|
552
554
|
responseKeys.map((key) => {
|
|
553
555
|
const descriptor = getDescriptor(response, key);
|
|
@@ -561,368 +563,381 @@ var ajaxHooker = (function () {
|
|
|
561
563
|
}
|
|
562
564
|
})
|
|
563
565
|
)
|
|
564
|
-
|
|
566
|
+
);
|
|
567
|
+
}
|
|
565
568
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
569
|
+
const proxyHandler = {
|
|
570
|
+
get(target, prop) {
|
|
571
|
+
const descriptor = getDescriptor(target, prop);
|
|
572
|
+
if (
|
|
573
|
+
descriptor &&
|
|
574
|
+
!descriptor.configurable &&
|
|
575
|
+
!descriptor.writable &&
|
|
576
|
+
!descriptor.get
|
|
577
|
+
)
|
|
578
|
+
return target[prop];
|
|
579
|
+
const ah = target.__ajaxHooker;
|
|
580
|
+
if (ah && ah.proxyProps) {
|
|
581
|
+
if (prop in ah.proxyProps) {
|
|
582
|
+
const pDescriptor = ah.proxyProps[prop];
|
|
583
|
+
if ("get" in pDescriptor) return pDescriptor.get();
|
|
584
|
+
if (typeof pDescriptor.value === "function")
|
|
585
|
+
return pDescriptor.value.bind(ah);
|
|
586
|
+
return pDescriptor.value;
|
|
587
|
+
}
|
|
588
|
+
if (typeof target[prop] === "function")
|
|
589
|
+
return target[prop].bind(target);
|
|
590
|
+
}
|
|
576
591
|
return target[prop];
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
592
|
+
},
|
|
593
|
+
set(target, prop, value) {
|
|
594
|
+
const descriptor = getDescriptor(target, prop);
|
|
595
|
+
if (
|
|
596
|
+
descriptor &&
|
|
597
|
+
!descriptor.configurable &&
|
|
598
|
+
!descriptor.writable &&
|
|
599
|
+
!descriptor.set
|
|
600
|
+
)
|
|
601
|
+
return true;
|
|
602
|
+
const ah = target.__ajaxHooker;
|
|
603
|
+
if (ah && ah.proxyProps && prop in ah.proxyProps) {
|
|
580
604
|
const pDescriptor = ah.proxyProps[prop];
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
605
|
+
pDescriptor.set
|
|
606
|
+
? pDescriptor.set(value)
|
|
607
|
+
: (pDescriptor.value = value);
|
|
608
|
+
} else {
|
|
609
|
+
target[prop] = value;
|
|
585
610
|
}
|
|
586
|
-
if (typeof target[prop] === "function")
|
|
587
|
-
return target[prop].bind(target);
|
|
588
|
-
}
|
|
589
|
-
return target[prop];
|
|
590
|
-
},
|
|
591
|
-
set(target, prop, value) {
|
|
592
|
-
const descriptor = getDescriptor(target, prop);
|
|
593
|
-
if (
|
|
594
|
-
descriptor &&
|
|
595
|
-
!descriptor.configurable &&
|
|
596
|
-
!descriptor.writable &&
|
|
597
|
-
!descriptor.set
|
|
598
|
-
)
|
|
599
611
|
return true;
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
612
|
+
},
|
|
613
|
+
};
|
|
614
|
+
class XhrHooker {
|
|
615
|
+
constructor(xhr) {
|
|
616
|
+
const ah = this;
|
|
617
|
+
Object.assign(ah, {
|
|
618
|
+
originalXhr: xhr,
|
|
619
|
+
proxyXhr: new Proxy(xhr, proxyHandler),
|
|
620
|
+
resThenable: new SyncThenable(),
|
|
621
|
+
proxyProps: {},
|
|
622
|
+
proxyEvents: {},
|
|
623
|
+
});
|
|
624
|
+
xhr.addEventListener("readystatechange", (e) => {
|
|
625
|
+
if (
|
|
626
|
+
ah.proxyXhr.readyState === 4 &&
|
|
627
|
+
ah.request &&
|
|
628
|
+
typeof ah.request.response === "function"
|
|
629
|
+
) {
|
|
630
|
+
const response = {
|
|
631
|
+
finalUrl: ah.proxyXhr.responseURL,
|
|
632
|
+
status: ah.proxyXhr.status,
|
|
633
|
+
responseHeaders: parseHeaders(
|
|
634
|
+
ah.proxyXhr.getAllResponseHeaders()
|
|
635
|
+
),
|
|
636
|
+
};
|
|
637
|
+
const tempValues = {};
|
|
638
|
+
for (const key of xhrResponses) {
|
|
639
|
+
try {
|
|
640
|
+
tempValues[key] = ah.originalXhr[key];
|
|
641
|
+
} catch (err) {}
|
|
642
|
+
defineProp(
|
|
643
|
+
response,
|
|
644
|
+
key,
|
|
645
|
+
() => {
|
|
646
|
+
return (response[key] = tempValues[key]);
|
|
647
|
+
},
|
|
648
|
+
(val) => {
|
|
649
|
+
delete response[key];
|
|
650
|
+
response[key] = val;
|
|
651
|
+
}
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
ah.resThenable = new AHRequest(ah.request)
|
|
655
|
+
.waitForResponseKeys(response)
|
|
656
|
+
.then(() => {
|
|
657
|
+
for (const key of xhrResponses) {
|
|
658
|
+
ah.proxyProps[key] = {
|
|
659
|
+
get: () => {
|
|
660
|
+
if (!(key in response)) response[key] = tempValues[key];
|
|
661
|
+
return response[key];
|
|
662
|
+
},
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
});
|
|
647
666
|
}
|
|
648
|
-
ah.
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
667
|
+
ah.dispatchEvent(e);
|
|
668
|
+
});
|
|
669
|
+
xhr.addEventListener("load", (e) => ah.dispatchEvent(e));
|
|
670
|
+
xhr.addEventListener("loadend", (e) => ah.dispatchEvent(e));
|
|
671
|
+
for (const evt of xhrAsyncEvents) {
|
|
672
|
+
const onEvt = "on" + evt;
|
|
673
|
+
ah.proxyProps[onEvt] = {
|
|
674
|
+
get: () => ah.proxyEvents[onEvt] || null,
|
|
675
|
+
set: (val) => ah.addEvent(onEvt, val),
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
for (const method of [
|
|
679
|
+
"setRequestHeader",
|
|
680
|
+
"addEventListener",
|
|
681
|
+
"removeEventListener",
|
|
682
|
+
"open",
|
|
683
|
+
"send",
|
|
684
|
+
]) {
|
|
685
|
+
ah.proxyProps[method] = { value: ah[method] };
|
|
660
686
|
}
|
|
661
|
-
ah.dispatchEvent(e);
|
|
662
|
-
});
|
|
663
|
-
xhr.addEventListener("load", (e) => ah.dispatchEvent(e));
|
|
664
|
-
xhr.addEventListener("loadend", (e) => ah.dispatchEvent(e));
|
|
665
|
-
for (const evt of xhrAsyncEvents) {
|
|
666
|
-
const onEvt = "on" + evt;
|
|
667
|
-
ah.proxyProps[onEvt] = {
|
|
668
|
-
get: () => ah.proxyEvents[onEvt] || null,
|
|
669
|
-
set: (val) => ah.addEvent(onEvt, val),
|
|
670
|
-
};
|
|
671
687
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
"
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
688
|
+
toJSON() {} // Converting circular structure to JSON
|
|
689
|
+
addEvent(type, event) {
|
|
690
|
+
if (type.startsWith("on")) {
|
|
691
|
+
this.proxyEvents[type] = typeof event === "function" ? event : null;
|
|
692
|
+
} else {
|
|
693
|
+
if (typeof event === "object" && event !== null)
|
|
694
|
+
event = event.handleEvent;
|
|
695
|
+
if (typeof event !== "function") return;
|
|
696
|
+
this.proxyEvents[type] = this.proxyEvents[type] || new Set();
|
|
697
|
+
this.proxyEvents[type].add(event);
|
|
698
|
+
}
|
|
680
699
|
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
if (typeof event !== "function") return;
|
|
690
|
-
this.proxyEvents[type] = this.proxyEvents[type] || new Set();
|
|
691
|
-
this.proxyEvents[type].add(event);
|
|
700
|
+
removeEvent(type, event) {
|
|
701
|
+
if (type.startsWith("on")) {
|
|
702
|
+
this.proxyEvents[type] = null;
|
|
703
|
+
} else {
|
|
704
|
+
if (typeof event === "object" && event !== null)
|
|
705
|
+
event = event.handleEvent;
|
|
706
|
+
this.proxyEvents[type] && this.proxyEvents[type].delete(event);
|
|
707
|
+
}
|
|
692
708
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
this.proxyEvents[type]
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
709
|
+
dispatchEvent(e) {
|
|
710
|
+
e.stopImmediatePropagation = stopImmediatePropagation;
|
|
711
|
+
defineProp(e, "target", () => this.proxyXhr);
|
|
712
|
+
this.proxyEvents[e.type] &&
|
|
713
|
+
this.proxyEvents[e.type].forEach((fn) => {
|
|
714
|
+
this.resThenable.then(
|
|
715
|
+
() => !e.ajaxHooker_isStopped && fn.call(this.proxyXhr, e)
|
|
716
|
+
);
|
|
717
|
+
});
|
|
718
|
+
if (e.ajaxHooker_isStopped) return;
|
|
719
|
+
const onEvent = this.proxyEvents["on" + e.type];
|
|
720
|
+
onEvent && this.resThenable.then(onEvent.bind(this.proxyXhr, e));
|
|
701
721
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
722
|
+
setRequestHeader(header, value) {
|
|
723
|
+
this.originalXhr.setRequestHeader(header, value);
|
|
724
|
+
if (this.originalXhr.readyState !== 1) return;
|
|
725
|
+
const headers = this.request.headers;
|
|
726
|
+
headers[header] =
|
|
727
|
+
header in headers ? `${headers[header]}, ${value}` : value;
|
|
728
|
+
}
|
|
729
|
+
addEventListener(...args) {
|
|
730
|
+
if (xhrAsyncEvents.includes(args[0])) {
|
|
731
|
+
this.addEvent(args[0], args[1]);
|
|
732
|
+
} else {
|
|
733
|
+
this.originalXhr.addEventListener(...args);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
removeEventListener(...args) {
|
|
737
|
+
if (xhrAsyncEvents.includes(args[0])) {
|
|
738
|
+
this.removeEvent(args[0], args[1]);
|
|
739
|
+
} else {
|
|
740
|
+
this.originalXhr.removeEventListener(...args);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
open(method, url, async = true, ...args) {
|
|
744
|
+
this.request = {
|
|
745
|
+
type: "xhr",
|
|
746
|
+
url: url.toString(),
|
|
747
|
+
method: method.toUpperCase(),
|
|
748
|
+
abort: false,
|
|
749
|
+
headers: {},
|
|
750
|
+
data: null,
|
|
751
|
+
response: null,
|
|
752
|
+
async: !!async,
|
|
753
|
+
};
|
|
754
|
+
this.openArgs = args;
|
|
755
|
+
this.resThenable = new SyncThenable();
|
|
756
|
+
[
|
|
757
|
+
"responseURL",
|
|
758
|
+
"readyState",
|
|
759
|
+
"status",
|
|
760
|
+
"statusText",
|
|
761
|
+
...xhrResponses,
|
|
762
|
+
].forEach((key) => {
|
|
763
|
+
delete this.proxyProps[key];
|
|
711
764
|
});
|
|
712
|
-
|
|
713
|
-
const onEvent = this.proxyEvents["on" + e.type];
|
|
714
|
-
onEvent && this.resThenable.then(onEvent.bind(this.proxyXhr, e));
|
|
715
|
-
}
|
|
716
|
-
setRequestHeader(header, value) {
|
|
717
|
-
this.originalXhr.setRequestHeader(header, value);
|
|
718
|
-
if (this.originalXhr.readyState !== 1) return;
|
|
719
|
-
const headers = this.request.headers;
|
|
720
|
-
headers[header] =
|
|
721
|
-
header in headers ? `${headers[header]}, ${value}` : value;
|
|
722
|
-
}
|
|
723
|
-
addEventListener(...args) {
|
|
724
|
-
if (xhrAsyncEvents.includes(args[0])) {
|
|
725
|
-
this.addEvent(args[0], args[1]);
|
|
726
|
-
} else {
|
|
727
|
-
this.originalXhr.addEventListener(...args);
|
|
765
|
+
return this.originalXhr.open(method, url, async, ...args);
|
|
728
766
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
767
|
+
send(data) {
|
|
768
|
+
const ah = this;
|
|
769
|
+
const xhr = ah.originalXhr;
|
|
770
|
+
const request = ah.request;
|
|
771
|
+
if (!request) return xhr.send(data);
|
|
772
|
+
request.data = data;
|
|
773
|
+
new AHRequest(request).waitForRequestKeys().then(() => {
|
|
774
|
+
if (request.abort) {
|
|
775
|
+
if (typeof request.response === "function") {
|
|
776
|
+
Object.assign(ah.proxyProps, {
|
|
777
|
+
responseURL: { value: request.url },
|
|
778
|
+
readyState: { value: 4 },
|
|
779
|
+
status: { value: 200 },
|
|
780
|
+
statusText: { value: "OK" },
|
|
781
|
+
});
|
|
782
|
+
xhrAsyncEvents.forEach((evt) =>
|
|
783
|
+
xhr.dispatchEvent(new Event(evt))
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
} else {
|
|
787
|
+
xhr.open(
|
|
788
|
+
request.method,
|
|
789
|
+
request.url,
|
|
790
|
+
request.async,
|
|
791
|
+
...ah.openArgs
|
|
792
|
+
);
|
|
793
|
+
for (const header in request.headers) {
|
|
794
|
+
xhr.setRequestHeader(header, request.headers[header]);
|
|
795
|
+
}
|
|
796
|
+
xhr.send(request.data);
|
|
797
|
+
}
|
|
798
|
+
});
|
|
735
799
|
}
|
|
736
800
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
801
|
+
function fakeXHR() {
|
|
802
|
+
const xhr = new winAh.realXHR();
|
|
803
|
+
if ("__ajaxHooker" in xhr)
|
|
804
|
+
console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
|
|
805
|
+
xhr.__ajaxHooker = new XhrHooker(xhr);
|
|
806
|
+
return xhr.__ajaxHooker.proxyXhr;
|
|
807
|
+
}
|
|
808
|
+
fakeXHR.prototype = win.XMLHttpRequest.prototype;
|
|
809
|
+
Object.keys(win.XMLHttpRequest).forEach(
|
|
810
|
+
(key) => (fakeXHR[key] = win.XMLHttpRequest[key])
|
|
811
|
+
);
|
|
812
|
+
function fakeFetch(url, options = {}) {
|
|
813
|
+
if (!url) return winAh.realFetch.call(win, url, options);
|
|
814
|
+
const init = {};
|
|
815
|
+
if (getType(url) === "[object Request]") {
|
|
816
|
+
for (const prop of fetchInitProps) init[prop] = url[prop];
|
|
817
|
+
url = url.url;
|
|
818
|
+
}
|
|
819
|
+
url = url.toString();
|
|
820
|
+
Object.assign(init, options);
|
|
821
|
+
init.method = init.method || "GET";
|
|
822
|
+
init.headers = init.headers || {};
|
|
823
|
+
const request = {
|
|
824
|
+
type: "fetch",
|
|
825
|
+
url: url,
|
|
826
|
+
method: init.method.toUpperCase(),
|
|
742
827
|
abort: false,
|
|
743
|
-
headers:
|
|
744
|
-
data:
|
|
828
|
+
headers: parseHeaders(init.headers),
|
|
829
|
+
data: init.body,
|
|
745
830
|
response: null,
|
|
746
|
-
async:
|
|
831
|
+
async: true,
|
|
747
832
|
};
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
833
|
+
const req = new AHRequest(request);
|
|
834
|
+
return new Promise((resolve, reject) => {
|
|
835
|
+
req
|
|
836
|
+
.waitForRequestKeys()
|
|
837
|
+
.then(() => {
|
|
838
|
+
if (request.abort) {
|
|
839
|
+
if (typeof request.response === "function") {
|
|
840
|
+
const response = {
|
|
841
|
+
finalUrl: request.url,
|
|
842
|
+
status: 200,
|
|
843
|
+
responseHeaders: {},
|
|
844
|
+
};
|
|
845
|
+
req.waitForResponseKeys(response).then(() => {
|
|
846
|
+
const key = fetchResponses.find((k) => k in response);
|
|
847
|
+
let val = response[key];
|
|
848
|
+
if (key === "json" && typeof val === "object") {
|
|
849
|
+
val = catchError(JSON.stringify.bind(JSON), val);
|
|
850
|
+
}
|
|
851
|
+
const res = new Response(val, {
|
|
852
|
+
status: 200,
|
|
853
|
+
statusText: "OK",
|
|
854
|
+
});
|
|
855
|
+
defineProp(res, "type", () => "basic");
|
|
856
|
+
defineProp(res, "url", () => request.url);
|
|
857
|
+
resolve(res);
|
|
858
|
+
});
|
|
859
|
+
} else {
|
|
860
|
+
reject(new DOMException("aborted", "AbortError"));
|
|
861
|
+
}
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
init.method = request.method;
|
|
865
|
+
init.headers = request.headers;
|
|
866
|
+
init.body = request.data;
|
|
867
|
+
winAh.realFetch.call(win, request.url, init).then((res) => {
|
|
868
|
+
if (typeof request.response === "function") {
|
|
869
|
+
const response = {
|
|
870
|
+
finalUrl: res.url,
|
|
871
|
+
status: res.status,
|
|
872
|
+
responseHeaders: parseHeaders(res.headers),
|
|
873
|
+
};
|
|
874
|
+
fetchResponses.forEach(
|
|
875
|
+
(key) =>
|
|
876
|
+
(res[key] = function () {
|
|
877
|
+
if (key in response)
|
|
878
|
+
return Promise.resolve(response[key]);
|
|
879
|
+
return resProto[key].call(this).then((val) => {
|
|
880
|
+
response[key] = val;
|
|
881
|
+
return req
|
|
882
|
+
.waitForResponseKeys(response)
|
|
883
|
+
.then(() => (key in response ? response[key] : val));
|
|
884
|
+
});
|
|
885
|
+
})
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
resolve(res);
|
|
889
|
+
}, reject);
|
|
890
|
+
})
|
|
891
|
+
.catch((err) => {
|
|
892
|
+
console.error(err);
|
|
893
|
+
resolve(winAh.realFetch.call(win, url, init));
|
|
894
|
+
});
|
|
758
895
|
});
|
|
759
|
-
return this.originalXhr.open(method, url, async, ...args);
|
|
760
896
|
}
|
|
761
|
-
|
|
762
|
-
const
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
request.data = data;
|
|
767
|
-
new AHRequest(request).waitForRequestKeys().then(() => {
|
|
768
|
-
if (request.abort) {
|
|
769
|
-
if (typeof request.response === "function") {
|
|
770
|
-
Object.assign(ah.proxyProps, {
|
|
771
|
-
responseURL: { value: request.url },
|
|
772
|
-
readyState: { value: 4 },
|
|
773
|
-
status: { value: 200 },
|
|
774
|
-
statusText: { value: "OK" },
|
|
775
|
-
});
|
|
776
|
-
xhrAsyncEvents.forEach((evt) => xhr.dispatchEvent(new Event(evt)));
|
|
777
|
-
}
|
|
778
|
-
} else {
|
|
779
|
-
xhr.open(request.method, request.url, request.async, ...ah.openArgs);
|
|
780
|
-
for (const header in request.headers) {
|
|
781
|
-
xhr.setRequestHeader(header, request.headers[header]);
|
|
782
|
-
}
|
|
783
|
-
xhr.send(request.data);
|
|
784
|
-
}
|
|
785
|
-
});
|
|
897
|
+
function fakeFetchClone() {
|
|
898
|
+
const descriptors = Object.getOwnPropertyDescriptors(this);
|
|
899
|
+
const res = winAh.realFetchClone.call(this);
|
|
900
|
+
Object.defineProperties(res, descriptors);
|
|
901
|
+
return res;
|
|
786
902
|
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
903
|
+
winAh = win.__ajaxHooker = winAh || {
|
|
904
|
+
version,
|
|
905
|
+
fakeXHR,
|
|
906
|
+
fakeFetch,
|
|
907
|
+
fakeFetchClone,
|
|
908
|
+
realXHR: win.XMLHttpRequest,
|
|
909
|
+
realFetch: win.fetch,
|
|
910
|
+
realFetchClone: resProto.clone,
|
|
911
|
+
hookInsts: new Set(),
|
|
912
|
+
};
|
|
913
|
+
if (winAh.version !== version)
|
|
791
914
|
console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
headers: parseHeaders(init.headers),
|
|
816
|
-
data: init.body,
|
|
817
|
-
response: null,
|
|
818
|
-
async: true,
|
|
915
|
+
win.XMLHttpRequest = winAh.fakeXHR;
|
|
916
|
+
win.fetch = winAh.fakeFetch;
|
|
917
|
+
resProto.clone = winAh.fakeFetchClone;
|
|
918
|
+
winAh.hookInsts.add(hookInst);
|
|
919
|
+
return {
|
|
920
|
+
hook: (fn) => hookInst.hookFns.push(fn),
|
|
921
|
+
filter: (arr) => {
|
|
922
|
+
if (Array.isArray(arr)) hookInst.filters = arr;
|
|
923
|
+
},
|
|
924
|
+
protect: () => {
|
|
925
|
+
readonly(win, "XMLHttpRequest", winAh.fakeXHR);
|
|
926
|
+
readonly(win, "fetch", winAh.fakeFetch);
|
|
927
|
+
readonly(resProto, "clone", winAh.fakeFetchClone);
|
|
928
|
+
},
|
|
929
|
+
unhook: () => {
|
|
930
|
+
winAh.hookInsts.delete(hookInst);
|
|
931
|
+
if (!winAh.hookInsts.size) {
|
|
932
|
+
writable(win, "XMLHttpRequest", winAh.realXHR);
|
|
933
|
+
writable(win, "fetch", winAh.realFetch);
|
|
934
|
+
writable(resProto, "clone", winAh.realFetchClone);
|
|
935
|
+
delete win.__ajaxHooker;
|
|
936
|
+
}
|
|
937
|
+
},
|
|
819
938
|
};
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
req
|
|
823
|
-
.waitForRequestKeys()
|
|
824
|
-
.then(() => {
|
|
825
|
-
if (request.abort) {
|
|
826
|
-
if (typeof request.response === "function") {
|
|
827
|
-
const response = {
|
|
828
|
-
finalUrl: request.url,
|
|
829
|
-
status: 200,
|
|
830
|
-
responseHeaders: {},
|
|
831
|
-
};
|
|
832
|
-
req.waitForResponseKeys(response).then(() => {
|
|
833
|
-
const key = fetchResponses.find((k) => k in response);
|
|
834
|
-
let val = response[key];
|
|
835
|
-
if (key === "json" && typeof val === "object") {
|
|
836
|
-
val = catchError(JSON.stringify.bind(JSON), val);
|
|
837
|
-
}
|
|
838
|
-
const res = new Response(val, {
|
|
839
|
-
status: 200,
|
|
840
|
-
statusText: "OK",
|
|
841
|
-
});
|
|
842
|
-
defineProp(res, "type", () => "basic");
|
|
843
|
-
defineProp(res, "url", () => request.url);
|
|
844
|
-
resolve(res);
|
|
845
|
-
});
|
|
846
|
-
} else {
|
|
847
|
-
reject(new DOMException("aborted", "AbortError"));
|
|
848
|
-
}
|
|
849
|
-
return;
|
|
850
|
-
}
|
|
851
|
-
init.method = request.method;
|
|
852
|
-
init.headers = request.headers;
|
|
853
|
-
init.body = request.data;
|
|
854
|
-
winAh.realFetch.call(win, request.url, init).then((res) => {
|
|
855
|
-
if (typeof request.response === "function") {
|
|
856
|
-
const response = {
|
|
857
|
-
finalUrl: res.url,
|
|
858
|
-
status: res.status,
|
|
859
|
-
responseHeaders: parseHeaders(res.headers),
|
|
860
|
-
};
|
|
861
|
-
fetchResponses.forEach(
|
|
862
|
-
(key) =>
|
|
863
|
-
(res[key] = function () {
|
|
864
|
-
if (key in response) return Promise.resolve(response[key]);
|
|
865
|
-
return resProto[key].call(this).then((val) => {
|
|
866
|
-
response[key] = val;
|
|
867
|
-
return req
|
|
868
|
-
.waitForResponseKeys(response)
|
|
869
|
-
.then(() => (key in response ? response[key] : val));
|
|
870
|
-
});
|
|
871
|
-
})
|
|
872
|
-
);
|
|
873
|
-
}
|
|
874
|
-
resolve(res);
|
|
875
|
-
}, reject);
|
|
876
|
-
})
|
|
877
|
-
.catch((err) => {
|
|
878
|
-
console.error(err);
|
|
879
|
-
resolve(winAh.realFetch.call(win, url, init));
|
|
880
|
-
});
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
|
-
function fakeFetchClone() {
|
|
884
|
-
const descriptors = Object.getOwnPropertyDescriptors(this);
|
|
885
|
-
const res = winAh.realFetchClone.call(this);
|
|
886
|
-
Object.defineProperties(res, descriptors);
|
|
887
|
-
return res;
|
|
888
|
-
}
|
|
889
|
-
winAh = win.__ajaxHooker = winAh || {
|
|
890
|
-
version,
|
|
891
|
-
fakeXHR,
|
|
892
|
-
fakeFetch,
|
|
893
|
-
fakeFetchClone,
|
|
894
|
-
realXHR: win.XMLHttpRequest,
|
|
895
|
-
realFetch: win.fetch,
|
|
896
|
-
realFetchClone: resProto.clone,
|
|
897
|
-
hookInsts: new Set(),
|
|
898
|
-
};
|
|
899
|
-
if (winAh.version !== version)
|
|
900
|
-
console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
|
|
901
|
-
win.XMLHttpRequest = winAh.fakeXHR;
|
|
902
|
-
win.fetch = winAh.fakeFetch;
|
|
903
|
-
resProto.clone = winAh.fakeFetchClone;
|
|
904
|
-
winAh.hookInsts.add(hookInst);
|
|
905
|
-
return {
|
|
906
|
-
hook: (fn) => hookInst.hookFns.push(fn),
|
|
907
|
-
filter: (arr) => {
|
|
908
|
-
if (Array.isArray(arr)) hookInst.filters = arr;
|
|
909
|
-
},
|
|
910
|
-
protect: () => {
|
|
911
|
-
readonly(win, "XMLHttpRequest", winAh.fakeXHR);
|
|
912
|
-
readonly(win, "fetch", winAh.fakeFetch);
|
|
913
|
-
readonly(resProto, "clone", winAh.fakeFetchClone);
|
|
914
|
-
},
|
|
915
|
-
unhook: () => {
|
|
916
|
-
winAh.hookInsts.delete(hookInst);
|
|
917
|
-
if (!winAh.hookInsts.size) {
|
|
918
|
-
writable(win, "XMLHttpRequest", winAh.realXHR);
|
|
919
|
-
writable(win, "fetch", winAh.realFetch);
|
|
920
|
-
writable(resProto, "clone", winAh.realFetchClone);
|
|
921
|
-
delete win.__ajaxHooker;
|
|
922
|
-
}
|
|
923
|
-
},
|
|
924
|
-
};
|
|
925
|
-
})();
|
|
939
|
+
})();
|
|
940
|
+
};
|
|
926
941
|
|
|
927
942
|
/**
|
|
928
943
|
*
|
|
@@ -3193,7 +3208,7 @@ class UtilsDictionary {
|
|
|
3193
3208
|
|
|
3194
3209
|
let Utils$1 = class Utils {
|
|
3195
3210
|
/** 版本号 */
|
|
3196
|
-
version = "2024.5.
|
|
3211
|
+
version = "2024.5.25";
|
|
3197
3212
|
addStyle(cssText) {
|
|
3198
3213
|
if (typeof cssText !== "string") {
|
|
3199
3214
|
throw new Error("Utils.addStyle 参数cssText 必须为String类型");
|
|
@@ -3308,7 +3323,7 @@ let Utils$1 = class Utils {
|
|
|
3308
3323
|
* + 版本:1.4.1
|
|
3309
3324
|
* + 文档:https://scriptcat.org/zh-CN/script-show-page/637/
|
|
3310
3325
|
*/
|
|
3311
|
-
ajaxHooker =
|
|
3326
|
+
ajaxHooker = AjaxHooker;
|
|
3312
3327
|
canvasClickByPosition(canvasElement, clientX = 0, clientY = 0, view = globalThis) {
|
|
3313
3328
|
if (!(canvasElement instanceof HTMLCanvasElement)) {
|
|
3314
3329
|
throw new Error("Utils.canvasClickByPosition 参数canvasElement必须是canvas元素");
|