Clash 中文网搜索

Clash Verge Rev 扩展脚本(Script)教程:用 JavaScript 修改订阅

Clash 中文网编辑部 · 更新于 2026/10/22 · 对照版本 Clash Verge Rev v2.5.8

扩展脚本是一段 JavaScript,Clash Verge Rev 会调用其中的 main(config, profileName) 函数,把订阅配置作为对象传进来,你修改后 return 回去即可。 它比 Merge 更灵活,可以追加、过滤、按条件批量处理。打开方式:

  • 右键订阅卡片 →「扩展脚本」:只对该订阅生效;
  • 订阅页顶部「全局扩展脚本」:对所有订阅生效。

脚本结构

新建的脚本默认内容如下:

// Define main function (script entry)

function main(config, profileName) {
  return config;
}
部分 说明
main 入口函数,名字不能改
config 当前配置对象,结构与 YAML 一一对应
profileName 当前订阅的名称
return config 必须返回一个配置对象

config 对象长什么样

YAML 配置会被转换成 JavaScript 对象。例如:

proxies:
  - name: 香港01
    type: ss
proxy-groups:
  - name: 节点选择
    type: select
    proxies: [香港01]
rules:
  - MATCH,节点选择

在脚本中对应:

YAML JavaScript
proxies config.proxies(数组,每项是对象)
proxy-groups config["proxy-groups"](名字带横线,要用方括号)
rules config.rules(字符串数组)
dns.nameserver config.dns.nameserver

带横线的字段名(proxy-groups、rule-providers、proxy-providers)必须用 config["proxy-groups"] 方括号写法。

执行顺序

订阅原文 → 全局扩展配置 → 全局扩展脚本 → 订阅扩展配置 → 订阅扩展脚本 → 交给内核

订阅扩展脚本是“应用设置回写前的最后一个扩展步骤”,可以修改前面所有步骤的结果。

常用示例

1. 在最前面追加规则

function main(config) {
  const myRules = [
    "DOMAIN-SUFFIX,openai.com,节点选择",
    "DOMAIN-SUFFIX,anthropic.com,节点选择",
    "DOMAIN-SUFFIX,corp.example.com,DIRECT",
    "PROCESS-NAME,qbittorrent.exe,DIRECT",
  ];
  config.rules = [...myRules, ...(config.rules || [])];
  return config;
}

把 节点选择 换成你的订阅中实际存在的代理组名称。用 ... 展开符把自定义规则放在前面,订阅原有规则放在后面。

2. 删除名称含“过期”“剩余”的信息节点

function main(config) {
  const bad = /过期|剩余|官网|到期|流量|重置/;
  const removed = new Set();
  config.proxies = (config.proxies || []).filter((p) => {
    if (bad.test(p.name)) {
      removed.add(p.name);
      return false;
    }
    return true;
  });
  // 同时从所有代理组中移除这些节点
  for (const g of config["proxy-groups"] || []) {
    if (Array.isArray(g.proxies)) {
      g.proxies = g.proxies.filter((n) => !removed.has(n));
    }
  }
  return config;
}

注意:删除节点后必须同时从代理组中移除,否则内核会报“找不到节点”的错误。

3. 按地区新建自动选择代理组

function main(config) {
  const regions = [
    { name: "香港自动", re: /港|HK|Hong Kong/i },
    { name: "日本自动", re: /日本|JP|Japan/i },
    { name: "美国自动", re: /美国|US|United States/i },
  ];
  const names = (config.proxies || []).map((p) => p.name);
  const newGroups = [];
  for (const r of regions) {
    const list = names.filter((n) => r.re.test(n));
    if (list.length) {
      newGroups.push({
        name: r.name,
        type: "url-test",
        proxies: list,
        url: "https://www.gstatic.com/generate_204",
        interval: 300,
        tolerance: 50,
      });
    }
  }
  config["proxy-groups"].push(...newGroups);
  // 把新组加入第一个手动选择组,方便在代理页选择
  const selector = config["proxy-groups"].find((g) => g.type === "select");
  if (selector) selector.proxies.unshift(...newGroups.map((g) => g.name));
  return config;
}

4. 节点重命名(加上国旗)

function main(config) {
  const flags = [
    [/港|HK/i, "🇭🇰"],
    [/日本|JP/i, "🇯🇵"],
    [/美国|US/i, "🇺🇸"],
    [/新加坡|SG/i, "🇸🇬"],
  ];
  const rename = new Map();
  for (const p of config.proxies || []) {
    const hit = flags.find(([re]) => re.test(p.name));
    if (hit && !p.name.startsWith(hit[1])) {
      const newName = `${hit[1]} ${p.name}`;
      rename.set(p.name, newName);
      p.name = newName;
    }
  }
  // 同步更新代理组中的引用
  for (const g of config["proxy-groups"] || []) {
    if (Array.isArray(g.proxies)) g.proxies = g.proxies.map((n) => rename.get(n) || n);
  }
  return config;
}

改名后同样必须更新代理组中的引用。

5. 修改 DNS 与嗅探

function main(config) {
  config.dns = {
    ...config.dns,
    enable: true,
    "enhanced-mode": "fake-ip",
    nameserver: ["https://dns.alidns.com/dns-query", "https://doh.pub/dns-query"],
  };
  config.sniffer = {
    enable: true,
    sniff: {
      HTTP: { ports: [80, "8080-8880"], "override-destination": true },
      TLS: { ports: [443, 8443] },
      QUIC: { ports: [443, 8443] },
    },
  };
  return config;
}

6. 只对某个订阅生效(写在全局脚本中)

function main(config, profileName) {
  if (profileName !== "我的机场") return config;
  // ……只对名为“我的机场”的订阅执行的修改
  return config;
}

profileName 就是订阅卡片上显示的名称。

7. 为所有订阅统一添加 AI 专用组和规则

function main(config) {
  const groups = config["proxy-groups"] || [];
  const selector = groups.find((g) => g.type === "select");
  if (!selector) return config;
  groups.unshift({
    name: "AI 服务",
    type: "select",
    proxies: [selector.name, ...(config.proxies || []).map((p) => p.name).filter((n) => /美国|US/i.test(n))],
  });
  config.rules = ["GEOSITE,openai,AI 服务", "GEOSITE,anthropic,AI 服务", ...(config.rules || [])];
  return config;
}

把它放进全局扩展脚本,无论切换到哪个订阅都会自动拥有“AI 服务”组。

调试脚本

使用 console.log

function main(config) {
  console.log("节点数量:", (config.proxies || []).length);
  console.log("代理组:", (config["proxy-groups"] || []).map((g) => g.name));
  return config;
}

保存后,在编辑器的「脚本控制台输出」中查看打印的内容和错误信息。

查看最终结果

保存后点击订阅页「查看运行时订阅」,确认修改是否符合预期。

常见错误

错误 原因
Cannot read properties of undefined 访问了不存在的字段,加 `
代理组引用了不存在的节点 删除或重命名节点后没有同步更新代理组
脚本没有效果 忘记 return config,或 main 函数名写错
端口等设置没变 这些字段由应用设置接管,脚本修改无效

脚本写坏了怎么恢复

把内容改回默认模板:

function main(config, profileName) {
  return config;
}

保存即可恢复原样。如果开启了「关键变更时自动备份」,也可以从 备份 中恢复全局脚本。

注意事项

  • 脚本运行在受限的 JavaScript 环境中,不能访问网络、文件;
  • 由应用设置接管的字段(端口、allow-lan、mode、log-level、ipv6、external-controller、secret、unified-delay)在脚本里修改不会生效;
  • 脚本每次激活订阅时都会运行,避免写非常耗时的逻辑。

相关教程

常见问题

脚本报错导致订阅加载失败怎么办?

打开扩展脚本编辑器查看「脚本控制台输出」中的错误信息;最简单的恢复办法是把脚本改回只有 return config 的初始模板。

扩展脚本和扩展覆写配置该用哪个?

只是覆盖几个字段用 Merge 更简单;需要追加、过滤、按条件批量处理时用脚本。

脚本里能联网请求吗?

不能。脚本运行在受限的 JavaScript 环境中,只能处理传入的配置对象,不能访问网络或文件。

需要会编程才能用吗?

照抄本文示例并修改其中的名称即可满足大多数需求。理解基本的 JavaScript 数组和对象操作会更得心应手。

还没安装 Clash Verge Rev?

最新版 v2.5.8,直链 GitHub 官方安装包。

前往下载