Chrome开发工具 - 通过页面重新加载记住所选元素

时间:2017-07-14 13:55:34

标签: javascript google-chrome google-chrome-extension google-chrome-devtools

我正在构建自己的Chrome开发工具类型(检查元素),它也将采用JavaScript扩展程序的形式。我希望它有一些与Chromes开发工具类似的功能,其中一个我很难揭穿它们是如何完成它的。

基本上,右键单击任何元素并单击"检查元素"它会打开开发工具(如果尚未打开)并将鼠标悬停在右键单击定位的HTML元素上。

我要复制的位是当您在开发工具中选择元素时刷新页面时,它将重新加载所有HTML并直接转到您在重新加载之前在开发工具中选择的元素。

如果它有点不清楚,我的意思是:

HTML:

<div class="1">
    <div class="2">
        <div class="3"></div>
    </div>
</div>

如果我正在和#34; 3&#34;并刷新页面,Chrome开发工具知道重新加载开发工具突出显示确切的div。即使有多个具有该类或类似结构的div,它也总是悬停在正确的div上。

有人知道这里最好的方法是使用一个大的if语句来查找元素的某些特征,例如理想情况下的id,但如果元素没有id,那么还会有大量的后退元素或与该元素相关的唯一类/属性?

我已尝试搜索Chrome扩展程序节点选择器&#39;或类似的变体,但未能找到任何信息。

4 个答案:

答案 0 :(得分:4)

已经存在一个非常好的“检查元素”扩展,您可以找到here。但是,它不支持保存被检查元素。但是,由于这是一个赏金的问题,我可以给你一些提示,以改善它的工作解决方案。

我在这里看到的主要问题是“序列化”元素。关于这个主题的一个很好的答案可以找到here。 (参见fiddle)它基本上总结为“找到最近的具有ID的祖先并跟踪向下到被检查元素的路径”。在你的情况下,这可能是:

tracePath: function (element, result) {
  if (element.id !== '') {
    result.push({
      id: element.id
    });
    return;
  }
  if (element === document.body) {
    result.push({
      tag: element.tagName
    });
    return;
  }

  var siblings = element.parentNode.childNodes;
  for (var i = 0; i < siblings.length; ++i) {
    var sibling = siblings[i];
    if (sibling === element) {
      result.push({
        index: i,
        tag: element.tagName
      });
      return this.tracePath(element.parentNode, result);
    }
  }
},

上面只是存储了反序列化过程中要遵循的节点数组:

find: function (path) {
  var element;
  while (path.length) {
    var current = path.pop();

    if (!current) return element;
    if (current.id) element = document.getElementById(current.id);
    else if (element) {
      if (current.index < element.childNodes.length && current.tag === element.childNodes[current.index].tagName)
        element = element.childNodes[current.index];
      else
        return;
    } else {
      var matches = document.getElementsByTagName(current.tag);
      if (matches.length)
          element = matches[0];
    }
  }
  return element;
},

一旦我们这两个,我们只需要存储/加载选择的方法:

store: function (path) {
  var selection = Object.create({});
  selection[window.location.href] = path;
  chrome.storage.local.set(selection, function () {
    if (chrome.runtime.lastError) {
      console.error(chrome.runtime.lastError)
    }
  })
},

并加载:

load: function () {
  var self = this, key = window.location.href;
  chrome.storage.local.get(key, function (found) {
    if (chrome.runtime.lastError) {
      console.error(chrome.runtime.lastError)
    } else if (found && found[key]) {
      var path = found[key],
        element = Util.find(path);

      if (element) {
        // zoom into inspected element
        element.scrollIntoView();
        // add selection to Inspector instance
        self.$selection = element;
        // function similar to layout() - highlights inspected element
        self.select();
      }
    }
  })
}

然后你可以编写一个突出显示功能,比如select来突出显示被检查的元素,类似于突出显示标尺的现有layout

点击它可以保存元素:

registerEvents: function() {
  ...
  document.addEventListener('click', function () {
      var path = [];
      Util.tracePath(this.$target, path);
      this.$selection = this.$target;
      this.select(true);
      this.storeSelection(path);
  }.bind(this));
  ...
},

有一个包含上述修改的分支,您可以找到here。您可以downloading尝试一下,然后将app文件夹作为解压扩展名加载到chrome://extensions/下的新标签中。享受!

截图

enter image description here

答案 1 :(得分:1)

您始终可以将idclassfont-family等元素的信息存储到chrome.storage.local / sync

要处理重新加载,您可以执行诸如在自定义开发工具标签中提取chrome.storage对象和window.location(myElement)之类的内容。

答案 2 :(得分:1)

以下是我的问题的解决方法。

想法:让内容脚本为被检查元素选择唯一的选择器,将其保存到chrome.storage.local中,这样就可以加载选择器,查找元素并运行{{ 1}}为了它。

首先是 manifest.json 文件:

inspect()

然后我在Devtools中创建一个新面板。

<强> loader.html

{
  "manifest_version": 2,
  "name": "remember element",
  "version": "1.0.0",
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content-script.js"],
      "run_at": "document_start"
    }
  ],
  "permissions": [
    "storage"
  ],
  "devtools_page": "loader.html"
}

<强> loader.js

<!doctype html>
<html lang="en">
<body>
  <script src="loader.js"></script>
</body>
</html>

<强> panel.html

chrome.devtools.panels.create('Remember element', null, 'panel.html');

因此,面板包含两个按钮:一个用于保存当前检查的元素,第二个用于检查先前保存的元素。

这里我们需要 panel.js

<!doctype html>
<html>
<body>

  <button id="save">Save</button>
  <button id="get">Get</button>

  <script src="panel.js"></script>
</body>
</html>

content-script.js

document.addEventListener('DOMContentLoaded', () => {

    // Ask content-script to resolve unique selector and save it in the storage
    document.getElementById('save').addEventListener('click', () => {
        chrome
            .devtools
            .inspectedWindow
            .eval("saveUniqueSelector($0)", {
                useContentScriptContext: true // run the code in the content-script
            });
    });

    document.getElementById('get').addEventListener('click', () => {
        // Getting saved selector
        chrome.storage.local.get('prev_selected', items => {

            // Find the element by selector and run inspection for it
            chrome
                .devtools
                .inspectedWindow
                .eval(`inspect(document.querySelector("${items.prev_selected}"))`);
        });
    });
});

有很多用于获取元素唯一选择器的库。我在这里使用css-selector-generator

这个例子有一个很大的缺陷:当你在devtools中选择它时,我找不到为元素进行自动保存的方法。 (除了setInterval,但它不是一个好主意)。

答案 3 :(得分:0)

扩展DomFlags正是这样做的。您可以在元素面板中设置多个标志,并且第一个会在页面重新加载时自动选择。

http://domflags.com/