部署說明:
1、創建 Cloudflare Workers (編輯代碼將下面的代碼複製~粘貼~部署)
2、創建 R2 存儲桶(隨意名稱舉例;AAA123)
3、在 Cloudflare Workers 設置~變量~R2 存儲桶綁定~添加變量名稱必須 JSBR2 選擇R2存儲桶 AAA123 部署即可。
注:修改了帖子裡 樹莓派 提出的問題手機瀏覽時,最底下的三兩行代碼會被狀態欄遮住。
注:增加了帖子裡 playbear 提出的問題 能不能輸入密碼後才能查看內容。
1、代碼如下:(無需密碼可查看內容)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- <div>addEventListener('fetch', event => {
- event.respondWith(handleRequest(event.request));
- });
- async function handleRequest(request) {
- const { pathname, searchParams } = new URL(request.url);
- // Check if password protection is enabled
- let ADMIN_PASSWORD = await JSBR2.get('admin_password');
- ADMIN_PASSWORD = ADMIN_PASSWORD ? await ADMIN_PASSWORD.text() : null;
- const isPasswordProtected = ADMIN_PASSWORD !== undefined && ADMIN_PASSWORD !== null;
- console.log('isPasswordProtected:', isPasswordProtected);
- if (request.method === 'GET' && pathname === '/') {
- return new Response(await getHTML(isPasswordProtected), {
- headers: { 'content-type': 'text/html;charset=UTF-8' },
- });
- }
- if (request.method === 'GET' && pathname.startsWith('/notes/')) {
- const key = pathname.replace('/notes/', '');
- try {
- const object = await JSBR2.get(key);
- if (!object) {
- return new Response('Note not found', {
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- const value = await object.text();
- return new Response(value, {
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- } catch (err) {
- console.error('Error retrieving note:', err);
- return new Response('Error retrieving note', {
- status: 500,
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- }
- if (request.method === 'PUT' && pathname.startsWith('/notes/')) {
- const key = pathname.replace('/notes/', '');
- const password = searchParams.get('password');
- if (isPasswordProtected && password !== ADMIN_PASSWORD) {
- return new Response('Unauthorized', {
- status: 401,
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- try {
- const value = await request.text();
- await JSBR2.put(key, value);
- const timestamp = new Date().toISOString();
- await JSBR2.put(`${key}_timestamp`, timestamp);
- return new Response('Note saved', {
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- } catch (err) {
- console.error('Error saving note:', err);
- return new Response('Error saving note', {
- status: 500,
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- }
- if (request.method === 'POST' && pathname === '/set-password') {
- const password = await request.text();
- await JSBR2.put('admin_password', password);
- return new Response('Password set', {
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- if (request.method === 'POST' && pathname === '/change-password') {
- const { oldPassword, newPassword } = await request.json();
- if (isPasswordProtected && oldPassword !== ADMIN_PASSWORD) {
- return new Response('Unauthorized', {
- status: 401,
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- await JSBR2.put('admin_password', newPassword);
- return new Response('Password changed', {
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- return new Response('Not found', {
- status: 404,
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- async function getHTML(isPasswordProtected) {
- return `
- <!DOCTYPE html>
- <html>
- <head>
- <title>記事本</title>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <style>
- body, html {
- margin: 0;
- padding: 0;
- height: 100%;
- width: 100%;
- display: flex;
- flex-direction: column;
- font-family: Arial, sans-serif;
- }
- textarea {
- flex: 1;
- width: 100%;
- box-sizing: border-box;
- padding: 10px;
- font-size: 16px;
- resize: none;
- }
- .status {
- background-color: rgba(0, 0, 0, 0.5);
- color: white;
- padding: 10px;
- border-radius: 5px;
- font-size: 14px;
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- }
- .status-row {
- display: flex;
- justify-content: space-between;
- width: 100%;
- }
- .status span, .status button {
- margin: 5px 10px;
- }
- .password-setup,
- .change-password {
- display: none;
- flex-direction: row;
- align-items: center;
- margin-top: 10px;
- }
- .password-setup input,
- .change-password input {
- margin-right: 10px;
- margin-bottom: 5px;
- }
- .change-password input {
- margin-right: 5px;
- }
- @media (max-width: 600px) {
- .status {
- position: static;
- width: 100%;
- padding: 5px;
- font-size: 12px;
- }
- .status-row {
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: space-between;
- }
- .status span, .status button {
- margin: 2px 5px;
- }
- .password-setup,
- .change-password {
- flex-direction: column;
- align-items: flex-start;
- }
- }
- @media (min-width: 601px) {
- .status {
- position: fixed;
- bottom: 10px;
- right: 10px;
- }
- }
- .dark-mode {
- background-color: black;
- color: white;
- }
- .dark-mode textarea {
- background-color: black;
- color: white;
- }
- .dark-mode #moon-icon path {
- fill: white;
- }
- #moon-icon path {
- fill: black;
- }
- </style>
- </head>
- <body>
- <textarea id="note" placeholder="開始輸入..."></textarea>
- <div class="status" id="status">
- <div class="status-row">
- <span>當前已使用:<span id="used-space">0.00 KB</span></span>
- <span>總剩餘空間:<span id="remaining-space">9.99 GB</span></span>
- </div>
- <div class="status-row">
- <span id="last-write-time-container">最後寫入時間:<span id="last-write-time">N/A</span></span>
- <button id="change-password-button" onclick="showChangePassword()" style="display: none; margin-right: 20px;">修改密碼</button>
- </div>
- <div class="password-setup" id="password-setup">
- <input type="password" id="admin-password" placeholder="設置管理員密碼" />
- <button onclick="setPassword()">確認</button>
- </div>
- <div class="change-password" id="change-password">
- <input type="password" id="old-password" placeholder="舊密碼" />
- <input type="password" id="new-password" placeholder="新密碼" />
- <button onclick="changePassword()">確定</button>
- </div>
- </div>
- <svg id="moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" style="position: fixed; top: 10px; right: 10px; cursor: pointer;">
- <path d="M12 2a10 10 0 0 0 0 20 10 10 0 0 0 0-20zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16z"/>
- </svg>
- <script>
- const TOTAL_STORAGE = 10 * 1024 * 1024 * 1024; // 10 GB in bytes
- function updateStorageStatus() {
- const note = document.getElementById('note').value;
- const usedBytes = new TextEncoder().encode(note).length;
- const remainingBytes = TOTAL_STORAGE - usedBytes;
- document.getElementById('used-space').textContent = formatBytes(usedBytes);
- document.getElementById('remaining-space').textContent = formatBytes(remainingBytes);
- }
- function formatBytes(bytes) {
- const units = ['B', 'KB', 'MB', 'GB'];
- let unitIndex = 0;
- let value = bytes;
- while (value >= 1024 && unitIndex < units.length - 1) {
- value /= 1024;
- unitIndex++;
- }
- return value.toFixed(2) + ' ' + units[unitIndex];
- }
- async function saveNote() {
- const note = document.getElementById('note').value;
- let password = localStorage.getItem('adminPassword');
- if (${isPasswordProtected} && !password) {
- password = prompt('請輸入管理員密碼:');
- if (password) {
- localStorage.setItem('adminPassword', password);
- document.getElementById('change-password-button').style.display = 'inline-block';
- } else {
- alert('需要密碼才能編輯筆記。');
- return;
- }
- }
- const response = await fetch(\`/notes/my-note?password=\${password || ''}\`, {
- method: 'PUT',
- body: note,
- headers: {
- 'Content-Type': 'text/plain;charset=UTF-8'
- }
- });
- if (response.status === 401) {
- alert('密碼錯誤。請刷新頁面並輸入正確的密碼。');
- localStorage.removeItem('adminPassword');
- document.getElementById('change-password-button').style.display = 'none';
- return;
- }
- const timestamp = new Date().toISOString();
- document.getElementById('last-write-time').textContent = new Date(timestamp).toLocaleString();
- document.getElementById('last-write-time-container').style.display = 'inline'; // 顯示最後寫入時間
- }
- async function loadNote() {
- const response = await fetch('/notes/my-note');
- const note = await response.text();
- document.getElementById('note').value = note;
- updateStorageStatus();
- updateLastWriteTime(); // Initial load of last write time
- }
- async function updateLastWriteTime() {
- const timestampResponse = await fetch('/notes/my-note_timestamp');
- if (timestampResponse.ok) {
- const timestamp = await timestampResponse.text();
- const localTimestamp = new Date(timestamp).toLocaleString();
- document.getElementById('last-write-time').textContent = localTimestamp;
- document.getElementById('last-write-time-container').style.display = 'inline'; // 顯示最後寫入時間
- } else {
- document.getElementById('last-write-time-container').style.display = 'none'; // 隱藏最後寫入時間
- }
- }
- function debounce(func, wait) {
- let timeout;
- return function() {
- const context = this, args = arguments;
- clearTimeout(timeout);
- timeout = setTimeout(() => func.apply(context, args), wait);
- };
- }
- const debouncedSaveNote = debounce(saveNote, 200);
- document.getElementById('note').addEventListener('input', () => {
- debouncedSaveNote();
- updateStorageStatus();
- });
- window.addEventListener('load', () => {
- loadNote();
- setInterval(updateLastWriteTime, 1000); // 每秒更新一次最後寫入時間
- const password = localStorage.getItem('adminPassword');
- if (password) {
- document.getElementById('change-password-button').style.display = 'inline-block';
- }
- });
- async function setPassword() {
- const password = document.getElementById('admin-password').value;
- if (password) {
- const response = await fetch('/set-password', {
- method: 'POST',
- body: password,
- headers: {
- 'Content-Type': 'text/plain;charset=UTF-8'
- }
- });
- if (response.ok) {
- alert('管理員密碼設置成功');
- document.getElementById('password-setup').style.display = 'none';
- } else {
- alert('設置管理員密碼失敗');
- }
- } else {
- alert('請輸入密碼');
- }
- }
- function showChangePassword() {
- const password = localStorage.getItem('adminPassword');
- if (!password) {
- alert('您尚未登陸,請登陸後再修改密碼');
- return;
- }
- document.getElementById('change-password').style.display = 'flex';
- document.getElementById('change-password-button').style.display = 'none';
- }
- async function changePassword() {
- const oldPassword = document.getElementById('old-password').value;
- const newPassword = document.getElementById('new-password').value;
- if (!oldPassword || !newPassword) {
- alert('請輸入舊密碼和新密碼');
- return;
- }
- const response = await fetch('/change-password', {
- method: 'POST',
- body: JSON.stringify({ oldPassword, newPassword }),
- headers: {
- 'Content-Type': 'application/json;charset=UTF-8'
- }
- });
- if (response.status === 401) {
- alert('舊密碼不正確');
- return;
- }
- if (response.ok) {
- alert('密碼修改成功');
- document.getElementById('change-password').style.display = 'none';
- localStorage.setItem('adminPassword', newPassword);
- } else {
- alert('密碼修改失敗');
- }
- }
- document.getElementById('moon-icon').addEventListener('click', () => {
- document.body.classList.toggle('dark-mode');
- });
- </script>
- </body>
- </html>
- `;
- }
- 2、代碼如下:(需要密碼可查看內容)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- addEventListener('fetch', event => {
- event.respondWith(handleRequest(event.request));
- });
- async function handleRequest(request) {
- const { pathname, searchParams } = new URL(request.url);
- // Check if password protection is enabled
- let ADMIN_PASSWORD = await JSBR2.get('admin_password');
- ADMIN_PASSWORD = ADMIN_PASSWORD ? await ADMIN_PASSWORD.text() : null;
- const isPasswordProtected = ADMIN_PASSWORD !== undefined && ADMIN_PASSWORD !== null;
- console.log('isPasswordProtected:', isPasswordProtected);
- if (request.method === 'GET' && pathname === '/') {
- return new Response(await getHTML(isPasswordProtected), {
- headers: { 'content-type': 'text/html;charset=UTF-8' },
- });
- }
- if (request.method === 'GET' && pathname.startsWith('/notes/')) {
- const key = pathname.replace('/notes/', '');
- const password = searchParams.get('password');
- if (isPasswordProtected && password !== ADMIN_PASSWORD) {
- return new Response('Unauthorized', {
- status: 401,
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- try {
- const object = await JSBR2.get(key);
- if (!object) {
- return new Response('Note not found', {
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- const value = await object.text();
- return new Response(value, {
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- } catch (err) {
- console.error('Error retrieving note:', err);
- return new Response('Error retrieving note', {
- status: 500,
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- }
- if (request.method === 'PUT' && pathname.startsWith('/notes/')) {
- const key = pathname.replace('/notes/', '');
- const password = searchParams.get('password');
- if (isPasswordProtected && password !== ADMIN_PASSWORD) {
- return new Response('Unauthorized', {
- status: 401,
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- try {
- const value = await request.text();
- await JSBR2.put(key, value);
- const timestamp = new Date().toISOString();
- await JSBR2.put(`${key}_timestamp`, timestamp);
- return new Response('Note saved', {
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- } catch (err) {
- console.error('Error saving note:', err);
- return new Response('Error saving note', {
- status: 500,
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- }
- if (request.method === 'POST' && pathname === '/set-password') {
- const password = await request.text();
- await JSBR2.put('admin_password', password);
- return new Response('Password set', {
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- if (request.method === 'POST' && pathname === '/change-password') {
- const { oldPassword, newPassword } = await request.json();
- if (isPasswordProtected && oldPassword !== ADMIN_PASSWORD) {
- return new Response('Unauthorized', {
- status: 401,
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- await JSBR2.put('admin_password', newPassword);
- return new Response('Password changed', {
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- return new Response('Not found', {
- status: 404,
- headers: { 'content-type': 'text/plain;charset=UTF-8' },
- });
- }
- async function getHTML(isPasswordProtected) {
- return `
- <!DOCTYPE html>
- <html>
- <head>
- <title>記事本</title>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <style>
- body, html {
- margin: 0;
- padding: 0;
- height: 100%;
- width: 100%;
- display: flex;
- flex-direction: column;
- font-family: Arial, sans-serif;
- }
- textarea {
- flex: 1;
- width: 100%;
- box-sizing: border-box;
- padding: 10px;
- font-size: 16px;
- resize: none;
- }
- .status {
- background-color: rgba(0, 0, 0, 0.5);
- color: white;
- padding: 10px;
- border-radius: 5px;
- font-size: 14px;
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- }
- .status-row {
- display: flex;
- justify-content: space-between;
- width: 100%;
- }
- .status span, .status button {
- margin: 5px 10px;
- }
- .password-setup,
- .change-password {
- display: none;
- flex-direction: row;
- align-items: center;
- margin-top: 10px;
- }
- .password-setup input,
- .change-password input {
- margin-right: 10px;
- margin-bottom: 5px;
- }
- .change-password input {
- margin-right: 5px;
- }
- @media (max-width: 600px) {
- .status {
- position: static;
- width: 100%;
- padding: 5px;
- font-size: 12px;
- }
- .status-row {
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: space-between;
- }
- .status span, .status button {
- margin: 2px 5px;
- }
- .password-setup,
- .change-password {
- flex-direction: column;
- align-items: flex-start;
- }
- }
- @media (min-width: 601px) {
- .status {
- position: fixed;
- bottom: 10px;
- right: 10px;
- }
- }
- .dark-mode {
- background-color: black;
- color: white;
- }
- .dark-mode textarea {
- background-color: black;
- color: white;
- }
- .dark-mode #moon-icon path {
- fill: white;
- }
- #moon-icon path {
- fill: black;
- }
- </style>
- </head>
- <body>
- <textarea id="note" placeholder="請輸入密碼以查看內容" disabled></textarea>
- <div class="status" id="status">
- <div class="status-row">
- <span>當前已使用:<span id="used-space">0.00 KB</span></span>
- <span>總剩餘空間:<span id="remaining-space">9.99 GB</span></span>
- </div>
- <div class="status-row">
- <span id="last-write-time-container">最後寫入時間:<span id="last-write-time">N/A</span></span>
- <button id="change-password-button" onclick="showChangePassword()" style="display: none; margin-right: 20px;">修改密碼</button>
- </div>
- <div class="password-setup" id="password-setup">
- <input type="password" id="admin-password" placeholder="設置管理員密碼" />
- <button onclick="setPassword()">確認</button>
- </div>
- <div class="change-password" id="change-password">
- <input type="password" id="old-password" placeholder="舊密碼" />
- <input type="password" id="new-password" placeholder="新密碼" />
- <button onclick="changePassword()">確定</button>
- </div>
- </div>
- <svg id="moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" style="position: fixed; top: 10px; right: 10px; cursor: pointer;">
- <path d="M12 2a10 10 0 0 0 0 20 10 10 0 0 0 0-20zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16z"/>
- </svg>
- <script>
- const TOTAL_STORAGE = 10 * 1024 * 1024 * 1024; // 10 GB in bytes
- function updateStorageStatus() {
- const note = document.getElementById('note').value;
- const usedBytes = new TextEncoder().encode(note).length;
- const remainingBytes = TOTAL_STORAGE - usedBytes;
- document.getElementById('used-space').textContent = formatBytes(usedBytes);
- document.getElementById('remaining-space').textContent = formatBytes(remainingBytes);
- }
- function formatBytes(bytes) {
- const units = ['B', 'KB', 'MB', 'GB'];
- let unitIndex = 0;
- let value = bytes;
- while (value >= 1024 && unitIndex < units.length - 1) {
- value /= 1024;
- unitIndex++;
- }
- return value.toFixed(2) + ' ' + units[unitIndex];
- }
- async function saveNote() {
- const note = document.getElementById('note').value;
- let password = localStorage.getItem('adminPassword');
- if (${isPasswordProtected} && !password) {
- password = prompt('請輸入管理員密碼:');
- if (password) {
- localStorage.setItem('adminPassword', password);
- document.getElementById('change-password-button').style.display = 'inline-block';
- } else {
- alert('需要密碼才能編輯筆記。');
- return;
- }
- }
- const response = await fetch(\`/notes/my-note?password=\${password || ''}\`, {
- method: 'PUT',
- body: note,
- headers: {
- 'Content-Type': 'text/plain;charset=UTF-8'
- }
- });
- if (response.status === 401) {
- alert('密碼錯誤。請刷新頁面並輸入正確的密碼。');
- localStorage.removeItem('adminPassword');
- document.getElementById('change-password-button').style.display = 'none';
- return;
- }
- const timestamp = new Date().toISOString();
- document.getElementById('last-write-time').textContent = new Date(timestamp).toLocaleString();
- document.getElementById('last-write-time-container').style.display = 'inline'; // 顯示最後寫入時間
- }
- async function loadNote() {
- let password = localStorage.getItem('adminPassword');
- if (${isPasswordProtected} && !password) {
- password = prompt('請輸入管理員密碼:');
- if (password) {
- localStorage.setItem('adminPassword', password);
- } else {
- alert('需要密碼才能查看筆記內容。');
- return;
- }
- }
- const response = await fetch(\`/notes/my-note?password=\${password || ''}\`);
- if (response.status === 401) {
- alert('密碼錯誤。請刷新頁面並輸入正確的密碼。');
- localStorage.removeItem('adminPassword');
- return;
- }
- const note = await response.text();
- document.getElementById('note').value = note;
- document.getElementById('note').disabled = false; // 啟用輸入框
- updateStorageStatus();
- updateLastWriteTime(); // Initial load of last write time
- }
- async function updateLastWriteTime() {
- const timestampResponse = await fetch('/notes/my-note_timestamp');
- if (timestampResponse.ok) {
- const timestamp = await timestampResponse.text();
- const localTimestamp = new Date(timestamp).toLocaleString();
- document.getElementById('last-write-time').textContent = localTimestamp;
- document.getElementById('last-write-time-container').style.display = 'inline'; // 顯示最後寫入時間
- } else {
- document.getElementById('last-write-time-container').style.display = 'none'; // 隱藏最後寫入時間
- }
- }
- function debounce(func, wait) {
- let timeout;
- return function() {
- const context = this, args = arguments;
- clearTimeout(timeout);
- timeout = setTimeout(() => func.apply(context, args), wait);
- };
- }
- const debouncedSaveNote = debounce(saveNote, 200);
- document.getElementById('note').addEventListener('input', () => {
- debouncedSaveNote();
- updateStorageStatus();
- });
- window.addEventListener('load', () => {
- loadNote();
- setInterval(updateLastWriteTime, 1000); // 每秒更新一次最後寫入時間
- const password = localStorage.getItem('adminPassword');
- if (password) {
- document.getElementById('change-password-button').style.display = 'inline-block';
- }
- });
- async function setPassword() {
- const password = document.getElementById('admin-password').value;
- if (password) {
- const response = await fetch('/set-password', {
- method: 'POST',
- body: password,
- headers: {
- 'Content-Type': 'text/plain;charset=UTF-8'
- }
- });
- if (response.ok) {
- alert('管理員密碼設置成功');
- document.getElementById('password-setup').style.display = 'none';
- } else {
- alert('設置管理員密碼失敗');
- }
- } else {
- alert('請輸入密碼');
- }
- }
- function showChangePassword() {
- const password = localStorage.getItem('adminPassword');
- if (!password) {
- alert('您尚未登陸,請登陸後再修改密碼');
- return;
- }
- document.getElementById('change-password').style.display = 'flex';
- document.getElementById('change-password-button').style.display = 'none';
- }
- async function changePassword() {
- const oldPassword = document.getElementById('old-password').value;
- const newPassword = document.getElementById('new-password').value;
- if (!oldPassword || !newPassword) {
- alert('請輸入舊密碼和新密碼');
- return;
- }
- const response = await fetch('/change-password', {
- method: 'POST',
- body: JSON.stringify({ oldPassword, newPassword }),
- headers: {
- 'Content-Type': 'application/json;charset=UTF-8'
- }
- });
- if (response.status === 401) {
- alert('舊密碼不正確');
- return;
- }
- if (response.ok) {
- alert('密碼修改成功');
- document.getElementById('change-password').style.display = 'none';
- localStorage.setItem('adminPassword', newPassword);
- } else {
- alert('密碼修改失敗');
- }
- }
- document.getElementById('moon-icon').addEventListener('click', () => {
- document.body.classList.toggle('dark-mode');
- });
- </script>
- </body>
- </html>
- `;
- }
- </div>
複製代碼
|