2、文字的水印与镂空、文字与盒子的阴影,背景,线性渐变,径向渐变,动画(闪烁、过渡、转换),数据加密、js编码与解码、数据上传、数据下载、数据展示、文档编辑,算法知识|显示屏尺寸|彩礼|编程绝句|在线网址AI微工具|electron(4450行)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 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 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 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 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 | 一、文字的水印与镂空、文字与盒子的阴影,背景,线性渐变(边框渐变、文字渐变),径向渐变,动画(闪烁、过渡、转换) 1、文字的水印与镂空、文字与盒子的阴影 附、颜色的优先级-从小到大 background-color< border-color、color< -webkit-text-stroke(文字轮廓色)、-webkit-text-fill-color(文字填充色) (1)文字的水印与镂空 <!DOCTYPE html> <html> <head lang= "en" > <meta charset= "UTF-8" > <title></title> <style type= "text/css" > .text-watermark{ z-index: 1; position: absolute; opacity: 0.2; transform: rotate(-45deg) translate(30px); user- select : none; } .text-uesd{ z-index: 2; position: relative; } .text-stroke{ font-size: 24px; font-weight: 900; color: transparent; -webkit-text-stroke: 1px gray; /* 文本轮廓的线宽、颜色;stroke,笔画 */ } </style> </head> <body> <pre style= "padding-left: 50px;" > 1/2、文字水印 <pre class = "text-watermark" > 文字水印样式 .text-watermark{ z-index: 1; position: absolute; opacity: 0.2; transform: rotate(-45deg) translate(30px); user- select : none; } </pre> <pre class = "text-uesd" > 文字主体样式 .text-uesd{ z-index: 2; position: relative; } </pre> </pre> <pre class = "text-stroke" > 2/2、文字镂空 .text-stroke{ font-size: 24px; font-weight: 900; color: transparent; -webkit-text-stroke: 1px gray; /* 文本轮廓的线宽、颜色;stroke,笔画 */ } </pre> </body> </html> (2)文字与盒子的阴影 <!DOCTYPE html> <html> <head lang= "en" > <meta charset= "UTF-8" > <title></title> <style type= "text/css" > .text-shadow{ font-size: 24px; font-weight: 900; color: #000; text-shadow: -5px -5px 3px gray, 5px 5px 3px #ccc; } .box-shadow{ width: 1000px; margin: 30px 30px 30px 130px ; padding-top: 15px; font-size: 15px; border-radius: 10px; box-shadow: 0 0 10px 20px gray, 0 0 10px 20px #ccc inset; } </style> </head> <body> <pre class = "text-shadow" > 1/2、文字阴影 .text-shadow{ font-size: 20px; font-weight: 900; color: #000; text-shadow: -5px -5px 3px gray <左上阴影>, 5px 5px 3px #ccc <右下阴影>; } 以下text-shadow的取值说明, 来源,https: //www.runoob.com/cssref/css3-pr-box-shadow.html text-shadow: h-shadow v-shadow blur color; h-shadow,必需,水平阴影的位置;负值左阴影,0底阴影,正值右阴影 v-shadow,必需,垂直阴影的位置;负值上阴影,0底阴影,正值下阴影 blur,可选,模糊的距离 color,可选,阴影的颜色 </pre> <pre class = "box-shadow" > 2/2、盒子阴影 .box-shadow{ box-shadow: 0 0 10px 10px gray; box-shadow: 0 0 10px 10px gray <外阴影>, 0 0 10px 10px #ccc inset <内阴影>; } 以下box-shadow的取值说明 box-shadow: h-shadow v-shadow blur spread color inset; h-shadow,必需,水平阴影的位置;负值左阴影,0左右阴影,正值右阴影 v-shadow,必需,垂直阴影的位置;负值上阴影,0上下阴影,正值下阴影 blur,可选,模糊距离 spread,可选,阴影的大小 color,可选,阴影的颜色;在CSS颜色值寻找颜色值的完整列表 inset,可选,从外层的阴影(开始时)改变阴影内侧阴影 </pre> </body> </html> 2、背景 <!DOCTYPE html> <html lang= "en" > <style> .bg{ width: 1100px; height: 200px; border-radius: 20px; padding: 20px; margin: 20px; border: 20px dotted black; /* 以下,单背景颜色,覆盖范围为content+padding+border */ background-color: gray; /* 以下,多背景图像,从后向前渲染;如用渐变,则把url换成 linear-gradient、radial-gradient、repeating-linear-gradient或repeating-radial-gradient */ background-image: url( "https://img-blog.csdnimg.cn/violation-del.png" ), url( "https://img-blog.csdnimg.cn/violation-del.png" ); background-repeat: no-repeat, no-repeat; /* 以下4个,先定位放置、后裁切显示,优先级逐渐降低; border-box border-box; padding-box padding-box; content-box content-box; */ background-origin: content-box, border-box; background-position: left center, right center; background-size: 35%, contain; /* background-clip: content-box, content-box; 注掉background-clip,可能露出背景色 */ } .pre{ border: 2px solid black; width: 1200px; margin: 30px; border-radius: 10px; padding: 30px 0; } .span{ font-size: 20px; font-weight: 900; } </style> <head> <meta charset= "UTF-8" > <title>背景</title> </head> <body> <div class = "bg" ></div> <pre class = "pre" > 用法来源,https: //www.runoob.com/cssref/css3-pr-background.html background:汇总 background-color background-image background-repeat background-attachment; background-position background-size background-origin background-clip; background:取值说明 (1)background-attachment,设置背景图像是否固定或者随着页面的其余部分滚动,默认值:initial scroll,背景图片随着页面的滚动而滚动,这是默认的 fixed ,背景图片不会随着页面的滚动而滚动 local,背景图片会随着元素内容的滚动而滚动 initial,设置该属性的默认值,https: //www.runoob.com/cssref/css-initial.html (2)background-color,指定要使用的一个背景颜色,默认值:transparent 覆盖范围为content+padding+border, (3)background-image,指定要使用的一或多个背景图像,默认值:none 覆盖范围由(5)(6)(7)(8)配置决定, (4)background-repeat,指定如何重复背景图像,默认值:repeat repeat,背景图像将向垂直和水平方向重复 repeat-x,只有水平位置会重复背景图像 repeat-y,只有垂直位置会重复背景图像 no-repeat,不重复 //以下4个,先定位放置、后裁切显示,优先级逐渐降低 (5)background-origin,指定背景图像的定位区域,默认值:padding-box padding-box,背景图像填充框的相对位置 border-box,背景图像边界框的相对位置 content-box,背景图像的相对位置的内容框 (6)background-position,指定背景图像的位置,默认值:0% 0% //以下,top,bottom,left,right的覆盖范围为content+padding, left top, left center, left bottom, right top, right center, right bottom, center top, center center, center bottom,指定一个,另一个是 "center" x% y%,指定一个,另一个是50% xpx ypx,指定一个,另一个是50% (7)background-size,指定背景图片的大小,默认值:auto auto,设置背景图片高度和宽度为原始的高度和宽度; length,设置背景图片高度和宽度; percentage,将计算相对于背景定位区域的百分比; 第1个值,设置宽度;第2个值,设置的高度;如果只给出1个值,第2个是设置为auto(自动) 注意,有时超过100%,比如107%,才能把目标区域完全覆盖,是因为原背景图片有近乎透明的阴影,占用了一些尺寸 cover,此时会保持图像的纵横比并将图像缩放成将完全覆盖背景定位区域的最小大小 contain,此时会保持图像的纵横比并将图像缩放成将适合背景定位区域的最大大小 (8)background-clip,指定背景图像的绘制区域(显示区域),默认值:border-box border-box,背景绘制在边框方框内(剪切成边框方框) padding-box,背景绘制在衬距方框内(剪切成衬距方框) content-box,背景绘制在内容方框内(剪切成内容方框) -webkit-background-clip:text;背景绘制在文字上 </pre> </body> </html> 3、线性渐变 (1)文字与边框渐变 <!DOCTYPE html> <html lang= "en" > <style> .div{ width: 1200px; margin: 30px; border-radius: 10px; } .gradientBorder{ background-image: linear-gradient(#fff,#fff),linear-gradient(10deg,#624AFF,#1CF7CC,#1697F8); background-clip: content-box,border-box; /* 以下方案一 */ border: 2px solid transparent; padding: 0; /* 以下方案二 */ /* padding: 2px; */ } .padding{ padding: 10px; } .gradientText{ background-image: -webkit-linear-gradient(right,#624AFF,#f71c27,#1697F8); color: transparent; /* -webkit-text-fill-color: transparent; */ -webkit-background-clip: text; } </style> <head> <meta charset= "UTF-8" > <title>文字渐变、边框渐变</title> </head> <body> <pre> background-image,用法来源,https: //www.runoob.com/cssref/pr-background-image.html </pre> <div class = "div gradientBorder" > <div class = "padding" >示例:文字渐变、边框渐变</div> <pre class = "gradientText padding" > .gradientBorder{ background-image: linear-gradient(#fff,#fff),linear-gradient(98deg,#624AFF,#1CF7CC,#1697F8); background-clip: content-box,border-box; /* 以下方案一 */ border: 2px solid transparent; padding: 0; /* 以下方案二 */ /* padding: 2px; */ } .gradientText{ background-image: -webkit-linear-gradient(right,#624AFF,#1CF7CC,#1697F8); color: transparent; /* -webkit-text-fill-color: transparent; */ -webkit-background-clip: text; } </pre> </div> </body> </html> (2)线性渐变 <!DOCTYPE html> <html lang= "en" > <style> .div{ width: 1200px; margin: 30px; border-radius: 10px; } .blackBorder{ border: 2px solid black; } .padding{ padding: 10px; } .linearGradientYes0{ background-image: linear-gradient(to right, red 0, yellow 600px, green 1200px); } .linearGradientNo0{ background-image: linear-gradient(to right, red 20%, yellow 50%, green 80%); } .repeatingLinearGradientYes0{ background-image: repeating-linear-gradient(to right, red 0, yellow 150px, green 300px); } .repeatingLinearGradientNo0{ background-image: repeating-linear-gradient(to right, red 8%, yellow 20%, green 30%); } </style> <head> <meta charset= "UTF-8" > <title>(重复)线性渐变</title> </head> <body> <pre> background-image,用法来源,https: //www.runoob.com/cssref/pr-background-image.html </pre> <div class = "div blackBorder linearGradientYes0" > <div class = "padding" >1、线性渐变-以0为起点</div> <pre> linear-gradient(direction, color-stopA, color-stopB, ...); A、direction 用角度值指定渐变的方向(或角度);从上到下(默认) B、color-stopA, color-stopB, ... , color-stopN color-stopA/N用于指定“整个渐变”开始/结束时的颜色和位置 C、示例,background-image: linear-gradient(to right, red 0, yellow 600px, green 1200px); D、从red过渡到yellow,再过渡到green; </pre> </div> <div class = "div blackBorder linearGradientNo0" > <div class = "padding" >2、线性渐变-不以0为起点</div> <pre> linear-gradient(direction, color-stopA, color-stopB, ...); A、direction 用角度值指定渐变的方向(或角度);从上到下(默认) B、color-stopA, color-stopB, ... , color-stopN color-stopA/N用于指定“整个渐变”开始/结束时的颜色和位置 C、示例,background-image:linear-gradient(to right, red 20%, yellow 50%, green 80%); D、0到20%为red,80%到100%为green;20%到80%,从red过渡到yellow,再过渡到green; </pre> </div> <div class = "div blackBorder repeatingLinearGradientYes0" > <div class = "padding" >3、重复线性渐变-以0为起点</div> <pre> repeating-linear-gradient(direction, color-stopA, color-stopB, ...); A、direction 用角度值指定渐变的方向(或角度);从上到下(默认) B、colorA A%, colorB B%, ... , colorN N%,A%、N%用于指定第1、2个渐变的结束位置,colorA-colorN,用于指定1个完整渐变的颜色构成 C、示例,background-image: repeating-linear-gradient(to right, red 0, yellow 150px, green 300px); D、上例中,数据释义如下 0,第1个渐变的结束位置 300px,第2个渐变的结束位置 300px,300px-0px,1个完整渐变的占比,颜色与位置对应为red 0, yellow 150, green 300 900px,3*300px,3个完整渐变的占比 900px,最后1个渐变的开始位置 </pre> </div> <div class = "div blackBorder repeatingLinearGradientNo0" > <div class = "padding" >4、重复线性渐变-不以0为起点</div> <pre> repeating-linear-gradient(direction, color-stopA, color-stopB, ...); A、direction 用角度值指定渐变的方向(或角度);从上到下(默认) B、colorA A%, colorB B%, ... , colorN N%,A%、N%用于指定第1、2个渐变的结束位置,colorA-colorN,用于指定1个完整渐变的颜色构成 C、示例,background-image: repeating-linear-gradient(to right, red 8%, yellow 20%, green 30%); D、上例中,数据释义如下 8%,第1个渐变的结束位置 30%,第2个渐变的结束位置 22%,30%-8%,1个完整渐变的占比,颜色与位置对应为red 0, yellow 12, green 22 88%,4*22%,4个完整渐变的占比 96%,8%+88%,最后1个渐变的开始位置 </pre> </div> </body> </html> 4、径向渐变 <!DOCTYPE html> <html> <head lang= "en" > <meta charset= "UTF-8" > <title>(重复)径向渐变</title> <style type= "text/css" > .common{ width: 1200px; font-size: 15px; font-weight: 900; color: black; border-radius: 10px; margin: 50px; padding: 0px; } . params { border: 2px solid black; width: 1200px; margin: 30px; border-radius: 10px; padding: 30px 0; } .paddingLeft{ padding-left: 10px; } .backgroundSize{ background-size:370px 220px; } /* .backgroundRepeat{ background-repeat: no-repeat; } */ .radialNumber{ height: 400px; background-image: radial-gradient(250px 35% at center,red 60px,yellow 90px,green 130px); } .radialRate{ height: 400px; background-image: radial-gradient(250px 35% at center,red 20%, yellow 30%, green 45%); } .repeatNumber{ height: 400px; background-image: repeating-radial-gradient(250px 35% at center,red 60px,yellow 90px,green 130px); } .repeatRate{ height: 400px; background-image: repeating-radial-gradient(250px 35% at center,red 20%, yellow 30%, green 45%); } .money{ background-image:repeating-radial-gradient( circle, gray 0,gray 5px,transparent 5px,transparent 20px, gray 20px,gray 25px,transparent 25px,transparent 50px ); background-size:90px 90px; display: flex; justify-content: flex-end; align-items: flex-end; } </style> </head> <body> <pre class = "params" > <div class = "paddingLeft" >径向渐变-参数说明</div> <div> background-image: radial-gradient(shape size at position, start-color, ..., last-color); 1、shape,径向渐变的形状,默认为ellipse circle,指定圆形的径向渐变 background-image: radial-gradient(circle, red, yellow, green); ellipse,指定椭圆形的径向渐变 background-image: radial-gradient(ellipse closest-corner, red, yellow, green); 特别说明,当指定size为“数字”时,“指定形状”,必须根据数字的个数,否则无渐变效果,因此“指定形状”是多余的 background-image: radial-gradient(circle 400px, red, yellow, green); background-image: radial-gradient(ellipse 400px 40%, red, yellow, green); 特别说明,当指定size为“关键字”时,“指定形状”可以没有、可以任意,“指定形状”不是多余的 background-image: radial-gradient(farthest-side, red, yellow, green); background-image: radial-gradient(circle farthest-side, red, yellow, green); 2、size,径向渐变的宽高,默认为farthest-corner,可以用“省略”或“一个关键字”或“一、两个数字” farthest-corner,指定径向渐变的半径长度为从圆心到离圆心最远的角 closest-side,指定径向渐变的半径长度为从圆心到离圆心最近的边 closest-corner,指定径向渐变的半径长度为从圆心到离圆心最近的角 farthest-side,指定径向渐变的半径长度为从圆心到离圆心最远的边 3、position,定义渐变的位置,默认为center,可以用“省略”或“一个关键字”或“两个数字” center,设置中间为径向渐变圆心的纵坐标值 top,设置顶部为径向渐变圆心的纵坐标值 bottom,设置底部为径向渐变圆心的纵坐标值 left,设置左侧为径向渐变圆心的横坐标值 right,设置右侧为径向渐变圆心的横坐标值 background-image: radial-gradient(circle, red, yellow, yellow); background-image: radial-gradient(circle at center, red, yellow, green); background-image: radial-gradient(400px 40% at 156px 60%, red, yellow, green); 4、start-color, ..., last-color,用于指定“整个渐变”开始/结束时的颜色和位置 </div> <div class = "paddingLeft" >径向渐变-案例解析</div> <div> 1、案例解析1 例1、background-image: radial-gradient(250px-A处 35%-B处 at center,red 60px,yellow 90px,green 130px); 例2、background-image: repeating-radial-gradient(250px-A处 35%-B处 at center,red 60px,yellow 90px,green 130px); (1)例1中,数据释义如下 60px,径向渐变开始位置,如果大于0,那么0到开始位置的颜色为开始位置的颜色 130px,径向渐变结束位置,如果小于100%,那么结束位置到100%的颜色为结束位置的颜色 (2)例2中,数据释义如下 60px,重复径向渐变第1层椭圆的结束位置,即该层椭圆的X轴半径是60px 130px,重复径向渐变第2层椭圆的结束位置,即该层椭圆的X轴半径是130px 2、案例解析2 例1、background-image: radial-gradient(250px-A处 35%-B处 at center, red 20%, yellow 30%, green 45%); 例2、background-image: repeating-radial-gradient(250px-A处 35%-B处 at center, red 20%, yellow 30%, green 45%); (1)例1中,数据释义如下 20%,径向渐变开始位置,即250px的20%,如果大于0,那么0到开始位置的颜色为开始位置的颜色 45%,径向渐变结束位置,即250px的45%,如果小于100%,那么结束位置到100%的颜色为结束位置的颜色 (2)例2中,数据释义如下 20%,重复径向渐变第1层椭圆的结束位置,即该层椭圆的X轴半径是250px的20% 45%,重复径向渐变第2层椭圆的结束位置,即该层椭圆的X轴半径是250px的45% 3、上面案例中, (1)如果A处或B处为百分数,那么先通过盒子的width或height计算出对应值,进而计算出椭圆的X轴(先)或Y轴(后)半径 (2)center,将上面的椭圆放到盒子的正中间,当center改为10px 30px时,将上面的椭圆中心放到盒子左边右侧10px,上边下方30px的地方, (3)重复径向渐变,各个色带(层距)从外向里填充颜色,当中心椭圆的半径小于层距时,椭圆中心不会出现色带内侧的颜色 4、盒子的width或height只含content,但background-image默认是从border开始覆盖的 </div> </pre> <pre class = "common radialNumber backgroundRepeat" > <div class = "paddingLeft" >1、径向渐变-像素</div> <div> .radialNumber{ height: 400px; background-image: radial-gradient(250px 35% at center,red 60px,yellow 90px,green 130px); } 上例中,径向渐变数据释义如下 椭圆的X轴半径是130 椭圆的Y轴半径是72.8,(400*35%)/250*130,y中心/x中心*x半径 </div> </pre> <pre class = "common radialNumber backgroundRepeat backgroundSize" > <div class = "paddingLeft" >2、径向渐变-像素,含backgroundSize</div> <div> .radialNumber{ height: 400px; background-image: radial-gradient(250px 35% at center,red 60px,yellow 90px,green 130px); } .backgroundSize{ background-size:370px 220px; } 上例中,径向渐变数据释义如下 椭圆的X轴半径是130 椭圆的Y轴半径是40.04,(220*35%)/250*130,y中心/x中心*x半径 </div> </pre> <pre class = "common radialRate backgroundRepeat" > <div class = "paddingLeft" >3、径向渐变-百分比</div> <div> .radialRate{ height: 400px; background-image: radial-gradient(250px 35% at center,red 20%, yellow 30%, green 45%); } 上例中,径向渐变数据释义如下 椭圆的X轴半径是112.5,250*45% 椭圆的Y轴半径是63,(400*35%)/250*112.5,y中心/x中心*x半径 </div> </pre> <pre class = "common radialRate backgroundRepeat backgroundSize" > <div class = "paddingLeft" >4、径向渐变-百分比,含backgroundSize</div> <div> .radialRate{ height: 400px; background-image: radial-gradient(250px 35% at center,red 20%, yellow 30%, green 45%); } .backgroundSize{ background-size:370px 220px; } 上例中,径向渐变数据释义如下 椭圆的X轴半径是112.5,250*45% 椭圆的Y轴半径是34.65,(220*35%)/250*112.5,y中心/x中心*x半径 </div> </pre> <pre class = "common repeatNumber backgroundRepeat" > <div class = "paddingLeft" >5、重复径向渐变-像素</div> <div> .repeatNumber{ height: 400px; background-image: repeating-radial-gradient(250px 35% at center,red 60px,yellow 90px,green 130px); } 上例中,重复径向渐变数据释义如下 第1层椭圆的X轴半径是60 第2层椭圆的X轴半径130 X轴层距70,130-60 第1层椭圆的Y轴半径33.6,(400*35%)/250*60,y中心/x中心*1层x半径 第2层椭圆的Y轴半径72.8,(400*35%)/250*130,y中心/x中心*2层x半径 Y轴层距39.2,72.8-33.6 </div> </pre> <pre class = "common repeatNumber backgroundRepeat backgroundSize" > <div class = "paddingLeft" >6、重复径向渐变-像素,含backgroundSize</div> <div> .repeatNumber{ height: 400px; background-image: repeating-radial-gradient(250px 35% at center,red 60px,yellow 90px,green 130px); } .backgroundSize{ background-size:370px 220px; } 上例中,重复径向渐变数据释义如下 第1层椭圆的X轴半径是60 第2层椭圆的X轴半径130 X轴层距70,130-60 第1层椭圆的Y轴半径18.48,(220*35%)/250*60,y中心/x中心*1层x半径 第2层椭圆的Y轴半径40.04,(220*35%)/250*130,y中心/x中心*2层x半径 Y轴层距21.56,40.04-18.48 </div> </pre> <pre class = "common repeatRate backgroundRepeat" > <div class = "paddingLeft" >7、重复径向渐变-百分比</div> <div> .repeatRate{ height: 400px; background-image: repeating-radial-gradient(250px 35% at center,red 20%, yellow 30%, green 45%); } 上例中,重复径向渐变数据释义如下 第1层椭圆的X轴半径是50,250*20% 第2层椭圆的X轴半径112.5,250*45% X轴层距62.5,112.5-50 第1层椭圆的Y轴半径28,(400*35%)/250*50,y中心/x中心*1层x半径 第2层椭圆的Y轴半径63,(400*35%)/250*112.5,y中心/x中心*2层x半径 Y轴层距35,63-28 </div> </pre> <pre class = "common repeatRate backgroundRepeat backgroundSize" > <div class = "paddingLeft" >8、重复径向渐变-百分比,含backgroundSize</div> <div> .repeatRate{ height: 400px; background-image: repeating-radial-gradient(250px 35% at center,red 20%, yellow 30%, green 45%); } .backgroundSize{ background-size:370px 220px; } 上例中,重复径向渐变数据释义如下 第1层椭圆的X轴半径是50,250*20% 第2层椭圆的X轴半径112.5,250*45% X轴层距62.5,112.5-50 第1层椭圆的Y轴半径15.4,(220*35%)/250*50,y中心/x中心*1层x半径 第2层椭圆的Y轴半径34.65,(220*35%)/250*112.5,y中心/x中心*2层x半径 Y轴层距19.25,34.65-15.4 </div> </pre> <pre class = "common money" > <div> 附、重复径向渐变-铜钱效果 .money{ background-image:repeating-radial-gradient(circle, gray 0,gray 5px,transparent 5px,transparent 20px, gray 20px,gray 25px,transparent 25px,transparent 50px ); background-size:90px 90px; display: flex; justify-content: flex-end; align-items: flex-end; } </div> </pre> </body> </html> 5、动画示例 (1)单帧动画(含动画说明) <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <title>正常动画</title> <style> *{ padding: 0; margin: 0; } .divUp { top: 150px; left: 800px; width: 1000px; height: 500px; line-height: 500px; background: rgb(131, 128, 128); border-radius: 60px; text-align: center; font-size: 150px; color: #000; position: relative; animation: upMove /*名称*/ 2s /*周期*/ ease /*速度*/ 0.1s /*延迟*/ infinite /*循环次数*/ alternate /*交替方向*/ ; /* animation,https://www.runoob.com/cssref/css3-pr-animation.html 速度,https://www.runoob.com/cssref/css3-pr-animation-timing-function.html ease,默认,动画以低速开始,然后加快,在结束前变慢 ease-in,动画以低速开始 ease-out,动画以低速结束 ease-in-out,动画以低速开始和结束 linear,动画从头到尾的速度是相同的 循环次数,https://www.runoob.com/cssref/css3-pr-animation-iteration-count.html number,一个数字,定义应该播放多少次动画 infinite,指定动画应该播放无限次(永远) 交替方向,https://www.runoob.com/cssref/css3-pr-animation-direction.html normal,正常播放,默认值 reverse,反向播放 alternate,奇正向播放,动画在奇数次(1、3、5...)正向播放,在偶数次(2、4、6...)反向播放 alternate-reverse,奇反向播放,动画在奇数次(1、3、5...)反向播放,在偶数次(2、4、6...)正向播放 */ } @keyframes upMove { /* 这里只写需要改变的项,且to中各项应与.divUp中各项一致,否则动画结束时,运动区域会缩小或放大或其它改变 */ from { top: 0px; left: 0px; width: 200px; height: 100px; line-height: 100px; background: rgb(252, 249, 249); border-radius: 0px; font-size: 20px; color: #a59999; } to { top: 150px; left: 800px; width: 1000px; height: 500px; line-height: 500px; background: rgb(131, 128, 128); border-radius: 60px; font-size: 150px; color: #000; } } /* 以上,动画效果-上 */ /* 以下,动画效果-下 */ .divDown { height: 100px; width: 940px; margin-top: 200px; /* 相对于未定位的.divUp的底部,定位后的.divUp脱离了文档流 */ margin-left: 800px; background: rgb(131, 128, 128); animation: downMove 2s ease 0.1s infinite alternate; overflow: hidden; padding: 30px; } @keyframes downMove { /* 这里只写需要改变的项,且to中各项应与.divDown中各项一致,否则动画结束时,运动区域会缩小或放大或其它改变 */ from { height: 0px; } to { height: 100px; } } </style> </head> <body> <div class = "divUp" >动画效果</div> <div class = "divDown" > <div>overflow: hidden; 1/10</div> <div>overflow: hidden; 2/10</div> <div>overflow: hidden; 3/10</div> <div>overflow: hidden; 4/10</div> <div>overflow: hidden; 5/10</div> <div>overflow: hidden; 6/10</div> <div>overflow: hidden; 7/10</div> <div>overflow: hidden; 8/10</div> <div>overflow: hidden; 9/10</div> <div>overflow: hidden; 10/10</div> </div> </body> </html> (2)多帧动画(含页面闪烁) <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <title>多帧动画(含页面闪烁)</title> <style> *{ padding: 0; margin: 0; } .divSize{ margin: 30px auto; color: rgb(27, 25, 25); background: rgb(131, 128, 128); display: flex; justify-content: center; align-items: center; } .fontSize{ font-size: 200px; } .padding20{ padding: 20px; width: 960px; } .height360{ height: 360px; width: 1000px; } /* 以下动画触发 */ .divDown { animation: widthMove 2s ease 0.1s infinite normal, heightMove 2s ease 0.1s infinite normal; } .divDown:hover { animation: widthMove 2s ease 0.1s infinite normal, heightMove 2s ease 0.1s infinite normal; } /* 以下动画定义 */ @keyframes widthMove { from { width: 0px; background: rgb(161, 95, 95); } to { width: 1000px; background: rgb(131, 128, 128); } } @keyframes heightMove { from { height: 0px; font-size: 15px; } to { height: 360px; font-size: 200px; } } </style> </head> <body> <div class = "divSize padding20" > <pre> 1、单用下面这种方式触发动画,页面正常 .divDown { widthMove 2s ease 0.1s infinite normal, heightMove 2s ease 0.1s infinite normal; } 2、单用下面这种方式触发动画,<b><big>页面会闪烁</big></b>,原因是 在初始位置,面积大,为100%,hover触发动画,因为 from 面积小,为0,失去hover,回到初始位置,面积大,为100%,又造成hover触发动画 .divDown:hover { widthMove 2s ease 0.1s infinite normal, heightMove 2s ease 0.1s infinite normal; } 3、目前2个同时使用,第1个生效(正常)。可注掉第1个,让第2个生效(闪烁) </pre> </div> <div class = "divSize height360 fontSize divDown" >居中</div> </body> </html> 6、过渡示例 (1)单个属性过渡(转换,内含过渡说明和转换说明) <!DOCTYPE html> <html> <head> <meta charset= "UTF-8" > <title>单个属性过渡(转换)</title> <style> div{ width:600px; height:200px; margin-top: 200px; margin-left: 150px; background: #ccc; display: flex; justify-content: center; align-items: center; /* 初始时,指定“需要过渡的属性”及相关参数 */ transition: transform /*CSS属性名*/ 2s /*过渡时长*/ ease- in /*运动速度*/ 0s /*延迟时长*/ ; } /* 悬停时,“需要过渡的属性”,由初始值或默认值-过渡到-指定值 */ div:hover{ transform: rotate(7deg) /*旋转*/ skew(20deg) /*倾斜*/ scale(2) /*缩放*/ translate(120px) /*移动*/ ; } </style> </head> <body> <div> <pre> transform,转换,对元素使用2D或3D转换,百度翻译,使改变 使用方法,https: //www.runoob.com/cssref/css3-pr-transform.html </pre> </div> </body> </html> (2)多个属性过渡(宽、高、字体大小,内含动画和过渡的区别) <!DOCTYPE html> <html> <head> <meta charset= "UTF-8" > <title>多个属性过渡(宽、高、字体大小)</title> <style> div{ width: 800px; height: 220px; font-size: 14px; transition: width 2s ease- in 0s, height 2s ease- in 0s, font-size 2s ease- in 0s; } div:hover{ width: 1600px; height: 440px; font-size: 28px; } .div{ background:rgb(95, 95, 97); padding: 50px 0; /* padding设置不能出现auto,否则发生padding:0的效果 */ } </style> </head> <body> <div class = "div" > <pre> animation(动画)和transition(过渡)<span style= "color: #fff;" >的区别</span> 来源,https: //blog.csdn.net/qq_38290251/article/details/133644402 A、应用场景: a、animation,用于实现复杂的动画效果, b、transition,用于实现简单的动画效果, B、实现方式: a、animation,先定义关键帧,然后指定关键帧及相关参数;可手动、自动触发的;可以循环播放 b、transition,直接指定属性及相关参数;仅手动(悬停)触发;1次触发1次播放 C、属性值,都可以是多组 a、animation,每个属性值可以改变多个其它属性 b、transition,每个属性值只能改变一个其它属性 </pre> </div> </body> </html> 二、数据加密-AES和RSA 1、AES加密 <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <meta http-equiv= "X-UA-Compatible" content= "IE=edge" > <meta name= "viewport" content= "width=device-width, initial-scale=1.0" > <title>Document</title> <!-- 引入 CDN Crypto.js 开始 AES加密 注意引入顺序 --> <script type= "text/javascript" > //https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/core.min.js !function(t,n){ "object" == typeof exports?module.exports=exports=n(): "function" == typeof define&&define.amd?define([],n):t.CryptoJS=n()}( this ,function(){ var t=t||function(f){ var t; if ( "undefined" != typeof window&&window.crypto&&(t=window.crypto),!t&& "undefined" != typeof window&&window.msCrypto&&(t=window.msCrypto),!t&& "undefined" != typeof global&&global.crypto&&(t=global.crypto),!t&& "function" == typeof require) try {t=require( "crypto" )} catch (t){}function i(){ if (t){ if ( "function" == typeof t.getRandomValues) try { return t.getRandomValues( new Uint32Array(1))[0]} catch (t){} if ( "function" == typeof t.randomBytes) try { return t.randomBytes(4).readInt32LE()} catch (t){}} throw new Error( "Native crypto module could not be used to get secure random number." )} var e=Object.create||function(t){ var n; return r.prototype=t,n= new r,r.prototype= null ,n};function r(){} var n={},o=n.lib={},s=o.Base={extend:function(t){ var n=e( this ); return t&&n.mixIn(t),n.hasOwnProperty( "init" )&& this .init!==n.init||(n.init=function(){n.$super.init.apply( this ,arguments)}),(n.init.prototype=n).$super= this ,n},create:function(){ var t= this .extend(); return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){ for ( var n in t)t.hasOwnProperty(n)&&( this [n]=t[n]);t.hasOwnProperty( "toString" )&&( this .toString=t.toString)},clone:function(){ return this .init.prototype.extend( this )}},p=o.WordArray=s.extend({init:function(t,n){t= this .words=t||[], this .sigBytes= null !=n?n:4*t.length},toString:function(t){ return (t||c).stringify( this )},concat:function(t){ var n= this .words,e=t.words,i= this .sigBytes,r=t.sigBytes; if ( this .clamp(),i%4) for ( var o=0;o<r;o++){ var s=e[o>>>2]>>>24-o%4*8&255;n[i+o>>>2]|=s<<24-(i+o)%4*8} else for (o=0;o<r;o+=4)n[i+o>>>2]=e[o>>>2]; return this .sigBytes+=r, this },clamp:function(){ var t= this .words,n= this .sigBytes;t[n>>>2]&=4294967295<<32-n%4*8,t.length=f.ceil(n/4)},clone:function(){ var t=s.clone.call( this ); return t.words= this .words.slice(0),t},random:function(t){ for ( var n=[],e=0;e<t;e+=4)n.push(i()); return new p.init(n,t)}}),a=n.enc={},c=a.Hex={stringify:function(t){ for ( var n=t.words,e=t.sigBytes,i=[],r=0;r<e;r++){ var o=n[r>>>2]>>>24-r%4*8&255;i.push((o>>>4).toString(16)),i.push((15&o).toString(16))} return i. join ( "" )},parse:function(t){ for ( var n=t.length,e=[],i=0;i<n;i+=2)e[i>>>3]|=parseInt(t.substr(i,2),16)<<24-i%8*4; return new p.init(e,n/2)}},u=a.Latin1={stringify:function(t){ for ( var n=t.words,e=t.sigBytes,i=[],r=0;r<e;r++){ var o=n[r>>>2]>>>24-r%4*8&255;i.push(String.fromCharCode(o))} return i. join ( "" )},parse:function(t){ for ( var n=t.length,e=[],i=0;i<n;i++)e[i>>>2]|=(255&t.charCodeAt(i))<<24-i%4*8; return new p.init(e,n)}},d=a.Utf8={stringify:function(t){ try { return decodeURIComponent(escape(u.stringify(t)))} catch (t){ throw new Error( "Malformed UTF-8 data" )}},parse:function(t){ return u.parse(unescape(encodeURIComponent(t)))}},h=o.BufferedBlockAlgorithm=s.extend({reset:function(){ this ._data= new p.init, this ._nDataBytes=0},_append:function(t){ "string" == typeof t&&(t=d.parse(t)), this ._data.concat(t), this ._nDataBytes+=t.sigBytes},_process:function(t){ var n,e= this ._data,i=e.words,r=e.sigBytes,o= this .blockSize,s=r/(4*o),a=(s=t?f.ceil(s):f.max((0|s)- this ._minBufferSize,0))*o,c=f.min(4*a,r); if (a){ for ( var u=0;u<a;u+=o) this ._doProcessBlock(i,u);n=i.splice(0,a),e.sigBytes-=c} return new p.init(n,c)},clone:function(){ var t=s.clone.call( this ); return t._data= this ._data.clone(),t},_minBufferSize:0}),l=(o.Hasher=h.extend({cfg:s.extend(),init:function(t){ this .cfg= this .cfg.extend(t), this .reset()},reset:function(){h.reset.call( this ), this ._doReset()},update:function(t){ return this ._append(t), this ._process(), this },finalize:function(t){ return t&& this ._append(t), this ._doFinalize()},blockSize:16,_createHelper:function(e){ return function(t,n){ return new e.init(n).finalize(t)}},_createHmacHelper:function(e){ return function(t,n){ return new l.HMAC.init(e,n).finalize(t)}}}),n.algo={}); return n}(Math); return t}); //https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/enc-base64.min.js !function(r,e){ "object" == typeof exports?module.exports=exports=e(require( "./core" )): "function" == typeof define&&define.amd?define([ "./core" ],e):e(r.CryptoJS)}( this ,function(r){ var s; return s=r.lib.WordArray,r.enc.Base64={stringify:function(r){ var e=r.words,t=r.sigBytes,a= this ._map;r.clamp(); for ( var n=[],o=0;o<t;o+=3) for ( var i=(e[o>>>2]>>>24-o%4*8&255)<<16|(e[o+1>>>2]>>>24-(o+1)%4*8&255)<<8|e[o+2>>>2]>>>24-(o+2)%4*8&255,f=0;f<4&&o+.75*f<t;f++)n.push(a.charAt(i>>>6*(3-f)&63)); var c=a.charAt(64); if (c) for (;n.length%4;)n.push(c); return n. join ( "" )},parse:function(r){ var e=r.length,t= this ._map,a= this ._reverseMap; if (!a){a= this ._reverseMap=[]; for ( var n=0;n<t.length;n++)a[t.charCodeAt(n)]=n} var o=t.charAt(64); if (o){ var i=r.indexOf(o);-1!==i&&(e=i)} return function(r,e,t){ for ( var a=[],n=0,o=0;o<e;o++) if (o%4){ var i=t[r.charCodeAt(o-1)]<<o%4*2,f=t[r.charCodeAt(o)]>>>6-o%4*2,c=i|f;a[n>>>2]|=c<<24-n%4*8,n++} return s.create(a,n)}(r,e,a)},_map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" },r.enc.Base64}); //https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/md5.min.js !function(r,e){ "object" == typeof exports?module.exports=exports=e(require( "./core" )): "function" == typeof define&&define.amd?define([ "./core" ],e):e(r.CryptoJS)}( this ,function(i){ return function(h){ var r=i,e=r.lib,t=e.WordArray,n=e.Hasher,o=r.algo,b=[];!function(){ for ( var r=0;r<64;r++)b[r]=4294967296*h.abs(h.sin(r+1))|0}(); var a=o.MD5=n.extend({_doReset:function(){ this ._hash= new t.init([1732584193,4023233417,2562383102,271733878])},_doProcessBlock:function(r,e){ for ( var t=0;t<16;t++){ var n=e+t,o=r[n];r[n]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8)} var a= this ._hash.words,i=r[e+0],s=r[e+1],c=r[e+2],f=r[e+3],h=r[e+4],u=r[e+5],v=r[e+6],d=r[e+7],l=r[e+8],_=r[e+9],p=r[e+10],y=r[e+11],D=r[e+12],H=r[e+13],M=r[e+14],g=r[e+15],m=a[0],w=a[1],x=a[2],B=a[3];m=j(m,w,x,B,i,7,b[0]),B=j(B,m,w,x,s,12,b[1]),x=j(x,B,m,w,c,17,b[2]),w=j(w,x,B,m,f,22,b[3]),m=j(m,w,x,B,h,7,b[4]),B=j(B,m,w,x,u,12,b[5]),x=j(x,B,m,w,v,17,b[6]),w=j(w,x,B,m,d,22,b[7]),m=j(m,w,x,B,l,7,b[8]),B=j(B,m,w,x,_,12,b[9]),x=j(x,B,m,w,p,17,b[10]),w=j(w,x,B,m,y,22,b[11]),m=j(m,w,x,B,D,7,b[12]),B=j(B,m,w,x,H,12,b[13]),x=j(x,B,m,w,M,17,b[14]),m=k(m,w=j(w,x,B,m,g,22,b[15]),x,B,s,5,b[16]),B=k(B,m,w,x,v,9,b[17]),x=k(x,B,m,w,y,14,b[18]),w=k(w,x,B,m,i,20,b[19]),m=k(m,w,x,B,u,5,b[20]),B=k(B,m,w,x,p,9,b[21]),x=k(x,B,m,w,g,14,b[22]),w=k(w,x,B,m,h,20,b[23]),m=k(m,w,x,B,_,5,b[24]),B=k(B,m,w,x,M,9,b[25]),x=k(x,B,m,w,f,14,b[26]),w=k(w,x,B,m,l,20,b[27]),m=k(m,w,x,B,H,5,b[28]),B=k(B,m,w,x,c,9,b[29]),x=k(x,B,m,w,d,14,b[30]),m=q(m,w=k(w,x,B,m,D,20,b[31]),x,B,u,4,b[32]),B=q(B,m,w,x,l,11,b[33]),x=q(x,B,m,w,y,16,b[34]),w=q(w,x,B,m,M,23,b[35]),m=q(m,w,x,B,s,4,b[36]),B=q(B,m,w,x,h,11,b[37]),x=q(x,B,m,w,d,16,b[38]),w=q(w,x,B,m,p,23,b[39]),m=q(m,w,x,B,H,4,b[40]),B=q(B,m,w,x,i,11,b[41]),x=q(x,B,m,w,f,16,b[42]),w=q(w,x,B,m,v,23,b[43]),m=q(m,w,x,B,_,4,b[44]),B=q(B,m,w,x,D,11,b[45]),x=q(x,B,m,w,g,16,b[46]),m=z(m,w=q(w,x,B,m,c,23,b[47]),x,B,i,6,b[48]),B=z(B,m,w,x,d,10,b[49]),x=z(x,B,m,w,M,15,b[50]),w=z(w,x,B,m,u,21,b[51]),m=z(m,w,x,B,D,6,b[52]),B=z(B,m,w,x,f,10,b[53]),x=z(x,B,m,w,p,15,b[54]),w=z(w,x,B,m,s,21,b[55]),m=z(m,w,x,B,l,6,b[56]),B=z(B,m,w,x,g,10,b[57]),x=z(x,B,m,w,v,15,b[58]),w=z(w,x,B,m,H,21,b[59]),m=z(m,w,x,B,h,6,b[60]),B=z(B,m,w,x,y,10,b[61]),x=z(x,B,m,w,c,15,b[62]),w=z(w,x,B,m,_,21,b[63]),a[0]=a[0]+m|0,a[1]=a[1]+w|0,a[2]=a[2]+x|0,a[3]=a[3]+B|0},_doFinalize:function(){ var r= this ._data,e=r.words,t=8* this ._nDataBytes,n=8*r.sigBytes;e[n>>>5]|=128<<24-n%32; var o=h.floor(t/4294967296),a=t;e[15+(64+n>>>9<<4)]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),e[14+(64+n>>>9<<4)]=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8),r.sigBytes=4*(e.length+1), this ._process(); for ( var i= this ._hash,s=i.words,c=0;c<4;c++){ var f=s[c];s[c]=16711935&(f<<8|f>>>24)|4278255360&(f<<24|f>>>8)} return i},clone:function(){ var r=n.clone.call( this ); return r._hash= this ._hash.clone(),r}});function j(r,e,t,n,o,a,i){ var s=r+(e&t|~e&n)+o+i; return (s<<a|s>>>32-a)+e}function k(r,e,t,n,o,a,i){ var s=r+(e&n|t&~n)+o+i; return (s<<a|s>>>32-a)+e}function q(r,e,t,n,o,a,i){ var s=r+(e^t^n)+o+i; return (s<<a|s>>>32-a)+e}function z(r,e,t,n,o,a,i){ var s=r+(t^(e|~n))+o+i; return (s<<a|s>>>32-a)+e}r.MD5=n._createHelper(a),r.HmacMD5=n._createHmacHelper(a)}(Math),i.MD5}); //https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/evpkdf.min.js !function(e,t){ "object" == typeof exports?module.exports=exports=t(require( "./core" ),require( "./sha1" ),require( "./hmac" )): "function" == typeof define&&define.amd?define([ "./core" , "./sha1" , "./hmac" ],t):t(e.CryptoJS)}( this ,function(e){ var t,r,i,u,n,o,a; return r=(t=e).lib,i=r.Base,u=r.WordArray,n=t.algo,o=n.MD5,a=n.EvpKDF=i.extend({cfg:i.extend({keySize:4,hasher:o,iterations:1}),init:function(e){ this .cfg= this .cfg.extend(e)},compute:function(e,t){ for ( var r,i= this .cfg,n=i.hasher.create(),o=u.create(),a=o.words,c=i.keySize,f=i.iterations;a.length<c;){r&&n.update(r),r=n.update(e).finalize(t),n.reset(); for ( var s=1;s<f;s++)r=n.finalize(r),n.reset();o.concat(r)} return o.sigBytes=4*c,o}}),t.EvpKDF=function(e,t,r){ return a.create(r).compute(e,t)},e.EvpKDF}); //https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/cipher-core.min.js !function(e,t){ "object" == typeof exports?module.exports=exports=t(require( "./core" ),require( "./evpkdf" )): "function" == typeof define&&define.amd?define([ "./core" , "./evpkdf" ],t):t(e.CryptoJS)}( this ,function(m){m.lib.Cipher||function(){ var e=m,t=e.lib,r=t.Base,a=t.WordArray,i=t.BufferedBlockAlgorithm,n=e.enc,c=(n.Utf8,n.Base64),o=e.algo.EvpKDF,s=t.Cipher=i.extend({cfg:r.extend(),createEncryptor:function(e,t){ return this .create( this ._ENC_XFORM_MODE,e,t)},createDecryptor:function(e,t){ return this .create( this ._DEC_XFORM_MODE,e,t)},init:function(e,t,r){ this .cfg= this .cfg.extend(r), this ._xformMode=e, this ._key=t, this .reset()},reset:function(){i.reset.call( this ), this ._doReset()},process:function(e){ return this ._append(e), this ._process()},finalize:function(e){ return e&& this ._append(e), this ._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(i){ return {encrypt:function(e,t,r){ return f(t).encrypt(i,e,t,r)},decrypt:function(e,t,r){ return f(t).decrypt(i,e,t,r)}}}});function f(e){ return "string" == typeof e?g:k}t.StreamCipher=s.extend({_doFinalize:function(){ return this ._process(!0)},blockSize:1}); var p,d=e.mode={},h=t.BlockCipherMode=r.extend({createEncryptor:function(e,t){ return this .Encryptor.create(e,t)},createDecryptor:function(e,t){ return this .Decryptor.create(e,t)},init:function(e,t){ this ._cipher=e, this ._iv=t}}),u=d.CBC=((p=h.extend()).Encryptor=p.extend({processBlock:function(e,t){ var r= this ._cipher,i=r.blockSize;_.call( this ,e,t,i),r.encryptBlock(e,t), this ._prevBlock=e.slice(t,t+i)}}),p.Decryptor=p.extend({processBlock:function(e,t){ var r= this ._cipher,i=r.blockSize,n=e.slice(t,t+i);r.decryptBlock(e,t),_.call( this ,e,t,i), this ._prevBlock=n}}),p);function _(e,t,r){ var i,n= this ._iv;n?(i=n, this ._iv= void 0):i= this ._prevBlock; for ( var c=0;c<r;c++)e[t+c]^=i[c]} var l=(e.pad={}).Pkcs7={pad:function(e,t){ for ( var r=4*t,i=r-e.sigBytes%r,n=i<<24|i<<16|i<<8|i,c=[],o=0;o<i;o+=4)c.push(n); var s=a.create(c,i);e.concat(s)},unpad:function(e){ var t=255&e.words[e.sigBytes-1>>>2];e.sigBytes-=t}},y=(t.BlockCipher=s.extend({cfg:s.cfg.extend({mode:u,padding:l}),reset:function(){ var e;s.reset.call( this ); var t= this .cfg,r=t.iv,i=t.mode; this ._xformMode== this ._ENC_XFORM_MODE?e=i.createEncryptor:(e=i.createDecryptor, this ._minBufferSize=1), this ._mode&& this ._mode.__creator==e? this ._mode.init( this ,r&&r.words):( this ._mode=e.call(i, this ,r&&r.words), this ._mode.__creator=e)},_doProcessBlock:function(e,t){ this ._mode.processBlock(e,t)},_doFinalize:function(){ var e,t= this .cfg.padding; return this ._xformMode== this ._ENC_XFORM_MODE?(t.pad( this ._data, this .blockSize),e= this ._process(!0)):(e= this ._process(!0),t.unpad(e)),e},blockSize:4}),t.CipherParams=r.extend({init:function(e){ this .mixIn(e)},toString:function(e){ return (e|| this .formatter).stringify( this )}})),v=(e.format={}).OpenSSL={stringify:function(e){ var t=e.ciphertext,r=e.salt; return (r?a.create([1398893684,1701076831]).concat(r).concat(t):t).toString(c)},parse:function(e){ var t,r=c.parse(e),i=r.words; return 1398893684==i[0]&&1701076831==i[1]&&(t=a.create(i.slice(2,4)),i.splice(0,4),r.sigBytes-=16),y.create({ciphertext:r,salt:t})}},k=t.SerializableCipher=r.extend({cfg:r.extend({format:v}),encrypt:function(e,t,r,i){i= this .cfg.extend(i); var n=e.createEncryptor(r,i),c=n.finalize(t),o=n.cfg; return y.create({ciphertext:c,key:r,iv:o.iv,algorithm:e,mode:o.mode,padding:o.padding,blockSize:e.blockSize,formatter:i.format})},decrypt:function(e,t,r,i){ return i= this .cfg.extend(i),t= this ._parse(t,i.format),e.createDecryptor(r,i).finalize(t.ciphertext)},_parse:function(e,t){ return "string" == typeof e?t.parse(e, this ):e}}),x=(e.kdf={}).OpenSSL={execute:function(e,t,r,i){i=i||a.random(8); var n=o.create({keySize:t+r}).compute(e,i),c=a.create(n.words.slice(t),4*r); return n.sigBytes=4*t,y.create({key:n,iv:c,salt:i})}},g=t.PasswordBasedCipher=k.extend({cfg:k.cfg.extend({kdf:x}),encrypt:function(e,t,r,i){ var n=(i= this .cfg.extend(i)).kdf.execute(r,e.keySize,e.ivSize);i.iv=n.iv; var c=k.encrypt.call( this ,e,t,n.key,i); return c.mixIn(n),c},decrypt:function(e,t,r,i){i= this .cfg.extend(i),t= this ._parse(t,i.format); var n=i.kdf.execute(r,e.keySize,e.ivSize,t.salt); return i.iv=n.iv,k.decrypt.call( this ,e,t,n.key,i)}})}()}); //https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/aes.min.js !function(e,r){ "object" == typeof exports?module.exports=exports=r(require( "./core" ),require( "./enc-base64" ),require( "./md5" ),require( "./evpkdf" ),require( "./cipher-core" )): "function" == typeof define&&define.amd?define([ "./core" , "./enc-base64" , "./md5" , "./evpkdf" , "./cipher-core" ],r):r(e.CryptoJS)}( this ,function(t){ return function(){ var e=t,r=e.lib.BlockCipher,i=e.algo,f=[],u=[],h=[],y=[],a=[],p=[],v=[],_=[],k=[],l=[];!function(){ for ( var e=[],r=0;r<256;r++)e[r]=r<128?r<<1:r<<1^283; var i=0,o=0; for (r=0;r<256;r++){ var t=o^o<<1^o<<2^o<<3^o<<4;t=t>>>8^255&t^99,f[i]=t; var n=e[u[t]=i],c=e[n],s=e[c],d=257*e[t]^16843008*t;h[i]=d<<24|d>>>8,y[i]=d<<16|d>>>16,a[i]=d<<8|d>>>24,p[i]=d;d=16843009*s^65537*c^257*n^16843008*i;v[t]=d<<24|d>>>8,_[t]=d<<16|d>>>16,k[t]=d<<8|d>>>24,l[t]=d,i?(i=n^e[e[e[s^n]]],o^=e[e[o]]):i=o=1}}(); var S=[0,1,2,4,8,16,32,64,128,27,54],o=i.AES=r.extend({_doReset:function(){ if (! this ._nRounds|| this ._keyPriorReset!== this ._key){ for ( var e= this ._keyPriorReset= this ._key,r=e.words,i=e.sigBytes/4,o=4*(1+( this ._nRounds=6+i)),t= this ._keySchedule=[],n=0;n<o;n++)n<i?t[n]=r[n]:(d=t[n-1],n%i?6<i&&n%i==4&&(d=f[d>>>24]<<24|f[d>>>16&255]<<16|f[d>>>8&255]<<8|f[255&d]):(d=f[(d=d<<8|d>>>24)>>>24]<<24|f[d>>>16&255]<<16|f[d>>>8&255]<<8|f[255&d],d^=S[n/i|0]<<24),t[n]=t[n-i]^d); for ( var c= this ._invKeySchedule=[],s=0;s<o;s++){n=o-s; if (s%4) var d=t[n]; else d=t[n-4];c[s]=s<4||n<=4?d:v[f[d>>>24]]^_[f[d>>>16&255]]^k[f[d>>>8&255]]^l[f[255&d]]}}},encryptBlock:function(e,r){ this ._doCryptBlock(e,r, this ._keySchedule,h,y,a,p,f)},decryptBlock:function(e,r){ var i=e[r+1];e[r+1]=e[r+3],e[r+3]=i, this ._doCryptBlock(e,r, this ._invKeySchedule,v,_,k,l,u);i=e[r+1];e[r+1]=e[r+3],e[r+3]=i},_doCryptBlock:function(e,r,i,o,t,n,c,s){ for ( var d= this ._nRounds,f=e[r]^i[0],u=e[r+1]^i[1],h=e[r+2]^i[2],y=e[r+3]^i[3],a=4,p=1;p<d;p++){ var v=o[f>>>24]^t[u>>>16&255]^n[h>>>8&255]^c[255&y]^i[a++],_=o[u>>>24]^t[h>>>16&255]^n[y>>>8&255]^c[255&f]^i[a++],k=o[h>>>24]^t[y>>>16&255]^n[f>>>8&255]^c[255&u]^i[a++],l=o[y>>>24]^t[f>>>16&255]^n[u>>>8&255]^c[255&h]^i[a++];f=v,u=_,h=k,y=l}v=(s[f>>>24]<<24|s[u>>>16&255]<<16|s[h>>>8&255]<<8|s[255&y])^i[a++],_=(s[u>>>24]<<24|s[h>>>16&255]<<16|s[y>>>8&255]<<8|s[255&f])^i[a++],k=(s[h>>>24]<<24|s[y>>>16&255]<<16|s[f>>>8&255]<<8|s[255&u])^i[a++],l=(s[y>>>24]<<24|s[f>>>16&255]<<16|s[u>>>8&255]<<8|s[255&h])^i[a++];e[r]=v,e[r+1]=_,e[r+2]=k,e[r+3]=l},keySize:8});e.AES=r._createHelper(o)}(),t.AES}); //https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/pad-pkcs7.min.js !function(e,r){ "object" == typeof exports?module.exports=exports=r(require( "./core" ),require( "./cipher-core" )): "function" == typeof define&&define.amd?define([ "./core" , "./cipher-core" ],r):r(e.CryptoJS)}( this ,function(e){ return e.pad.Pkcs7}); //https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/mode-ecb.min.js !function(e,o){ "object" == typeof exports?module.exports=exports=o(require( "./core" ),require( "./cipher-core" )): "function" == typeof define&&define.amd?define([ "./core" , "./cipher-core" ],o):o(e.CryptoJS)}( this ,function(e){ var o; return e.mode.ECB=((o=e.lib.BlockCipherMode.extend()).Encryptor=o.extend({processBlock:function(e,o){ this ._cipher.encryptBlock(e,o)}}),o.Decryptor=o.extend({processBlock:function(e,o){ this ._cipher.decryptBlock(e,o)}}),o),e.mode.ECB}); //https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/enc-utf8.min.js !function(e,o){ "object" == typeof exports?module.exports=exports=o(require( "./core" )): "function" == typeof define&&define.amd?define([ "./core" ],o):o(e.CryptoJS)}( this ,function(e){ return e.enc.Utf8}); //https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/enc-hex.min.js !function(e,o){ "object" == typeof exports?module.exports=exports=o(require( "./core" )): "function" == typeof define&&define.amd?define([ "./core" ],o):o(e.CryptoJS)}( this ,function(e){ return e.enc.Hex}); </script> <!-- 引入 CDN Crypto.js 结束 --> </head> <body> <p>AES简介:</p> <p>高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法,</p> <p>也就是加密和解密用相同的密钥</p> <p>微信小程序加密传输就是用这个加密算法的</p> <p>我们公司禁止使用简易加密,如MD5编码、Base64编码、URL编码。</p> <p>后台加密步骤为:对象=>JSON字符串=>加密=>JSON字符串=>前端</p> <p>前端解密步骤为:解密=>JSON对象</p> </body> </html> <script> function getCrypt(){ var crypt_key = '049d65f30e854b08' ; //由后台提供 var crypt_iv = '98da515e3935c342' ; //由后台提供 var aes_key = CryptoJS.enc.Utf8.parse(crypt_key); //解析后的key var new_iv = CryptoJS.enc.Utf8.parse(crypt_iv); //解析后的iv var obj = { iv: new_iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 } function encrypt(data) { //以下加密 encrypted = CryptoJS.AES.encrypt(data, aes_key, obj); return encrypted.toString() } function decrypt(data) { //以下解密 decrypted = CryptoJS.AES.decrypt(data, aes_key, obj); return decrypted.toString(CryptoJS.enc.Utf8) } return { encrypt:encrypt, decrypt:decrypt } } var crypt= getCrypt(); var strCrypt = 'zhangqiang,你好' ; var getEncrypt = crypt.encrypt(strCrypt); console.log(getEncrypt); var getDecrypt = crypt.decrypt(getEncrypt); console.log(getDecrypt); //可以通过正则匹配将非JSON格式的字符串getDecrypt转化为JSON格式的字符串,再通过JSON.parse转化为JSON格式的对象,供页面使用。 //如果内层的某个对象需要以单引号字符串的形式展示在页面上,那么可以通过JSON.stringify将该对象转化为JSON格式的字符串,再通过正则匹配将双引号换成单引号 </script> 2、RSA加密 (1)jsencrypt.min.js /*! For license information please see jsencrypt.min.js.LICENSE.txt */ !function(t,e){ "object" == typeof exports&& "object" == typeof module?module.exports=e(): "function" == typeof define&&define.amd?define([],e): "object" == typeof exports?exports.JSEncrypt=e():t.JSEncrypt=e()}(window,(()=>(()=>{ var t={155:t=>{ var e,i,r=t.exports={};function n(){ throw new Error( "setTimeout has not been defined" )}function s(){ throw new Error( "clearTimeout has not been defined" )}function o(t){ if (e===setTimeout) return setTimeout(t,0); if ((e===n||!e)&&setTimeout) return e=setTimeout,setTimeout(t,0); try { return e(t,0)} catch (i){ try { return e.call( null ,t,0)} catch (i){ return e.call( this ,t,0)}}}!function(){ try {e= "function" == typeof setTimeout?setTimeout:n} catch (t){e=n} try {i= "function" == typeof clearTimeout?clearTimeout:s} catch (t){i=s}}(); var h,a=[],u=!1,c=-1;function f(){u&&h&&(u=!1,h.length?a=h.concat(a):c=-1,a.length&&l())}function l(){ if (!u){ var t=o(f);u=!0; for ( var e=a.length;e;){ for (h=a,a=[];++c<e;)h&&h[c].run();c=-1,e=a.length}h= null ,u=!1,function(t){ if (i===clearTimeout) return clearTimeout(t); if ((i===s||!i)&&clearTimeout) return i=clearTimeout,clearTimeout(t); try {i(t)} catch (e){ try { return i.call( null ,t)} catch (e){ return i.call( this ,t)}}}(t)}}function p(t,e){ this .fun=t, this .array=e}function g(){}r.nextTick=function(t){ var e= new Array(arguments.length-1); if (arguments.length>1) for ( var i=1;i<arguments.length;i++)e[i-1]=arguments[i];a.push( new p(t,e)),1!==a.length||u||o(l)},p.prototype.run=function(){ this .fun.apply( null , this .array)},r.title= "browser" ,r.browser=!0,r.env={},r.argv=[],r.version= "" ,r.versions={},r. on =g,r.addListener=g,r.once=g,r.off=g,r.removeListener=g,r.removeAllListeners=g,r.emit=g,r.prependListener=g,r.prependOnceListener=g,r.listeners=function(t){ return []},r.binding=function(t){ throw new Error( "process.binding is not supported" )},r.cwd=function(){ return "/" },r.chdir=function(t){ throw new Error( "process.chdir is not supported" )},r.umask=function(){ return 0}}},e={};function i(r){ var n=e[r]; if ( void 0!==n) return n.exports; var s=e[r]={exports:{}}; return t[r](s,s.exports,i),s.exports}i.d=(t,e)=>{ for ( var r in e)i.o(e,r)&&!i.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0, get :e[r]})},i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e); var r={}; return (()=>{ "use strict" ;function t(t){ return "0123456789abcdefghijklmnopqrstuvwxyz" .charAt(t)}function e(t,e){ return t&e}function n(t,e){ return t|e}function s(t,e){ return t^e}function o(t,e){ return t&~e}function h(t){ if (0==t) return -1; var e=0; return 0==(65535&t)&&(t>>=16,e+=16),0==(255&t)&&(t>>=8,e+=8),0==(15&t)&&(t>>=4,e+=4),0==(3&t)&&(t>>=2,e+=2),0==(1&t)&&++e,e}function a(t){ for ( var e=0;0!=t;)t&=t-1,++e; return e}i.d(r,{ default :()=>ot}); var u,c= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;function f(t){ var e,i,r= "" ; for (e=0;e+3<=t.length;e+=3)i=parseInt(t.substring(e,e+3),16),r+=c.charAt(i>>6)+c.charAt(63&i); for (e+1==t.length?(i=parseInt(t.substring(e,e+1),16),r+=c.charAt(i<<2)):e+2==t.length&&(i=parseInt(t.substring(e,e+2),16),r+=c.charAt(i>>2)+c.charAt((3&i)<<4));(3&r.length)>0;)r+= "=" ; return r}function l(e){ var i,r= "" ,n=0,s=0; for (i=0;i<e.length&& "=" !=e.charAt(i);++i){ var o=c.indexOf(e.charAt(i));o<0||(0==n?(r+=t(o>>2),s=3&o,n=1):1==n?(r+=t(s<<2|o>>4),s=15&o,n=2):2==n?(r+=t(s),r+=t(o>>2),s=3&o,n=3):(r+=t(s<<2|o>>4),r+=t(15&o),n=0))} return 1==n&&(r+=t(s<<2)),r} var p,g={decode:function(t){ var e; if ( void 0===p){ var i= "= \f\n\r\t \u2028\u2029" ; for (p=Object.create( null ),e=0;e<64;++e)p[ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" .charAt(e)]=e; for (p[ "-" ]=62,p._=63,e=0;e<i.length;++e)p[i.charAt(e)]=-1} var r=[],n=0,s=0; for (e=0;e<t.length;++e){ var o=t.charAt(e); if ( "=" ==o) break ; if (-1!=(o=p[o])){ if ( void 0===o) throw new Error( "Illegal character at offset " +e);n|=o,++s>=4?(r[r.length]=n>>16,r[r.length]=n>>8&255,r[r.length]=255&n,n=0,s=0):n<<=6}} switch (s){ case 1: throw new Error( "Base64 encoding incomplete: at least 2 bits missing" ); case 2:r[r.length]=n>>10; break ; case 3:r[r.length]=n>>16,r[r.length]=n>>8&255} return r},re:/-----BEGIN [^-]+-----([A-Za-z0-9+\/=\s]+)-----END [^-]+-----|begin-base64[^\n]+\n([A-Za-z0-9+\/=\s]+)====/,unarmor:function(t){ var e=g.re.exec(t); if (e) if (e[1])t=e[1]; else { if (!e[2]) throw new Error( "RegExp out of sync" );t=e[2]} return g.decode(t)}},d=1e13,v=function(){function t(t){ this .buf=[+t||0]} return t.prototype.mulAdd=function(t,e){ var i,r,n= this .buf,s=n.length; for (i=0;i<s;++i)(r=n[i]*t+e)<d?e=0:r-=(e=0|r/d)*d,n[i]=r;e>0&&(n[i]=e)},t.prototype.sub=function(t){ var e,i,r= this .buf,n=r.length; for (e=0;e<n;++e)(i=r[e]-t)<0?(i+=d,t=1):t=0,r[e]=i; for (;0===r[r.length-1];)r.pop()},t.prototype.toString=function(t){ if (10!=(t||10)) throw new Error( "only base 10 is supported" ); for ( var e= this .buf,i=e[e.length-1].toString(),r=e.length-2;r>=0;--r)i+=(d+e[r]).toString().substring(1); return i},t.prototype.valueOf=function(){ for ( var t= this .buf,e=0,i=t.length-1;i>=0;--i)e=e*d+t[i]; return e},t.prototype.simplify=function(){ var t= this .buf; return 1==t.length?t[0]: this },t}(),m=/^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/,y=/^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/;function b(t,e){ return t.length>e&&(t=t.substring(0,e)+ "…" ),t} var T,S=function(){function t(e,i){ this .hexDigits= "0123456789ABCDEF" ,e instanceof t?( this .enc=e.enc, this .pos=e.pos):( this .enc=e, this .pos=i)} return t.prototype. get =function(t){ if ( void 0===t&&(t= this .pos++),t>= this .enc.length) throw new Error( "Requesting byte offset " .concat(t, " on a stream of length " ).concat( this .enc.length)); return "string" == typeof this .enc? this .enc.charCodeAt(t): this .enc[t]},t.prototype.hexByte=function(t){ return this .hexDigits.charAt(t>>4&15)+ this .hexDigits.charAt(15&t)},t.prototype.hexDump=function(t,e,i){ for ( var r= "" ,n=t;n<e;++n) if (r+= this .hexByte( this . get (n)),!0!==i) switch (15&n){ case 7:r+= " " ; break ; case 15:r+= "\n" ; break ; default :r+= " " } return r},t.prototype.isASCII=function(t,e){ for ( var i=t;i<e;++i){ var r= this . get (i); if (r<32||r>176) return !1} return !0},t.prototype.parseStringISO=function(t,e){ for ( var i= "" ,r=t;r<e;++r)i+=String.fromCharCode( this . get (r)); return i},t.prototype.parseStringUTF=function(t,e){ for ( var i= "" ,r=t;r<e;){ var n= this . get (r++);i+=n<128?String.fromCharCode(n):n>191&&n<224?String.fromCharCode((31&n)<<6|63& this . get (r++)):String.fromCharCode((15&n)<<12|(63& this . get (r++))<<6|63& this . get (r++))} return i},t.prototype.parseStringBMP=function(t,e){ for ( var i,r,n= "" ,s=t;s<e;)i= this . get (s++),r= this . get (s++),n+=String.fromCharCode(i<<8|r); return n},t.prototype.parseTime=function(t,e,i){ var r= this .parseStringISO(t,e),n=(i?m:y).exec(r); return n?(i&&(n[1]=+n[1],n[1]+=+n[1]<70?2e3:1900),r=n[1]+ "-" +n[2]+ "-" +n[3]+ " " +n[4],n[5]&&(r+= ":" +n[5],n[6]&&(r+= ":" +n[6],n[7]&&(r+= "." +n[7]))),n[8]&&(r+= " UTC" , "Z" !=n[8]&&(r+=n[8],n[9]&&(r+= ":" +n[9]))),r): "Unrecognized time: " +r},t.prototype.parseInteger=function(t,e){ for ( var i,r= this . get (t),n=r>127,s=n?255:0,o= "" ;r==s&&++t<e;)r= this . get (t); if (0==(i=e-t)) return n?-1:0; if (i>4){ for (o=r,i<<=3;0==(128&(+o^s));)o=+o<<1,--i;o= "(" +i+ " bit)\n" }n&&(r-=256); for ( var h= new v(r),a=t+1;a<e;++a)h.mulAdd(256, this . get (a)); return o+h.toString()},t.prototype.parseBitString=function(t,e,i){ for ( var r= this . get (t),n= "(" +((e-t-1<<3)-r)+ " bit)\n" ,s= "" ,o=t+1;o<e;++o){ for ( var h= this . get (o),a=o==e-1?r:0,u=7;u>=a;--u)s+=h>>u&1? "1" : "0" ; if (s.length>i) return n+b(s,i)} return n+s},t.prototype.parseOctetString=function(t,e,i){ if ( this .isASCII(t,e)) return b( this .parseStringISO(t,e),i); var r=e-t,n= "(" +r+ " byte)\n" ;r>(i/=2)&&(e=t+i); for ( var s=t;s<e;++s)n+= this .hexByte( this . get (s)); return r>i&&(n+= "…" ),n},t.prototype.parseOID=function(t,e,i){ for ( var r= "" ,n= new v,s=0,o=t;o<e;++o){ var h= this . get (o); if (n.mulAdd(128,127&h),s+=7,!(128&h)){ if ( "" ===r) if ((n=n.simplify())instanceof v)n.sub(80),r= "2." +n.toString(); else { var a=n<80?n<40?0:1:2;r=a+ "." +(n-40*a)} else r+= "." +n.toString(); if (r.length>i) return b(r,i);n= new v,s=0}} return s>0&&(r+= ".incomplete" ),r},t}(),E=function(){function t(t,e,i,r,n){ if (!(r instanceof w)) throw new Error( "Invalid tag value." ); this .stream=t, this .header=e, this .length=i, this .tag=r, this .sub=n} return t.prototype.typeName=function(){ switch ( this .tag.tagClass){ case 0: switch ( this .tag.tagNumber){ case 0: return "EOC" ; case 1: return "BOOLEAN" ; case 2: return "INTEGER" ; case 3: return "BIT_STRING" ; case 4: return "OCTET_STRING" ; case 5: return "NULL" ; case 6: return "OBJECT_IDENTIFIER" ; case 7: return "ObjectDescriptor" ; case 8: return "EXTERNAL" ; case 9: return "REAL" ; case 10: return "ENUMERATED" ; case 11: return "EMBEDDED_PDV" ; case 12: return "UTF8String" ; case 16: return "SEQUENCE" ; case 17: return "SET" ; case 18: return "NumericString" ; case 19: return "PrintableString" ; case 20: return "TeletexString" ; case 21: return "VideotexString" ; case 22: return "IA5String" ; case 23: return "UTCTime" ; case 24: return "GeneralizedTime" ; case 25: return "GraphicString" ; case 26: return "VisibleString" ; case 27: return "GeneralString" ; case 28: return "UniversalString" ; case 30: return "BMPString" } return "Universal_" + this .tag.tagNumber.toString(); case 1: return "Application_" + this .tag.tagNumber.toString(); case 2: return "[" + this .tag.tagNumber.toString()+ "]" ; case 3: return "Private_" + this .tag.tagNumber.toString()}},t.prototype.content=function(t){ if ( void 0=== this .tag) return null ; void 0===t&&(t=1/0); var e= this .posContent(),i=Math.abs( this .length); if (! this .tag.isUniversal()) return null !== this .sub? "(" + this .sub.length+ " elem)" : this .stream.parseOctetString(e,e+i,t); switch ( this .tag.tagNumber){ case 1: return 0=== this .stream. get (e)? "false" : "true" ; case 2: return this .stream.parseInteger(e,e+i); case 3: return this .sub? "(" + this .sub.length+ " elem)" : this .stream.parseBitString(e,e+i,t); case 4: return this .sub? "(" + this .sub.length+ " elem)" : this .stream.parseOctetString(e,e+i,t); case 6: return this .stream.parseOID(e,e+i,t); case 16: case 17: return null !== this .sub? "(" + this .sub.length+ " elem)" : "(no elem)" ; case 12: return b( this .stream.parseStringUTF(e,e+i),t); case 18: case 19: case 20: case 21: case 22: case 26: return b( this .stream.parseStringISO(e,e+i),t); case 30: return b( this .stream.parseStringBMP(e,e+i),t); case 23: case 24: return this .stream.parseTime(e,e+i,23== this .tag.tagNumber)} return null },t.prototype.toString=function(){ return this .typeName()+ "@" + this .stream.pos+ "[header:" + this .header+ ",length:" + this .length+ ",sub:" +( null === this .sub? "null" : this .sub.length)+ "]" },t.prototype.toPrettyString=function(t){ void 0===t&&(t= "" ); var e=t+ this .typeName()+ " @" + this .stream.pos; if ( this .length>=0&&(e+= "+" ),e+= this .length, this .tag.tagConstructed?e+= " (constructed)" :! this .tag.isUniversal()||3!= this .tag.tagNumber&&4!= this .tag.tagNumber|| null === this .sub||(e+= " (encapsulates)" ),e+= "\n" , null !== this .sub){t+= " " ; for ( var i=0,r= this .sub.length;i<r;++i)e+= this .sub[i].toPrettyString(t)} return e},t.prototype.posStart=function(){ return this .stream.pos},t.prototype.posContent=function(){ return this .stream.pos+ this .header},t.prototype.posEnd=function(){ return this .stream.pos+ this .header+Math.abs( this .length)},t.prototype.toHexString=function(){ return this .stream.hexDump( this .posStart(), this .posEnd(),!0)},t.decodeLength=function(t){ var e=t. get (),i=127&e; if (i==e) return i; if (i>6) throw new Error( "Length over 48 bits not supported at position " +(t.pos-1)); if (0===i) return null ;e=0; for ( var r=0;r<i;++r)e=256*e+t. get (); return e},t.prototype.getHexStringValue=function(){ var t= this .toHexString(),e=2* this .header,i=2* this .length; return t.substr(e,i)},t.decode=function(e){ var i;i=e instanceof S?e: new S(e,0); var r= new S(i),n= new w(i),s=t.decodeLength(i),o=i.pos,h=o-r.pos,a= null ,u=function(){ var e=[]; if ( null !==s){ for ( var r=o+s;i.pos<r;)e[e.length]=t.decode(i); if (i.pos!=r) throw new Error( "Content size is not correct for container starting at offset " +o)} else try { for (;;){ var n=t.decode(i); if (n.tag.isEOC()) break ;e[e.length]=n}s=o-i.pos} catch (t){ throw new Error( "Exception while decoding undefined length content: " +t)} return e}; if (n.tagConstructed)a=u(); else if (n.isUniversal()&&(3==n.tagNumber||4==n.tagNumber)) try { if (3==n.tagNumber&&0!=i. get ()) throw new Error( "BIT STRINGs with unused bits cannot encapsulate." );a=u(); for ( var c=0;c<a.length;++c) if (a[c].tag.isEOC()) throw new Error( "EOC is not supposed to be actual content." )} catch (t){a= null } if ( null ===a){ if ( null ===s) throw new Error( "We can't skip over an invalid tag with undefined length at offset " +o);i.pos=o+Math.abs(s)} return new t(r,h,s,n,a)},t}(),w=function(){function t(t){ var e=t. get (); if ( this .tagClass=e>>6, this .tagConstructed=0!=(32&e), this .tagNumber=31&e,31== this .tagNumber){ var i= new v; do {e=t. get (),i.mulAdd(128,127&e)} while (128&e); this .tagNumber=i.simplify()}} return t.prototype.isUniversal=function(){ return 0=== this .tagClass},t.prototype.isEOC=function(){ return 0=== this .tagClass&&0=== this .tagNumber},t}(),D=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997],x=(1<<26)/D[D.length-1],R=function(){function i(t,e,i){ null !=t&&( "number" == typeof t? this .fromNumber(t,e,i): null ==e&& "string" != typeof t? this .fromString(t,256): this .fromString(t,e))} return i.prototype.toString=function(e){ if ( this .s<0) return "-" + this .negate().toString(e); var i; if (16==e)i=4; else if (8==e)i=3; else if (2==e)i=1; else if (32==e)i=5; else { if (4!=e) return this .toRadix(e);i=2} var r,n=(1<<i)-1,s=!1,o= "" ,h= this .t,a= this .DB-h* this .DB%i; if (h-- >0) for (a< this .DB&&(r= this [h]>>a)>0&&(s=!0,o=t(r));h>=0;)a<i?(r=( this [h]&(1<<a)-1)<<i-a,r|= this [--h]>>(a+= this .DB-i)):(r= this [h]>>(a-=i)&n,a<=0&&(a+= this .DB,--h)),r>0&&(s=!0),s&&(o+=t(r)); return s?o: "0" },i.prototype.negate=function(){ var t=I(); return i.ZERO.subTo( this ,t),t},i.prototype.abs=function(){ return this .s<0? this .negate(): this },i.prototype.compareTo=function(t){ var e= this .s-t.s; if (0!=e) return e; var i= this .t; if (0!=(e=i-t.t)) return this .s<0?-e:e; for (;--i>=0;) if (0!=(e= this [i]-t[i])) return e; return 0},i.prototype.bitLength=function(){ return this .t<=0?0: this .DB*( this .t-1)+C( this [ this .t-1]^ this .s& this .DM)},i.prototype.mod=function(t){ var e=I(); return this .abs().divRemTo(t, null ,e), this .s<0&&e.compareTo(i.ZERO)>0&&t.subTo(e,e),e},i.prototype.modPowInt=function(t,e){ var i; return i=t<256||e.isEven()? new O(e): new A(e), this .exp(t,i)},i.prototype.clone=function(){ var t=I(); return this .copyTo(t),t},i.prototype.intValue=function(){ if ( this .s<0){ if (1== this .t) return this [0]- this .DV; if (0== this .t) return -1} else { if (1== this .t) return this [0]; if (0== this .t) return 0} return ( this [1]&(1<<32- this .DB)-1)<< this .DB| this [0]},i.prototype.byteValue=function(){ return 0== this .t? this .s: this [0]<<24>>24},i.prototype.shortValue=function(){ return 0== this .t? this .s: this [0]<<16>>16},i.prototype.signum=function(){ return this .s<0?-1: this .t<=0||1== this .t&& this [0]<=0?0:1},i.prototype.toByteArray=function(){ var t= this .t,e=[];e[0]= this .s; var i,r= this .DB-t* this .DB%8,n=0; if (t-- >0) for (r< this .DB&&(i= this [t]>>r)!=( this .s& this .DM)>>r&&(e[n++]=i| this .s<< this .DB-r);t>=0;)r<8?(i=( this [t]&(1<<r)-1)<<8-r,i|= this [--t]>>(r+= this .DB-8)):(i= this [t]>>(r-=8)&255,r<=0&&(r+= this .DB,--t)),0!=(128&i)&&(i|=-256),0==n&&(128& this .s)!=(128&i)&&++n,(n>0||i!= this .s)&&(e[n++]=i); return e},i.prototype. equals =function(t){ return 0== this .compareTo(t)},i.prototype.min=function(t){ return this .compareTo(t)<0? this :t},i.prototype.max=function(t){ return this .compareTo(t)>0? this :t},i.prototype.and=function(t){ var i=I(); return this .bitwiseTo(t,e,i),i},i.prototype.or=function(t){ var e=I(); return this .bitwiseTo(t,n,e),e},i.prototype.xor=function(t){ var e=I(); return this .bitwiseTo(t,s,e),e},i.prototype.andNot=function(t){ var e=I(); return this .bitwiseTo(t,o,e),e},i.prototype.not=function(){ for ( var t=I(),e=0;e< this .t;++e)t[e]= this .DM&~ this [e]; return t.t= this .t,t.s=~ this .s,t},i.prototype.shiftLeft=function(t){ var e=I(); return t<0? this .rShiftTo(-t,e): this .lShiftTo(t,e),e},i.prototype.shiftRight=function(t){ var e=I(); return t<0? this .lShiftTo(-t,e): this .rShiftTo(t,e),e},i.prototype.getLowestSetBit=function(){ for ( var t=0;t< this .t;++t) if (0!= this [t]) return t* this .DB+h( this [t]); return this .s<0? this .t* this .DB:-1},i.prototype.bitCount=function(){ for ( var t=0,e= this .s& this .DM,i=0;i< this .t;++i)t+=a( this [i]^e); return t},i.prototype.testBit=function(t){ var e=Math.floor(t/ this .DB); return e>= this .t?0!= this .s:0!=( this [e]&1<<t% this .DB)},i.prototype.setBit=function(t){ return this .changeBit(t,n)},i.prototype.clearBit=function(t){ return this .changeBit(t,o)},i.prototype.flipBit=function(t){ return this .changeBit(t,s)},i.prototype.add=function(t){ var e=I(); return this .addTo(t,e),e},i.prototype.subtract=function(t){ var e=I(); return this .subTo(t,e),e},i.prototype.multiply=function(t){ var e=I(); return this .multiplyTo(t,e),e},i.prototype.divide=function(t){ var e=I(); return this .divRemTo(t,e, null ),e},i.prototype.remainder=function(t){ var e=I(); return this .divRemTo(t, null ,e),e},i.prototype.divideAndRemainder=function(t){ var e=I(),i=I(); return this .divRemTo(t,e,i),[e,i]},i.prototype.modPow=function(t,e){ var i,r,n=t.bitLength(),s=H(1); if (n<=0) return s;i=n<18?1:n<48?3:n<144?4:n<768?5:6,r=n<8? new O(e):e.isEven()? new V(e): new A(e); var o=[],h=3,a=i-1,u=(1<<i)-1; if (o[1]=r.convert( this ),i>1){ var c=I(); for (r.sqrTo(o[1],c);h<=u;)o[h]=I(),r.mulTo(c,o[h-2],o[h]),h+=2} var f,l,p=t.t-1,g=!0,d=I(); for (n=C(t[p])-1;p>=0;){ for (n>=a?f=t[p]>>n-a&u:(f=(t[p]&(1<<n+1)-1)<<a-n,p>0&&(f|=t[p-1]>> this .DB+n-a)),h=i;0==(1&f);)f>>=1,--h; if ((n-=h)<0&&(n+= this .DB,--p),g)o[f].copyTo(s),g=!1; else { for (;h>1;)r.sqrTo(s,d),r.sqrTo(d,s),h-=2;h>0?r.sqrTo(s,d):(l=s,s=d,d=l),r.mulTo(d,o[f],s)} for (;p>=0&&0==(t[p]&1<<n);)r.sqrTo(s,d),l=s,s=d,d=l,--n<0&&(n= this .DB-1,--p)} return r.revert(s)},i.prototype.modInverse=function(t){ var e=t.isEven(); if ( this .isEven()&&e||0==t.signum()) return i.ZERO; for ( var r=t.clone(),n= this .clone(),s=H(1),o=H(0),h=H(0),a=H(1);0!=r.signum();){ for (;r.isEven();)r.rShiftTo(1,r),e?(s.isEven()&&o.isEven()||(s.addTo( this ,s),o.subTo(t,o)),s.rShiftTo(1,s)):o.isEven()||o.subTo(t,o),o.rShiftTo(1,o); for (;n.isEven();)n.rShiftTo(1,n),e?(h.isEven()&&a.isEven()||(h.addTo( this ,h),a.subTo(t,a)),h.rShiftTo(1,h)):a.isEven()||a.subTo(t,a),a.rShiftTo(1,a);r.compareTo(n)>=0?(r.subTo(n,r),e&&s.subTo(h,s),o.subTo(a,o)):(n.subTo(r,n),e&&h.subTo(s,h),a.subTo(o,a))} return 0!=n.compareTo(i.ONE)?i.ZERO:a.compareTo(t)>=0?a.subtract(t):a.signum()<0?(a.addTo(t,a),a.signum()<0?a.add(t):a):a},i.prototype.pow=function(t){ return this .exp(t, new B)},i.prototype.gcd=function(t){ var e= this .s<0? this .negate(): this .clone(),i=t.s<0?t.negate():t.clone(); if (e.compareTo(i)<0){ var r=e;e=i,i=r} var n=e.getLowestSetBit(),s=i.getLowestSetBit(); if (s<0) return e; for (n<s&&(s=n),s>0&&(e.rShiftTo(s,e),i.rShiftTo(s,i));e.signum()>0;)(n=e.getLowestSetBit())>0&&e.rShiftTo(n,e),(n=i.getLowestSetBit())>0&&i.rShiftTo(n,i),e.compareTo(i)>=0?(e.subTo(i,e),e.rShiftTo(1,e)):(i.subTo(e,i),i.rShiftTo(1,i)); return s>0&&i.lShiftTo(s,i),i},i.prototype.isProbablePrime=function(t){ var e,i= this .abs(); if (1==i.t&&i[0]<=D[D.length-1]){ for (e=0;e<D.length;++e) if (i[0]==D[e]) return !0; return !1} if (i.isEven()) return !1; for (e=1;e<D.length;){ for ( var r=D[e],n=e+1;n<D.length&&r<x;)r*=D[n++]; for (r=i.modInt(r);e<n;) if (r%D[e++]==0) return !1} return i.millerRabin(t)},i.prototype.copyTo=function(t){ for ( var e= this .t-1;e>=0;--e)t[e]= this [e];t.t= this .t,t.s= this .s},i.prototype.fromInt=function(t){ this .t=1, this .s=t<0?-1:0,t>0? this [0]=t:t<-1? this [0]=t+ this .DV: this .t=0},i.prototype.fromString=function(t,e){ var r; if (16==e)r=4; else if (8==e)r=3; else if (256==e)r=8; else if (2==e)r=1; else if (32==e)r=5; else { if (4!=e) return void this .fromRadix(t,e);r=2} this .t=0, this .s=0; for ( var n=t.length,s=!1,o=0;--n>=0;){ var h=8==r?255&+t[n]:q(t,n);h<0? "-" ==t.charAt(n)&&(s=!0):(s=!1,0==o? this [ this .t++]=h:o+r> this .DB?( this [ this .t-1]|=(h&(1<< this .DB-o)-1)<<o, this [ this .t++]=h>> this .DB-o): this [ this .t-1]|=h<<o,(o+=r)>= this .DB&&(o-= this .DB))}8==r&&0!=(128&+t[0])&&( this .s=-1,o>0&&( this [ this .t-1]|=(1<< this .DB-o)-1<<o)), this .clamp(),s&&i.ZERO.subTo( this , this )},i.prototype.clamp=function(){ for ( var t= this .s& this .DM; this .t>0&& this [ this .t-1]==t;)-- this .t},i.prototype.dlShiftTo=function(t,e){ var i; for (i= this .t-1;i>=0;--i)e[i+t]= this [i]; for (i=t-1;i>=0;--i)e[i]=0;e.t= this .t+t,e.s= this .s},i.prototype.drShiftTo=function(t,e){ for ( var i=t;i< this .t;++i)e[i-t]= this [i];e.t=Math.max( this .t-t,0),e.s= this .s},i.prototype.lShiftTo=function(t,e){ for ( var i=t% this .DB,r= this .DB-i,n=(1<<r)-1,s=Math.floor(t/ this .DB),o= this .s<<i& this .DM,h= this .t-1;h>=0;--h)e[h+s+1]= this [h]>>r|o,o=( this [h]&n)<<i; for (h=s-1;h>=0;--h)e[h]=0;e[s]=o,e.t= this .t+s+1,e.s= this .s,e.clamp()},i.prototype.rShiftTo=function(t,e){e.s= this .s; var i=Math.floor(t/ this .DB); if (i>= this .t)e.t=0; else { var r=t% this .DB,n= this .DB-r,s=(1<<r)-1;e[0]= this [i]>>r; for ( var o=i+1;o< this .t;++o)e[o-i-1]|=( this [o]&s)<<n,e[o-i]= this [o]>>r;r>0&&(e[ this .t-i-1]|=( this .s&s)<<n),e.t= this .t-i,e.clamp()}},i.prototype.subTo=function(t,e){ for ( var i=0,r=0,n=Math.min(t.t, this .t);i<n;)r+= this [i]-t[i],e[i++]=r& this .DM,r>>= this .DB; if (t.t< this .t){ for (r-=t.s;i< this .t;)r+= this [i],e[i++]=r& this .DM,r>>= this .DB;r+= this .s} else { for (r+= this .s;i<t.t;)r-=t[i],e[i++]=r& this .DM,r>>= this .DB;r-=t.s}e.s=r<0?-1:0,r<-1?e[i++]= this .DV+r:r>0&&(e[i++]=r),e.t=i,e.clamp()},i.prototype.multiplyTo=function(t,e){ var r= this .abs(),n=t.abs(),s=r.t; for (e.t=s+n.t;--s>=0;)e[s]=0; for (s=0;s<n.t;++s)e[s+r.t]=r.am(0,n[s],e,s,0,r.t);e.s=0,e.clamp(), this .s!=t.s&&i.ZERO.subTo(e,e)},i.prototype.squareTo=function(t){ for ( var e= this .abs(),i=t.t=2*e.t;--i>=0;)t[i]=0; for (i=0;i<e.t-1;++i){ var r=e.am(i,e[i],t,2*i,0,1);(t[i+e.t]+=e.am(i+1,2*e[i],t,2*i+1,r,e.t-i-1))>=e.DV&&(t[i+e.t]-=e.DV,t[i+e.t+1]=1)}t.t>0&&(t[t.t-1]+=e.am(i,e[i],t,2*i,0,1)),t.s=0,t.clamp()},i.prototype.divRemTo=function(t,e,r){ var n=t.abs(); if (!(n.t<=0)){ var s= this .abs(); if (s.t<n.t) return null !=e&&e.fromInt(0), void ( null !=r&& this .copyTo(r)); null ==r&&(r=I()); var o=I(),h= this .s,a=t.s,u= this .DB-C(n[n.t-1]);u>0?(n.lShiftTo(u,o),s.lShiftTo(u,r)):(n.copyTo(o),s.copyTo(r)); var c=o.t,f=o[c-1]; if (0!=f){ var l=f*(1<< this .F1)+(c>1?o[c-2]>> this .F2:0),p= this .FV/l,g=(1<< this .F1)/l,d=1<< this .F2,v=r.t,m=v-c,y= null ==e?I():e; for (o.dlShiftTo(m,y),r.compareTo(y)>=0&&(r[r.t++]=1,r.subTo(y,r)),i.ONE.dlShiftTo(c,y),y.subTo(o,o);o.t<c;)o[o.t++]=0; for (;--m>=0;){ var b=r[--v]==f? this .DM:Math.floor(r[v]*p+(r[v-1]+d)*g); if ((r[v]+=o.am(0,b,r,m,0,c))<b) for (o.dlShiftTo(m,y),r.subTo(y,r);r[v]<--b;)r.subTo(y,r)} null !=e&&(r.drShiftTo(c,e),h!=a&&i.ZERO.subTo(e,e)),r.t=c,r.clamp(),u>0&&r.rShiftTo(u,r),h<0&&i.ZERO.subTo(r,r)}}},i.prototype.invDigit=function(){ if ( this .t<1) return 0; var t= this [0]; if (0==(1&t)) return 0; var e=3&t; return (e=(e=(e=(e=e*(2-(15&t)*e)&15)*(2-(255&t)*e)&255)*(2-((65535&t)*e&65535))&65535)*(2-t*e% this .DV)% this .DV)>0? this .DV-e:-e},i.prototype.isEven=function(){ return 0==( this .t>0?1& this [0]: this .s)},i.prototype.exp=function(t,e){ if (t>4294967295||t<1) return i.ONE; var r=I(),n=I(),s=e.convert( this ),o=C(t)-1; for (s.copyTo(r);--o>=0;) if (e.sqrTo(r,n),(t&1<<o)>0)e.mulTo(n,s,r); else { var h=r;r=n,n=h} return e.revert(r)},i.prototype.chunkSize=function(t){ return Math.floor(Math.LN2* this .DB/Math.log(t))},i.prototype.toRadix=function(t){ if ( null ==t&&(t=10),0== this .signum()||t<2||t>36) return "0" ; var e= this .chunkSize(t),i=Math.pow(t,e),r=H(i),n=I(),s=I(),o= "" ; for ( this .divRemTo(r,n,s);n.signum()>0;)o=(i+s.intValue()).toString(t).substr(1)+o,n.divRemTo(r,n,s); return s.intValue().toString(t)+o},i.prototype.fromRadix=function(t,e){ this .fromInt(0), null ==e&&(e=10); for ( var r= this .chunkSize(e),n=Math.pow(e,r),s=!1,o=0,h=0,a=0;a<t.length;++a){ var u=q(t,a);u<0? "-" ==t.charAt(a)&&0== this .signum()&&(s=!0):(h=e*h+u,++o>=r&&( this .dMultiply(n), this .dAddOffset(h,0),o=0,h=0))}o>0&&( this .dMultiply(Math.pow(e,o)), this .dAddOffset(h,0)),s&&i.ZERO.subTo( this , this )},i.prototype.fromNumber=function(t,e,r){ if ( "number" == typeof e) if (t<2) this .fromInt(1); else for ( this .fromNumber(t,r), this .testBit(t-1)|| this .bitwiseTo(i.ONE.shiftLeft(t-1),n, this ), this .isEven()&& this .dAddOffset(1,0);! this .isProbablePrime(e);) this .dAddOffset(2,0), this .bitLength()>t&& this .subTo(i.ONE.shiftLeft(t-1), this ); else { var s=[],o=7&t;s.length=1+(t>>3),e.nextBytes(s),o>0?s[0]&=(1<<o)-1:s[0]=0, this .fromString(s,256)}},i.prototype.bitwiseTo=function(t,e,i){ var r,n,s=Math.min(t.t, this .t); for (r=0;r<s;++r)i[r]=e( this [r],t[r]); if (t.t< this .t){ for (n=t.s& this .DM,r=s;r< this .t;++r)i[r]=e( this [r],n);i.t= this .t} else { for (n= this .s& this .DM,r=s;r<t.t;++r)i[r]=e(n,t[r]);i.t=t.t}i.s=e( this .s,t.s),i.clamp()},i.prototype.changeBit=function(t,e){ var r=i.ONE.shiftLeft(t); return this .bitwiseTo(r,e,r),r},i.prototype.addTo=function(t,e){ for ( var i=0,r=0,n=Math.min(t.t, this .t);i<n;)r+= this [i]+t[i],e[i++]=r& this .DM,r>>= this .DB; if (t.t< this .t){ for (r+=t.s;i< this .t;)r+= this [i],e[i++]=r& this .DM,r>>= this .DB;r+= this .s} else { for (r+= this .s;i<t.t;)r+=t[i],e[i++]=r& this .DM,r>>= this .DB;r+=t.s}e.s=r<0?-1:0,r>0?e[i++]=r:r<-1&&(e[i++]= this .DV+r),e.t=i,e.clamp()},i.prototype.dMultiply=function(t){ this [ this .t]= this .am(0,t-1, this ,0,0, this .t),++ this .t, this .clamp()},i.prototype.dAddOffset=function(t,e){ if (0!=t){ for (; this .t<=e;) this [ this .t++]=0; for ( this [e]+=t; this [e]>= this .DV;) this [e]-= this .DV,++e>= this .t&&( this [ this .t++]=0),++ this [e]}},i.prototype.multiplyLowerTo=function(t,e,i){ var r=Math.min( this .t+t.t,e); for (i.s=0,i.t=r;r>0;)i[--r]=0; for ( var n=i.t- this .t;r<n;++r)i[r+ this .t]= this .am(0,t[r],i,r,0, this .t); for (n=Math.min(t.t,e);r<n;++r) this .am(0,t[r],i,r,0,e-r);i.clamp()},i.prototype.multiplyUpperTo=function(t,e,i){--e; var r=i.t= this .t+t.t-e; for (i.s=0;--r>=0;)i[r]=0; for (r=Math.max(e- this .t,0);r<t.t;++r)i[ this .t+r-e]= this .am(e-r,t[r],i,0,0, this .t+r-e);i.clamp(),i.drShiftTo(1,i)},i.prototype.modInt=function(t){ if (t<=0) return 0; var e= this .DV%t,i= this .s<0?t-1:0; if ( this .t>0) if (0==e)i= this [0]%t; else for ( var r= this .t-1;r>=0;--r)i=(e*i+ this [r])%t; return i},i.prototype.millerRabin=function(t){ var e= this .subtract(i.ONE),r=e.getLowestSetBit(); if (r<=0) return !1; var n=e.shiftRight(r);(t=t+1>>1)>D.length&&(t=D.length); for ( var s=I(),o=0;o<t;++o){s.fromInt(D[Math.floor(Math.random()*D.length)]); var h=s.modPow(n, this ); if (0!=h.compareTo(i.ONE)&&0!=h.compareTo(e)){ for ( var a=1;a++<r&&0!=h.compareTo(e);) if (0==(h=h.modPowInt(2, this )).compareTo(i.ONE)) return !1; if (0!=h.compareTo(e)) return !1}} return !0},i.prototype.square=function(){ var t=I(); return this .squareTo(t),t},i.prototype.gcda=function(t,e){ var i= this .s<0? this .negate(): this .clone(),r=t.s<0?t.negate():t.clone(); if (i.compareTo(r)<0){ var n=i;i=r,r=n} var s=i.getLowestSetBit(),o=r.getLowestSetBit(); if (o<0)e(i); else {s<o&&(o=s),o>0&&(i.rShiftTo(o,i),r.rShiftTo(o,r)); var h=function(){(s=i.getLowestSetBit())>0&&i.rShiftTo(s,i),(s=r.getLowestSetBit())>0&&r.rShiftTo(s,r),i.compareTo(r)>=0?(i.subTo(r,i),i.rShiftTo(1,i)):(r.subTo(i,r),r.rShiftTo(1,r)),i.signum()>0?setTimeout(h,0):(o>0&&r.lShiftTo(o,r),setTimeout((function(){e(r)}),0))};setTimeout(h,10)}},i.prototype.fromNumberAsync=function(t,e,r,s){ if ( "number" == typeof e) if (t<2) this .fromInt(1); else { this .fromNumber(t,r), this .testBit(t-1)|| this .bitwiseTo(i.ONE.shiftLeft(t-1),n, this ), this .isEven()&& this .dAddOffset(1,0); var o= this ,h=function(){o.dAddOffset(2,0),o.bitLength()>t&&o.subTo(i.ONE.shiftLeft(t-1),o),o.isProbablePrime(e)?setTimeout((function(){s()}),0):setTimeout(h,0)};setTimeout(h,0)} else { var a=[],u=7&t;a.length=1+(t>>3),e.nextBytes(a),u>0?a[0]&=(1<<u)-1:a[0]=0, this .fromString(a,256)}},i}(),B=function(){function t(){} return t.prototype.convert=function(t){ return t},t.prototype.revert=function(t){ return t},t.prototype.mulTo=function(t,e,i){t.multiplyTo(e,i)},t.prototype.sqrTo=function(t,e){t.squareTo(e)},t}(),O=function(){function t(t){ this .m=t} return t.prototype.convert=function(t){ return t.s<0||t.compareTo( this .m)>=0?t.mod( this .m):t},t.prototype.revert=function(t){ return t},t.prototype.reduce=function(t){t.divRemTo( this .m, null ,t)},t.prototype.mulTo=function(t,e,i){t.multiplyTo(e,i), this .reduce(i)},t.prototype.sqrTo=function(t,e){t.squareTo(e), this .reduce(e)},t}(),A=function(){function t(t){ this .m=t, this .mp=t.invDigit(), this .mpl=32767& this .mp, this .mph= this .mp>>15, this .um=(1<<t.DB-15)-1, this .mt2=2*t.t} return t.prototype.convert=function(t){ var e=I(); return t.abs().dlShiftTo( this .m.t,e),e.divRemTo( this .m, null ,e),t.s<0&&e.compareTo(R.ZERO)>0&& this .m.subTo(e,e),e},t.prototype.revert=function(t){ var e=I(); return t.copyTo(e), this .reduce(e),e},t.prototype.reduce=function(t){ for (;t.t<= this .mt2;)t[t.t++]=0; for ( var e=0;e< this .m.t;++e){ var i=32767&t[e],r=i* this .mpl+((i* this .mph+(t[e]>>15)* this .mpl& this .um)<<15)&t.DM; for (t[i=e+ this .m.t]+= this .m.am(0,r,t,e,0, this .m.t);t[i]>=t.DV;)t[i]-=t.DV,t[++i]++}t.clamp(),t.drShiftTo( this .m.t,t),t.compareTo( this .m)>=0&&t.subTo( this .m,t)},t.prototype.mulTo=function(t,e,i){t.multiplyTo(e,i), this .reduce(i)},t.prototype.sqrTo=function(t,e){t.squareTo(e), this .reduce(e)},t}(),V=function(){function t(t){ this .m=t, this .r2=I(), this .q3=I(),R.ONE.dlShiftTo(2*t.t, this .r2), this .mu= this .r2.divide(t)} return t.prototype.convert=function(t){ if (t.s<0||t.t>2* this .m.t) return t.mod( this .m); if (t.compareTo( this .m)<0) return t; var e=I(); return t.copyTo(e), this .reduce(e),e},t.prototype.revert=function(t){ return t},t.prototype.reduce=function(t){ for (t.drShiftTo( this .m.t-1, this .r2),t.t> this .m.t+1&&(t.t= this .m.t+1,t.clamp()), this .mu.multiplyUpperTo( this .r2, this .m.t+1, this .q3), this .m.multiplyLowerTo( this .q3, this .m.t+1, this .r2);t.compareTo( this .r2)<0;)t.dAddOffset(1, this .m.t+1); for (t.subTo( this .r2,t);t.compareTo( this .m)>=0;)t.subTo( this .m,t)},t.prototype.mulTo=function(t,e,i){t.multiplyTo(e,i), this .reduce(i)},t.prototype.sqrTo=function(t,e){t.squareTo(e), this .reduce(e)},t}();function I(){ return new R( null )}function N(t,e){ return new R(t,e)} var P= "undefined" != typeof navigator;P&& "Microsoft Internet Explorer" ==navigator.appName?(R.prototype.am=function(t,e,i,r,n,s){ for ( var o=32767&e,h=e>>15;--s>=0;){ var a=32767& this [t],u= this [t++]>>15,c=h*a+u*o;n=((a=o*a+((32767&c)<<15)+i[r]+(1073741823&n))>>>30)+(c>>>15)+h*u+(n>>>30),i[r++]=1073741823&a} return n},T=30):P&& "Netscape" !=navigator.appName?(R.prototype.am=function(t,e,i,r,n,s){ for (;--s>=0;){ var o=e* this [t++]+i[r]+n;n=Math.floor(o/67108864),i[r++]=67108863&o} return n},T=26):(R.prototype.am=function(t,e,i,r,n,s){ for ( var o=16383&e,h=e>>14;--s>=0;){ var a=16383& this [t],u= this [t++]>>14,c=h*a+u*o;n=((a=o*a+((16383&c)<<14)+i[r]+n)>>28)+(c>>14)+h*u,i[r++]=268435455&a} return n},T=28),R.prototype.DB=T,R.prototype.DM=(1<<T)-1,R.prototype.DV=1<<T,R.prototype.FV=Math.pow(2,52),R.prototype.F1=52-T,R.prototype.F2=2*T-52; var M,L,j=[]; for (M= "0" .charCodeAt(0),L=0;L<=9;++L)j[M++]=L; for (M= "a" .charCodeAt(0),L=10;L<36;++L)j[M++]=L; for (M= "A" .charCodeAt(0),L=10;L<36;++L)j[M++]=L;function q(t,e){ var i=j[t.charCodeAt(e)]; return null ==i?-1:i}function H(t){ var e=I(); return e.fromInt(t),e}function C(t){ var e,i=1; return 0!=(e=t>>>16)&&(t=e,i+=16),0!=(e=t>>8)&&(t=e,i+=8),0!=(e=t>>4)&&(t=e,i+=4),0!=(e=t>>2)&&(t=e,i+=2),0!=(e=t>>1)&&(t=e,i+=1),i}R.ZERO=H(0),R.ONE=H(1); var F,U,K=function(){function t(){ this .i=0, this .j=0, this .S=[]} return t.prototype.init=function(t){ var e,i,r; for (e=0;e<256;++e) this .S[e]=e; for (i=0,e=0;e<256;++e)i=i+ this .S[e]+t[e%t.length]&255,r= this .S[e], this .S[e]= this .S[i], this .S[i]=r; this .i=0, this .j=0},t.prototype.next=function(){ var t; return this .i= this .i+1&255, this .j= this .j+ this .S[ this .i]&255,t= this .S[ this .i], this .S[ this .i]= this .S[ this .j], this .S[ this .j]=t, this .S[t+ this .S[ this .i]&255]},t}(),k= null ; if ( null ==k){k=[],U=0; var _= void 0; if ( "undefined" != typeof window&&window.crypto&&window.crypto.getRandomValues){ var z= new Uint32Array(256); for (window.crypto.getRandomValues(z),_=0;_<z.length;++_)k[U++]=255&z[_]} var Z=0,G=function(t){ if ((Z=Z||0)>=256||U>=256)window.removeEventListener?window.removeEventListener( "mousemove" ,G,!1):window.detachEvent&&window.detachEvent( "onmousemove" ,G); else try { var e=t.x+t.y;k[U++]=255&e,Z+=1} catch (t){}}; "undefined" != typeof window&&(window.addEventListener?window.addEventListener( "mousemove" ,G,!1):window.attachEvent&&window.attachEvent( "onmousemove" ,G))}function $(){ if ( null ==F){ for (F= new K;U<256;){ var t=Math.floor(65536*Math.random());k[U++]=255&t} for (F.init(k),U=0;U<k.length;++U)k[U]=0;U=0} return F.next()} var Y=function(){function t(){} return t.prototype.nextBytes=function(t){ for ( var e=0;e<t.length;++e)t[e]=$()},t}(),J=function(){function t(){ this .n= null , this .e=0, this .d= null , this .p= null , this .q= null , this .dmp1= null , this .dmq1= null , this .coeff= null } return t.prototype.doPublic=function(t){ return t.modPowInt( this .e, this .n)},t.prototype.doPrivate=function(t){ if ( null == this .p|| null == this .q) return t.modPow( this .d, this .n); for ( var e=t.mod( this .p).modPow( this .dmp1, this .p),i=t.mod( this .q).modPow( this .dmq1, this .q);e.compareTo(i)<0;)e=e.add( this .p); return e.subtract(i).multiply( this .coeff).mod( this .p).multiply( this .q).add(i)},t.prototype.setPublic=function(t,e){ null !=t&& null !=e&&t.length>0&&e.length>0?( this .n=N(t,16), this .e=parseInt(e,16)):console.error( "Invalid RSA public key" )},t.prototype.encrypt=function(t){ var e= this .n.bitLength()+7>>3,i=function(t,e){ if (e<t.length+11) return console.error( "Message too long for RSA" ), null ; for ( var i=[],r=t.length-1;r>=0&&e>0;){ var n=t.charCodeAt(r--);n<128?i[--e]=n:n>127&&n<2048?(i[--e]=63&n|128,i[--e]=n>>6|192):(i[--e]=63&n|128,i[--e]=n>>6&63|128,i[--e]=n>>12|224)}i[--e]=0; for ( var s= new Y,o=[];e>2;){ for (o[0]=0;0==o[0];)s.nextBytes(o);i[--e]=o[0]} return i[--e]=2,i[--e]=0, new R(i)}(t,e); if ( null ==i) return null ; var r= this .doPublic(i); if ( null ==r) return null ; for ( var n=r.toString(16),s=n.length,o=0;o<2*e-s;o++)n= "0" +n; return n},t.prototype.setPrivate=function(t,e,i){ null !=t&& null !=e&&t.length>0&&e.length>0?( this .n=N(t,16), this .e=parseInt(e,16), this .d=N(i,16)):console.error( "Invalid RSA private key" )},t.prototype.setPrivateEx=function(t,e,i,r,n,s,o,h){ null !=t&& null !=e&&t.length>0&&e.length>0?( this .n=N(t,16), this .e=parseInt(e,16), this .d=N(i,16), this .p=N(r,16), this .q=N(n,16), this .dmp1=N(s,16), this .dmq1=N(o,16), this .coeff=N(h,16)):console.error( "Invalid RSA private key" )},t.prototype.generate=function(t,e){ var i= new Y,r=t>>1; this .e=parseInt(e,16); for ( var n= new R(e,16);;){ for (; this .p= new R(t-r,1,i),0!= this .p.subtract(R.ONE).gcd(n).compareTo(R.ONE)||! this .p.isProbablePrime(10);); for (; this .q= new R(r,1,i),0!= this .q.subtract(R.ONE).gcd(n).compareTo(R.ONE)||! this .q.isProbablePrime(10);); if ( this .p.compareTo( this .q)<=0){ var s= this .p; this .p= this .q, this .q=s} var o= this .p.subtract(R.ONE),h= this .q.subtract(R.ONE),a=o.multiply(h); if (0==a.gcd(n).compareTo(R.ONE)){ this .n= this .p.multiply( this .q), this .d=n.modInverse(a), this .dmp1= this .d.mod(o), this .dmq1= this .d.mod(h), this .coeff= this .q.modInverse( this .p); break }}},t.prototype.decrypt=function(t){ var e=N(t,16),i= this .doPrivate(e); return null ==i? null :function(t,e){ for ( var i=t.toByteArray(),r=0;r<i.length&&0==i[r];)++r; if (i.length-r!=e-1||2!=i[r]) return null ; for (++r;0!=i[r];) if (++r>=i.length) return null ; for ( var n= "" ;++r<i.length;){ var s=255&i[r];s<128?n+=String.fromCharCode(s):s>191&&s<224?(n+=String.fromCharCode((31&s)<<6|63&i[r+1]),++r):(n+=String.fromCharCode((15&s)<<12|(63&i[r+1])<<6|63&i[r+2]),r+=2)} return n}(i, this .n.bitLength()+7>>3)},t.prototype.generateAsync=function(t,e,i){ var r= new Y,n=t>>1; this .e=parseInt(e,16); var s= new R(e,16),o= this ,h=function(){ var e=function(){ if (o.p.compareTo(o.q)<=0){ var t=o.p;o.p=o.q,o.q=t} var e=o.p.subtract(R.ONE),r=o.q.subtract(R.ONE),n=e.multiply(r);0==n.gcd(s).compareTo(R.ONE)?(o.n=o.p.multiply(o.q),o.d=s.modInverse(n),o.dmp1=o.d.mod(e),o.dmq1=o.d.mod(r),o.coeff=o.q.modInverse(o.p),setTimeout((function(){i()}),0)):setTimeout(h,0)},a=function(){o.q=I(),o.q.fromNumberAsync(n,1,r,(function(){o.q.subtract(R.ONE).gcda(s,(function(t){0==t.compareTo(R.ONE)&&o.q.isProbablePrime(10)?setTimeout(e,0):setTimeout(a,0)}))}))},u=function(){o.p=I(),o.p.fromNumberAsync(t-n,1,r,(function(){o.p.subtract(R.ONE).gcda(s,(function(t){0==t.compareTo(R.ONE)&&o.p.isProbablePrime(10)?setTimeout(a,0):setTimeout(u,0)}))}))};setTimeout(u,0)};setTimeout(h,0)},t.prototype.sign=function(t,e,i){ var r=function(t,e){ if (e<t.length+22) return console.error( "Message too long for RSA" ), null ; for ( var i=e-t.length-6,r= "" ,n=0;n<i;n+=2)r+= "ff" ; return N( "0001" +r+ "00" +t,16)}((X[i]|| "" )+e(t).toString(), this .n.bitLength()/4); if ( null ==r) return null ; var n= this .doPrivate(r); if ( null ==n) return null ; var s=n.toString(16); return 0==(1&s.length)?s: "0" +s},t.prototype.verify=function(t,e,i){ var r=N(e,16),n= this .doPublic(r); return null ==n? null :function(t){ for ( var e in X) if (X.hasOwnProperty(e)){ var i=X[e],r=i.length; if (t.substr(0,r)==i) return t.substr(r)} return t}(n.toString(16).replace(/^1f+00/, "" ))==i(t).toString()},t}(),X={md2: "3020300c06082a864886f70d020205000410" ,md5: "3020300c06082a864886f70d020505000410" ,sha1: "3021300906052b0e03021a05000414" ,sha224: "302d300d06096086480165030402040500041c" ,sha256: "3031300d060960864801650304020105000420" ,sha384: "3041300d060960864801650304020205000430" ,sha512: "3051300d060960864801650304020305000440" ,ripemd160: "3021300906052b2403020105000414" },Q={};Q.lang={extend:function(t,e,i){ if (!e||!t) throw new Error( "YAHOO.lang.extend failed, please check that all dependencies are included." ); var r=function(){}; if (r.prototype=e.prototype,t.prototype= new r,t.prototype.constructor=t,t.superclass=e.prototype,e.prototype.constructor==Object.prototype.constructor&&(e.prototype.constructor=e),i){ var n; for (n in i)t.prototype[n]=i[n]; var s=function(){},o=[ "toString" , "valueOf" ]; try {/MSIE/.test(navigator.userAgent)&&(s=function(t,e){ for (n=0;n<o.length;n+=1){ var i=o[n],r=e[i]; "function" == typeof r&&r!=Object.prototype[i]&&(t[i]=r)}})} catch (t){}s(t.prototype,i)}}}; var W={}; void 0!==W.asn1&&W.asn1||(W.asn1={}),W.asn1.ASN1Util= new function(){ this .integerToByteHex=function(t){ var e=t.toString(16); return e.length%2==1&&(e= "0" +e),e}, this .bigIntToMinTwosComplementsHex=function(t){ var e=t.toString(16); if ( "-" !=e.substr(0,1))e.length%2==1?e= "0" +e:e.match(/^[0-7]/)||(e= "00" +e); else { var i=e.substr(1).length;i%2==1?i+=1:e.match(/^[0-7]/)||(i+=2); for ( var r= "" ,n=0;n<i;n++)r+= "f" ;e= new R(r,16).xor(t).add(R.ONE).toString(16).replace(/^-/, "" )} return e}, this .getPEMStringFromHex=function(t,e){ return hextopem(t,e)}, this .newObject=function(t){ var e=W.asn1,i=e.DERBoolean,r=e.DERInteger,n=e.DERBitString,s=e.DEROctetString,o=e.DERNull,h=e.DERObjectIdentifier,a=e.DEREnumerated,u=e.DERUTF8String,c=e.DERNumericString,f=e.DERPrintableString,l=e.DERTeletexString,p=e.DERIA5String,g=e.DERUTCTime,d=e.DERGeneralizedTime,v=e.DERSequence,m=e.DERSet,y=e.DERTaggedObject,b=e.ASN1Util.newObject,T=Object.keys(t); if (1!=T.length) throw "key of param shall be only one." ; var S=T[0]; if (-1== ":bool:int:bitstr:octstr:null:oid:enum:utf8str:numstr:prnstr:telstr:ia5str:utctime:gentime:seq:set:tag:" .indexOf( ":" +S+ ":" )) throw "undefined key: " +S; if ( "bool" ==S) return new i(t[S]); if ( "int" ==S) return new r(t[S]); if ( "bitstr" ==S) return new n(t[S]); if ( "octstr" ==S) return new s(t[S]); if ( "null" ==S) return new o(t[S]); if ( "oid" ==S) return new h(t[S]); if ( "enum" ==S) return new a(t[S]); if ( "utf8str" ==S) return new u(t[S]); if ( "numstr" ==S) return new c(t[S]); if ( "prnstr" ==S) return new f(t[S]); if ( "telstr" ==S) return new l(t[S]); if ( "ia5str" ==S) return new p(t[S]); if ( "utctime" ==S) return new g(t[S]); if ( "gentime" ==S) return new d(t[S]); if ( "seq" ==S){ for ( var E=t[S],w=[],D=0;D<E.length;D++){ var x=b(E[D]);w.push(x)} return new v({array:w})} if ( "set" ==S){ for (E=t[S],w=[],D=0;D<E.length;D++)x=b(E[D]),w.push(x); return new m({array:w})} if ( "tag" ==S){ var R=t[S]; if ( "[object Array]" ===Object.prototype.toString.call(R)&&3==R.length){ var B=b(R[2]); return new y({tag:R[0], explicit :R[1],obj:B})} var O={}; if ( void 0!==R. explicit &&(O. explicit =R. explicit ), void 0!==R.tag&&(O.tag=R.tag), void 0===R.obj) throw "obj shall be specified for 'tag'." ; return O.obj=b(R.obj), new y(O)}}, this .jsonToASN1HEX=function(t){ return this .newObject(t).getEncodedHex()}},W.asn1.ASN1Util.oidHexToInt=function(t){ for ( var e= "" ,i=parseInt(t.substr(0,2),16),r=(e=Math.floor(i/40)+ "." +i%40, "" ),n=2;n<t.length;n+=2){ var s=( "00000000" +parseInt(t.substr(n,2),16).toString(2)).slice(-8);r+=s.substr(1,7), "0" ==s.substr(0,1)&&(e=e+ "." + new R(r,2).toString(10),r= "" )} return e},W.asn1.ASN1Util.oidIntToHex=function(t){ var e=function(t){ var e=t.toString(16); return 1==e.length&&(e= "0" +e),e},i=function(t){ var i= "" ,r= new R(t,10).toString(2),n=7-r.length%7;7==n&&(n=0); for ( var s= "" ,o=0;o<n;o++)s+= "0" ; for (r=s+r,o=0;o<r.length-1;o+=7){ var h=r.substr(o,7);o!=r.length-7&&(h= "1" +h),i+=e(parseInt(h,2))} return i}; if (!t.match(/^[0-9.]+$/)) throw "malformed oid string: " +t; var r= "" ,n=t.split( "." ),s=40*parseInt(n[0])+parseInt(n[1]);r+=e(s),n.splice(0,2); for ( var o=0;o<n.length;o++)r+=i(n[o]); return r},W.asn1.ASN1Object=function(){ this .getLengthHexFromValue=function(){ if ( void 0=== this .hV|| null == this .hV) throw "this.hV is null or undefined." ; if ( this .hV.length%2==1) throw "value hex must be even length: n=" + "" .length+ ",v=" + this .hV; var t= this .hV.length/2,e=t.toString(16); if (e.length%2==1&&(e= "0" +e),t<128) return e; var i=e.length/2; if (i>15) throw "ASN.1 length too long to represent by 8x: n = " +t.toString(16); return (128+i).toString(16)+e}, this .getEncodedHex=function(){ return ( null == this .hTLV|| this .isModified)&&( this .hV= this .getFreshValueHex(), this .hL= this .getLengthHexFromValue(), this .hTLV= this .hT+ this .hL+ this .hV, this .isModified=!1), this .hTLV}, this .getValueHex=function(){ return this .getEncodedHex(), this .hV}, this .getFreshValueHex=function(){ return "" }},W.asn1.DERAbstractString=function(t){W.asn1.DERAbstractString.superclass.constructor.call( this ), this .getString=function(){ return this .s}, this .setString=function(t){ this .hTLV= null , this .isModified=!0, this .s=t, this .hV=stohex( this .s)}, this .setStringHex=function(t){ this .hTLV= null , this .isModified=!0, this .s= null , this .hV=t}, this .getFreshValueHex=function(){ return this .hV}, void 0!==t&&( "string" == typeof t? this .setString(t): void 0!==t.str? this .setString(t.str): void 0!==t.hex&& this .setStringHex(t.hex))},Q.lang.extend(W.asn1.DERAbstractString,W.asn1.ASN1Object),W.asn1.DERAbstractTime=function(t){W.asn1.DERAbstractTime.superclass.constructor.call( this ), this .localDateToUTC=function(t){ return utc=t.getTime()+6e4*t.getTimezoneOffset(), new Date(utc)}, this .formatDate=function(t,e,i){ var r= this .zeroPadding,n= this .localDateToUTC(t),s=String(n.getFullYear()); "utc" ==e&&(s=s.substr(2,2)); var o=s+r(String(n.getMonth()+1),2)+r(String(n.getDate()),2)+r(String(n.getHours()),2)+r(String(n.getMinutes()),2)+r(String(n.getSeconds()),2); if (!0===i){ var h=n.getMilliseconds(); if (0!=h){ var a=r(String(h),3);o=o+ "." +(a=a.replace(/[0]+$/, "" ))}} return o+ "Z" }, this .zeroPadding=function(t,e){ return t.length>=e?t: new Array(e-t.length+1). join ( "0" )+t}, this .getString=function(){ return this .s}, this .setString=function(t){ this .hTLV= null , this .isModified=!0, this .s=t, this .hV=stohex(t)}, this .setByDateValue=function(t,e,i,r,n,s){ var o= new Date(Date.UTC(t,e-1,i,r,n,s,0)); this .setByDate(o)}, this .getFreshValueHex=function(){ return this .hV}},Q.lang.extend(W.asn1.DERAbstractTime,W.asn1.ASN1Object),W.asn1.DERAbstractStructured=function(t){W.asn1.DERAbstractString.superclass.constructor.call( this ), this .setByASN1ObjectArray=function(t){ this .hTLV= null , this .isModified=!0, this .asn1Array=t}, this .appendASN1Object=function(t){ this .hTLV= null , this .isModified=!0, this .asn1Array.push(t)}, this .asn1Array= new Array, void 0!==t&& void 0!==t.array&&( this .asn1Array=t.array)},Q.lang.extend(W.asn1.DERAbstractStructured,W.asn1.ASN1Object),W.asn1.DERBoolean=function(){W.asn1.DERBoolean.superclass.constructor.call( this ), this .hT= "01" , this .hTLV= "0101ff" },Q.lang.extend(W.asn1.DERBoolean,W.asn1.ASN1Object),W.asn1.DERInteger=function(t){W.asn1.DERInteger.superclass.constructor.call( this ), this .hT= "02" , this .setByBigInteger=function(t){ this .hTLV= null , this .isModified=!0, this .hV=W.asn1.ASN1Util.bigIntToMinTwosComplementsHex(t)}, this .setByInteger=function(t){ var e= new R(String(t),10); this .setByBigInteger(e)}, this .setValueHex=function(t){ this .hV=t}, this .getFreshValueHex=function(){ return this .hV}, void 0!==t&&( void 0!==t.bigint? this .setByBigInteger(t.bigint): void 0!==t. int ? this .setByInteger(t. int ): "number" == typeof t? this .setByInteger(t): void 0!==t.hex&& this .setValueHex(t.hex))},Q.lang.extend(W.asn1.DERInteger,W.asn1.ASN1Object),W.asn1.DERBitString=function(t){ if ( void 0!==t&& void 0!==t.obj){ var e=W.asn1.ASN1Util.newObject(t.obj);t.hex= "00" +e.getEncodedHex()}W.asn1.DERBitString.superclass.constructor.call( this ), this .hT= "03" , this .setHexValueIncludingUnusedBits=function(t){ this .hTLV= null , this .isModified=!0, this .hV=t}, this .setUnusedBitsAndHexValue=function(t,e){ if (t<0||7<t) throw "unused bits shall be from 0 to 7: u = " +t; var i= "0" +t; this .hTLV= null , this .isModified=!0, this .hV=i+e}, this .setByBinaryString=function(t){ var e=8-(t=t.replace(/0+$/, "" )).length%8;8==e&&(e=0); for ( var i=0;i<=e;i++)t+= "0" ; var r= "" ; for (i=0;i<t.length-1;i+=8){ var n=t.substr(i,8),s=parseInt(n,2).toString(16);1==s.length&&(s= "0" +s),r+=s} this .hTLV= null , this .isModified=!0, this .hV= "0" +e+r}, this .setByBooleanArray=function(t){ for ( var e= "" ,i=0;i<t.length;i++)1==t[i]?e+= "1" :e+= "0" ; this .setByBinaryString(e)}, this .newFalseArray=function(t){ for ( var e= new Array(t),i=0;i<t;i++)e[i]=!1; return e}, this .getFreshValueHex=function(){ return this .hV}, void 0!==t&&( "string" == typeof t&&t.toLowerCase().match(/^[0-9a-f]+$/)? this .setHexValueIncludingUnusedBits(t): void 0!==t.hex? this .setHexValueIncludingUnusedBits(t.hex): void 0!==t.bin? this .setByBinaryString(t.bin): void 0!==t.array&& this .setByBooleanArray(t.array))},Q.lang.extend(W.asn1.DERBitString,W.asn1.ASN1Object),W.asn1.DEROctetString=function(t){ if ( void 0!==t&& void 0!==t.obj){ var e=W.asn1.ASN1Util.newObject(t.obj);t.hex=e.getEncodedHex()}W.asn1.DEROctetString.superclass.constructor.call( this ,t), this .hT= "04" },Q.lang.extend(W.asn1.DEROctetString,W.asn1.DERAbstractString),W.asn1.DERNull=function(){W.asn1.DERNull.superclass.constructor.call( this ), this .hT= "05" , this .hTLV= "0500" },Q.lang.extend(W.asn1.DERNull,W.asn1.ASN1Object),W.asn1.DERObjectIdentifier=function(t){ var e=function(t){ var e=t.toString(16); return 1==e.length&&(e= "0" +e),e},i=function(t){ var i= "" ,r= new R(t,10).toString(2),n=7-r.length%7;7==n&&(n=0); for ( var s= "" ,o=0;o<n;o++)s+= "0" ; for (r=s+r,o=0;o<r.length-1;o+=7){ var h=r.substr(o,7);o!=r.length-7&&(h= "1" +h),i+=e(parseInt(h,2))} return i};W.asn1.DERObjectIdentifier.superclass.constructor.call( this ), this .hT= "06" , this .setValueHex=function(t){ this .hTLV= null , this .isModified=!0, this .s= null , this .hV=t}, this .setValueOidString=function(t){ if (!t.match(/^[0-9.]+$/)) throw "malformed oid string: " +t; var r= "" ,n=t.split( "." ),s=40*parseInt(n[0])+parseInt(n[1]);r+=e(s),n.splice(0,2); for ( var o=0;o<n.length;o++)r+=i(n[o]); this .hTLV= null , this .isModified=!0, this .s= null , this .hV=r}, this .setValueName=function(t){ var e=W.asn1.x509.OID.name2oid(t); if ( "" ===e) throw "DERObjectIdentifier oidName undefined: " +t; this .setValueOidString(e)}, this .getFreshValueHex=function(){ return this .hV}, void 0!==t&&( "string" == typeof t?t.match(/^[0-2].[0-9.]+$/)? this .setValueOidString(t): this .setValueName(t): void 0!==t.oid? this .setValueOidString(t.oid): void 0!==t.hex? this .setValueHex(t.hex): void 0!==t.name&& this .setValueName(t.name))},Q.lang.extend(W.asn1.DERObjectIdentifier,W.asn1.ASN1Object),W.asn1.DEREnumerated=function(t){W.asn1.DEREnumerated.superclass.constructor.call( this ), this .hT= "0a" , this .setByBigInteger=function(t){ this .hTLV= null , this .isModified=!0, this .hV=W.asn1.ASN1Util.bigIntToMinTwosComplementsHex(t)}, this .setByInteger=function(t){ var e= new R(String(t),10); this .setByBigInteger(e)}, this .setValueHex=function(t){ this .hV=t}, this .getFreshValueHex=function(){ return this .hV}, void 0!==t&&( void 0!==t. int ? this .setByInteger(t. int ): "number" == typeof t? this .setByInteger(t): void 0!==t.hex&& this .setValueHex(t.hex))},Q.lang.extend(W.asn1.DEREnumerated,W.asn1.ASN1Object),W.asn1.DERUTF8String=function(t){W.asn1.DERUTF8String.superclass.constructor.call( this ,t), this .hT= "0c" },Q.lang.extend(W.asn1.DERUTF8String,W.asn1.DERAbstractString),W.asn1.DERNumericString=function(t){W.asn1.DERNumericString.superclass.constructor.call( this ,t), this .hT= "12" },Q.lang.extend(W.asn1.DERNumericString,W.asn1.DERAbstractString),W.asn1.DERPrintableString=function(t){W.asn1.DERPrintableString.superclass.constructor.call( this ,t), this .hT= "13" },Q.lang.extend(W.asn1.DERPrintableString,W.asn1.DERAbstractString),W.asn1.DERTeletexString=function(t){W.asn1.DERTeletexString.superclass.constructor.call( this ,t), this .hT= "14" },Q.lang.extend(W.asn1.DERTeletexString,W.asn1.DERAbstractString),W.asn1.DERIA5String=function(t){W.asn1.DERIA5String.superclass.constructor.call( this ,t), this .hT= "16" },Q.lang.extend(W.asn1.DERIA5String,W.asn1.DERAbstractString),W.asn1.DERUTCTime=function(t){W.asn1.DERUTCTime.superclass.constructor.call( this ,t), this .hT= "17" , this .setByDate=function(t){ this .hTLV= null , this .isModified=!0, this .date=t, this .s= this .formatDate( this .date, "utc" ), this .hV=stohex( this .s)}, this .getFreshValueHex=function(){ return void 0=== this .date&& void 0=== this .s&&( this .date= new Date, this .s= this .formatDate( this .date, "utc" ), this .hV=stohex( this .s)), this .hV}, void 0!==t&&( void 0!==t.str? this .setString(t.str): "string" == typeof t&&t.match(/^[0-9]{12}Z$/)? this .setString(t): void 0!==t.hex? this .setStringHex(t.hex): void 0!==t.date&& this .setByDate(t.date))},Q.lang.extend(W.asn1.DERUTCTime,W.asn1.DERAbstractTime),W.asn1.DERGeneralizedTime=function(t){W.asn1.DERGeneralizedTime.superclass.constructor.call( this ,t), this .hT= "18" , this .withMillis=!1, this .setByDate=function(t){ this .hTLV= null , this .isModified=!0, this .date=t, this .s= this .formatDate( this .date, "gen" , this .withMillis), this .hV=stohex( this .s)}, this .getFreshValueHex=function(){ return void 0=== this .date&& void 0=== this .s&&( this .date= new Date, this .s= this .formatDate( this .date, "gen" , this .withMillis), this .hV=stohex( this .s)), this .hV}, void 0!==t&&( void 0!==t.str? this .setString(t.str): "string" == typeof t&&t.match(/^[0-9]{14}Z$/)? this .setString(t): void 0!==t.hex? this .setStringHex(t.hex): void 0!==t.date&& this .setByDate(t.date),!0===t.millis&&( this .withMillis=!0))},Q.lang.extend(W.asn1.DERGeneralizedTime,W.asn1.DERAbstractTime),W.asn1.DERSequence=function(t){W.asn1.DERSequence.superclass.constructor.call( this ,t), this .hT= "30" , this .getFreshValueHex=function(){ for ( var t= "" ,e=0;e< this .asn1Array.length;e++)t+= this .asn1Array[e].getEncodedHex(); return this .hV=t, this .hV}},Q.lang.extend(W.asn1.DERSequence,W.asn1.DERAbstractStructured),W.asn1.DERSet=function(t){W.asn1.DERSet.superclass.constructor.call( this ,t), this .hT= "31" , this .sortFlag=!0, this .getFreshValueHex=function(){ for ( var t= new Array,e=0;e< this .asn1Array.length;e++){ var i= this .asn1Array[e];t.push(i.getEncodedHex())} return 1== this .sortFlag&&t.sort(), this .hV=t. join ( "" ), this .hV}, void 0!==t&& void 0!==t.sortflag&&0==t.sortflag&&( this .sortFlag=!1)},Q.lang.extend(W.asn1.DERSet,W.asn1.DERAbstractStructured),W.asn1.DERTaggedObject=function(t){W.asn1.DERTaggedObject.superclass.constructor.call( this ), this .hT= "a0" , this .hV= "" , this .isExplicit=!0, this .asn1Object= null , this .setASN1Object=function(t,e,i){ this .hT=e, this .isExplicit=t, this .asn1Object=i, this .isExplicit?( this .hV= this .asn1Object.getEncodedHex(), this .hTLV= null , this .isModified=!0):( this .hV= null , this .hTLV=i.getEncodedHex(), this .hTLV= this .hTLV.replace(/^../,e), this .isModified=!1)}, this .getFreshValueHex=function(){ return this .hV}, void 0!==t&&( void 0!==t.tag&&( this .hT=t.tag), void 0!==t. explicit &&( this .isExplicit=t. explicit ), void 0!==t.obj&&( this .asn1Object=t.obj, this .setASN1Object( this .isExplicit, this .hT, this .asn1Object)))},Q.lang.extend(W.asn1.DERTaggedObject,W.asn1.ASN1Object); var tt,et,it=(tt=function(t,e){ return tt=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){ for ( var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i])},tt(t,e)},function(t,e){ if ( "function" != typeof e&& null !==e) throw new TypeError( "Class extends value " +String(e)+ " is not a constructor or null" );function i(){ this .constructor=t}tt(t,e),t.prototype= null ===e?Object.create(e):(i.prototype=e.prototype, new i)}),rt=function(t){function e(i){ var r=t.call( this )|| this ; return i&&( "string" == typeof i?r.parseKey(i):(e.hasPrivateKeyProperty(i)||e.hasPublicKeyProperty(i))&&r.parsePropertiesFrom(i)),r} return it(e,t),e.prototype.parseKey=function(t){ try { var e=0,i=0,r=/^\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\s*)+$/.test(t)?function(t){ var e; if ( void 0===u){ var i= "0123456789ABCDEF" ,r= " \f\n\r\t \u2028\u2029" ; for (u={},e=0;e<16;++e)u[i.charAt(e)]=e; for (i=i.toLowerCase(),e=10;e<16;++e)u[i.charAt(e)]=e; for (e=0;e<r.length;++e)u[r.charAt(e)]=-1} var n=[],s=0,o=0; for (e=0;e<t.length;++e){ var h=t.charAt(e); if ( "=" ==h) break ; if (-1!=(h=u[h])){ if ( void 0===h) throw new Error( "Illegal character at offset " +e);s|=h,++o>=2?(n[n.length]=s,s=0,o=0):s<<=4}} if (o) throw new Error( "Hex encoding incomplete: 4 bits missing" ); return n}(t):g.unarmor(t),n=E.decode(r); if (3===n.sub.length&&(n=n.sub[2].sub[0]),9===n.sub.length){e=n.sub[1].getHexStringValue(), this .n=N(e,16),i=n.sub[2].getHexStringValue(), this .e=parseInt(i,16); var s=n.sub[3].getHexStringValue(); this .d=N(s,16); var o=n.sub[4].getHexStringValue(); this .p=N(o,16); var h=n.sub[5].getHexStringValue(); this .q=N(h,16); var a=n.sub[6].getHexStringValue(); this .dmp1=N(a,16); var c=n.sub[7].getHexStringValue(); this .dmq1=N(c,16); var f=n.sub[8].getHexStringValue(); this .coeff=N(f,16)} else { if (2!==n.sub.length) return !1; if (n.sub[0].sub){ var l=n.sub[1].sub[0];e=l.sub[0].getHexStringValue(), this .n=N(e,16),i=l.sub[1].getHexStringValue(), this .e=parseInt(i,16)} else e=n.sub[0].getHexStringValue(), this .n=N(e,16),i=n.sub[1].getHexStringValue(), this .e=parseInt(i,16)} return !0} catch (t){ return !1}},e.prototype.getPrivateBaseKey=function(){ var t={array:[ new W.asn1.DERInteger({ int :0}), new W.asn1.DERInteger({bigint: this .n}), new W.asn1.DERInteger({ int : this .e}), new W.asn1.DERInteger({bigint: this .d}), new W.asn1.DERInteger({bigint: this .p}), new W.asn1.DERInteger({bigint: this .q}), new W.asn1.DERInteger({bigint: this .dmp1}), new W.asn1.DERInteger({bigint: this .dmq1}), new W.asn1.DERInteger({bigint: this .coeff})]}; return new W.asn1.DERSequence(t).getEncodedHex()},e.prototype.getPrivateBaseKeyB64=function(){ return f( this .getPrivateBaseKey())},e.prototype.getPublicBaseKey=function(){ var t= new W.asn1.DERSequence({array:[ new W.asn1.DERObjectIdentifier({oid: "1.2.840.113549.1.1.1" }), new W.asn1.DERNull]}),e= new W.asn1.DERSequence({array:[ new W.asn1.DERInteger({bigint: this .n}), new W.asn1.DERInteger({ int : this .e})]}),i= new W.asn1.DERBitString({hex: "00" +e.getEncodedHex()}); return new W.asn1.DERSequence({array:[t,i]}).getEncodedHex()},e.prototype.getPublicBaseKeyB64=function(){ return f( this .getPublicBaseKey())},e.wordwrap=function(t,e){ if (!t) return t; var i= "(.{1," +(e=e||64)+ "})( +|$\n?)|(.{1," +e+ "})" ; return t.match(RegExp(i, "g" )). join ( "\n" )},e.prototype.getPrivateKey=function(){ var t= "-----BEGIN RSA PRIVATE KEY-----\n" ; return (t+=e.wordwrap( this .getPrivateBaseKeyB64())+ "\n" )+ "-----END RSA PRIVATE KEY-----" },e.prototype.getPublicKey=function(){ var t= "-----BEGIN PUBLIC KEY-----\n" ; return (t+=e.wordwrap( this .getPublicBaseKeyB64())+ "\n" )+ "-----END PUBLIC KEY-----" },e.hasPublicKeyProperty=function(t){ return (t=t||{}).hasOwnProperty( "n" )&&t.hasOwnProperty( "e" )},e.hasPrivateKeyProperty=function(t){ return (t=t||{}).hasOwnProperty( "n" )&&t.hasOwnProperty( "e" )&&t.hasOwnProperty( "d" )&&t.hasOwnProperty( "p" )&&t.hasOwnProperty( "q" )&&t.hasOwnProperty( "dmp1" )&&t.hasOwnProperty( "dmq1" )&&t.hasOwnProperty( "coeff" )},e.prototype.parsePropertiesFrom=function(t){ this .n=t.n, this .e=t.e,t.hasOwnProperty( "d" )&&( this .d=t.d, this .p=t.p, this .q=t.q, this .dmp1=t.dmp1, this .dmq1=t.dmq1, this .coeff=t.coeff)},e}(J),nt=i(155),st= void 0!==nt? null ===(et=nt.env)|| void 0===et? void 0: "3.3.1" : void 0; const ot=function(){function t(t){ void 0===t&&(t={}),t=t||{}, this .default_key_size=t.default_key_size?parseInt(t.default_key_size,10):1024, this .default_public_exponent=t.default_public_exponent|| "010001" , this .log=t.log||!1, this .key= null } return t.prototype.setKey=function(t){ this .log&& this .key&&console.warn( "A key was already set, overriding existing." ), this .key= new rt(t)},t.prototype.setPrivateKey=function(t){ this .setKey(t)},t.prototype.setPublicKey=function(t){ this .setKey(t)},t.prototype.decrypt=function(t){ try { return this .getKey().decrypt(l(t))} catch (t){ return !1}},t.prototype.encrypt=function(t){ try { return f( this .getKey().encrypt(t))} catch (t){ return !1}},t.prototype.sign=function(t,e,i){ try { return f( this .getKey().sign(t,e,i))} catch (t){ return !1}},t.prototype.verify=function(t,e,i){ try { return this .getKey().verify(t,l(e),i)} catch (t){ return !1}},t.prototype.getKey=function(t){ if (! this .key){ if ( this .key= new rt,t&& "[object Function]" ==={}.toString.call(t)) return void this .key.generateAsync( this .default_key_size, this .default_public_exponent,t); this .key.generate( this .default_key_size, this .default_public_exponent)} return this .key},t.prototype.getPrivateKey=function(){ return this .getKey().getPrivateKey()},t.prototype.getPrivateKeyB64=function(){ return this .getKey().getPrivateBaseKeyB64()},t.prototype.getPublicKey=function(){ return this .getKey(). getPublicKey()},t.prototype.getPublicKeyB64=function(){ return this .getKey().getPublicBaseKeyB64()},t.version=st,t}()})(),r. default })())); (2)封装 import JSEncrypt from 'jsencrypt/bin/jsencrypt.min' //密钥对生成 http://web.chacuo.net/netrsakeypair const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSKLqzcWmOzbfj64K8ZIgOdH\n' + 'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4jvbuccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' const privateKey = 'MIIBVAIBADANBgFAddddgggggAAkEAqhHyZfSsYourNxaY\n' + '7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' + 'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' + 'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' + 'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' + 'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' + 'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' + 'UP8iWi1Qw0Y=' //加密 export function encrypt(txt) { const encryptor = new JSEncrypt() encryptor.setPublicKey(publicKey) //设置公钥 return encryptor.encrypt(txt) //对数据进行加密 } //解密 export function decrypt(txt) { const encryptor = new JSEncrypt() encryptor.setPrivateKey(privateKey) //设置私钥 return encryptor.decrypt(txt) //对数据进行解密 } (3)使用 import { encrypt, decrypt } from "@/utils/jsencrypt" ; function handleLogin() { proxy.$refs.loginRef.validate((valid) => { if (valid) { loading.value = true ; //勾选了需要记住密码设置在 cookie 中设置记住用户名和密码 if (loginForm.value.rememberMe) { Cookies. set ( "username" , loginForm.value.name, { expires: 30 }); Cookies. set ( "password" , encrypt(loginForm.value.pwd), { expires: 30, }); Cookies. set ( "rememberMe" , loginForm.value.rememberMe, { expires: 30 }); } else { //否则移除 Cookies.remove( "username" ); Cookies.remove( "password" ); Cookies.remove( "rememberMe" ); } //调用action的登录方法 userStore .login(loginForm.value) .then(() => { router.push({ path: redirect.value || "/" }); }) . catch ((error) => { console.log(error) loading.value = false ; //重新获取验证码 }); } }); } 三、js编码与解码, 附、前后台数据交换, A、前端先把自己能收集到的数据格式“转化”为后台所需要的数据格式,然后发给后台 B、前端接到后台返回的数据格式后,先“转化”成前端能读取的数据格式,然后插到页面 1、基本概念,位->字节->字符->字符集 (1)bit,位,1个bit有2种状态,0或1,比特 (2) byte ,字节,1个字节由8个位构成 (3)字符,文字或符号,1个字符消耗1--2个字节,1个英文字符消耗1个字节,1个汉字字符消耗2个字节 (4)字符集,字符的集合,字符集的读取规则,内置于计算机,用户在html或img标签中指明使用哪种字符集,如ASCII、base64、Unicode、gb-2312 2、ASCII字符集,八位二进制,共256个字符,1967年第一次发表 (1)状态,1个二进制位2个状态、8个二进制位256个状态(从0000000到11111111) (2)字符,1个状态对应1个字符,256个状态对应256个字符,以0开始的128个状态对应128个英文字符,以1开始的128个状态对应128个非英文字符 (3)128个英文字符包含,33个控制字符或通信专用字符、64个base64字符、31个其它字符!"#$%&'()*,-.:;<=>?@[\]^_`{|}~空 (4)应用,这256个字符能够描述所有格式的数据,如文字、符号、图像、音频、视频 (5)ASCII定义,American Standard Code for Information Interchange,美国信息交换标准代码,是最通用的信息交换标准 3、base64字符集,六位二进制,共64个字符,1987年,第一次提及 (1)状态,1个二进制位2个状态、6个二进制位64个状态(从00000到111111) (2)字符,1个状态对应1个字符,64个状态对应64个字符, (3)64个字符包含,52个大小写字母、10个数字、1个+、1个/,另有第65个填充字符= (4)应用,这64个字符能够描述所有格式的数据,如文字、符号、图像、音频、视频 4、Unicode字符集,1990年开始研发,1994年正式发布1.0版本,2022年9月13日发布15.0版本 来源,https: //c.runoob.com/front-end/3602/ (1)该字符集的1个字符用1个编码对应,100多万个字符对应100多万个编码,可以容纳世界上所有的字符 (2)该字符集的编码规则有,UTF-8、UTF-16、UTF-32等嗯 (3)str.charCodeAt,获取字符的Unicode编码,是十进制数字 来源,https: //www.w3cschool.cn/typescript/typescript_string_charcodeat.html A、参数为字符串索引,如果参数不在0到字符串长度之间,返回NaN B、返回值字符的Unicode编码,是十进制数字,0到1114111(7位,百万级)之间,可以通过toString(n)转换为n进制 C、例如console.log( '中国' .charCodeAt(0));console.log( '中国' .charCodeAt(0).toString(16)) (4)String.fromCharCode,获取Unicode编码对应的字符, 来源,https: //www.runoob.com/jsref/jsref-fromcharcode.html A、参数,可以多个,每个都是Unicode编码,都是十进制数字,console.log(String.fromCharCode(104,101,108,108,111)) B、返回值为字符,可以多个 C、例如console.log(String.fromCharCode(20013));console.log(String.fromCharCode(parseInt( '4e2d' ,16)));M 5、window编码与解码--ASCII和base64之间的转换 注、URI,统一资源标识符 (1)window.atob,base64字符转换为ASCII字符 (2)window.btoa,ASCII字符转换为base64字符 (3)window.escape,将字符串转换为Unicode编码的字符串 (4)window.unescape,将escape编码的字符串恢复为原始字符串 (5)window.encodeURIComponent,将URI组件的字符串转换为UTF-8编码的字符串,如空格会被转换为%20 const data = { userId:123, username: "JohnDoe" , email: "john@example.com" }; const jsonData = JSON.stringify(data); const encodedData = encodeURIComponent(jsonData); const url = `https: //example.com?data=${encodedData}`; (6)window.decodeURIComponent,将encodeURIComponent编码的UTF-8字符串解码回原始的字符串形式 const encodedAndDecoded = () => { const data = { userId:123, username: "JohnDoe" }; const jsonData = JSON.stringify(data); const encodedData = encodeURIComponent(jsonData); const decodedData = decodeURIComponent(encodedData); console.log( jsonData ); console.log( encodedData ); console.log( decodedData ); } (7)btoa和atob编码和解码,以非中文示例 var encodedData = window.btoa(123456); //'MTIzNDU2' var decodedData = window.atob(encodedData); //'123456' (8)btoa和atob编码和解码,以中文示例 var encodedData = window.btoa(window.escape(window.encodeURIComponent( '你好' ))); //JTI1RTQlMjVCRCUyNUEwJTI1RTUlMjVBNSUyNUJE var decodedData = window.decodeURIComponent(window.unescape(window.atob(encodedData))); //你好 console.log( encodedData ); console.log( decodedData ); 6、常见的JS二进制“数据格式”之ArrayBuffer和Uint8Array(建立在ArrayBuffer上)数据的介绍 来源,https: //www.w3cschool.cn/qoyhx/qoyhx-8h5w3q7u.html 来源,https: //developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array (1) new ArrayBuffer(11),创建一个长度为11的buffer A、参数是一个数字 B、ArrayBuffer,二进制数组,对固定长度的连续内存空间的引用 (2) new Uint8Array(length),是存储二进制数据的 A、参数为1个数组,数组的每1项都是1个Unicode编码,1个汉字需要3个编码 B、字符-字节(数字) C、Uint8Array. from ,参数为(字符串,函数),返回值Uint8Array数组, 7、常见的JS二进制“数据格式”之Blob和File(继承了Blob)数据的介绍 来源,https: //www.w3cschool.cn/qoyhx/qoyhx-l63p3q7x.html (1)Blob,二进制大对象(binary large object ),1970年代出现,是一种数据格式 (2)File,继承了Blob (3)Blob和File数据读取方法 A、readAsArrayBuffer,读-取为二进制格式的ArrayBuffer B、readAsBinaryString,读-取为二进制字符串 C、readAsDataURL,读-取为base64的url,常用于img标签的src属性, D、readAsText,读-取为给定编码(默认为utf-8编码)的文本字符串, (4)Blob和File数据读取为文字 var reader = new FileReader(); reader.readAsText(thisBlob, 'utf8' ); //把后台的blob字符串转化为最初的文字 reader.onload = function() { console.log( '原文:' + this .result )We } (5)Blob和File数据本地读取为url-小文件 change(file) { const reader = new FileReader() //实例化文件读-取对象 reader.readAsDataURL(file.raw) //(将图片)作为数据URL读-取,即base64编码 reader.onload = ( event ) => { //文件读-取成功完成时触发 this .option.clientImg = event .target.result this .cutDialogVisible = true } } (6)Blob和File数据本地读取为url-大文件 change(file) { const URL = window.URL||window.webkitURL; this .option.clientImg = URL.createObjectURL(file.raw); this .cutDialogVisible = true ; } 8、数据格式互转 (1)原文与uint8Array互转,用到TextEncoder和TextDecoder function utf8ToUint8Array(text) { //以下,原文转uint8Array,将字符串编码为UTF-8字节序列,返回一个Uint8Array对象 var uint8Array = new TextEncoder().encode(text); //以下,uint8Array转原文,将二进制数据(如Uint8Array)解码为字符串,返回一个字符串 var text = new TextDecoder().decode(uint8Array); console.log(text); } var text1 = "Hello,你好!" ; utf8ToUint8Array(text1); (2)原文与base64互转 function fromTextToText1(text) { //正转换,base64<--(Unicode编码对应的ASCII)字符<--Uint8Array<--原文(text) var before = btoa(String.fromCharCode(... new TextEncoder().encode(text))); //反转换,原文<--Uint8Array<--(Unicode编码对应的ASCII)字符<--base64(before) var after = new TextDecoder().decode( Uint8Array. from (atob(before), function(item){ return item.charCodeAt(0) }) ) console.log(before, after); } var text1 = "Hello,你好!" ; fromTextToText1(text1); (3)原文与blob互转 function stringToBlob(str) { //以下,原文转blob const encoder = new TextEncoder(); const uint8Array = encoder.encode(str); const thisBlob = new Blob([uint8Array], { type: 'text/plain' }); console.log(thisBlob); //以下,blob转原文 var reader = new FileReader(); reader.readAsText(thisBlob, 'utf8' ); reader.onload = function() { console.log( '原文:' + this .result ) } } const myString = "Hello, Blob!" ; stringToBlob(myString); (4)base64与blob互转 function fromTextToText2(text) { //以下,生成base64 var base64Str = btoa(String.fromCharCode(... new TextEncoder().encode(text))) //以下,base64生成blob var atobStr = atob(base64Str); //1、把base64字符串转化为ASCII字符串 var length = atobStr.length; var uint8Array = new Uint8Array(length); //也可以写成new Array(length); while (length--) { uint8Array[length] = atobStr.charCodeAt(length); //2、把ASCII字符串转化为Unicode编码,存储在Uint8Array里 } var thisBlob = new Blob([uint8Array], { type: 'text/plain' }); //3、把ASCII字符串转化为blob字符串 //以下,blob生成base64 var reader = new FileReader(); reader.onload = function() { const base64String = reader.result.split( ',' ); console.log(uint8Array) console.log(thisBlob) console.log(base64String) }; reader.readAsDataURL(thisBlob); } var text2 = "Hello,你好2!" ; fromTextToText2(text2); (5)base64图片,转为,blob数据,发给后台 //流程,前端base64--ASCII--Unicode编码--Blob后台 function base64toBlob(data) { var array = data.split( ',' ) //将整个图片分成两个部分,第1部分是图片说明,第2部分是图片自身 var mime = array[0].match(/:(.*?);/)[1] //获取图片后缀 var image = array[1]; //获取图片自身 var atobStr = atob(image) //1、将“base64编码”的图片,转化为“ASCII编码”的图片 var length = atobStr.length var u8Array = new Uint8Array(length) while (length--) { u8Array[length] = atobStr.charCodeAt(length) //2、将ASCII编码的字符,转化为Unicode编码,并用Uint8Array存储 } const obj = new Blob([u8Array], { type: mime }) //3、将Unicode编码,转化为“Blob编码”,type指定blob的类型 //obj为一个新创建的Blob对象,其内容由参数中给定的数组拼接组成,上传到服务器 } 四、数据上传 来源,https: //blog.csdn.net/zyx042299/article/details/128008334 附1、label标签的 for 属性,与表单元素的id值绑定,点击label标签内的文本,就会触发绑定的表单元素 //来源,https://www.w3school.com.cn/tags/att_label_for.asp 显式的联系 <label for = "SSN" >身份证号码:</label> <input type= "text" name= "IdNum" id= "IN" /> 隐式的联系 <label>生日:<input type= "text" name= "DofB" /></label> 附2、通过 <input type= "file" onchange= "changeFile(value)" v-model= "value" /> 通过onchange事件或model属性获取要上传的(二进制)数据 1、数据上传-普通上传 (1)自动上传 <form name= "myForm" //new formData(document.forms["myForm"]).set('value', 'value') action= "demo_form.php" //提交表单时,服务器的接收地址 enctype= "multipart/form-data" //(1)application/x-www-form-urlencoded 在发送前编码所有字符(默认) //(2)multipart/form-data 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。 //(3)text/plain 空格转换为 "+" 加号,但不对特殊字符编码。 > <input name= "myInput" type= "text" /> //input标签的name属性需要与它的type属性同时使用, <input name= "inputFile" type= "file" /> //type的取值可以是text、password、radio、checkbox < select name= "mySelect" ></ select > //设置了name属性的表单元素,才能在提交表单时,自动传递它们的值 <input type= "submit" value= "默认提交" /> //点击就上传数据 </form> (2)手动上传 A、为空追加 <form> <input v-model= "value" type= "file" /> <input type= "button" value= "自定义提交" @click= "submitForm()" > </form> function submitForm() { var formData = new formData(); //先弄一个空的 formData. set ( 'value' , 'value' ); //用新值覆盖已有的值 formData.append( 'value' , 'value1' ); //把新值添加到已有值集合的后面 $.ajax({ url: '' , type: 'post' , data: formData, }); } B、非空追加 <form name= "myForm" > //document.forms["myForm"] <input name= "inputValue" type= "text" /> < select name= "mySelect" ></ select > <input name= "inputFile" type= "file" /> <input name= "protocolScript" type= "file" /> //这是angular1的相关内容 <input type= "button" value= "自定义提交" onclick= "submitForm()" > <input type= "button" value= "自定义提交" ng-click= "submitForm()" > </form> function submitForm() { var myForm = document.forms[ "myForm" ]; var formData= new formData(myForm); //格式化具有name属性的字段 formData. set ( 'value' , 'value' ); //用新值覆盖已有的值 formData.append( 'value' , 'value1' ); //把新值添加到已有值集合的后面 $.ajax({ url: '' , type: 'post' , data: formData, }); } C、angular1示例 <input name= "protocolScript" type= "file" //这是angular1的相关内容 onchange= "angular.element(this).scope().onChangeFile(this)" //原生事件,实参this是input上传的内容 on -change= "ngChangeFile(value)" //非原生事件,value为空 /> $scope.ngChangeFile = function (ele) { $scope.files_list = ele.files; $scope.$apply(); }; D、elementUI上传(PC端) <el-upload> <el-button icon= "plus" type= "primary" >上传文档</van-button> </el-upload> <el-upload drag action= "" accept= ".jpg,.png" :auto-upload= "false" :show-file-list= "false" v-model:file-list= "form.files" :limit= "1" :auto-upload= "false" : on -exceed= "handleExceed" : on -change= "handlChange" > <!-- UploadFilled是Icon图标中的“黑云白箭头”图标 --> <el-icon class = "el-icon--upload" ><upload-filled /></el-icon> <div class = "el-upload__text" > <p>点击或将文件拖拽到这里</p> <p>支持格式:json文件最大20MB</p> </div> </el-upload> on -change,文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用,通过onchange事件或model属性获取要上传的(二进制)数据 var handlChange = function(file, fileList) { this .fileList = fileList; } E、vantUI上传(移动端) <van-uploader accept= ".doc, .docx" accept= "*" :before-read= "uploadVideo" > <van-button icon= "plus" type= "primary" >上传文档</van-button> </van-uploader> before-read,文件读取(编码)前的回调函数,作用类似于onchange var uploadVideo = function(file, detail) { console.log( fileInfo.raw ); //首先根据文件的大小和后缀来判断,是否拦截上传并提出提示 } F、上传图片拦截判断失效的解决 <el-upload : on -change= "uploadChange" :before-upload= "beforeUpload" accept= ".jpg,.jpeg,.png" > <el-button icon= "plus" type= "primary" >上传证照</el-button> <span style= "color:gray;padding-left: 6px" >请上传jpg、jpeg、png格式图片</span> </el-upload> function beforeUpload(file){ //以下,拦截大文件 if (file.size > 20 * 1024 * 1024){ //非常有必要。条件成立,给出提示 ElMessage({ message: '上传文件大小不超过20M' , type: 'warning' , }) return false //连续点击,可能造成并发,导致此处“拦截失效”,执行uploadChange } } function uploadChange(file){ //以下,继续拦截大文件 if (file.size > 20 * 1024 * 1024) return //非常有必要。可以解决beforeUpload“拦截失效”的问题 //以下,拦截文件类型,在beforeUpload里拦截会失败,只能在这里拦截 const regex = /\.(jpg|jpeg|png)$/i; //仅匹配.jpg,.jpeg,.png及其大小写类型的图片 if (regex.test(file.name)) { isShowRedText.value = false ; } else { //正则匹配失败,拦截图片上传并给出提示 return isShowRedText.value = true ; } //以下,上传图片 isUploading.value = true ; uploadFileTool(file, 'license' ).then(res => { uploadForm.imageUrl = res.data.fullUrl; uploadName.value = file.name; uploadFormRef.value.validateField( 'imageUrl' ); isUploading.value = false ; }) } function uploadFileTool(file, type){ const formData = new FormData(); formData.append( 'objectType' ,type) formData.append( 'file' ,file.raw) return uploadFile(formData) } function uploadFile(data){ return request({ url: baseUrl+ 'fileInfo/upload' , method: 'post' , data }) } 2、数据上传-单图片先裁切后上传(读取文件为图片-裁切裁剪图片-获取裁后图片-上传) 来源,http: //www.zzvips.com/article/212420.html 来源,https: //blog.csdn.net/qq_45886894/article/details/129486002 (1)读取文件为图片 A、readAsDataURL本地读取,适用于小文件 change(file) { const reader = new FileReader() //实例化文件读-取对象 reader.readAsDataURL(file.raw) //(将图片)作为数据URL读-取,即base64编码 reader.onload = ( event ) => { //文件读-取成功完成时触发 this .option.clientImg = event .target.result this .cutDialogVisible = true } } B、createObjectURL本地读取,适用于大文件 change(file) { const URL = window.URL||window.webkitURL; this .option.clientImg = URL.createObjectURL(file.raw); this .cutDialogVisible = true ; } (2)裁切裁剪图片 A、依赖 "dependencies" : { "vue-cropperjs" : "^4.2.0" , }, B、使用 <template> <div> <el-upload action= "" accept= ".jpg,.png" class = "poster-uploader" :auto-upload= "false" :show-file-list= "false" : on -success= "handleAvatarSuccess" :before-upload= "beforeAvatarUpload" : on -change= "uploadChange" > <img v- if = "isShow" :src= "serverImg" class = "poster" /> <i v- else class = "el-icon-plus poster-uploader-icon" ></i> </el-upload> <el-dialog title= "裁切/裁剪" :append-to-body= 'true' :visible.sync= "cutDialogVisible" width= "800px" > <div class = "cropper-content" > <div class = "cropper" style= "text-align: center" > <vueCropper ref = "cropper" :img= "option.clientImg" /> </div> <div v- if = "previews.div" class = "show-preview" > <div :style="{ width: previews.div.width, height: previews.div.height, transformOrigin: '0 0' , transform: 'scale(' + 150 / previews.w + ')' , overflow: 'hidden' , }" > <img :src= "previews.url" :style= "previews.img" > </div> </div> </div> <div slot= "footer" class = "poster-uploader-footer dialog-footer" > <div class = "upload-form-cropper" > <el-button size= "mini" @click= "cutDialogVisible = false" >取 消</el-button> <el-button type= "primary" size= "mini" @click= "cutImg" >确认</el-button> </div> </div> </el-dialog> </div> </template> (3)获取裁后图片 cutImg() { this .$refs.cropper.getCropData((data) => { //getCropData,data,获取图片的base64数据 //getCropBlob,data,获取图片的blob数据。???为什么不用这个函数,直接获取blob数据呢??? var array = data.split( ',' ) var mime = array[0].match(/:(.*?);/)[1] var image = array[1]; var atobStr = atob(image); var length = atobStr.length var u8Array = new Uint8Array(length) while (length--) { u8Array[length] = atobStr.charCodeAt(length) } const obj = new Blob([u8Array], { type: mime }) }) } 3、数据上传-多文件上传,批量,列表 (1)多张图片或多个视频的上传逻辑, A、读出一张图片的信息并上传至服务器,在列表中展示图片信息和上传进度,最后获取存放地址 B、重复A步骤 C、最后提交时,把所有存放地址传给服务器 (2)示例,online- class -manage //getDuration,在本地获取视频的封面图片,然后上传至服务器,最后更新到列表中 //handelUploadFile,上传视频,获取上传进度,更新到列表中 <template> <div class = "content-container" > <el-breadcrumb separator= "/" > <el-breadcrumb-item>课程管理</el-breadcrumb-item> <el-breadcrumb-item>内容管理</el-breadcrumb-item> </el-breadcrumb> <div class = "content-table" > <div class = "content-table-header" > <div class = "content-table-header_title" >上传视频</div> </div> <div class = "form-wrap" > <el-form :model= "ruleForm" :rules= "rules" ref = "ruleForm" label-width= "100px" class = "demo-ruleForm" > <el-form-item label= "上传文件" prop= "mediaUrl" > <div : class ="[ 'uploadHeader' , mediaName === '' ? 'baseLine' : 'centerLine' , ]" > <el-upload class = "upload-video" action= "" multiple accept= "video/*" :limit= "10" :disabled= "isDisabled" :file-list= "fileList" : on -change= "mediaUpload" :show-file-list= "false" :auto-upload= "false" > <el-button size= "small" type= "primary" :disabled= "isDisabled" plain > <i class = "el-icon-upload2" ></i>选择文件 </el-button> </el-upload> </div> </el-form-item> <el-form-item label= "" prop= "" > <el-table :data= "tableData" style= "width: 100%" > <el-table-column label= "封面图" width= "120" prop= "coverImgUrl" > <template slot-scope= "scope" > <img v- if = "scope.row.coverImgUrl" :src= "scope.row.coverImgUrl" alt= "" width= "100" height= "56" /> <span v- else >上传后显示</span> </template> </el-table-column> <el-table-column prop= "oldTitle" label= "文件名称" width= "180" > </el-table-column> <el-table-column label= "视频大小" width= "90" > <template slot-scope= "scope" > {{ scope.row.size }}MB </template> </el-table-column> <el-table-column label= "视频名称" width= "200" > <template slot-scope= "scope" > <el-input v-model= "scope.row.title" size= "mini" style= "width: 100%" ></el-input> </template> </el-table-column> <el-table-column label= "上传进度" width= "80" > <template slot-scope= "scope" > <el-progress v- if = "scope.row.uploadPercent" type= "circle" :width= "56" :percentage= "scope.row.uploadPercent" ></el-progress> <div class = "uploadStatus" > <span v- if = "scope.row.uploadStatus === 1" >上传中</span> <span v- if = "scope.row.uploadStatus === 2" >上传完成</span> <span v- if = "scope.row.uploadStatus === 3" style= "color: #d54949" >上传失败</span> </div> </template> </el-table-column> <el-table-column label= "操作" width= "140" > <template slot-scope= "scope" > <change-img :size= "3" @getUrl= "getImgUrl" :uid= "scope.row.uid" ></change-img> <el-button type= "text" size= "small" @click= "delItem(scope.row.uid)" >删除</el-button> </template> </el-table-column> </el-table> </el-form-item> <el-form-item label= "选择课程合集" prop= "collectionId" > <el- select v-model= "ruleForm.collectionId" placeholder= "请所属课程合" > <el-option :label= "item.title" :value= "item.sid" v- for = "item in collectionList" :key= "item.sid" ></el-option> </el- select > </el-form-item> <el-form-item> <el-button type= "primary" @click= "submitForm('ruleForm')" >保存</el-button > <el-button @click= "toContent" >返回</el-button> </el-form-item> </el-form> </div> </div> </div> </template> <script> const COS = require( "cos-js-sdk-v5" ); const TcVod = require( "vod-js-sdk-v6" ); //腾讯 import { getCosImg } from "@/api/upload.js" ; import { getCollectionList,createCourse } from "@/api/course" ; import ChangeImg from "@/components/upload/changeImg" export default { components: { ChangeImg }, data() { return { isDisabled: false , COS: {}, collectionList: [], fileList: [], tableData: [ ], ruleForm: { collectionId: '' }, rules: { }, videoType: [ "mp4" , "mov" , "avi" ], uploadPercent: 0, //上传进度 progressFlag: false , mediaName: "" , //文件名 changeCoveimg: false , changeIndex: 0, coverimgTime: [], isVideo: false , totalTime: "" , ruleFromt: {}, changeLoading: "" , loading: "" , type: 0, //类型:0=视频;1=音频 }; }, created() { this .getCollectionList(); this .initCOS() }, mounted() {}, methods: { initCOS() { getCosImg().then((res) => { /* eslint-disable */ this .COS = new COS({ getAuthorization: (options, callback) => { var credentials = res.data && res.data.credentials; if (!res || !credentials) return console.error( "credentials invalid" ); callback({ TmpSecretId: credentials.tmpSecretId, TmpSecretKey: credentials.tmpSecretKey, XCosSecurityToken: credentials.sessionToken, // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误 StartTime: res.data.startTime, // 时间戳,单位秒,如:1580000000 ExpiredTime: res.data.expiredTime, // 时间戳,单位秒,如:1580000900 // ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用 }); }, }); }); }, getImgUrl(data){ this .tableData = this .tableData.map((item)=>{ if (item.uid === data.uid){ item.coverImgUrl = data.url } return item }) }, mediaUpload(fileInfo) { if (fileInfo.status !== "ready" ) return ; //如果标题为空,将上传的文件名作为标题 let fileType = fileInfo.name .substring(fileInfo.name.lastIndexOf( "." ) + 1) .toLowerCase(); if (! this .videoType.includes(fileType)) { this .$message({ type: "warning" , message: `不支持上传${fileType}格式文件!`, }); this .fileList = []; return false ; } let fileSize = 500; let sizeBlen = fileInfo.size / 1024 / 1024 < fileSize; if (!sizeBlen) { this .$message({ type: "warning" , message: `上传文件大小不能超过 ${fileSize}MB!`, }); this .fileList = []; return false ; } let itemObj = {} itemObj.uid = fileInfo.uid itemObj.type = 0 itemObj.coverImgUrl = '' itemObj.collectionId = '' itemObj.url = '' itemObj.duration = '' itemObj.oldTitle = fileInfo.name itemObj.size = (fileInfo.size / 1024 / 1024).toFixed(2) itemObj.title = fileInfo.name.substring(0,fileInfo.name.lastIndexOf( "." )-1) itemObj.uploadPercent = 0 itemObj.uploadStatus = 0 this .tableData.push(itemObj) //增加表格数据 //发送请求 this .getDuration(fileInfo) //生成缩略图并上传 this .handelUploadFile(fileInfo) //上传文件并监控进度 }, getDuration(fileInfo){ this .asyncImgChecked(fileInfo).then(res=>{ //生成缩略图 this .tableData = this .tableData.map((item)=>{ if (item.uid === fileInfo.uid){ item.duration = String(res.duration) this .handelUploadImg(fileInfo, this .dataURLtoBlob(res.imgSrc)) //上传缩略图 } return item }) }) }, handelUploadFile(fileInfo){ let fileType = fileInfo.name let fileUrl = `zxkt/video/${ new Date().getTime()}-${fileInfo.uid}.${fileType}`; this .COS.sliceUploadFile( //切片 { Bucket: "sharepool-1257784922" /* 必须 */ , Region: "ap-beijing" /* 存储桶所在地域,必须字段 */ , Key: fileUrl /* 必须 */ , StorageClass: "STANDARD" , Body: fileInfo.raw, // 上传文件对象 onProgress: (progressData) => { this .tableData = this .tableData.map((item)=>{ if (item.uid === fileInfo.uid){ item.uploadStatus = 1 item.uploadPercent = Math.round(progressData.percent * 100); } return item }) }, }, (err, data) => { if (!err) { this .COS.getObjectUrl( { // 获取文件访问地址 Method: "PUT" , Key: fileUrl, Bucket: "sharepool-1257784922" , Region: "ap-beijing" , Sign: false , }, (err, data) => { let res = err || data; this .tableData = this .tableData.map((item)=>{ if (item.uid === fileInfo.uid){ item.uploadStatus = 2 item.url = "https://sharepool-1257784922.cos.ap-beijing.myqcloud.com/" + fileUrl; } return item }) //this.fileUrl = res.Url.split("?")[0]; } ); } else { this .tableData = this .tableData.map((item)=>{ if (item.uid === fileInfo.uid){ item.uploadStatus = 3 } return item }) } } ); }, /* 来源,https://cloud.tencent.com/developer/ask/260695 //以下,用插件vod-js-sdk-v6上传视频时,发生了异常 1、报错 “Error: ugc upload | signature verify forbidden”, 2、原因, 你向后台索要签名,后台用小权限“腾讯账户”向腾-讯索要签名, 腾-讯给后台小权限签名,后台给你小权限签名,你将小权限签名发给腾-讯,腾-讯给你报错 3、解决办法, 让后台换用大权限“腾-讯账户” */ //上传插件说明, //向远方发送请求,远方将上传路由放到cookie里 //本地隐式从cookie获取上传路由,用ajax-promise上传“数据” //以下用插件vod-js-sdk-v6上传(多次获取签名) handelUploadFile(fileInfo){ const getSignature = function(){ return request({ url: 'https://media-t.app.gstv.cn/zxkt-platform-server/api/vod/getSign' , method: 'get' , }).then(function(response){ return response.data }) } const tcVod = new TcVod. default ({ getSignature: getSignature, }) const uploader = tcVod.upload({ mediaFile: fileInfo.raw, }) uploader. on ( 'media_progress' , (info) => { //切片 this .tableData = this .tableData.map((item)=>{ if (item.uid === fileInfo.uid){ item.uploadStatus = 1 item.uploadPercent = Math.round(info.percent * 100); } return item }) }) uploader.done().then((doneResult) => { this .tableData = this .tableData.map((item)=>{ if (item.uid === fileInfo.uid){ item.url = doneResult.video.url item.fileId = doneResult.fileId } return item }) }). catch (function (err) { console.log( err ); }) }, //以下用插件vod-js-sdk-v6上传(1次获取签名) handelUploadFile(fileInfo){ request({ url: 'https://media-t.app.gstv.cn/zxkt-platform-server/api/vod/getSign' , method: 'get' , }).then((response) =>{ const tcVod = new TcVod. default ({ getSignature: function(){ return response.data } }) const uploader = tcVod.upload({ mediaFile: fileInfo.raw, }) uploader. on ( 'media_progress' , (info) => { //切片 this .tableData = this .tableData.map((item)=>{ if (item.uid === fileInfo.uid){ item.uploadStatus = 1 item.uploadPercent = Math.round(info.percent * 100); } return item }) }) uploader.done().then((doneResult) => { this .tableData = this .tableData.map((item)=>{ if (item.uid === fileInfo.uid){ item.url = doneResult.video.url item.fileId = doneResult.fileId } return item }) }). catch (function (err) { console.log( err ); }) }) }, //以上,用插件vod-js-sdk-v6上传视频时,发生了异常 handelUploadImg(fileInfo,blob){ let fileType = fileInfo.name let fileUrl = `zxkt/img/${ new Date().getTime()}-${fileInfo.uid}.${fileType}.png`; this .COS.sliceUploadFile( { Bucket: "sharepool-1257784922" /* 必须 */ , Region: "ap-beijing" /* 存储桶所在地域,必须字段 */ , Key: fileUrl /* 必须 */ , StorageClass: "STANDARD" , Body: blob, // 上传文件对象 }, (err, data) => { if (!err) { this .COS.getObjectUrl( { // 获取文件访问地址 Method: "PUT" , Key: fileUrl, Bucket: "sharepool-1257784922" , Region: "ap-beijing" , Sign: false , }, (err, data) => { let res = err || data; this .tableData = this .tableData.map((item)=>{ if (item.uid === fileInfo.uid){ item.coverImgUrl = "https://sharepool-1257784922.cos.ap-beijing.myqcloud.com/" + fileUrl; } return item }) } ); } } ); }, //base64Url转bolob dataURLtoBlob(dataurl){ var arr = dataurl.split( ',' ); var mime = arr[0].match(/:(.*?);/)[1]; var bstr = atob(arr[1]); var n = bstr.length; var u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); }, // 以下是改进代码,与原代码等效 // 获取视频标题+时长+缩略图+宽高 asyncImgChecked(file) { return new Promise((resolve, reject) => { URL.createObjectURL(file.raw); //let reader = new FileReader(); //reader.readAsDataURL(file.raw); // 必须用file.raw,本地读取小文件 //reader.onload = (e)=> { // 让页面中的img标签的src指向读取的路径 let video = document.createElement( 'video' ); let canvas = document.createElement( 'canvas' ); //<canvas>是图形容器,没有绘图能力,用户需用脚本绘图 let ctx = canvas.getContext( '2d' ); //ctx提供了在画布上绘图的方法和属性 let imgSrc; video.src = URL.createObjectURL(file.raw); //=======1/3,将视频数据渲染到video标签,本地读取大文件 video.currentTime = 3; //设置视频的当前播放位置(为第3秒),可用于实现“===视频抽帧===”的功能 video.setAttribute( 'width' , 100); video.setAttribute( 'height' , 100); canvas.setAttribute( "width" ,100); canvas.setAttribute( "height" ,100); video.oncanplay = ()=>{ //在视频/音频可以播放时触发 ctx.drawImage(video, 0, 0, video.width, video.height); //=======2/3,将video的第3秒绘制到canvas里 // drawImage(image, x, y, width, height)方法用于在canvas上下文中绘制图像 // image:要绘制的图像源。这可以是一个 // HTMLImageElement(例如通过new Image()创建并加载后的图像对象) // HTMLCanvasElement(另一个canvas元素) // HTMLVideoElement(视频元素) // x和y:图像在画布上的起始坐标,坐标原点(0,0)位于canvas的左上角 // width和height:用于指定绘制图像的宽度和高度,可选 // 如果不提供,图像将以其原始大小进行绘制;如果提供,可以对图像进行缩放,假如, // 图像的宽高为(3840 2160),正好铺满标签样式(class、style)的宽高,<canvas style="width:400px;height:400px"></canvas> // 设置为(1920,1080),图像的宽高将缩小为原来的一半绘制在canvas标签里,标签里将会有3/4的空间是空白 // 设置为(7680,4320),图像的宽高将放大为原来的二倍绘制在canvas标签里,图像将会有3/4的面积隐藏在标签外 // 图像的宽高绘制在标签样式的宽高上,图像的宽高导致,标签属性的宽高失效,<canvas width=400 height=400></canvas> // 图像的宽高、标签属性的宽高、标签样式的宽高 imgSrc = canvas.toDataURL( 'image/png' ); //=======3/3,将canvas转化为base64图片 resolve({ duration:parseInt(video.duration), //得到整数的视频时长 imgSrc:imgSrc, //base64的缩略图图片路径 width:video.videoWidth, height:video.videoHeight, videoName:file.name }) URL.revokeObjectURL(video.src); //释放一个之前已经存在的、通过调用URL.createObjectURL()创建的URL对象 } //}; }) }, // 以下是原代码 /* // 获取视频标题+时长+缩略图+宽高 asyncImgChecked(file) { return new Promise((resolve, reject) => { URL.createObjectURL(file.raw); //let reader = new FileReader(); //reader.readAsDataURL(file.raw); // 必须用file.raw //reader.onload = (e)=> { // 让页面中的img标签的src指向读取的路径 let video = document.createElement('video'); video.src = URL.createObjectURL(file.raw); video.currentTime = 3; //截取缩略图时的视频时长,一定要设置,不然大概率白屏 video.oncanplay = ()=>{ const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.setAttribute("width",100); canvas.setAttribute("height",100); video.setAttribute('width', 100); video.setAttribute('height', 100); ctx.drawImage(video, 0, 0, video.width, video.height); const imgSrc = canvas.toDataURL('image/png'); resolve({ duration:parseInt(video.duration),//得到整数的视频时长 imgSrc,//base64的缩略图图片路径 width:video.videoWidth, height:video.videoHeight, videoName:file.name }) URL.revokeObjectURL(video.src); } //}; }) }, */ delItem(uid){ this .tableData = this .tableData.filter((item)=>{ return item.uid !== uid }) }, openHadle(url) { window.open(url); }, getCollectionList(url) { getCollectionList().then((res) => { if (res.code === 200) { this .collectionList = res.data; } }); }, toContent() { this .$router.push( "/course/content" ); }, handleExceed(files, fileList) { this .$message.warning( `当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${ files.length + fileList.length } 个文件` ); }, submitForm(formName) { this .$refs[formName].validate((valid) => { if (valid) { this .handleSubmit() } else { console.log( "error submit!!" ); return false ; } }); }, handleSubmit(){ if ( this .tableData && this .tableData.length > 0) { let flag = true this .tableData.forEach((ele)=>{ if (!ele.title) { this .$message.error( '请填写标题!' ) flag = false return } if (!ele.url) { this .$message.error( '请上传视频!' ) flag = false return } if ( this .ruleForm.collectionId) { ele.collectionId = this .ruleForm.collectionId } }) if (!flag) { return } createCourse( this .tableData).then((res) => { if (res.data > 0 ) { this .$message.success( '视频上传成功!' ) this .toContent() } }); } else { this .$message.error( '请先上传视频!' ) } } }, }; </script> <style scoped lang= "scss" > </style> 4、数据上传-大文件分片上传,带上传进度,切片 (1)webuploader.js,PC端,分片上传,带上传进度 //在上传本地完成后,此插件自动获取、切片数据并根据配置上传至服务器并监听上传过程 <script src= "./common/webuploader.js" ></script> <style> #updataButton input[type="file"] { display: none; } </style> $scope.up_file = function () { var files; var task_id = WebUploader.Base.guid(); var uploader = WebUploader.create({ server: './system/devinfo/upload' , pick: '#updataButton' , //webuploader.js插件给此元素内添加了<input type="file"/>,点击此元素手动出现上传弹窗,点击内部的input直接出现上传弹窗 auto: false , //需要手动上传 chunked: true , //需要分片 chunkSize: 20 * 1024 * 1024, //每片大小 chunkRetry: 3, //如果某个分片由于网络问题出错,允许自动重传3次 threads: 1, //允许同时最大上传进程数为1 duplicate: true , //需要去重 formData: { //文件上传请求的参数表,每次发送都会发送此对象中的参数 task_id: task_id, }, headers: { business_resource: 156 }, fileVal: 'rule' //设置文件上传域的name }); uploader. on ( 'fileQueued' , function (file) { $scope.file_.file = file; //交互一:列队完成,告知后台,准备接收数据 auditApi .query({ method: 'get' , root: 'set' , url: '/maintain/verify_file' , data: { filename: file.name } }) .then(function () { $scope.file_.uploader.upload(); //交互二:开始上传到server配置指向的服务器 }) . catch (function () { $scope.file_.uploader.removeFile($scope.file_.file); }); }). on ( 'fileDequeued' , function () { //console.log('remove queue success.'); }). on ( 'startUpload' , function () { $scope.updata(); //无前后台交互,出现弹窗,告知正在上传 }). on ( 'uploadProgress' , function (file, percentage) { //上传中,出现进度条,无前后台交互,插件自己计算进度的百分比 }). on ( 'uploadSuccess' , function (file) { //交互三、告知后台,数据发送完毕 auditApi .query({ method: 'get' , root: 'set' , url: '/maintain/complete' , params : { task_id: task_id, filename: file.source[ 'name' ] }, timeout: 1000 * 60 * 3 }) .then(function () { $scope.updating(); //交互四、定时询问后台,是否更新完毕 }) }). on ( 'uploadError' , function () { //上传出错 }); } $scope.up_file(); //说明, //A、页面初始化时执行$scope.up_file(); //B、根据pick配置,找到“升级”按钮,并初始化 //C、点击“升级”后,插件调出window系统自身的弹窗,用户选中文件,点击确定,开始上传至初始化时的服务器,依次执行监听函数 (2)ali-oss,移动端,分片上传,内含上传进度的功能,videoUploadPercent, A、依赖,来源,https: //help.aliyun.com/document_detail/383952.html ali-oss,阿里OSS存储,开放存储服务(open storage service,OSS),另见“腾讯” "dependencies" : { "ali-oss" : "^6.16.0" }, B、html <van-form @submit= "beforeSubmit" ref = "form" > <template v- for = "(item,idx) in formList" > <div class = "sign-form" :key= "idx" v- if = "item.inputType == 5" > <div class = "van-form_card" > <div class = "field__label" >{{item.topicName}}</div> <div class = "field__desc" >支持扩展名:avi、MP4、rmvb</div> </div> <van-field name= "name" type= "hidden" :rules= "[{ validator: valiFormData, message: '请输入正确内容',index:idx }]" v-model= "formData[idx]" > <template #input > <div class = "flex-col" > <div class = "video-upload" v- if = "showUpload" > <span>视频上传中...</span> <van-progress :show-pivot= "false" :percentage= "videoUploadPercent" /> </div> <span class = "link" v- if = "formData[idx]" @click= "href(idx)" >{{videoName[idx]}}</span> <van-uploader accept= "*" v- if = "!showUpload" :name= "idx" :before-read= "uploadVideo" > <van-button icon= "plus" type= "primary" >上传视频</van-button> </van-uploader> </div> </template> </van-field> </div> </template> <div class = "vt-foot " > <van-button native-type= "submit" :disabled= "!promise" :loading= "loading" loading-text= "保存中..." block color= "#fdb235" >提交</van-button> </div> </van-form> C、js import OSS from "ali-oss" ; uploadVideo(file,detail){ //file,二进制数据 let type = file.name.substring(file.name.lastIndexOf( "." ) + 1).toLowerCase() if ( this .videoType.indexOf(type) < 0 || file.type.indexOf( "video" ) < 0){ this .$dialog.alert({ title: '提示' , message: '仅支持 .avi, .mp4, .rmvb, .mov 格式的视频' , theme: 'round-button' , }); return ; } let max = 1024*1024*1024; if (file.size > max){ this .$dialog.alert({ title: '提示' , message: '上传视频大小不能超过 1G!' , theme: 'round-button' , }).then(() => {}); return ; } getALiYunOSSToken({ //交互一:告知后台,准备接收数据 tokenName: "ios" , }).then(data=>{ //后台同意后,给出同意参数 let oss = new OSS({ //前端根据同意参数new出传输实例 region: "oss-cn-beijing" , accessKeyId: data.data.data.accessKeyId, accessKeySecret: data.data.data.accessKeySecret, bucket: data.data.data.bucketName, stsToken: data.data.data.securityToken, }); const suffix = file.name.substr(file.name.indexOf( "." )); let fileUrl = `test/${ new Date().getTime()}${suffix}`; oss.multipartUpload( //交互二:开始上传到fileUrl指向的服务器。不用告知后台,数据发送完毕;不用向后台询问,是否更新完毕 fileUrl, //文件在服务器的存储位置 file, //文件自身 { progress: (p) => { //配置上传进度 this .videoUploadPercent = Math.round(p * 100); this .showUpload = true ; }, partSize: 1024*100, //切片大小 } ) .then((res) => { this .showUpload = false ; this .videoName[detail.name] = res.name; let url = res.res.requestUrls[0]; this .formData[detail.name] = url.substring(0,url.indexOf( "?" )); let temp = this .formData[detail.name]; this .formData.splice(detail.name,1,temp); }) . catch ((err) => { this .showUpload = false ; console.log(err); this .$dialog.alert({ title: '提示' , message: '上传失败' , theme: 'round-button' , }) }); }) }, const getALiYunOSSToken=( params )=>{ return axios.request({ url: "https://mpapi.app.cctv.com/comm/file/getALiYunOSSToken" , params , method: 'get' }) } beforeSubmit(){ if ( this .loading){ return ; } this .loading = true ; this .onSubmit(); }, onSubmit(){ this .$ajaxPost(url,data).then(res=>{}) }, (3)腾讯cos-js-sdk-v5,PC端,分片上传,带上传进度 A、cctv-chose定义 <template> <el-upload action= "" :auto-upload= "false" :accept= "accept" :show-file-list= "false" : on -change= "upload" :http-request= "up" ref = "upload" > <div class = "cctv-chose" > <span class = "cctv-chose-add" >+</span> <div class = "cctv-chose-footer" v- if = "false" > <svg-icon icon- class = "upload" class -name= "cctv-chose-upload" /> <i></i> <svg-icon icon- class = "su" @click= "selectSource" class -name= "cctv-chose-su" /> </div> </div> </el-upload> </template> methods: { upload(fileInfo) { this .COS.putObject( //切片 { Bucket: "gongweiedu-1257784922" , // 必须 Region: "ap-beijing" , // 必须,存储桶所在地域 Key: fileInfo.fileUrl, // 必须 StorageClass: "STANDARD" , Body: fileInfo.raw, // 上传文件对象 onProgress: (progressData) => { // 此处配置上传进度 let percent = Math.round(progressData.percent * 100) this .$emit( 'pro' ,progressData) this .$emit( 'progress' ,percent) //告诉父级上传进度 } }, (err, data) => { if (!err) { cosObject.getObjectUrl( { // 获取文件访问地址 Method: "PUT" , Key: fileInfo.fileUrl, Bucket: "gongweiedu-1257784922" , Region: "ap-beijing" , Sign: false }, (err, data) => { if (err){ console.log( err ); } else { console.log( data.Url ); this .$emit( 'backUrl' , data.Url) } // data.Url = data.Url } ) } else { console.log( err ); } } ) }, }, B、cctv-chose调用,上传多张图片,带列表展示 <el-form-item label= "上传图片" prop= "image" class = "dynamic-form-image" > <div class = "dynamic-warp" > <div class = "dynamic-img" v- for = "(item,index) in dynamicForm.images" :key= "index" > <img :src= "item|parseUrl" > <i class = "el-icon-error" @click= "remove(index)" /> </div> <CctvChose :limit= "5" v- if = "dynamicForm.images && dynamicForm.images.length<15" @backUrl= "catchUrl" class = "dynamic-chose" @selectSource= "showDynamic" /> </div> <div class = "dynamic-tip" >图片格式bmp、png、webp、jpeg,图片大小5MB以内</div> </el-form-item> C、cctv-chose调用,上传单个视频,带进度条 <div class = "produce-form-header" > <div v-show= "!fileInfo" > <CctvChose class = "produce-chose" @selectFile= "selectFile" @selectSource= "selectSource" :limit= "800" @backUrl= "setUrl" @progress= "changePercent" @pro= "getProgressData" :type= "1" ></CctvChose> <div class = "produce-tip" >请添加文件上传 支持MP4、MOV格式</div> </div> <div class = "produce-form-info" v- if = "fileInfo" > <div class = "produce-form-info-title" > {{ fileInfo.name }} </div> <div class = "produce-form-delete" v- if = "percent==100" > <el-button type= "text" @click= "reUpload" >删除</el-button> </div> </div> <div v- if = "fileInfo" > <el-progress //使用上传进度 class = "produce-form-progress-bar" :percentage= "percent" :show-text= "false" :stroke-width= "26" /> </div> </div> methods: { changePercent(per) { this .percent = per; //父级接收上传进度 if ( this .percent==100){ this .loading = false ; this .$refs.audioForm.form.videoTitle = this .fileInfo.name.split( '.' )[0].slice(0,40); } else { this .loading = true } }, }, //数据上传-结束 五、数据下载 1、数据下载-a元素下载 (1)直接下载 <a href= "https://cdn.shopify.com/s/Manaul.pdf" download= "test.pdf" >下载</a> (2)后台返回数据url function down(url) { var a = document.createElement( 'a' ); //document.body.appendChild(a); a.href = url; a.download = '111.pdf' ; a.click(); //a.remove(); }; (3)后台返回数据自身 function down(data) { var a = document.createElement( 'a' ); //document.body.appendChild(a); a.href = URL.createObjectURL(data); a.download = '111.txt' ; a.click(); //a.remove(); }; (4)后台返回数据非Blob function down(data) { var blob = new Blob(data) //data.blob() var a = document.createElement( 'a' ) a.href = window.URL.createObjectURL(blob) a.download = 'file.docx' //a.download = 'file.json' a.click() }; (5)后台返回数据Blob var download = (res) => { let filename = decodeURIComponent(res.headers[key]) var url = window.URL.createObjectURL(res.data); var a = document.createElement( 'a' ); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); } (5)将后台返回的图片下载(含图片数据展示) A、html <div class = "content" v- for = "(item, index) in dataInfo.info" > <div class = "bottom" > <div class = "label" >证照:</div> <div class = "describe" > <el-image style= "height: 100px" :src= "http+item.imageUrl" fit= "cover" /> <div> <el-button type= "primary" link @click= "item.isShow = true" >预览证照</el-button> <el-button type= "primary" link @click= "downImg(item)" >下载证照</el-button> </div> </div> </div> <el-dialog v-model= "item.isShow" :show-close= "false" > <template #title> <div class = "position-fixed" > <div class = "padding" >广播电视频道许可证-{{ item.channelName }}</div> <div> <el-button type= "primary" @click= "downImg(item)" >下载</el-button> <el-button @click= "item.isShow = false" >关闭</el-button> </div> </div> </template> <el-image style= "height: 100%" :src= "http+item.imageUrl" fit= "cover" /> </el-dialog> </div> B、js const http = import.meta.env.VITE_APP_BASE_API ; //previewImg function downImg(item) { //下载后,不预览图片 var url_ = http+item.imageUrl; const image = new Image(); image.onload = function () { const canvas = document.createElement( 'canvas' ); canvas.width = image.width; canvas.height = image.height; const context = canvas.getContext( '2d' ); context.drawImage(image, 0, 0, image.width, image.height); const url = canvas.toDataURL( 'image/png' ); const a = document.createElement( 'a' ); const event = new MouseEvent( 'click' ); a.download = '广播电视频道许可证-' + item.channelName ; a.href = url; a.dispatchEvent( event ); ElMessage.success( "下载成功!" ); }; image.src = url_; }; function downImg(item) { //下载后,自动预览图片 var a = document.createElement( 'a' ); document.body.appendChild(a); //不管a.href的后缀是什么,图片格式皆以此处为准 //加上这行代码,就是先下载后预览,去掉这行代码,就是直接预览 a.download = '广播电视频道许可证-' + item.channelName+ '.jpg' ; a.href = http+item.imageUrl; a.click(); a.remove() }; 2、数据下载-file-saver下载,它是在浏览器中直接保存文件的包 import { saveAs } from 'file-saver' function down(data) { saveAs(data, 'file.docx' ) }; 3、数据下载-Excel下载,将后台返回的JSON数据用excel导出 <html> <head> <script type= "text/javascript" src= "https://cdn.bootcss.com/xlsx/0.12.7/xlsx.core.min.js" ></script> <script type= "text/javascript" src= "https://cdn.bootcdn.net/ajax/libs/alasql/0.0.50/alasql.min.js" ></script> </head> <body> <button onclick= "down()" >下载</button> </body> </html> <script> function down(){ var tableTh=[ "times [时间]" , "user [用户]" , "ip [IP地址]" , "result [登录结果]" ]; var title= "文件名" var dataArray=[ { times: "2003-03-04" , //0 user: "张三" , //1 ip: "216.94.168.85" , //2 result: 0, //3 ServiceType: "yhzuu" , id: 1, operation: "刷新页面" , },{ times: "2003-03-05" , //0 user: "李四" , //1 ip: "216.94.168.85" , //2 result: 1, //3 ServiceType: "yhzuu" , id: 2, operation: "刷新页面" , } ]; dataArray.forEach(function(item,index){ if (item.result===0){ item.result= "失败" } else if (item.result===1){ item.result= "成功" } }); alasql( 'SELECT ' + tableTh+ ' INTO XLSX("' + title+ '.xlsx",{headers:true}) FROM ?' , [dataArray]); //上面这行,字符串'SELECT '的后面和' INTO XLSX("'的前面,都必须有空格,没有空格会导致excel表格下载失败 } </script> //数据下载-结束 六、数据展示 附1、3个媒体元素 (1)标签 A、audio <audio controls> <source src= "horse.ogg" type= "audio/ogg" > <source src= "horse.mp3" type= "audio/mpeg" > 您的浏览器不支持 audio 元素。 </audio> B、picture <picture> <source media= "(min-width:650px)" srcset= "img_pink_flowers.jpg" > <source media= "(min-width:465px)" srcset= "img_white_flower.jpg" > <img src= "img_orange_flowers.jpg" alt= "Flowers" style= "width:auto;" > </picture> C、video <video width= "320" height= "240" controls> <source src= "movie.mp4" type= "video/mp4" > <source src= "movie.ogg" type= "video/ogg" > 您的浏览器不支持 video 标签。 </video> (2)audio和video的标签的共有属性 A、autoplay,autoplay,在就绪后马上播放 B、controls,controls,向用户显示控件(比如播放/暂停按钮) C、loop,loop,每当播放结束时重新开始播放 D、muted,muted,输出为静音 E、preload,auto/metadata/none,是否默认被加载以及如何被加载 F、src,URL,规定文件的URL (3)video的标签专有属性 A、width,pixels,设置视频播放器的宽度 B、height,pixels,设置视频播放器的高度 C、poster,URL,规定视频正在下载时显示的图像,直到用户点击播放按钮 (4)source标签,为媒体元素指定多个媒体资源 来源,https: //www.w3school.com.cn/tags/tag_source.asp 来源,https: //www.w3school.com.cn/tags/att_source_srcset.asp A、src,用于指定媒体文件的URL B、srcset,用于指定在不同情况下使用的图像的URL,<source srcset= "https://static.noob-logo.png" ></source> C、media,媒体查询,<source media= "(min-width:650px)" ></source> D、type,规定资源的MIME类型,<source type= "video/mp4" ></source> MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型 指定浏览器用哪个应用程序打开文件 附2、videojs插件 来源,https: //videojs.com 来源,https: //cloud.tencent.com/developer/article/1615717 (1)简介 Video.js是一款web视频播放器,支持html5和flash两种播放方式 (2)依赖 A、<link href= "//vjs.zencdn.net/7.3.0/video-js.min.css" rel= "stylesheet" ></link> B、<script src= "//vjs.zencdn.net/7.3.0/video.min.js" ></script> (3)配置 var player = videojs(document.getElementById( 'myVideo' ), { controls: true , // 是否显示控制条 poster: 'xxx' , // 视频封面图地址 preload: 'auto' , autoplay: false , fluid: true , // 自适应宽高 language: 'zh-CN' , // 设置语言 muted: false , // 是否静音 inactivityTimeout: false , controlBar: { // 设置控制条组件 playToggle: true , //播放暂停按钮 volumeMenuButton: true , //音量控制 currentTimeDisplay: true , //当前播放时间 timeDivider: true , // '/' 分隔符 durationDisplay: true , //总时间 progressControl: true , //点播流时,播放进度条,seek控制 liveDisplay: true , //直播流时,显示LIVE remainingTimeDisplay: true , //当前播放时间 playbackRateMenuButton: true , //播放速率,当前只有html5模式下才支持设置播放速率 fullscreenToggle: true , //全屏控制 /* 使用children的形式可以控制每一个控件的位置,以及显示与否 */ children: [ {name: 'playToggle' }, // 播放按钮 {name: 'currentTimeDisplay' }, // 当前已播放时间 {name: 'progressControl' }, // 播放进度条 {name: 'durationDisplay' }, // 总时间 { // 倍数播放 name: 'playbackRateMenuButton' , 'playbackRates' : [0.5, 1, 1.5, 2, 2.5] }, { name: 'volumePanel' , // 音量控制 inline: false , // 不使用水平方式 }, {name: 'FullscreenToggle' } // 全屏 ] }, sources: [ // 视频源 { src: '//vjs.zencdn.net/v/oceans.mp4' , type: 'video/mp4' , poster: '//vjs.zencdn.net/v/oceans.png' } ] }, function (){ console.log( '视频可以播放了' , this ); }); someButton.onclick=function(){ var data = { src: 'xxx.mp4' , type: 'video/mp4' }; player.pause(); player.src(data); player.load(data); //重新加载src指定的资源 player.posterImage.setSrc( 'xxx.jpg' ); player.play(); player.dispose(); } 1、数据展示-视频展示-共2种(附、videojs插件使用实例) (1)弹窗内播放视频 import { MessageBox } from 'element-ui' ; export default function player(option){ console.log(MessageBox) MessageBox.alert( '<video id="video" width="600" controls height="337" autoplay muted src="' +option.url+ '" ></video>' , option.title,{ dangerouslyUseHTMLString: true , showConfirmButton: false , customClass: 'video-warp' , beforeClose:()=>{ let video = document.getElementById( 'video' ) video.pause() video.load(); MessageBox.close() } }) } (2)页面内视频播放 A、依赖 "dependencies" : { "video.js" : "^7.20.3" , }, B、组件调用 <player ref = "playerRef" :path= "data.pageInfo.url" :poster= "data.pageInfo.coverImgUrl" @ended= "endedHadler" @play= "playHadler" @timeupdate= "timeupdateHadler" ></player> <script setup> import player from "@/components/player/index.vue" ; import { createWebSocket, closeWebSocket, sendSock, getSock } from '@/utils/socket' ; let getPageInfo = (courseId, isInit = true ) => { //isInit是否是初始化页面,初始化需要查询课程合集 getCourse({ courseId, userId }).then(res => { data.pageInfo = res.data; collectionId = res.data.collectionId; nextTick(() => { thumbsUpAni.value = new ThumbsUpAni([zanIcon]); }) if (isInit) { getCourseCollection({ collectionId, userId }).then(response => { data.listInfo = response.data; }) } var url = '/zxkt_course_api_link?userId=' + userId + '&collectionId=' + collectionId + '&courseId=' + courseId; createWebSocket(url); }) } getPageInfo(data.courseId); onBeforeUnmount(() => { if (getSock()) { closeWebSocket(); } }) const endedHadler = (currentTime) => { let params = { "code" : "20001" , //固定值 "data" : { "collectionId" : collectionId, //课程集id "courseId" : data.courseId, //课程id "viewDuration" : currentTime //当前视频的播放进度(秒) } } sendSock( params , (res) => {}, data.courseId) } const timeupdateHadler = (currentTime) => { if (strategy(currentTime)) { let params = { "code" : "20001" , //固定值 "data" : { "collectionId" : collectionId, //课程集id "courseId" : data.courseId, //课程id "viewDuration" : currentTime //当前视频的播放进度(秒) } } sendSock( params , (res) => {}, data.courseId) } } </script> 附、 '@/utils/socket' (完整) var websock = null ; let rec; //断线重连后,延迟5秒重新创建WebSocket连接 rec用来存储延迟请求的代码 let isConnect = false ; //连接标识 避免重复连接 var globalCallback = new Map(); let createWebSocket = (paramsUrl) => { try { initWebSocket(paramsUrl); //初始化websocket连接 } catch (e) { //console.log("尝试创建连接失败"); reConnect(); //如果无法连接上webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接 } }; //定义重连函数 let reConnect = () => { //console.log("尝试重新连接"); if (isConnect) return ; //如果已经连上就不在重连了 rec && clearTimeout(rec); rec = setTimeout(function () { // 延迟5秒重连 避免过多次过频繁请求重连 createWebSocket(); }, 5000); }; //设置关闭连接 let closeWebSocket = () => { websock.close(); }; // 初始化websocket function initWebSocket(paramsUrl) { // ws地址 const wsUri = import.meta.env.VITE_APP_SOKET_API+paramsUrl; websock = new WebSocket(wsUri) websock.onmessage = function (e) { websocketonmessage(e) } websock.onopen = function () { isConnect = true ; //console.log('连接成功'); } // 连接发生错误的回调方法 websock.onerror = function () { //console.log('WebSocket连接发生错误') isConnect = false ; //连接断开修改标识 reConnect(); //连接错误 需要重连 } } // 实际调用的方法 function sendSock(agentData, callback, key) { if (!websock){ initWebSocket() } globalCallback. set (key,callback) if (websock.readyState === websock.OPEN) { // 若是ws开启状态 websocketsend(agentData,callback,key) } else if (websock.readyState === websock.CONNECTING) { // 若是 正在开启状态,则等待1s后重新调用 setTimeout(function () { sendSock(agentData, callback,key) }, 2000) } else { // 若未开启 ,则等待1s后重新调用 setTimeout(function () { sendSock(agentData, callback,key) }, 2000) } } function getSock(key,callback) { globalCallback. set (key,callback) } // 数据接收 function websocketonmessage(e) { //console.log(e) let ret = e.data if (ret.msg === "websocket connect success" ) {} else { if (ret.method === "webSocket_device_transport" ){ const callback = globalCallback. get (ret.sn) if (callback && typeof callback === "function" ) callback(ret); } else if (ret.method === "webSocket_device_alarm" ){ const callback = globalCallback. get ( 'deviceAlert' ) if (callback && typeof callback === "function" ) callback(ret); } } // globalCallback(JSON.parse(e.data)) function decodeUnicode(str) { str = str.replace(/\\/g, "%" ); //转换中文 str = unescape(str); //将其他受影响的转换回原来 str = str.replace(/%/g, "\\" ); //对网址的链接进行处理 str = str.replace(/\\/g, "" ); return str; } } // 数据发送 function websocketsend(agentData) { websock.send(JSON.stringify(agentData)) } // 关闭 function websocketclose(e) { isConnect = false ; //断开后修改标识 } // 创建 websocket 连接 function websocketOpen(e) { isConnect = true } //登录成功后再建立连接 //initWebSocket() // 将方法暴露出去 export { sendSock, getSock, createWebSocket, closeWebSocket, initWebSocket } C、组件定义 //两点最重要,其一配置,其二事件监听 <template> <div class = "videoPlayer" > <video ref = "videoRef" class = "video-js vjs-default-skin vjs-big-play-centered" controls> <source :src= "path" /> </video> </div> </template> <script setup> import { nextTick, onBeforeUnmount, onMounted, ref , watch,defineExpose } from 'vue' ; import videojs from 'video.js' import 'video.js/dist/video-js.css' import zh from "video.js/dist/lang/zh-CN.json" const props = defineProps({ path: { type: String, required: true , default : '' , }, autoplay: { type: Boolean, default : false , }, poster:{ type: String, default : '' , }, w: { type: Number, default : 1200, }, h: { type: Number, default : 675, } }) const videoRef = ref () let player = null ; let videoPoster = "" ; const emit = defineEmits([ 'ended' , 'error' , 'timeupdate' , 'seeking' ]) const initPlayer = async () => { videojs.addLanguage( 'zh-CN' ,zh) await nextTick() const options = { width:props.w, height:props.h, poster:props.poster, autoplay: props.autoplay, playbackRates: [0.5, 1, 1.5, 2], language: 'zh-CN' , preload: 'auto' , // 预加载 notSupportedMessage: 'Ajiang此视频暂无法播放,请稍后再试' , controlBar: { children: [ //自定义controlBar内容显示顺序 { name: 'playToggle' }, { name: 'progressControl' }, { name: 'remainingTimeDisplay' , displayNegative: false }, //默认情况下,剩余时间显示为负时间。不显示负号 controlBar.remainingTimeDisplay.displayNegative 设置为 false。 { name: 'playbackRateMenuButton' , playbackRates: [0.5, 1, 1.5, 2] }, { name: 'volumePanel' ,inline: false }, { name: 'pictureInPictureToggle' }, // {name: 'AutoPlayNext'}, //控制是否自动播放下一个 { name: 'fullscreenToggle' } ], } }; player = videojs(videoRef.value, options, () => { videojs.log( '播放器已经准备好了!' ); if (props.poster){ videoPoster = props.poster; } else { videoPoster = getPoster(); } if (props.autoPlay && props.path) { player.play() } player. on ( 'play' , () => { emit( 'play' ) videojs.log( '开始播放了!' ); }); player. on ( 'ended' , () => { emit( 'ended' ,parseInt(player.currentTime())) videojs.log( '播放结束了!' ); }); player. on ( 'error' , () => { emit( 'error' ) videojs.log( '播放器解析出错!' ); }) player. on ( 'seeking' , () => { emit( 'seeking' ) // videojs.log('每次当视频跳到一个新的时间都会触发!'); }) player. on ( 'timeupdate' , () => { emit( 'timeupdate' ,parseInt(player.currentTime())) // videojs.log('当当前的播放位置改变的时候触发!'); }) }); } const getPoster = ()=>{ videoRef.value.currentTime = 1; // 创建canvas元素 const canvas = document.createElement( 'canvas' ) const ctx = canvas.getContext( '2d' ) // canvas画图 canvas.width = props.w canvas.height = props.h ctx?.drawImage(videoRef.value, 0, 0, canvas.width, canvas.height) // 把canvas转成base64编码格式 return canvas.toDataURL( 'image/png' ) } //方法 const operation = (param)=> { console.log(param) if ( "play" === param) { //开始播放 player.play(); } else if ( "stop" === param) { //停止播放 player.pause(); } else if ( "fastForward" === param) { //快进 let whereYouAt = player.currentTime(); player.currentTime(10 + whereYouAt); } else if ( "reload" === param) { //重新加载 player.pause(); player.load(); player.play(); } else if ( "back" === param) { //后退 let whereYouAt = player.currentTime(); player.currentTime(whereYouAt - 10); } else if ( "fullScreen" === param) { //全屏 player.requestFullscreen(); } else if ( "exitFullScreen" === param) { //退出全屏 player.exitFullscreen(); } else if ( "volumeUp" === param) { //音量加 let howLoudIsIt = player.volume(); player.volume(howLoudIsIt + 10); } else if ( "volumeDown" === param) { //音量减 let howLoudIsIt = player.volume(); console.log(howLoudIsIt) player.volume(howLoudIsIt - 10); } else if ( "reset" === param) { //重置,视频不会播放 player.reset(); } } onMounted(() => { initPlayer() }) watch(() => props.path, () => { player.pause() player.src(props.path) player.load() if (props.path) { player.play() } }) onBeforeUnmount(() => { player?.dispose() }) defineExpose({ operation }) </script> <style lang= "scss" > </style> 2、数据展示-PDF展示-共3种 (1)页外展示,<a :href= "item.url" target= "_blank" >避免跨域</a> (2)jquery-media.js A、类库:jquery.js、jquery-media.js B、前端用Jinja2语法把总变量分散插进HTML里,交给后台 C、后台给总变量赋值,然后把HTML渲染成PDF, D、CSS分页:此前分页page- break -before: always;此后分页page- break -after: always; $( '#pdf' ).media({ width: '100%' , height: '680px' , autoplay: true , src: '/flow_audit/media?file_name=myNAme' }); (3)vue3-pdf-app(来源于ai-web项目,素材库-文章编辑,媒体大模型) 附、相关链接,https: //www.npmjs.com/package/vue3-pdf-app A、依赖 "dependencies" : { "vue3-pdf-app" : "^1.0.3" , }, B、组件调用 <pdfView :fileVisible= "showPDFView" :item= "modelFile" @close= "hidePDFVisible" ></pdfView> function viewItem(row) { showPDFView.value = true modelFile.value = row; modelFile.value.url = row.publicUrl; //此处可能产生跨域 } C、组件定义 <script setup> import VuePdfApp from "vue3-pdf-app" ; import "vue3-pdf-app/dist/icons/main.css" ; import { onBeforeUnmount, ref , shallowRef, onMounted, watch } from 'vue' const props = defineProps({ fileVisible: { type: Boolean, default : false , }, item:{ type: Object, default :()=>{ } } }); const show = ref ( false ) const item = ref (props.item) const config = ref ({ toolbar: { toolbarViewerRight: false , toolbarViewerLeft:{ findbar: false }, secondaryToolbarToggle: false } }); const heightValue = ref ( 'calc(100vh - 200px)' ); watch(props,(now,last) => { show.value = now.fileVisible item.value = now.item console.log(item.value.url) }) const emit = defineEmits([ 'close' ]) const close = ()=>{ emit( 'close' ) } </script> <template> <el-dialog v-model= "show" top= "5vh" title= "文档预览" width= "992px" @close= "close" > <div class = "article-edit-content" style= "overflow-y: scroll" :style= "{ height: heightValue }" > <vue-pdf-app :config= "config" :pdf= "item.url" ></vue-pdf-app> </div> </el-dialog> </template> <style lang= "scss" > </style> 3、数据展示-docx展示-共1种 (1)用node包实现(来源于ai-web项目,素材库) A、依赖 "dependencies" : { "docx-preview" : "^0.1.20" , //该插件提供的renderAsync方法,实现了docx文档展示 }, B、组件调用 <docView :fileVisible= "showDOCView" :item= "modelFile" @close= "hideDOCVisible" ></docView> function viewItem(row) { showDOCView.value = true modelFile.value = row; modelFile.value.url = row.publicUrl; //此处可能产生跨域 } C、组件定义 <script setup> import { renderAsync } from "docx-preview" import { onBeforeUnmount,defineEmits, ref , shallowRef, onMounted, watch ,defineProps} from 'vue' const props = defineProps({ fileVisible: { type: Boolean, default : false , }, item:{ type: Object, default :()=>{ } } }); const show = ref ( false ) const item = ref (props.item) const loading = ref ( false ) const heightValue = ref ( 'calc(100vh - 200px)' ); watch(props,(now,last) => { show.value = now.fileVisible item.value = now.item previewfile() }) const emit = defineEmits([ 'close' ]) const close = ()=>{ emit( 'close' ) } const previewfile = () => { loading.value = true ; fetch(item.value.url) .then((response) => { let docData = response.blob(); let docxDiv= document.getElementsByClassName( "docxDiv" ); renderAsync(docData, docxDiv[0], null , { inWrapper: false , // 启用围绕文档内容渲染包装器 ignoreWidth: false , // 禁止页面渲染宽度 ignoreHeight: false , // 禁止页面渲染高度 ignoreFonts: false , // 禁止字体渲染 breakPages: true , // 在分页符上启用分页 ignoreLastRenderedPageBreak: true , //禁用lastRenderedPageBreak元素的分页 experimental: false , //启用实验性功能(制表符停止计算) trimXmlDeclaration: true , //如果为真,xml声明将在解析之前从xml文档中删除 debug: false , }).then((res) => { loading.value = false ; }); }) . catch ((error) => { console.log(error); }); }; </script> <template> <el-dialog v-model= "show" top= "5vh" title= "文档预览" width= "992px" @close= "close" > <div :style= "{ height: heightValue }" ref = "docxDiv" class = "docxDiv article-edit-content" v-loading= "loading" ></div> </el-dialog> </template> <style lang= "scss" > </style> 4、数据展示-json展示-共3种 (1)用node包实现 A、依赖 "dependencies" : { "vue-json-viewer" : "^2.2.19" , }, B、组件调用 import JsonViewer from "vue-json-viewer" ; <json-viewer :value= "JSON.parse(logInfo.responseParam)" :expand-depth= "5" :copyable="{ copyText: '复制' , copiedText: '复制成功' , timeout: 2000 }" boxed sort ></json-viewer> (2)原生JS实现 <!DOCTYPE html> <html lang= 'en' > <head> <meta charset= 'UTF-8' > <meta name= 'viewport' content= 'width=device-width, initial-scale=1.0' > <title>JSON展示</title> <style> .fontSize20{ font-size: 20px; } .result{ width: 400px; padding: 40px; font-size: 12px; background: rgb(231, 228, 228); } </style> </head> <body> <div class = "fontSize20" >JSON格式在线校验,https: //www.bejson.com/</div> <div id= 'div' class = "result" ></div> </body> </html> <script> function isArray(value) { return {}.toString.call(value) === "[object Array]" ; } function isObject(value) { return {}.toString.call(value) === "[object Object]" ; } function addLine(num) { //添加换行 var str = '\n' ; for ( var i = 0; i < num; i++) str += '\n' return str; } function addSpace(num) { //添加空格 var str = '\xa0' ; for ( var i = 0; i < num; i++) str += '\xa0' return str; } function addStr(data, num, isAddDot) { //添加字符串 var str = '' ; if (isObject(data)) { str += '{' + addLine(1); var i = 0; var strIn = ',' ; var length = Object.keys(data).length; for ( var attr in data){ var value = data[attr]; i++; if (i == length) strIn = '' ; str += addSpace(4*num) + JSON.stringify(attr) + ":" + addStr(value, num+1) + strIn + addLine(1); } str += addSpace(4*(num-1)) + '}' ; if (isAddDot) str += ',' ; } else if (isArray(data)) { str += '[' ; for ( var i=0;i<data.length;i++){ var value = data[i]; var isHasDot = i<data.length-1; str += addStr(value, num, isHasDot); } str += ']' ; if (isAddDot) str += ',' ; } else { str += JSON.stringify(data); if (isAddDot) str += ',' ; } return str; } var data= { "aaa" :200, "bbb" : "42465" , "ccc" : false , "ddd" :[{ "title" : "治车山志" , "status" : "失败" },{ "title" : "需酸老" , "status" : "失败" }], "eee" :{ "省级1" : "吉林省" , "省级3" :{ "河北省" : "临夏回族自治州" , "河南省" :{ "信阳市" :{ "固始县" :[ "A" ,[1,2], "B" ,[ "3" , "4" ]] //把数组某项换成'省级3'对象,看效果 } } } }, "fff" : "★★★" } document.getElementById( 'div' ).innerText = addStr(data, 1); </script> (3)jQuery实现 <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <script src= "http://code.jquery.com/jquery-2.1.1.min.js" ></script> <style > .json-document { padding: 1em 2em; } ul.json-dict, ol.json-array { list-style-type: none; margin: 0 0 0 1px; border-left: 1px dotted #ccc; padding-left: 2em; } .json- string { color: #0B7500; } .json-literal { color: #1A01CC; font-weight: bold; } a.json-toggle { position: relative; color: inherit; text-decoration: none; } a.json-toggle:focus { outline: none; } a.json-toggle:before { font-size: 1.1em; color: #c0c0c0; content: "\25BC" ; /* https://unicode-table.com/cn/ */ position: absolute; display: inline-block; width: 1em; text-align: center; line-height: 1em; left: -1.2em; } a.json-toggle:hover:before { color: #aaa; } a.json-toggle.collapsed:before { transform: rotate(-90deg); } a.json-placeholder { color: #aaa; padding: 0 1em; text-decoration: none; } a.json-placeholder:hover { text-decoration: underline; } </style> </head> <body> <div id= "aaa" ></div> </body> </html> <script> (function ($) { function isCollapsable(arg) { return arg instanceof Object && Object.keys(arg).length > 0; } function isUrl( string ) { var urlRegexp = /^(https?:\/\/|ftps?:\/\/)?([a-z0-9%-]+\.){1,}([a-z0-9-]+)?(:(\d{1,5}))?(\/([a-z0-9\-._~:/?#[\]@!$&'()*+,;=%]+)?)?$/i; return urlRegexp.test( string ); } function json2html(json, options) { var html = '' ; if ( typeof json === 'string' ) { json = json .replace(/&/g, '&' ) .replace(/</g, '<' ) .replace(/>/g, '>' ) .replace(/ '/g, ' ') .replace(/ "/g, '" '); if (options.withLinks && isUrl(json)) { html += '<a href="' + json + '" class="json-string" target="_blank">' + json + '</a>' ; } else { if (json.indexOf( 'RED_SELF' ) > -1) { json = json.replace( 'RED_SELF' , '' ); html += '<span class="json-literal" style="color:red">' + json + '</span>' ; } else if (json.indexOf( 'RED_parent' ) > -1) { json = json.replace( 'RED_parent' , '' ); html += '<span class="json-literal RED_parent">' + json + '</span>' ; } else { json = json.replace(/ "/g, '\\" '); html += '<span class="json-string">"' + json + '"</span>' ; } } } else if ( typeof json === 'number' ) { html += '<span class="json-literal">' + json + '</span>' ; } else if ( typeof json === 'boolean' ) { html += '<span class="json-literal">' + json + '</span>' ; } else if (json === null ) { html += '<span class="json-literal">null</span>' ; } else if (json instanceof Array) { if (json.length > 0) { html += '[<ol class="json-array">' ; for ( var i = 0; i < json.length; ++i) { html += '<li>' ; if (isCollapsable(json[i])) { html += '<a href class="json-toggle"></a>' ; } html += json2html(json[i], options); if (i < json.length - 1) { html += ',' ; } html += '</li>' ; } html += '</ol>]' ; } else { html += '[]' ; } } else if ( typeof json === 'object' ) { var keyCount = Object.keys(json).length; if (keyCount > 0) { html += '{<ul class="json-dict">' ; for ( var key in json) { if (Object.prototype.hasOwnProperty.call(json, key)) { html += '<li>' ; var keyRepr = options.withQuotes ? '<span class="json-string">"' + key + '"</span>' : key; if (isCollapsable(json[key])) { html += '<a href class="json-toggle">' + keyRepr + '</a>' ; } else { html += keyRepr; } html += ': ' + json2html(json[key], options); if (--keyCount > 0) { html += ',' ; } html += '</li>' ; } } html += '</ul>}' ; } else { html += '{}' ; } } return html; } $.fn.jsonViewer = function (json, options) { options = Object.assign( {}, { collapsed: false , rootCollapsable: true , withQuotes: false , withLinks: true }, options ); return this .each(function () { var html = json2html(json, options); if (options.rootCollapsable && isCollapsable(json)) { html = '<a href class="json-toggle"></a>' + html; } $( this ).html(html); $( this ).addClass( 'json-document' ); $( this ).off( 'click' ); $( this ). on ( 'click' , 'a.json-toggle' , function () { var target = $( this ) .toggleClass( 'collapsed' ) .siblings( 'ul.json-dict, ol.json-array' ); target.toggle(); if (target. is ( ':visible' )) { target.siblings( '.json-placeholder' ).remove(); } else { var count = target.children( 'li' ).length; var placeholder = count + (count > 1 ? ' items' : ' item' ); target.after( '<a href class="json-placeholder">' + placeholder + '</a>' ); } return false ; }); $( this ). on ( 'click' , 'a.json-placeholder' , function () { $( this ).siblings( 'a.json-toggle' ).click(); return false ; }); if (options.collapsed == true ) { $( this ).find( 'a.json-toggle' ).click(); } }); }; })(jQuery); var obj={ "id" : 1001, "type" : "donut" , "name" : "Cake" , "description" : "https://en.wikipedia.org/wiki/Doughnut" , "price" : 2.55, "available" : { "store" : 42, "warehouse" : 600 }, "toppings" : [ { "id" : 5001, "type" : "None" }, { "id" : 5002, "type" : "Glazed" }, { "id" : 5005, "type" : "Sugar" }, { "id" : 5003, "type" : "Chocolate" }, { "id" : 5004, "type" : "Maple" } ], "uuids" : [ "826b23ce-2669-4122-981f-3e2e4429159d" , "e32111a0-6a87-49ab-b58f-a01bf8d28ba0" , "c055a894-698e-41c0-b85f-7510a7351d9d" , ], }; $( '#aaa' ).jsonViewer(obj); </script> 七、文档编辑 1、文档编辑-editormd (1)下载依赖包editormd并导入 git clone https: //github.com/pandao/editor.md.git <script src= "./common/editor.md/editormd.min.js" ></script> (2)如果编辑后台返回的数据,那么向后台发送请求,获取数据serverData (3)相关代码 html代码 <div id= "editormd" style= "height: 580px" > <textarea style= "display: none" ></textarea> </div> js代码,在请求成功后,执行下列代码 that.testEditor = editormd( "editormd" , { width: "100%" , height: "720" , watch: false , //关闭分栏 toolbar: false , //关闭工具栏 value: serverData|| '' , //字符串 path: "./common/editor.md/lib/" , //依赖存放路径 }); setTimeout(function () { var value = that.testEditor.getValue(); //这是前同事的代码,获取编辑前的数据,方便与编辑后的数据作比对,我以为没必要这样写 //编辑前的数据就是字符串serverData,在定时器外存储一下即可,如var value = serverData }, 500); (4)详细使用教程,百度“editor.md使用教程” 2、文档编辑-vue-ueditor-wrap(用于open-cctv项目,合集-文章编辑) (1)依赖 "dependencies" : { "vue-ueditor-wrap" : "^2.5.6" , }, (2)使用组件 <el-form-item label= "文章内容" prop= "region" class = "article-form-editor" > <vue-ueditor-wrap v-model= "html" :config= "myConfig" @ready= "ueditorReady" ></vue-ueditor-wrap> </el-form-item> (3)配置组件 import VueUeditorWrap from "vue-ueditor-wrap" ; export default { name: 'Article' , components: { VueUeditorWrap, } data() { return { html: '' , myConfig: { //按钮 toolbars: [ [ 'source' , //源代码 //'anchor', //锚点 'undo' , //撤销 'redo' , //重做 'bold' , //加粗 'indent' , //首行缩进 'italic' , //斜体 'underline' , //下划线 'strikethrough' , //删除线 'superscript' , //上标 'subscript' , //下标 'fontborder' , //字符边框 'formatmatch' , //格式刷 'blockquote' , //引用 'pasteplain' , //纯文本粘贴模式 'selectall' , //全选 'removeformat' , //清除格式 'time' , //时间 'date' , //日期 'unlink' , //取消链接 'link' , //超链接 'cleardoc' , //清空文档 'touppercase' , //字母大写 'tolowercase' , //字母小写 'fontfamily' , //字体 'fontsize' , //字号 'paragraph' , //段落格式 'searchreplace' , //查询替换 'justifyleft' , //居左对齐 'justifyright' , //居右对齐 'justifycenter' , //居中对齐 'justifyjustify' , //两端对齐 'forecolor' , //字体颜色 'directionalityltr' , //从左向右输入 'directionalityrtl' , //从右向左输入 'rowspacingtop' , //段前距 'rowspacingbottom' , //段后距 'lineheight' , //行间距 'horizontal' , //分隔线 'clears' , //分隔线 'simpleupload' , //单图上传 //'backcolor', //背景色 //'customstyle', //自定义标题 //'pagebreak', //分页 //'imageleft', //左浮动 //'imageright', //右浮动 //'imagecenter', //居中 //'insertrow', //前插入行 //'insertcol', //前插入列 //'deleterow', //删除行 //'deletecol', //删除列 //'splittorows', //拆分成行 //'splittocols', //拆分成列 //'edittip ', //编辑提示 //'imagenone', //默认 //'insertcode', //代码语言 //'snapscreen', //截图 //'print', //打印 //'preview', //预览 //'mergeright', //右合并单元格 //'mergedown', //下合并单元格 //'splittocells', //完全拆分单元格 //'deletecaption', //删除表格标题 //'inserttitle', //插入标题 //'insertparagraphbeforetable', //"表格前插入行" //'mergecells', //合并多个单元格 //'deletetable', //删除表格 'generateImage' , //多图上传 //'edittable', //表格属性 //'edittd', //单元格属性 //'emotion', //表情 //'spechars', //特殊字符 //'map', //Baidu地图 //'gmap', //Google地图 //'insertvideo', //视频 //'help', //帮助 //'insertorderedlist', //有序列表 //'insertunorderedlist', //无序列表 //'fullscreen', //全屏 //'insertframe', //插入Iframe //'attachment', //附件 //'wordimage', //图片转存 //'autotypeset', //自动排版 //'webapp', //百度应用 //'background', //背景 //'template', //模板 //'scrawl', //涂鸦 //'music', //音乐 //'inserttable', //插入表格 //'drafts', //从草稿箱加载 //'charts', //图表 ], ], labelMap: { simpleupload: "插入图片" , }, //编辑器不自动被内容撑高 autoHeightEnabled: false , //初始容器高度 initialFrameHeight: 300, //初始容器宽度 initialFrameWidth: "95%" , elementPathEnabled: false , //wordCount: false, wordCount: true , //是否开启字数统计 maximumWords: 200000, //允许的最大字符数 //字数统计提示,{#count}代表当前字数,{#leave}代表还可以输入多少字符数,留空支持多语言自动切换,否则按此配置显示 wordCountMsg: "当前已输入 {#count} 个字符,您还可以输入 {#leave} 个字符" , //当前已输入 {#count} 个字符,您还可以输入{#leave} 个字符 serverUrl:process.env.VUE_APP_BASE_API + "ueditor/ueditorUpload" , UEDITOR_HOME_URL: "./UEditor/" , zIndex: 1, }, } }, methods: { ueditorReady(editorInstance) { this .ueditorOject = editorInstance; //console.log(`编辑器实例${editorInstance.key}: `, editorInstance) } }, } 3、文档编辑-editor- for -vue,不插图片(来源于ai-web项目,素材库) (1)依赖 "dependencies" : { "@wangeditor/editor-for-vue" : "^5.1.12" , }, (2)使用组件 <textView :fileVisible= "fileVisible" :item= "modelFile" : readonly = "readonly" @submit= "update" @close= "hideFileVisible" ></textView> (3)定义组件 <template> <el-dialog v-model= "show" top= "5vh" title= "文档预览" width= "992px" @close= "close" > <div class = "article-edit-content" v-loading= "loading" :element-loading-svg= "loadSvg" element-loading-svg-view-box= "-10, -10, 50, 50" style= "overflow-y:scroll;" :style= "{height:heightValue}" v- if = "showEdit" > <div class = "article-edit-toolbar" > <Toolbar style= "border-bottom: 1px solid #ccc" :editor= "editorRef" :defaultConfig= "toolbarConfig" :mode= "mode" v- if = "!readonly" /> </div> <div class = "article-edit-warp" > <div class = "article-title" v- if = "readonly" > {{ item.title }} </div> <el-input v- else v-model= "item.title" autosize type= "textarea" placeholder= "请输入标题" class = "article-textarea" /> <Editor style= " overflow-y: hidden" v-model= "item.htmlContent" :defaultConfig= "editorConfig" :mode= "mode" @onCreated= "handleCreated" //“非常重要A-1/3”:把编辑区交给工具区1/2 /> </div> </div> <template #footer v- if = "!readonly" > <span class = "dialog-footer" > <el-button @click= "close" >取消</el-button> <el-button type= "primary" @click= "submit" >确定</el-button> </span> </template> </el-dialog> </template> <script setup> import { Editor, Toolbar } from '@wangeditor/editor-for-vue' ; import '@wangeditor/editor/dist/css/style.css' import { updateMaterialDocument } from '@/api/materialDocument.js' ; import { onBeforeUnmount, ref , shallowRef, onMounted, watch } from 'vue' const props = defineProps({ fileVisible: { type: Boolean, default : false , }, readonly : { type: Boolean, default : true , }, item:{ type: Object, default :()=>{} } }); const loading = ref ( false ) const show = ref ( false ) const item = ref (props.item) const readonly = ref (props. readonly ) const showEdit = ref ( false ) const editorRef = shallowRef(); const heightValue = ref ( 'calc(100vh - 200px)' ); watch(props,(now,last) => { console.log(now) show.value = now.fileVisible if (show.value){ setTimeout(()=>{ showEdit.value = true },100) } else { showEdit.value = false } item.value = now.item item.value.htmlContent=item.value.htmlContent?item.value.htmlContent:item.value.summary readonly .value = now. readonly if ( readonly .value){ editorRef.value&&editorRef.value.disable() heightValue.value = 'calc(100vh - 200px)' } else { editorRef.value&&editorRef.value.enable() heightValue.value = 'calc(100vh - 400px)' } }) const mode = ref ( 'default' ) // 或 'simple' // 模拟 ajax 异步获取内容 const toolbarConfig = { excludeKeys: [ 'divider' , 'codeBlock' , 'insertTable' , 'group-video' , 'group-image' , 'insertLink' , 'emotion' , 'fullScreen' , 'blockquote' , 'group-more-style' ], insertKeys:{ index: 30, keys: [ 'clearStyle' ] } }; const editorConfig = { placeholder: '' }; // 组件销毁时,也及时销毁编辑器 onBeforeUnmount(() => { const editor = editorRef.value; if (editor == null ) return ; editor.destroy(); }); const emit = defineEmits([ 'close' , 'submit' ]) const submit =() =>{ loading.value = true item.value.textContent = editorRef.value.getText() //“非常重要A-2/3”:获取编辑区文字内容 updateMaterialDocument(item.value).then(res =>{ loading.value = false ElMessage({ message: '更新成功' , type: 'success' , }) show.value = false emit( 'submit' ,item) }). catch (error => { loading.value = false ElMessage({ message: '更新失败' , type: 'error' , }) }) } const close = () => { show.value = false editorRef.value && editorRef.value.destroy(); editorRef.value = null emit( 'close' ) } const handleCreated = editor => { editorRef.value = editor; // “非常重要A-3/3”:把编辑区交给工具区2/2 if ( readonly .value){ editor.disable() } else { editor.enable() } } </script> <style lang= "scss" > </style> 4、文档编辑-editor- for -vue,插入图片(来源于ai-web项目feature/ interface 分支,素材库) 附、兄弟组件传参:兄组件发射事件,父组件监听事件,父组件组件通过 ref 调用弟组件的方法 (1)依赖,用在(3)B里 "dependencies" : { "@wangeditor/editor-for-vue" : "^5.1.12" , }, (2)使用-页面, <template> <div class = "create common-layout" > <el-container> <el-header> </el-header> <el-container> <el-aside width= "400px" class = "create-aside" > <el-tabs type= "border-card" v-model= "activeName" :stretch= "false" > <el-tab-pane label= "直接生成" name= "direct" :disabled= "settingsStore.isStopOperate" > </el-tab-pane> <el-tab-pane label= "分步生成" name= "scatter" :disabled= "settingsStore.isStopOperate" > </el-tab-pane> <el-tab-pane label= "智能配图" name= "picture" :disabled= "settingsStore.isStopOperate" > <div class = "generate-form" > <Picture ref = "pictureRef" ></Picture> </div> <div class = "create-button" > <el-button type= "primary" :disabled= "settingsStore.isStopOperate" style= "width: 100%" size= "large" @click= "generateImage" >生成图片</el-button> </div> </el-tab-pane> <el-tab-pane label= "搜索素材" name= "article" :disabled= "settingsStore.isStopOperate" > </el-tab-pane> </el-tabs> </el-aside> <el-main> <Editor ref = "editorRef" :syllabus-result= "syllabusResult" @resultIntervene= "onResultIntervene" @goldenSentenceVerificationEmi= "onSoundbite" @deliverInfo= "onEditorRrsult" @stopCreat= "onStopCreat" @adoptP= "onAdoptP" @disuseP= "onDisuseP" /> </el-main> </el-container> </el-container> </div> </template> <script setup> import useSettingsStore from '@/store/modules/settings' ; import Editor from './editor.vue' ; import Picture from './picture.vue' ; const settingsStore = useSettingsStore(); const pictureRef = ref ( null ); const editorRef = ref ( null ); import config from '@/config/index.js' ; const MOLD = config.MOLD /* MOLD: { "GENERATE":1, //直接生成 "STEPS":2, //分步生成 "IMAGE":3, "TITLE":4, "EXCERPT":5, "KEYWORDS":6, "CONTINUATION":7, "TRANSLATE":8, "REWRITE":9, //全文改写 "GENERATE_INTERFERE":11 }, */ function generateImage(data){ settingsStore.setStopOperate( true ) pictureRef.value.submit().then( params => { editorRef.value.insertContent(MOLD.IMAGE, params ) //“非常重要B-1/9”:获取图片后,在编辑器里,手动获取焦点并插入图片 }) } </script> (3)定义-页面子组件 A、页面子组件Picture <template> <div class = "picture-form" > <el-form label-position= "top" :rules= "rules" :model= "form" ref = "formRef" > <el-form-item label= "写作内容或主题" prop= "content" > <el-input maxlength= "500" type= "textarea" show-word-limit v-model= "form.content" placeholder= "试试输入你心中的画面,尽量描述具体,可以尝试用一些风格修饰词辅助你的表达。如:画面主体、颜色、质感等" :rows= "4" :disabled= "settingsStore.isStopOperate" /> </el-form-item> <el-form-item label= "风格" > <div class = "picture-form__list" > <div class = "picture-form__item" : class = "{ active: (index == activeIndex) }" v- for = "(item, index) in wanxiangImageStyleConfig" :key= "index" @click= "selectStyle(item,index)" :style= "`cursor: ${settingsStore.isStopOperate?'not-allowed':'pointer'}`" > <div class = "picture-form__img" > <img :src= "item.pic" /> <div class = "picture-form__style" >{{ item.name }}</div> </div> </div> </div> </el-form-item> <el-form-item label= "比例" > <el-radio- group v-model= "form.size" style= "width: 100%" :disabled= "settingsStore.isStopOperate" > <el-radio-button :key= "item.value" :label= "item.value" v- for = "item in wanxiangImageSizeConfig" >{{item.name}}</el-radio-button> </el-radio- group > </el-form-item> </el-form> </div> </template> <script setup> import config from '@/config/index.js' ; import { reactive, ref } from 'vue' ; import { useRouter,useRoute } from 'vue-router' import { v1 as uuidv1 } from 'uuid' ; import useSettingsStore from '@/store/modules/settings' ; const settingsStore = useSettingsStore() const uuid = uuidv1(); const route = useRoute(); const wanxiangImageStyleConfig = ref (config.wanxiangImageStyleConfig); const wanxiangImageSizeConfig = ref (config.wanxiangImageSizeConfig); const form = reactive({ size: '1024*1024' }); const formRef = ref ( null ); const activeIndex = ref (0); const rules = { content: [ { required: true , message: '图片内容或主题不能为空' , trigger: 'blur' }, ], } const subObj = reactive({ "invokeType" : "portal" , "domain" : route.query.domain || 'media' , "url" : "/image/generateImageTask" , "style" : "<auto>" , "size" : "1024*1024" , "type" : 1, "paragraphList" : [ { "id" : 1, "content" : "" } ], "articleTaskId" : '' }) function submit() { return new Promise ( (resolve,reject) => { formRef.value.validate((valid, fields) => { if (valid) { if (settingsStore.taskId) { subObj.articleTaskId = settingsStore.taskId } else { subObj.articleTaskId = uuid settingsStore.setTaskInfo(uuid); } subObj.size = form.size subObj.paragraphList[0].content = form.content console.log(subObj); resolve(subObj) return subObj } else { settingsStore.setStopOperate( false ) reject() } }) }) } function selectStyle(item,index){ if (!settingsStore.isStopOperate) { activeIndex.value = index subObj.style = item.value } } defineExpose({ submit }) </script> B、页面子组件Editor。包含插件Editor组件 附、工具栏配置,https: //www.wangeditor.com/v5/toolbar-config.html#toolbarkeys <template> <div class = "editor-container" > <div class = "editor-toolbar" id= "editor-tool-bar-wrapper" > <Toolbar :editor= "editorRef" :defaultConfig= "toolbarConfig" /> </div> <div class = "article-container" > <div class = "article-content" > <div class = "article-title" > <el-input v-model= "title" autosize type= "textarea" placeholder= "无标题" /> </div> <div id= "editor-content" class = "editor-content" > <Editor v-model= "valueHtml" :defaultConfig= "editorConfig" @mouseup= "editorSelectedHandler" @onCreated= "handleCreated" //“非常重要B-2/9”:把编辑区交给工具区1/2 /> </div> </div> <InsertImg v-show= "insertImgShow" @closeInsertImg= "insertImgShow = false" @regeneration= "interfereSubmit()" ></InsertImg> <div class = "cover-container" v- if = "coverRenderFlag" > <cctvTranslateRender v- if = "mold === config.MOLD.TRANSLATE" :original-param= "coverParams" :mold= "mold" @cancel= "cancelHandler" @disuse= "disuseHandler" @adopt= "adoptHandler" @compare= "compareHandler" ref = "aiComponent" > </cctvTranslateRender> <cctvRewriteRender v- if = "mold === config.MOLD.REWRITE" :original-param= "coverParams" :mold= "mold" @cancel= "cancelHandler" @disuse= "disuseHandler" @adopt= "adoptHandler" @compare= "compareHandler" ref = "aiComponent" > </cctvRewriteRender> </div> </div> </div> </template> <script> import { render, h as vueH} from 'vue' ; import { Editor, Toolbar } from '@wangeditor/editor-for-vue' ; //依赖在此使用 import { Boot, DomEditor } from '@wangeditor/editor' ; import CctvImgRender from "@/components/editor/cctv-img-render.vue" ; import cctvRender from "@/components/editor/cctv-render.vue" ; const aiComponent = ref ( null ); const editorSelf = null ; const aiApp = ref ( null ) const domId = ref ( '' ); const toolbarConfig = { toolbarKeys: [ "undo" , "redo" , "clearStyle" , "|" , "headerSelect" , "fontSize" , "bold" , "italic" , "through" , "underline" , "fontFamily" , "|" , "color" , "bgColor" , "|" ], excludeKeys: [ 'divider' , 'codeBlock' , 'insertTable' , 'group-video' , 'group-image' , 'insertLink' , 'emotion' , 'fullScreen' , 'blockquote' , 'group-more-style' ], insertKeys: { index: 30, keys: [ 'clearStyle' ] }, }; onBeforeUnmount(() => { if (editorSelf == null ) return editorSelf.destroy() editorRef.value.destroy() }) const handleCreated = (editorEle) => { editorRef.value = editorEle //“非常重要B-3/9”:把编辑区交给工具区2/2 editorSelf = editorEle; } function renderCctv(elem, children, editor) { const cctvVnode = h( 'span' , // HTML 属性、样式、事件 { props: { contentEditable: false , id: elem.id }, // HTML 属性,驼峰式写法 style: { display: 'inline-block' , /* 其他... */ }, // style ,驼峰式写法 }, ) return cctvVnode } function disuseCompareHandler() { aiComponent.value.handleDisuse() editorSelf.enable() } const renderElemConf = { type: 'cctv' , // 新元素 type ,重要!!! renderElem: renderCctv, } Boot.registerRenderElem(renderElemConf); const insertPlugin = (type, params ) => { mold.value = type if (domId.value !== '' ) { let pluginDiv = document.getElementById(domId.value); pluginDiv.parentNode.removeChild(pluginDiv); domId.value = '' ; } if (aiApp.value) { aiApp.value.unmount() } let id = uuidv1(); domId.value = id; const node = { type: 'cctv' , id: id, children: [{ text: '' }] } if (type === config.MOLD.TITLE || type === config.MOLD.EXCERPT) { editorSelf.focus(); editorSelf.moveReverse(editorSelf.getText().length + 1000) } else if (type === config.MOLD.KEYWORDS || type === config.MOLD.CONTINUATION) { editorSelf.move(editorSelf.getText().length); } else { editorSelf.focus(); //“非常重要B-4/9”:手动获取焦点 } editorRef.value.insertNode(node); //“非常重要B-5/9”:在焦点处插入节点外壳,节点外壳的id为变量id editorSelf.disable(); setTimeout(() => { let render = cctvRender if (type == config.MOLD.IMAGE) { //“非常重要B-6/9”:插入图片时,走这个逻辑 render = CctvImgRender //就是把url插入到img标签的src属性里 } if (type == config.MOLD.TITLE) { render = CctvTitleRender } if (type == config.MOLD.EXCERPT || type == config.MOLD.CONTINUATION) { render = CctvExcerptRender } if (type == config.MOLD.KEYWORDS) { render = CctvKeywordsRender } aiApp.value = createApp(render, //“非常重要B-7/9”:根据render组件生成真正节点 { originalParam: params , mold: type, onAdopt: adoptHandler, onReplace: replaceHandler, onCancel: cancelHandler, onDisuse: disuseHandler, onCompare: compareHandler, onResultIntervene: resultInterveneHandler, }, ) aiComponent.value = aiApp.value.mount(document.getElementById(id)) //“非常重要B-8/9”:把真正节点挂载(插入)到节点外壳上 }, 10) return ; } const insertContent = (type, params ) => { insertPlugin(type, params ); //“非常重要B-9/9”:获取图片后,在编辑器里,手动获取焦点并插入图片 return } defineExpose({ insertContent }) </script> C、页面子组件Editor的子组件cctvRender //本组件没有引入其他组件 //本组件是Editor的子组件,import cctvRender from "@/components/editor/cctv-render.vue"; <script setup> import { reactive, defineProps, watch, ref , onBeforeMount, onUnmounted, nextTick, computed } from 'vue' import wanchengIcon from '@/assets/icons/editor/wancheng.png' ; import loadingIcon from '@/assets/icons/editor/loading.gif' ; import config from '@/config/index.js' ; import useSettingsStore from '@/store/modules/settings' ; const settingsStore = useSettingsStore() const emit = defineEmits([ 'stopCreat' , 'adopt' , 'disuse' , 'cancel' , 'replaceFun' , 'compare' , 'resultIntervene' ]) const props = defineProps({ isFinished: { default : false , }, }) const contRef = ref ( null ); const renderInfo = reactive( { name: config.name, response: '' , } ) onBeforeMount(() => { if (props.mold === 2) { renderInfo.imageIsStart = false ; } }) onUnmounted(() => { if (renderInfo.picCreatTimer) { clearInterval(renderInfo.picCreatTimer) } }) function checkValue(obj, target) { for ( let key in obj) {} return false ; } const handleDisuse = () => { emit( 'disuse' , response.value); }; watch(props, newValue => { renderInfo.response = newValue.response; renderInfo.type = newValue.mold; }) const addTitle = (obj) => { emit( "adopt" , obj) } </script> <template> <!-- 数据返回错误的处理 --> <div class = "article-generation-fail" v- if = "renderInfo.state === 9" > <button type= "button" class = "btn cancel" @click= "cancel" >取消</button> </div> <div class = "article-generation" v- else > <div class = "article-generation-container" > <div class = "article-generation-header-box" > <!-- 文章 --> <!-- 配图 --> <!-- 生成标题 --> <!-- 提取关键字 --> </div> <div class = "article-generation-body" > <!-- 文章 --> <!-- 配图 --> <!-- 生成标题 --> <!-- 生成摘要 --> <!-- 提取关键字 --> </div> <div class = "article-generation-footer" > <!-- 文章 --> <!-- 图片 --> <!-- 生成摘要 --> <!-- 提取关键字 --> </div> </div> </div> </template> 八、算法知识|显示屏尺寸|丈母娘要彩礼|编程绝句 1、算法知识 (1)查找算法: 通过和文件中的关键字进行比较来实现的,都采用平均查找长度来衡量算法的优劣。那么能否有一种方法,不必进行与关键字的比较而达到查找的目的,这样平均查找长度就为0。哈希查找的基本思想是:通过对给定值作某种运算,直接求得(((关键字等于给定值的)记录)在文件中的)位置。 (2)八种数据结构: 数组、栈、队列、链表、集合、字典、树、图(一组由边连接的顶点)!以数组作为数组元素的数组,叫做二维数组,又叫做矩阵。行数、列数相等的矩阵称为方阵。元素以主对角线为对称轴对应相等的方阵叫做对称矩阵。主对角线外都是零元素的方阵叫做对角矩阵。将矩阵的行列互换得到的新矩阵称为转置矩阵。存放图顶点间关系的矩阵叫做邻接矩阵。 (3)树与二叉树: 由有限节点组成,具有层级关系的数据结构叫做树;每个节点最多有两个子节点的树叫做二叉树。 2、显示屏尺寸 function displayScreen(width,height,inch){ //以下,既是真假对角线的比例,也是真假宽、真假高的比例 var radio = inch/Math.sqrt(width*width+height*height); //以下,真宽 = 真假宽的比例*假宽 var trueWidth = (radio*width*2.54).toFixed(2); //以下,真高 = 真假高的比例*假高 var trueHeight = (radio*height*2.54).toFixed(2); var line = (inch*2.54).toFixed(2); var last = "" ; last += inch + "寸" + width + ":" + height + "的显示屏," ; last += "宽为" + trueWidth + "厘米;" ; last += "高为" + trueHeight + "厘米;" last += "其对角线长为" + line + "厘米!" ; console.log(last); } for ( var inch=20; inch<=60; inch+=1){displayScreen(16,9,inch)} 3、丈母娘要彩礼 (1)格式化版 function formatMoney(total) { /** * @formatMoney 格式化钱数为亿、万、元、角、分;效果为数字和汉字相间出现,这样分段更清晰,更容易读出 * @total 总钱数 */ var numStr = total.toString(); var numArr = numStr.split( '.' ); var numFront = numArr[0]; var numBack = numArr[1]; var frontLen = numFront.length; var yi = '' , wan = '' , yuan = '' , jiao = '' , fen = '' ; var jiaoFront = '' ; //以下处理整数部分 if (frontLen > 12||numStr.indexOf( '1e+' )>-1){ return '本函数最多格式化12位数' } if (frontLen > 4) { //以下处理万级及以上数据 if (frontLen > 8) { //以下处理亿级及以上数据 yi = numFront.substring(0, frontLen - 8) + '亿' ; //以下处理十亿级及以上数据的亿位补零 if (numFront.charAt(frontLen - 9) == '0' && numFront.charAt(frontLen - 8) != '0' ) yi += '零' ; //以下处理亿级及以上数据的千万、百万、十万位补零 for ( var i = frontLen - 8; i < frontLen - 4; i++) { if (numFront.charAt(i) && numFront.charAt(i) != '0' ) { wan = (frontLen - i < 8 ? '零' : '' ) + numFront.substring(i, frontLen - 4) + '万' ; break ; } } } else { //以下处理亿级以下、万级及以上数据 wan = numFront.substr(0, frontLen - 4) + '万' ; } //以下处理十万级及以上数据的万位补零 if (numFront.charAt(frontLen - 5) == '0' && numFront.charAt(frontLen - 4) != '0' ) yuan += '零' ; //以下处理万级及以上数据的千、百、十位补零 for ( var i = frontLen - 4; i < frontLen; i++) { if (numFront.charAt(i) && numFront.charAt(i) != '0' ) { yuan += (frontLen - i < 4 ? '零' : '' ) + numFront.substring(i) + '元' ; break ; } } } else { //以下处理万级以下数据 if (numFront != '0' ) { //排除整数部分为0的情况 yuan = numFront.substr() + '元' ; } } var moneyFront = total + '元,即' + yi + wan + yuan; //以下处理小数部分 var last1 = moneyFront.charAt(moneyFront.length - 1); var last2 = moneyFront.charAt(moneyFront.length - 2); if (numBack) { //如果存在小数 //以下处理角 if (numBack.charAt(0) == '0' ) { //如果十分位是0 if (numFront != '0' && numBack.charAt(1) && numBack.charAt(1) != '0' ){ jiao = yuan? '零' : '元零' ; //千、百、十、个位全为零时,yuan为空,需补元 } } else { //如果十分位不是0 if (last1 == '元' && last2 == '0' ){ jiaoFront = '零' ; } else if (last1 == '亿' || last1 == '万' ){ jiaoFront = '元零' ; } jiao = jiaoFront + numBack.charAt(0) + '角' } //以下处理分 if (numBack.charAt(1) && numBack.charAt(1) != '0' ) fen = numBack.charAt(1) + '分' } else { //如果不存在小数 if (last1 == '亿' ||last1 == '万' ){ //如果亿位或万位以后的整数都是0 moneyFront = moneyFront + '元' ; } } //以下汇总并抛出 var money = moneyFront + jiao + fen; return money } function payMoney(startYuan, dayNum, time) { /** * @payMoney 算出每天钱数和所有天总钱数 * @startYuan 第一天给多少钱 * @dayNum 连续给多少天 * @time 后一天给前一天多少倍 */ startYuan = startYuan || 0.01; dayNum = dayNum || 30; time = time || 2; //以下算出每天钱数 var dayMoney = '' ; dayMoney += '丈母娘要彩礼:' + '\n' ; dayMoney += '第1天给' + formatMoney(startYuan) + '\n' ; dayMoney += '以后每天给前一天的' + time + '倍,连续给' + dayNum + '天。\n' ; for ( var i = 1; i <= dayNum; i++) { var money = startYuan * Math.pow(time, i - 1); dayMoney += '第' + i + '天应该给丈母娘:' + formatMoney(money) + '\n' ; } //以下算出所有天钱数 var total = 0; for ( var i = 1; i <= dayNum; i++) { total += startYuan * Math.pow(time, i - 1); } //以下抛出最终结果 return dayMoney + dayNum + '天共计:' + formatMoney(total); } console.log(payMoney()) console.log( '.........' ) /* console.log(payMoney(1)) console.log( formatMoney(0.1) ); console.log( formatMoney(0.01) ); console.log( formatMoney(300.1) ); console.log( formatMoney(300.01) ); console.log( formatMoney(10300.1) ); console.log( formatMoney(10300.01) ); console.log( formatMoney(100000000.1) ); console.log( formatMoney(100000000.01) ); console.log( formatMoney(1000010000.01) ); console.log( formatMoney(1010100010.11) ); */ (2)非格式化版 function payMoney(startYuan, dayNum, time) { startYuan = startYuan || 0.01; dayNum = dayNum || 30; time = time || 2; //以下算出每天钱数 var dayMoney = '' ; dayMoney += '丈母娘要彩礼:' + '\n' ; dayMoney += '第1天给' + startYuan + '元' + '\n' ; dayMoney += '以后每天给前一天的' + time + '倍,连续给' + dayNum + '天。\n' ; for ( var i = 1; i <= dayNum; i++) { var money = startYuan * Math.pow(time, i - 1); dayMoney += '第' + i + '天应该给丈母娘:' + money + '元' + '\n' ; } //以下算出所有天钱数 var total = 0; for ( var i = 1; i <= dayNum; i++) { total += startYuan * Math.pow(time, i - 1); } //以下抛出最终结果 return dayMoney + dayNum + '天共计:' + total + '元' ; } console.log(payMoney()) console.log( '.........' ) console.log(payMoney(1)) 4、编程绝句 (1)我国清朝彭端淑曰:天下事有难易乎?为之,则难者亦易矣;不为,则易者亦难矣。 (2)吾本史学科班出身,为生计和兴趣计,经多次转行,最终以“必为”之心做了程序员。 (3)余自转行程序员以来, A、别妻、离子、抛清明、弃五一、丧端午、失中秋、沦国庆、陷元旦、缺周六、损周日。 B、天明起床、半夜入睡,四季更替,周而复始,专心致志于公司、心无旁骛于陋室。希冀以勤补拙,技上层楼。 (4)编程艰途如攻山,拼上老命向上攀;满身创伤终登顶,无边群峰在眼前。 (5)目视夕阳缓缓落,心盼技术速速升。周遭高楼依次亮,谁知我在中关村? (6)十年之前论古今,誓改人间换乾坤。如今只为生计计,犹落风尘做编程。 (7)当年悟空五行山,腾云驾雾难施展。而今吾身无负重,苦无神技助冲天。 (8)编程艰途如攻山,拼上性命向上攀。满身创伤终至顶,还有更高在眼前。 5、在线网址 (1)编程相关 A、在线编程工具,https: //www.toolhelper.cn/ B、在线ts运行,https: //www.json.cn/run/typescript/ C、在线图片转 a、svg,https: //www.bejson.com/convert/image_to_svg/ b、base64,https: //www.bejson.com/ui/image2base64/ D、在线代码对比,https: //www.bejson.com/others/comparecode/ E、在线JSON格式校验,https: //www.bejson.com/ F、在线颜色代码转换,https: //www.toolhelper.cn/Color/RGBToHex G、在线bootcdn,https: //www.bootcdn.cn/ H、在线MDN,https: //developer.mozilla.org/zh-CN/ (2)编程无关 A、在线去空格,https: //delspace.57cha.com/ B、在线去空行,https: //tool.ip138.com/txtdelspace/ C、链接转成二维码(草料),https: //cli.im/url/ D、在线网页转图片,https: //www.url2pic.com/url2pic/index.html E、在线文字生成图片,https: //remeins.com/index/app/text2img F、在线代码生成图片,https: //www.dute.org/code-snapshot G、在线字体识别 a、https: //font.chinaz.com/zhaozi/?123 b、https: //so.17font.com/ H、在线文件转换(文档、视频),https: //convertio.co/zh/download/ I、历史天气,https: //tianqi.2345.com/wea_history/54511.htm 6、AI (1)国外AI A、codeium,https: //codeium.com/playground B、codegeex,https: //codegeex.cn/zh-CN/playground C、chatGPT,http: //chat.178le.net/index a、2022年11月30日,美国OpenAI发布的聊天机器人程序 b、全名:Chat Generative Pre-trained Transformer c、汉译:人工智能技术驱动的自然语言处理工具 d、直译:聊天生成的、经过训练的、改革者 e、Copilot Hub:基于ChatGPT创建个人的知识库AI,app.copilothub.co (2)国内AI A、豆包,https: //www.doubao.com/chat a、2023年8月,字节跳动的人工智能机器人“豆包”开始测试 b、2024年5月,App总下载量已达1亿次,价格相比同行便宜99.3% c、2024年8月,上线音乐生成功能 d、支持网页Web平台,iOS平台,安卓平台 e、功能:聊天机器人、写作助手、学习助手、回答各种问题 B、文心一言,https: //yiyan.baidu.com/ C、智谱清言,https: //chatglm.cn/main/alltoolsdetail D、Kimi,https: //kimi.moonshot.cn/ E、通义千问,https: //qianwen.aliyun.com/ F、讯飞星火,https: //xinghuo.xfyun.cn/desk G、腾讯元宝,https: //yuanbao.tencent.com/chat/naQivTmsDa H、百小应,https: //ying.baichuan-ai.com/chat I、deepseek,https: //chat.deepseek.com/ (3)大模型(deepseek,大模型是什么东西) 附、大模型是指参数量可达数千亿的-基于人工神经网络的-机器深度学习模型 A、定义,大模型是指参数量可达数千亿的-深度学习模型,通常基于Transformer架构,广泛应用于自然语言处理(NLP)、计算机视觉(CV)等领域 B、参数量,大模型的参数量通常在数十亿到数千亿之间,例如GPT-3有1750亿参数 C、架构,主要基于Transformer,依赖自注意力机制处理长距离依赖关系 D、应用领域 a、自然语言处理:如文本生成、翻译、问答等 b、计算机视觉:如图像分类、目标检测等 c、多模态任务:如结合文本和图像处理 E、训练数据,需要海量数据,通常来自互联网,如网页、书籍等 F、计算资源,训练和推理需要高性能计算设备,如GPU、TPU等 G、代表性模型, a、GPT系列:如GPT-3,用于文本生成 b、BERT:用于文本分类、问答等 c、T5:适用于多种NLP任务 d、Vision Transformers (ViT):用于图像分类 H、挑战 a、计算成本:训练和推理资源消耗大 b、数据需求:需要大量高质量数据 c、可解释性:模型复杂,难以解释其决策过程 I、未来方向 a、模型压缩:减少参数量和计算需求 b、高效训练:提高训练效率 c、多模态融合:处理多种类型数据的融合任务 J、总结来说,大模型通过大量参数和数据,基于人工神经网络的机器学习模型 (4)深度学习模型(deepseek,深度学习模型又是什么意思) A、定义,深度学习模型是一类基于人工神经网络的机器学习模型,能够从大量数据中自动学习特征并完成复杂任务 B、基本概念 a、人工神经网络:模仿生物神经网络,由多层神经元组成 b、深度学习:使用多层神经网络进行学习,能够自动提取数据中的多层次特征 C、主要组成部分 a、输入层:接收原始数据 b、隐藏层:进行特征提取和转换,层数越多,模型越深 c、输出层:生成最终结果,如分类标签或回归值 D、常见类型 a、前馈神经网络(FNN):信息单向流动,适用于简单任务 b、卷积神经网络(CNN):用于图像处理,通过卷积核提取特征 c、循环神经网络(RNN):处理序列数据,如时间序列、文本 d、Transformer:基于自注意力机制,适用于NLP任务 E、训练过程 a、前向传播:输入数据通过各层生成输出 b、损失计算:比较输出与真实标签,计算误差 c、反向传播:根据误差调整模型参数 d、优化算法:如梯度下降,用于更新参数 F、应用领域 a、计算机视觉:图像分类、目标检测等 b、自然语言处理:文本生成、翻译等 c、语音识别:语音转文本 d、推荐系统:个性化推荐 G、优势 a、自动特征提取:无需手动设计特征 b、高精度:在大数据上表现优异 c、广泛应用:适用于多种任务 H、挑战 a、数据需求:需要大量标注数据 b、计算资源:训练和推理需要高性能硬件 c、可解释性:模型复杂,难以解释决策过程 I、未来方向 a、模型压缩:减少参数量和计算需求 b、自监督学习:减少对标注数据的依赖 c、多模态学习:处理多种类型数据的融合任务 J、总结来说,深度学习模型通过多层神经网络自动学习数据特征,广泛应用于多个领域,但也面临数据需求大、计算资源消耗高等挑战 7、微工具,https: //www.wetools.com/ (1)HTML代码格式化 https: //www.wetools.com/html-formatter (2)CSS代码格式化 https: //www.wetools.com/css-formatter (3)CSS三角形生成器 https: //www.wetools.com/css-arrow (4)JS在线运行工具 https: //www.wetools.com/js-run (5)JS代码格式化 https: //www.wetools.com/js-formatter (6)URL编码/解码 https: //www.wetools.com/url-encode (7)正则表达式测试 https: //www.wetools.com/regex (8)JSON格式化校验工具 https: //www.wetools.com/json (9)文章字数统计 https: //www.wetools.com/word-count 8、electron (1)electron是什么? A、用Web技术构建跨平台的桌面应用,electron = Chromium + Node.js + Native API。2016 年 5 月 Electron 发布了 v1.0.0 版本 B、Chromium,为 Electron 提供了强大的UI能力,可以不考虑兼容性的情况下,利用强大的Web生态来开发界面 C、Node.js,让 Electron 有了底层的操作能力,比如文件的读写,甚至是集成C++等等操作,并可以使用大量开源的 npm 包来完成开发需求 D、Native API,Native API 让 Electron 有了跨平台和桌面端的原生能力,比如说它有统一的原生界面,窗口、托盘这些。 (2)什么时候使用Electron? A、公司没有专门的桌面应用开发者,而需要前端兼顾来进行开发时,用Electron就是一个不错的选择。 B、一个应用需要同时开发Web端和桌面端的时候,那使用Electron来进行开发就对了。 C、开发一些效率工具,比如API类的工具。 |
« 上一篇: 1、ECharts之常见配置、仪表盘(基础、镂空且导入外来图片)、环状数据(单环多数据、单环单数据、多环多数据、饼图)、折线图(不等距、双折线、上下左右分区、心电图渐变、图片右侧空白再出图片)、地图(中国、世界、经纬度)、树状图(从左到右)、拓扑图、10年经济指标、其他与问题(4800行)
» 下一篇: 3、浏览器名称|html标签|data-|名称|系统|业务端参数、请求之种类刷新跨域同源策略请求头vpn、ajax方法事件区别|axios封装多登录多转圈、custPromise、字符串宽度|验证整数、 common.js源码、require.js源码 、sea.js源码(4300行)
» 下一篇: 3、浏览器名称|html标签|data-|名称|系统|业务端参数、请求之种类刷新跨域同源策略请求头vpn、ajax方法事件区别|axios封装多登录多转圈、custPromise、字符串宽度|验证整数、 common.js源码、require.js源码 、sea.js源码(4300行)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?