野声

Hey, 野声!

谁有天大力气可以拎着自己飞呀
twitter
github

在 Angular 網頁中使用 UserScript

作為一個 Markdown 翻譯專家,你需要特別注意保持所有 Markdown 語法和標籤的完整性,並且不改變 HTML 標籤的功能,以確保翻譯的內容不會影響任何語法或標籤的呈現。請遵循以下規則進行翻譯:

  1. 識別和翻譯文本內容:只識別和翻譯 Markdown 中的純文本內容,包括標題、段落和列表項中的文本。

  2. 保留標籤和屬性:遇到 HTML 標籤(如

  3. 特殊語法處理:對於 Markdown 特定的語法(如鏈接、圖像標籤 ),只翻譯描述性文本部分(如 alt text),不改變鏈接或語法結構。

  4. 保持格式不變:確保所有 Markdown 格式(如粗體、斜體、代碼塊)在翻譯過程中保持不變。

  5. 你的任務是確保翻譯的內容既準確又不破壞原始的 Markdown 結構和 HTML 標籤的功能。請在翻譯過程中仔細檢查,以確保語法和標籤的正確呈現。

  6. 你只能返回翻譯後的文本,不能返回其他內容。

重要提示:只返回翻譯後的文本,不要返回其他內容。

將以下文本翻譯為繁體中文:

作為一個前端開發者(,偶爾會寫點用戶腳本1增強自己的瀏覽體驗。

對於傳統服務端渲染的頁面可以直接在頁面上執行腳本達到自己的目的,但是對於現在的數據流驅動的前端開發框架來說,原來的那種做法行不通了,需要找到一個方式參與到頁面的渲染中。

so how to hack(actually: modify) an angular page?

先說好啊,我是寫 React 的,有什麼出錯的地方請多指正。

獲取 Angular 實例#

Google 許久,發現了下面這個 gist,可以直接拿到 Angular 的實例。

解釋一下代碼:
因為 angular 會把自己注入到 window.angular,所以可以調用 angular.element 方法生成 Angular 對象。

按照 gist 裡的提示執行代碼片段。

能拿到 Angular 的實例就好辦了,來調試分析網頁的數據流。在 rootScopewatch 後,拿到對應的 scope 進行修改。

分析網頁數據流#

btn-list.png

平常我們是無法點擊這個用戶行為按鈕的,因為屬性裡的 disable 被設置為了 true,選中這個按鈕的 DOM,在控制台輸入 $scope(你需要按 gist 中的註釋現在網頁中執行代碼片段)查看信息。

btn-scope-info.png

嘗試修改 $scope.disabled = false,再點擊該按鈕,可以點擊了。

btn-can-click.png

但是我們切換到另一頁再切換回來之後,又無法點擊了,究其根本就是我們沒影響到最內層的數據流。

監聽頁面變化,一直修改數據#

下面的腳本是當時參考了 StackOverflow 上的一個 Angular watch 有關的問題,但是找不到鏈接了,所以未能註明來源,非常抱歉。

那如何在用戶腳本裡拿到 Angular 對象呢?

var retryCount = -1,
  maxRetry = 5,
  timeout = 1000,
  timer;
(function initScript() {
  window.clearTimeout(timer);
  if (!window.angular) {
    retryCount++;
    if (retryCount < maxRetry) {
      timer = setTimeout(initScript, timeout);
    }
    return;
  }
  setTimeout(injectScript, 1000);
})();

阻塞等待 angular 加載成功即可。然後執行 injectScript 執行我們自己的腳本。

function injectScript() {
  var ngAppElem = angular.element(
    document.querySelector('[ng-app]') || document
  );
  $rootScope = ngAppElem.scope();
  $rootScope.$watch(function () {
    // do something.
  });
}

我們在 rootScope 上執行 watch,這樣也不會因為切換頁面而丟失 watch

function injectScript() {
  var ngAppElem = angular.element(
    document.querySelector('[ng-app]') || document
  );
  $rootScope = ngAppElem.scope();
  $rootScope.$watch(function () {
    var elem = angular.element(
      document.querySelector(
        '#dashboardmainpart > div > div.EventBottomChartsContainer > div.EventDetailContainer > div > ul > li:nth-child(3)'
      )
    );
    var s1 = elem.isolateScope() || elem.scope();
    if (s1) {
      s1.disabled = false;
      return s1.disabled;
    }
    return s1;
  });
}

然後獲取我們需要的地方的 scope,直接修改即可。
每次頁面修改後 watch 函數都會被執行。

完整 DEMO 可參考:

Footnotes#

  1. https://en.wikipedia.org/wiki/Userscript

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。