搜尋
首頁web前端js教程建置網站攔截跨瀏覽器擴展

在本文中,我將解釋建立用於阻止網站的瀏覽器擴充功能的逐步過程,並描述我遇到的挑戰和我提出的解決方案。這並不是一份詳盡的指南。我並不聲稱自己是任何方面的專家。我只是想分享我建構這個專案背後的思考過程。因此,對這裡的一切都持保留態度。我不會涵蓋每一行,而是專注於專案的關鍵點、困難、有趣的案例和專案的怪癖。歡迎您自己更詳細地探索原始碼。


目錄:

  • 前言
  • 設定項目
  • 建立主輸入表單
  • 處理 URL 屏蔽
  • 建立選項頁
  • 實作嚴格模式
  • 結論

前言

就像許多人一樣,我很難專注於不同的任務,尤其是在網路成為無所不在的干擾因素的情況下。幸運的是,作為一名程式設計師,我已經培養了出色的解決問題的技能,因此我決定,我不去尋找更好的現有解決方案,而是創建自己的瀏覽器擴充功能來阻止用戶想要限制訪問的網站。
首先,讓我們概述一下要求和主要特徵。擴充必須:

  • 跨瀏覽器。
  • 將網站從黑名單中封鎖。
  • 允許選擇阻止選項:阻止整個網域及其子網域或僅封鎖所選 URL。
  • 提供停用被封鎖網站的功能,而無需將其從黑名單中刪除。
  • 提供一個選項,以便在使用者舊病復發或忘記重新啟用已停用的 URL 時自動限制存取(對患有 ADHD 的人很有幫助)。

設定項目

首先,這是我選擇的主堆疊:

  • TypeScript:我選擇了 TS 而不是 JS,因為有大量不熟悉的 API 用於擴充而沒有自動完成功能。
  • Webpack:與用於 TS 編譯的 tsc 相比,在此上下文中更容易使用。此外,我在使用 tsc.
  • 產生相容瀏覽器的 JS 時遇到了問題
  • CSS:Vanilla CSS 符合我的目標,即簡單、更小的套件大小和最小的依賴關係。另外,我覺得對於只有幾頁的擴充來說,其他任何東西都太過分了。基於這些原因,我也決定不使用 React 等工具或特定的擴充建置框架。

擴充功能開發與常規 Web 開發的主要區別在於,擴充功能依賴於處理大多數事件、內容腳本以及它們之間的訊息傳遞的服務工作者。

建立清單

為了支援跨瀏覽器功能,我建立了兩個清單檔案:

  • manifest.chrome.json: Chrome 的 Manifest v3 要求。
  • manifest.firefox.json:適用於 Firefox,更好地支援 Manifest v2。 這是兩份文件之間的主要區別:

manifest.chrome.json:

{
  "manifest_version": 3,
  "action": {
    "default_title": "Click to show the form"
  },
  "incognito": "split",
  "permissions": [
    "activeTab",
    "declarativeNetRequestWithHostAccess",
    "scripting",
    "storage",
    "tabs"
  ],
  "host_permissions": ["*://*/"], // get access to all URLs
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"]
  }],
  "web_accessible_resources": [
    {
      "resources": ["blocked.html", "options.html", "about.html", "icons/*.svg"],
      "matches": ["<all_urls>"]
    }
  ],
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
}
</all_urls></all_urls>

manifest.firefox.json:

{
  "manifest_version": 2,
  "browser_action": {
    "default_title": "Click to show the form"
  },
  "permissions": [
    "activeTab",
    "declarativeNetRequest",
    "declarativeNetRequestWithHostAccess",
    "scripting", 
    "storage",
    "tabs",
    "*://*/"
  ],
  "background": {
    "scripts": [
      "background.js"
    ],
    "persistent": false
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": [
      "options.js",
      "blocked.js",
      "about.js"
    ]
  }],
  "web_accessible_resources": [
    "blocked.html",
    "options.html", 
    "icons/*.svg"
  ],
  "content_security_policy": "script-src 'self'; object-src 'self'",
}
</all_urls>

這裡一件有趣的事情是 Chrome 需要“incognito”:“split”,該屬性指定為在隱身模式下正常工作,而 Firefox 沒有它也可以正常工作。

這是擴充的基本檔案結構:

dist/
node_modules/
src/
|-- background.tsc
|-- content.ts
static/
|-- manifest.chrome.json
|-- manifest.firefox.json
package.json
tsconfig.json
webpack.config.js

現在讓我們來談談擴充應該如何運作。使用者應該能夠觸發某種表單來提交他想要封鎖的 URL。當他訪問 URL 時,擴充功能將攔截該請求並檢查是否應該阻止或允許該請求。它還需要某種選項頁面,使用者可以在其中查看所有被封鎖 URL 的列表,並能夠從列表中新增、編輯、停用或刪除 URL。

建立主輸入表單

當使用者點擊擴充圖示或鍵入鍵盤快速鍵時,透過將 HTML 和 CSS 注入目前頁面來顯示表單。顯示表單的方式有多種,例如呼叫彈出窗口,但根據我的口味,它的自訂選項有限。後台腳本如下:

背景.ts:

import browser, { DeclarativeNetRequest } from 'webextension-polyfill';

// on icon click
const action = chrome.action ?? browser.browserAction; // Manifest v2 only has browserAction method
action.onClicked.addListener(tab => {
  triggerPopup(tab as browser.Tabs.Tab);
});

// on shortcut key press 
browser.commands.onCommand.addListener(command => {
  if (command === 'trigger_form') {
    browser.tabs.query({ active: true, currentWindow: true })
      .then((tabs) => {
        const tab = tabs[0];
        if (tab) {
          triggerPopup(tab);
        }
      })
      .catch(error => console.error(error));
  }
});

function triggerPopup(tab: browser.Tabs.Tab) {
  if (tab.id) {
    const tabId = tab.id;
    browser.scripting.insertCSS(({
      target: { tabId },
      files: ['global.css', './popup.css'],
    }))
      .then(() => {
        browser.scripting.executeScript
          ? browser.scripting.executeScript({
            target: { tabId },
            files: ['./content.js'], // refer to the compiled JS files, not the original TS ones 
          })
          : browser.tabs.executeScript({
            file: './content.js',
          });
      })
      .catch(error => console.error(error));
  }
}

將 HTML 注入每個頁面可能會導致不可預測的結果,因為很難預測不同樣式的網頁將如何影響表單。更好的替代方案似乎是使用 Shadow DOM,因為它創建了自己的樣式範圍。這絕對是我未來想要努力的潛在改進。

我使用 webextension-polyfill 來實作瀏覽器相容性。透過使用它,我不需要為不同版本的清單編寫單獨的擴充功能。您可以在此處閱讀有關其功能的更多資訊。為了使其正常工作,我在清單檔案中的其他腳本之前包含了 browser-polyfill.js 檔案。

manifest.chrome.json:

{
  "content_scripts": [{
    "js": ["browser-polyfill.js"]
  }],
}

manifest.firefox.json:

{
  "background": {
    "scripts": [
      "browser-polyfill.js",
      // other scripts
    ],
  },
  "content_scripts": [{
    "js": [
      "browser-polyfill.js",
      // other scripts
    ]
  }],
}

注入表單的過程是一種簡單的 DOM 操作,但請注意,每個元素必須單獨創建,而不是將一個模板文字應用於元素。雖然更加冗長乏味,但此方法避免了我們在瀏覽器中嘗試執行編譯後的程式碼時收到的不安全 HTML 注入警告。

content.ts:

import browser from 'webextension-polyfill';
import { maxUrlLength, minUrlLength } from "./globals";
import { GetCurrentUrl, ResToSend } from "./types";
import { handleFormSubmission } from './helpers';

async function showPopup() {
  const body = document.body;
  const formExists = document.getElementById('extension-popup-form');
  if (!formExists) {
    const msg: GetCurrentUrl = { action: 'getCurrentUrl' };

    try {
      const res: ResToSend = await browser.runtime.sendMessage(msg);

      if (res.success && res.url) {
        const currUrl: string = res.url;
        const popupForm = document.createElement('form');
        popupForm.classList.add('extension-popup-form');
        popupForm.id = 'extension-popup-form';

        /* Create every child element the same way as above */

        body.appendChild(popupForm);
        popupForm.addEventListener('submit', (e) => {
          e.preventDefault();
          handleFormSubmission(popupForm, handleSuccessfulSubmission); // we'll discuss form submission later
        });
        document.addEventListener('keydown', (e) => {
          if (e.key === 'Escape') {
            if (popupForm) {
              body.removeChild(popupForm);
            }
          }
        });
      }
    } catch (error) {
      console.error(error);
      alert('Something went wrong. Please try again.');
    }
  }
}

function handleSuccessfulSubmission() {
  hidePopup();
  setTimeout(() => {
    window.location.reload();
  }, 100); // need to wait a little bit in order to see the changes
}

function hidePopup() {
  const popup = document.getElementById('extension-popup-form');
  popup && document.body.removeChild(popup);
}

現在是時候確保表單顯示在瀏覽器中了。為了執行所需的編譯步驟,我像這樣設定了 Webpack:

webpack.config.ts:

{
  "manifest_version": 3,
  "action": {
    "default_title": "Click to show the form"
  },
  "incognito": "split",
  "permissions": [
    "activeTab",
    "declarativeNetRequestWithHostAccess",
    "scripting",
    "storage",
    "tabs"
  ],
  "host_permissions": ["*://*/"], // get access to all URLs
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"]
  }],
  "web_accessible_resources": [
    {
      "resources": ["blocked.html", "options.html", "about.html", "icons/*.svg"],
      "matches": ["<all_urls>"]
    }
  ],
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
}
</all_urls></all_urls>

基本上,它從我執行的命令的環境變數中取得瀏覽器名稱,以在 2 個清單檔案之間進行選擇,並將 TypeScript 程式碼編譯到 dist/ 目錄中。

我本來打算為擴充功能編寫適當的測試,但我發現 Puppeteer 不支援內容腳本測試,因此無法測試大多數功能。如果您知道內容腳本測試的任何解決方法,我很樂意在評論中聽到它們。

package.json 中我的建置指令是:

{
  "manifest_version": 2,
  "browser_action": {
    "default_title": "Click to show the form"
  },
  "permissions": [
    "activeTab",
    "declarativeNetRequest",
    "declarativeNetRequestWithHostAccess",
    "scripting", 
    "storage",
    "tabs",
    "*://*/"
  ],
  "background": {
    "scripts": [
      "background.js"
    ],
    "persistent": false
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": [
      "options.js",
      "blocked.js",
      "about.js"
    ]
  }],
  "web_accessible_resources": [
    "blocked.html",
    "options.html", 
    "icons/*.svg"
  ],
  "content_security_policy": "script-src 'self'; object-src 'self'",
}
</all_urls>

所以,例如,每當我跑步時

dist/
node_modules/
src/
|-- background.tsc
|-- content.ts
static/
|-- manifest.chrome.json
|-- manifest.firefox.json
package.json
tsconfig.json
webpack.config.js

Chrome 的檔案被編譯到 dist/ 目錄中。透過點擊操作圖示或按快捷鍵在任何網站上觸發表單後,表單如下所示:

Main form display

處理 URL 區塊

現在主表單已準備就緒,接下來的任務是提交它。為了實現阻止功能,我利用了 declarativeNetRequest API 和動態規則。這些規則將儲存在擴充功能的儲存中。操作動態規則只能在服務工作線程文件中進行,因此為了在服務工作線程和內容腳本之間交換數據,我將在它們之間發送帶有必要數據的訊息。由於此擴充功能需要相當多類型的操作,因此我為每個操作建立了類型。這是一個範例操作類型:

types.ts:

import browser, { DeclarativeNetRequest } from 'webextension-polyfill';

// on icon click
const action = chrome.action ?? browser.browserAction; // Manifest v2 only has browserAction method
action.onClicked.addListener(tab => {
  triggerPopup(tab as browser.Tabs.Tab);
});

// on shortcut key press 
browser.commands.onCommand.addListener(command => {
  if (command === 'trigger_form') {
    browser.tabs.query({ active: true, currentWindow: true })
      .then((tabs) => {
        const tab = tabs[0];
        if (tab) {
          triggerPopup(tab);
        }
      })
      .catch(error => console.error(error));
  }
});

function triggerPopup(tab: browser.Tabs.Tab) {
  if (tab.id) {
    const tabId = tab.id;
    browser.scripting.insertCSS(({
      target: { tabId },
      files: ['global.css', './popup.css'],
    }))
      .then(() => {
        browser.scripting.executeScript
          ? browser.scripting.executeScript({
            target: { tabId },
            files: ['./content.js'], // refer to the compiled JS files, not the original TS ones 
          })
          : browser.tabs.executeScript({
            file: './content.js',
          });
      })
      .catch(error => console.error(error));
  }
}

由於能夠從主表單和選項頁面新增 URL 是合理的,因此提交是由新檔案中的可重複使用函數執行的:

helpers.ts:

{
  "content_scripts": [{
    "js": ["browser-polyfill.js"]
  }],
}

我在 content.ts 中呼叫 handleFormSubmission() 來驗證提供的 URL,然後將其傳送到 Service Worker 以將其新增至黑名單中。

動態規則設定了需要考慮的最大大小。嘗試為其保存動態規則時,傳遞太長的 URL 字串將導致意外行為。我發現就我而言,75 個字元長的 URL 是規則的最佳最大長度。

以下是 Service Worker 將如何處理收到的訊息:

背景.ts:

{
  "background": {
    "scripts": [
      "browser-polyfill.js",
      // other scripts
    ],
  },
  "content_scripts": [{
    "js": [
      "browser-polyfill.js",
      // other scripts
    ]
  }],
}

為了提交,我建立了一個新的規則物件並更新動態規則以包含它。一個簡單的條件正規表示式允許我選擇阻止整個網域或僅阻止指定的 URL。

完成後,我將回應訊息傳回內容腳本。這段程式碼中最有趣的是 nanoid 的使用。透過反覆試驗,我發現動態規則的數量是有限制的 - 較舊的瀏覽器為 5000 個,較新的瀏覽器為 30000 個。當我嘗試將 ID 分配給大於 5000 的規則時,我發現了一個錯誤。我無法為我的 ID 建立低於 4999 的限制,因此我必須將我的 ID 限制為 3 位數字( 0-999,即總共 1000 個唯一 ID)。這意味著我將擴展程序的規則總數從5000 條減少到1000 條,一方面這非常重要,但另一方面- 用戶擁有這麼多URL 進行阻止的可能性非常低,所以我決定接受這個不太優雅的解決方案。

現在,使用者可以將新的 URL 新增到黑名單中,並選擇他想要指派給它們的封鎖類型。如果他嘗試存取被封鎖的資源,他將被重新導向到封鎖頁面:

Block page

但是,有一個邊緣情況需要解決。如果使用者直接存取該擴充程序,該擴充功能將封鎖任何不必要的 URL。但如果該網站是具有客戶端重定向的 SPA,則擴充功能將無法捕獲那裡的禁止 URL。為了處理這種情況,我更新了 background.ts 以偵聽目前標籤並查看 URL 是否已變更。發生這種情況時,我會手動檢查該 URL 是否在黑名單中,如果是,我會重新導向使用者。

背景.ts:

{
  "manifest_version": 3,
  "action": {
    "default_title": "Click to show the form"
  },
  "incognito": "split",
  "permissions": [
    "activeTab",
    "declarativeNetRequestWithHostAccess",
    "scripting",
    "storage",
    "tabs"
  ],
  "host_permissions": ["*://*/"], // get access to all URLs
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"]
  }],
  "web_accessible_resources": [
    {
      "resources": ["blocked.html", "options.html", "about.html", "icons/*.svg"],
      "matches": ["<all_urls>"]
    }
  ],
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
}
</all_urls></all_urls>

getRules() 是一個利用 declarativeNetRequest.getDynamicRules() 方法來檢索所有動態規則清單的函數,我將其轉換為更易讀的格式。

現在,擴充功能可以正確阻止直接存取和透過 SPA 存取的 URL。

建立選項頁面

選項頁面介面簡潔,如下圖:

Options page

這是具有主要功能的頁面,例如編輯、刪除、停用和套用嚴格模式。這是我的接線方式。

編輯和刪除功能

編輯可能是最複雜的任務。使用者可以透過修改字串或變更其封鎖類型(阻止整個網域或僅阻止特定網域)來編輯 URL。編輯時,我將編輯的 URL 的 ID 收集到一個陣列中。儲存後,我建立更新的動態規則,並將其傳遞給服務工作人員以套用變更。每次儲存變更或重新載入後,我都會重新取得動態規則並將其呈現在表中。下面是它的簡化版本:

options.ts:

{
  "manifest_version": 3,
  "action": {
    "default_title": "Click to show the form"
  },
  "incognito": "split",
  "permissions": [
    "activeTab",
    "declarativeNetRequestWithHostAccess",
    "scripting",
    "storage",
    "tabs"
  ],
  "host_permissions": ["*://*/"], // get access to all URLs
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"]
  }],
  "web_accessible_resources": [
    {
      "resources": ["blocked.html", "options.html", "about.html", "icons/*.svg"],
      "matches": ["<all_urls>"]
    }
  ],
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'self'"
  },
}
</all_urls></all_urls>

我決定是否阻止或允許特定規則的方法只是有條件地檢查其 isActive 屬性。更新規則和檢索規則 - 這是新增到我的後台偵聽器中的另外 2 個操作:

背景.ts:

{
  "manifest_version": 2,
  "browser_action": {
    "default_title": "Click to show the form"
  },
  "permissions": [
    "activeTab",
    "declarativeNetRequest",
    "declarativeNetRequestWithHostAccess",
    "scripting", 
    "storage",
    "tabs",
    "*://*/"
  ],
  "background": {
    "scripts": [
      "background.js"
    ],
    "persistent": false
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": [
      "options.js",
      "blocked.js",
      "about.js"
    ]
  }],
  "web_accessible_resources": [
    "blocked.html",
    "options.html", 
    "icons/*.svg"
  ],
  "content_security_policy": "script-src 'self'; object-src 'self'",
}
</all_urls>

更新功能要正確執行有點棘手,因為當編輯的 URL 成為現有規則的重複時,就會出現邊緣情況。除此之外,都是相同的內容 - 更新動態規則並在完成後發送適當的訊息。

刪除 URL 可能是最簡單的任務。此擴充功能中有兩種刪除類型:刪除特定規則和刪除所有規則。

選項.ts:

dist/
node_modules/
src/
|-- background.tsc
|-- content.ts
static/
|-- manifest.chrome.json
|-- manifest.firefox.json
package.json
tsconfig.json
webpack.config.js

並且,就像以前一樣,我為 Service Worker 監聽器添加了另外 2 個操作:

背景.ts:

import browser, { DeclarativeNetRequest } from 'webextension-polyfill';

// on icon click
const action = chrome.action ?? browser.browserAction; // Manifest v2 only has browserAction method
action.onClicked.addListener(tab => {
  triggerPopup(tab as browser.Tabs.Tab);
});

// on shortcut key press 
browser.commands.onCommand.addListener(command => {
  if (command === 'trigger_form') {
    browser.tabs.query({ active: true, currentWindow: true })
      .then((tabs) => {
        const tab = tabs[0];
        if (tab) {
          triggerPopup(tab);
        }
      })
      .catch(error => console.error(error));
  }
});

function triggerPopup(tab: browser.Tabs.Tab) {
  if (tab.id) {
    const tabId = tab.id;
    browser.scripting.insertCSS(({
      target: { tabId },
      files: ['global.css', './popup.css'],
    }))
      .then(() => {
        browser.scripting.executeScript
          ? browser.scripting.executeScript({
            target: { tabId },
            files: ['./content.js'], // refer to the compiled JS files, not the original TS ones 
          })
          : browser.tabs.executeScript({
            file: './content.js',
          });
      })
      .catch(error => console.error(error));
  }
}

實施嚴格模式

該擴充功能的主要功能可能是能夠為需要更嚴格控制其瀏覽習慣的人自動強制執行停用(允許存取)規則阻止。這個想法是,當嚴格模式關閉時,用戶禁用的任何 URL 將保持停用狀態,直到用戶更改它。啟用嚴格模式後,任何已停用的規則將在 1 小時後自動重新啟用。為了實現這樣的功能,我使用擴展的本地儲存來儲存代表每個禁用規則的物件數組。每個物件都包含規則 ID、解除封鎖日期和 URL 本身。每當使用者存取新資源或刷新黑名單時,擴充功能都會先檢查儲存中是否有過期規則並進行相應更新。

選項.ts:

{
  "content_scripts": [{
    "js": ["browser-polyfill.js"]
  }],
}

isStrictModeOn 布林值也儲存在儲存中。如果這是真的,我會循環所有規則,並將那些被禁用的規則添加到儲存中,並為它們創建新的解鎖時間。然後,對於每個回應,我都會檢查儲存中是否有任何停用的規則,刪除過期的規則(如果存在),然後更新它們:

背景.ts:

{
  "background": {
    "scripts": [
      "browser-polyfill.js",
      // other scripts
    ],
  },
  "content_scripts": [{
    "js": [
      "browser-polyfill.js",
      // other scripts
    ]
  }],
}

完成後,網站攔截擴充就完成了。使用者可以新增、編輯、刪除和停用他們想要的任何 URL,應用程式部分或整個網域阻止,並使用嚴格模式來幫助他們在瀏覽中保持更多紀律。

Extension work example


結論

這是我的網站阻止擴充功能的基本概述。這是我的第一個擴展,這是一次有趣的經歷,特別是考慮到 Web 開發的世界有時會變得平凡。肯定有改進的空間和新功能。黑名單中 URL 的搜尋欄、添加適當的測試、嚴格模式的自訂持續時間、一次提交多個 URL - 這些只是我腦海中的一些事情,我想有一天添加到這個專案中。我最初也計劃使擴展程式跨平台,但無法使其在我的手機上運行。
如果您喜歡閱讀本演練、學到了新東西或有任何其他回饋,我們非常感謝您的評論。感謝您的閱讀。

原始碼
現場版

以上是建置網站攔截跨瀏覽器擴展的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Python vs. JavaScript:選擇合適的工具Python vs. JavaScript:選擇合適的工具May 08, 2025 am 12:10 AM

選擇Python還是JavaScript取決於項目類型:1)數據科學和自動化任務選擇Python;2)前端和全棧開發選擇JavaScript。 Python因其在數據處理和自動化方面的強大庫而備受青睞,而JavaScript則因其在網頁交互和全棧開發中的優勢而不可或缺。

Python和JavaScript:了解每個的優勢Python和JavaScript:了解每個的優勢May 06, 2025 am 12:15 AM

Python和JavaScript各有優勢,選擇取決於項目需求和個人偏好。 1.Python易學,語法簡潔,適用於數據科學和後端開發,但執行速度較慢。 2.JavaScript在前端開發中無處不在,異步編程能力強,Node.js使其適用於全棧開發,但語法可能複雜且易出錯。

JavaScript的核心:它是在C還是C上構建的?JavaScript的核心:它是在C還是C上構建的?May 05, 2025 am 12:07 AM

javascriptisnotbuiltoncorc; sanInterpretedlanguagethatrunsonenginesoftenwritteninc.1)JavascriptwasdesignedAsignedAsalightWeight,drackendedlanguageforwebbrowsers.2)Enginesevolvedfromsimpleterterpretpretpretpretpreterterpretpretpretpretpretpretpretpretpretcompilerers,典型地,替代品。

JavaScript應用程序:從前端到後端JavaScript應用程序:從前端到後端May 04, 2025 am 12:12 AM

JavaScript可用於前端和後端開發。前端通過DOM操作增強用戶體驗,後端通過Node.js處理服務器任務。 1.前端示例:改變網頁文本內容。 2.後端示例:創建Node.js服務器。

Python vs. JavaScript:您應該學到哪種語言?Python vs. JavaScript:您應該學到哪種語言?May 03, 2025 am 12:10 AM

選擇Python還是JavaScript應基於職業發展、學習曲線和生態系統:1)職業發展:Python適合數據科學和後端開發,JavaScript適合前端和全棧開發。 2)學習曲線:Python語法簡潔,適合初學者;JavaScript語法靈活。 3)生態系統:Python有豐富的科學計算庫,JavaScript有強大的前端框架。

JavaScript框架:為現代網絡開發提供動力JavaScript框架:為現代網絡開發提供動力May 02, 2025 am 12:04 AM

JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

JavaScript,C和瀏覽器之間的關係JavaScript,C和瀏覽器之間的關係May 01, 2025 am 12:06 AM

引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr

node.js流帶打字稿node.js流帶打字稿Apr 30, 2025 am 08:22 AM

Node.js擅長於高效I/O,這在很大程度上要歸功於流。 流媒體匯總處理數據,避免內存過載 - 大型文件,網絡任務和實時應用程序的理想。將流與打字稿的類型安全結合起來創建POWE

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器