【问题标题】:How to copy text from the active tab?如何从活动选项卡复制文本?
【发布时间】:2020-04-23 00:11:09
【问题描述】:

我创建了一个带有三个按钮的选项卡菜单。传递<div> id 后,我可以复制单个选项卡内容。如何获取活动<div> 的ID,以便通过range.selectNode(document.getElementById(*ID*)) 传递ID 以复制当前活动选项卡的内容?

//  function to copy
function CopyToClipboard(){
   var range = document.createRange();

   range.selectNode(document.getElementById("Cricket"));

   window.getSelection().removeAllRanges(); /* clear current selection*/
   window.getSelection().addRange(range); /* to select text*/
   document.execCommand("copy");
   window.getSelection().removeAllRanges();/* to deselect*/
}

function openGame(evt, GameName){
    var i, tabcontent, tablinks;
    tabcontent = document.getElementsByClassName("tabcontent");
    for (i = 0; i < tabcontent.length; i++) {
    tabcontent[i].style.display = "none";
    }
    tablinks = document.getElementsByClassName("tablinks");
    for (i = 0; i < tablinks.length; i++) {
    tablinks[i].className = tablinks[i].className.replace(" active", "");
    }
    document.getElementById(GameName).style.display = "block";
    evt.currentTarget.className += " active";
}
<button onclick="CopyToClipboard()" >Copy</button>
<p>Click to copy:</p>
<div class="tab">
    <button class="tablinks" onclick="openGame(event, 'Cricket')">Cricket</button>
    <button class="tablinks" onclick="openGame(event, 'Football')">Football</button>
    <button class="tablinks" onclick="openGame(event, 'Chess')">Chess</button>
</div>
		
<div class="container" id="frame">
  <div id="Cricket" class="tabcontent"> 
    <p>Cricket</p>
  </div>

  <div id="Football" class="tabcontent">
    <p>Football</p> 
  </div>

  <div id="Chess" class="tabcontent">
    <p>Chess</p>
  </div>
</div>

【问题讨论】:

    标签: javascript html


    【解决方案1】:

    在本例中,您所要做的就是将活动选项卡 ID 存储在这些函数范围之外的变量中。

    //  function to copy
    var activeTabId = 'Cricket'; // Or whatever your default tab is
    
    function CopyToClipboard(){
       var range = document.createRange();
    
       //range.selectNode(document.getElementById("Cricket"));
       range.selectNode(document.getElementById(activeTabId)); // here you use the variable
       
       window.getSelection().removeAllRanges(); /* clear current selection*/
       window.getSelection().addRange(range); /* to select text*/
       document.execCommand("copy");
       window.getSelection().removeAllRanges();/* to deselect*/
    }
    
    function openGame(evt, GameName){
        var i, tabcontent, tablinks;
        tabcontent = document.getElementsByClassName("tabcontent");
        for (i = 0; i < tabcontent.length; i++) {
        tabcontent[i].style.display = "none";
        }
        tablinks = document.getElementsByClassName("tablinks");
        for (i = 0; i < tablinks.length; i++) {
        tablinks[i].className = tablinks[i].className.replace(" active", "");
        }
        document.getElementById(GameName).style.display = "block";
        evt.currentTarget.className += " active";
        
        activeTabId = GameName; // here you assign the active tab value
    }

    还有。 您可能希望提前获取选项卡的引用 - 这样您就不必在每次执行两个函数时都搜索 DOM。

    【讨论】:

      【解决方案2】:

      您可以简单地将 CopyToClipboard 函数调整为:

      我使用 querySelector 来获取活动的 tablink 元素,然后获取它的内部文本,它是 tabcontent id 之一。

      //  function to copy
      function CopyToClipboard(){
        var activeTabId = document.querySelector('.tablinks.active').innerText;
      
         var range = document.createRange();
      
         range.selectNode(document.getElementById(activeTabId));
      
         window.getSelection().removeAllRanges(); /* clear current selection*/
         window.getSelection().addRange(range); /* to select text*/
         document.execCommand("copy");
         window.getSelection().removeAllRanges();/* to deselect*/
      }
      

      【讨论】:

      • innerText 刚好和ID一样。你应该避免“在现实生活中”这样的事情:)
      【解决方案3】:

      您可以像CopyToClipboard(GameName) 一样在openGame() 中调用函数CopyToClipboard() 并将range.select 节点更改为range.selectNode(document.getElementById(GameName)); 在定义复制到剪贴板功能时也传递一个参数。

      【讨论】:

      • CopyToClipboard() 函数只应在单击复制按钮时调用。否则,之前的剪贴板内容将在每个选项卡切换操作中更新。
      • openGame() 在点击按钮时被触发,导致复制功能在此之后运行。这样做你可以删除复制按钮。或者,在复制功能中,您可以获取class = 'tabcontent' 的内部html,并从代码中删除&lt;p&gt;,以确保仅复制游戏名称。
      • 是的,我明白你的意思。不需要一个额外的按钮。实际上我的目标是使复制操作成为可选的。在这里,通过在 openGame() 中放置“复制功能”,不仅可以切换选项卡,还可以复制内容。感谢您的建议!
      • 从用户体验的角度来看。不要运行执行用户可能从未想过的事情的代码。 “更改标签”与“复制其内容”是两个完全不同的任务。另外 - 小心剪贴板操作。它是系统范围的。由于选项卡更改,您可能不想覆盖某些复制的密码、图片、银行帐户或其他任何内容。
      【解决方案4】:

      问题:“如何获取活动&lt;div&gt; 的ID?”

      回答这个具体问题:

      活动按钮具有“tablinks active”类,它的 innerHTML 包含与活动 div 的 ID 相同的文本。

      此函数将从活动按钮中检索与 div 的 ID 匹配的文本:

        // return the active div's ID
        function activeDivId () {
          let activeButtons =
            document.getElementsByClassName('tablinks active');
          if (activeButtons.length === 0) {
            return null;
          }
          const activeButton = activeButtons[0];
          return activeButton.innerHTML;
        }
      

      让它变得更好

      虽然这严格回答了问题,但它并不是最有效的方法,并且有多种方法可以使代码变得更好。

      以下原则可以指导改进:

      1. 始终将应用的状态存储在 DOM 之外。
      2. 为了提高速度,尽量减少对 DOM 的查询和操作。
      3. 为避免命名冲突,请将变量和函数名称包含在对象中。
      4. for...offor...in 足够时,避免使用索引for 循环。

      以下是该游戏的修改版本,遵循以下原则:

        // put game inside an object to avoid global name conflicts
        const myGame = {
      
          // static parts of the DOM
          tabcontent: document.getElementsByClassName('tabcontent'),
          tablinks: document.getElementsByClassName('tablinks'),
      
          // name of currently active game
          activeGame: null,
      
          // div of active game content
          activeTabContent: null,
      
          // button of active game
          activeTabLink: null,
      
          // open the game
          openGame: function (button, gameName) {
      
            const { tablinks, tabcontent } = myGame;
      
            // clear former active game
            if (myGame.activeGame) {
              myGame.activeTabLink.classList.remove('active');
              myGame.activeTabContent.style.display = 'none';
            } else {
              // clear all games
              for (const tl of tablinks) {
                tl.classList.remove('active');
              }
              for (const tc of tabcontent) {
                tc.style.display = 'none';
              }
            }
      
            // activate new game
            myGame.activeTabLink = button;
            myGame.activeGame = gameName;
            myGame.activeTabContent = document.getElementById(gameName);
            myGame.activeTabContent.style.display = 'block';
            myGame.activeTabLink.classList.add('active');
          },
      
          // copy contents of active game
          copyActiveToClipboard: function () {
            const range = document.createRange();
      
            range.selectNode(myGame.activeTabContent);
            window.getSelection().removeAllRanges(); /* clear current selection*/
            window.getSelection().addRange(range); /* to select text*/
            document.execCommand("copy");
            window.getSelection().removeAllRanges();/* to deselect*/
          }
        };
      /* highlight active button */
      .tablinks.active {
        color: blue;
      }
      <p>Copy contents of active game to clipboard:</p>
      <button onclick="myGame.copyActiveToClipboard()">Copy</button>
      <p>Click to select game:</p>
      <div class="tab">
        <button class="tablinks" onclick="myGame.openGame(this, 'Cricket')">Cricket
        </button>
        <button class="tablinks" onclick="myGame.openGame(this, 'Football')">Football
        </button>
        <button class="tablinks" onclick="myGame.openGame(this, 'Chess')">Chess
        </button>
      </div>
      
      <div class="container" id="frame">
        <div id="Cricket" class="tabcontent">
          <p>Cricket</p>
        </div>
      
        <div id="Football" class="tabcontent">
          <p>Football</p>
        </div>
      
        <div id="Chess" class="tabcontent">
          <p>Chess</p>
        </div>
      </div>

      【讨论】:

      • 函数返回的不是ID,而是innerHTML。请不要提出语义不正确的解决方案:)。此外 - 每次运行此函数时都会搜索 DOM - 它引入了第三个函数,该函数在 DOM 中搜索相同的东西。进一步堆叠可能会导致明显的性能问题。
      • 具体问题回答正确。当然,还有更好的模式。但这不是问题。
      • 尊敬的先生,但在回答问题时,您也在教那个人。你应该感到有责任提出你能想出的最佳解决方案。否则,您可以说使用数据库和 REST API 设置后端也可以回答这个问题。问候。
      • 好吧,我添加了一个演示改进的修订版本。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      相关资源
      最近更新 更多