欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解如何使用JavaScript獲取自動(dòng)消失的聯(lián)想詞

 更新時(shí)間:2024年06月11日 11:48:10   作者:洛小豆  
前幾天在做數(shù)據(jù)分析時(shí),我嘗試獲取某網(wǎng)站上輸入搜索詞后的聯(lián)想詞,輸入搜索詞后會(huì)彈出一個(gè)顯示聯(lián)想詞的框,有趣的是,輸入框失去焦點(diǎn)后,聯(lián)想詞彈框就自動(dòng)消失了,這種情況下該怎么辦呢,所以本文給大家介紹了如何使用JavaScript獲取自動(dòng)消失的聯(lián)想詞,需要的朋友可以參考下

我問題

前幾天在做數(shù)據(jù)分析時(shí),我嘗試獲取某網(wǎng)站上輸入搜索詞后的聯(lián)想詞,輸入搜索詞后會(huì)彈出一個(gè)顯示聯(lián)想詞的框。有趣的是,當(dāng)我嘗試通過按F12定位這個(gè)彈框在HTML中的位置時(shí),輸入框失去焦點(diǎn)后,聯(lián)想詞彈框就自動(dòng)消失了。我觀察到 HTML 代碼中div元素也從代碼中消失了。這種情況下,我該如何才能準(zhǔn)確地定位這個(gè)元素彈框并獲取其中的聯(lián)想詞呢?

動(dòng)畫.gif

解決方案

方法一:查找DOM節(jié)點(diǎn)

這算是最簡單的操作,通過調(diào)試框可以看到網(wǎng)頁dom結(jié)構(gòu)的變化,當(dāng)觸發(fā)聯(lián)想詞彈框時(shí),記下彈框?qū)?yīng)標(biāo)簽的類名或者id,然后查找得到這個(gè)標(biāo)簽的html代碼,從中解析出聯(lián)想詞。

const elementByClassName = document.querySelector(".luoxiaodou");
if (elementByClassName) {
    const htmlContent = elementByClassName.innerHTML;
    console.log(htmlContent);
}

輸入框獲取焦點(diǎn)時(shí),聯(lián)想詞彈框出現(xiàn),輸入框失去焦點(diǎn)時(shí),聯(lián)想詞彈框消失。咱們先給輸入框添加焦點(diǎn),彈框出現(xiàn)時(shí),運(yùn)行上面的代碼獲取節(jié)點(diǎn)對應(yīng)的html內(nèi)容。

這個(gè)想法很好,但是這里有一個(gè)問題:就是元素的加載需要時(shí)間,需要請求服務(wù)端獲取數(shù)據(jù),然后再加載出來。,如果是輸入框獲取焦點(diǎn)后立即去查找元素,大概率獲取的結(jié)果是空,所以這中間要有延遲的時(shí)間,咱們就說這坑大家有沒有踩過吧。

方法二:使用MutationObserver來監(jiān)視DOM變化

我還有兩個(gè)想法,第一個(gè)是:咱們能不能攔截一下網(wǎng)絡(luò),然后從服務(wù)器的響應(yīng)里頭撈點(diǎn)聯(lián)想詞出來?我個(gè)人覺得這招兒挺靠譜的,但目前還沒來得及試試。等我嘗試之后寫一下關(guān)于監(jiān)聽網(wǎng)絡(luò)請求獲取聯(lián)想詞的內(nèi)容,咱們就先記個(gè)賬,到時(shí)候一定補(bǔ)上。

另一種方式就是使用MutationObserver來監(jiān)視DOM變化,可以在控制臺中編寫一個(gè)JavaScript函數(shù),當(dāng)包含特定類的元素出現(xiàn)在DOM中時(shí),打印出該元素的HTML內(nèi)容。為此,你可以使用MutationObserver來監(jiān)視DOM變化。

而我選擇了另一種可能的解決方案,就是利用MutationObserver這個(gè)JavaScript API。一旦檢測到DOM中有特定類的元素出現(xiàn),就立即打印出它的HTML內(nèi)容。MutationObserver 是 JavaScript 自帶的 API,它用于監(jiān)視DOM樹的變化。這是瀏覽器原生支持的功能,包括我們常用的Chrome在內(nèi)。正好在插件開發(fā)中使用。

咱們可以創(chuàng)建一個(gè)函數(shù),傳參是標(biāo)簽選擇器和一個(gè)回調(diào)函數(shù),當(dāng)獲取到變化的網(wǎng)頁時(shí),調(diào)用回調(diào)函數(shù)解析獲取聯(lián)想詞。這里使用一個(gè)map集合,可以保證管理多個(gè)監(jiān)視器,以下是實(shí)現(xiàn)代碼:

const observers = new Map()

/**
 * 啟動(dòng)監(jiān)視指定選擇器的元素變化。
 * @param {string} selector - CSS選擇器,可以是類名(以`.`開頭)或ID(以`#`開頭)。
 * @param {function} callback - 回調(diào)函數(shù),當(dāng)符合選擇器的元素添加到DOM時(shí)調(diào)用。
 */
function startObserving(selector, callback) {
  /**
   * 觀察者回調(diào)函數(shù),監(jiān)視DOM樹的變化。
   * @param {MutationRecord[]} mutationsList - DOM變化記錄的列表。
   * @param {MutationObserver} observer - 觀察者實(shí)例。
   */
  const observerCallback = function (mutationsList, observer) {
    for (const mutation of mutationsList) {
      if (mutation.type === 'childList') {
        mutation.addedNodes.forEach((node) => {
          if (node.nodeType === Node.ELEMENT_NODE) {
            if (selector.startsWith('#') && node.id === selector.slice(1)) {
              callback(node.outerHTML)
            } else if (selector.startsWith('.') && node.classList.contains(selector.slice(1))) {
              callback(node.outerHTML)
            }
          }
        })
      }
    }
  }
  // 創(chuàng)建一個(gè)觀察者實(shí)例并開始觀察指定的目標(biāo)節(jié)點(diǎn)和配置
  const observer = new MutationObserver(observerCallback)
  // 觀察配置,配置對象指定我們希望觀察子節(jié)點(diǎn)的變化(`childList: true`)以及觀察整個(gè)子樹中的變化(`subtree: true`)
  const config = { childList: true, subtree: true }
  // 觀察整個(gè)文檔,所以將目標(biāo)節(jié)點(diǎn)設(shè)置為`document.body`。
  observer.observe(document.body, config)
  // 將觀察者存儲在Map中
  observers.set(selector, observer)

  // 設(shè)置定時(shí)器,指定時(shí)間后自動(dòng)停止觀察并刪除觀察者,回收資源
  setTimeout(() => {
    stopObserving(selector)
  }, 5 * 60 * 1000)
}


/**
 * 停止監(jiān)視指定選擇器的元素變化。
 * @param {string} selector - CSS選擇器,可以是類名(以`.`開頭)或ID(以`#`開頭)。
 */
function stopObserving(selector) {
    const observer = observers.get(selector);

    if (observer) {
        observer.disconnect();
        observers.delete(selector);
    }
}

export { startObserving, stopObserving };

然后就是在使用的地方,導(dǎo)入這些方法,傳一下參數(shù)就可以了,有一點(diǎn)要注意:回調(diào)函數(shù)中的參數(shù)是獲取到的網(wǎng)頁信息。

import { startObserving, stopObserving } from './element-observer.js';

// 通過類名啟動(dòng)監(jiān)視
startObserving('.xiaodou-class', (htmlContent) => {
    console.log('Element with class added:', htmlContent);
});

// 通過ID啟動(dòng)監(jiān)視
startObserving('#xiaodou-id', (htmlContent) => {
    console.log('Element with ID added:', htmlContent);
});

// 停止監(jiān)視
setTimeout(() => {
    stopObserving('.xiaodou-class');
    stopObserving('#xiaodou-id');
}, 6000);

你是不是以為這就結(jié)束?我當(dāng)時(shí)就是這么想的,但是還是有問題:從第二次開始獲取到的內(nèi)容是上一個(gè)輸入詞的聯(lián)想詞。假設(shè)第一次輸入“貓咪”,然后獲取的“貓咪”的聯(lián)想詞,第二次輸入“狗狗”,但是獲取的還是“貓咪”的聯(lián)想詞,第三次輸入“兔兔”,這次獲取的是“狗狗”的聯(lián)想詞,這是哪里出問題了呢?

接著咱們來分析一下原因,首先觀察一下聯(lián)想詞彈框的變化,比如下圖,修改”貓咪貍花貓“到”貓咪貍“的這個(gè)過程中,聯(lián)想詞彈框先出來跟”貓咪貍花貓“相關(guān)的內(nèi)容, 再請求服務(wù)器獲取”貓咪貍“的聯(lián)想詞,再更新彈框內(nèi)容。

動(dòng)畫.gif

當(dāng)頁面變動(dòng)時(shí),監(jiān)控頁面變化的函數(shù)會(huì)立即執(zhí)行,這個(gè)執(zhí)行速度是優(yōu)于請求服務(wù)器更新彈框內(nèi)容的速度,所以這里導(dǎo)致獲取的內(nèi)容是是上一個(gè)聯(lián)想詞的。

發(fā)現(xiàn)了問題,就好修改了,可以嘗試在 MutationObserver 回調(diào)函數(shù)中使用 setTimeout,以確保 DOM 完全渲染后再獲取 outerHTML。

/**
* 觀察者回調(diào)函數(shù),監(jiān)視DOM樹的變化。
* @param {MutationRecord[]} mutationsList - DOM變化記錄的列表。
* @param {MutationObserver} observer - 觀察者實(shí)例。
*/
const observerCallback = function (mutationsList, observer) {
for (const mutation of mutationsList) {
  if (mutation.type === 'childList') {
    mutation.addedNodes.forEach((node) => {
      if (node.nodeType === Node.ELEMENT_NODE) {
        if (selector.startsWith('#') && node.id === selector.slice(1)) {
          // 使用 setTimeout 確保 DOM 完全渲染后獲取 outerHTML
          setTimeout(() => callback(node.outerHTML), 1000);
        } else if (selector.startsWith('.') && node.classList.contains(selector.slice(1))) {
          // 使用 setTimeout 確保 DOM 完全渲染后獲取 outerHTML
          setTimeout(() => callback(node.outerHTML), 1000);
        }
      }
    });
  }
}

這里確實(shí)解決了問題,但是我還有一個(gè)疑問:為什么在修改”貓咪貍花貓“到”貓咪貍“的這個(gè)過程中,彈框內(nèi)容有兩次變化,觀察者只觸發(fā)了一次?,在上面的觀察者配置是希望觀察子節(jié)點(diǎn)的變化以及觀察整個(gè)子樹中的變化,這個(gè)變化不包含節(jié)點(diǎn)內(nèi)容的變化,不知道這樣理解對不對?

以上就是詳解如何使用JavaScript獲取自動(dòng)消失的聯(lián)想詞的詳細(xì)內(nèi)容,更多關(guān)于JavaScript獲取聯(lián)想詞的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Electron 使? electron-builder 打包應(yīng)用過程詳解

    Electron 使? electron-builder 打包應(yīng)用過程詳解

    Electron應(yīng)用開發(fā)中,electron-builder是一個(gè)常用的打包工具,提供了多種自定義配置,不過,使用npm安裝electron-builder時(shí)可能會(huì)遇到下載依賴慢或失敗的問題,本文給大家介紹Electron 使? electron-builder 打包應(yīng)用的相關(guān)操作,感興趣的朋友一起看看吧
    2024-10-10
  • javascript中日期轉(zhuǎn)換成時(shí)間戳的小例子

    javascript中日期轉(zhuǎn)換成時(shí)間戳的小例子

    javascript中日期轉(zhuǎn)換成時(shí)間戳的小例子,需要的朋友可以參考一下
    2013-03-03
  • 使用json對象轉(zhuǎn)化為key,value的對象數(shù)組

    使用json對象轉(zhuǎn)化為key,value的對象數(shù)組

    這篇文章主要介紹了使用json對象轉(zhuǎn)化為key,value的對象數(shù)組方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • JavaScript實(shí)現(xiàn)tab欄切換的效果

    JavaScript實(shí)現(xiàn)tab欄切換的效果

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)tab欄切換的效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • JS實(shí)現(xiàn)頁面打?。ㄕw、局部)

    JS實(shí)現(xiàn)頁面打印(整體、局部)

    本篇文章主要介紹了JS實(shí)現(xiàn)頁面打印(整體、局部),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • JavaScript壓縮并加密圖片的方法你了解嗎

    JavaScript壓縮并加密圖片的方法你了解嗎

    這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)學(xué)生成績管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • JS拖拽的進(jìn)一步練習(xí),移動(dòng)與拉伸實(shí)現(xiàn)代碼

    JS拖拽的進(jìn)一步練習(xí),移動(dòng)與拉伸實(shí)現(xiàn)代碼

    這次增加了一些相關(guān)的功能,增加四個(gè)角的拉伸改變寬度,主要還是用到一些簡單的坐標(biāo)位置計(jì)算,沒有什么技術(shù)難度,熟練了一下自己對拖拽的運(yùn)用
    2012-05-05
  • WordPress 插件——CoolCode使用方法與下載

    WordPress 插件——CoolCode使用方法與下載

    本插件原修改自 Chroder.com 的 WordPress Code Highlight 插件。但 CoolCode 插件在它基礎(chǔ)上修改了很多的內(nèi)容。
    2007-07-07
  • 最新評論