在 flexdashboard 中单击时更改第二个标签集

Posted

技术标签:

【中文标题】在 flexdashboard 中单击时更改第二个标签集【英文标题】:Change second tabset on click in flexdashboard 【发布时间】:2020-08-10 23:35:33 【问题描述】:

我正在开发一个自包含的 flexdashboard 项目,我想知道当用户单击一个选项卡集中的新选项卡时,它是否可能也会更改为第二个选项卡集中的新选项卡。

因此,例如,当您单击下面的“图表 B1”时,我还想将第二列中的视图更改为“图表 B2”。点击“Chart A2”会变回“Chart A1”等等。

---
title: "Untitled"
output: 
  flexdashboard::flex_dashboard:
    orientation: columns
    vertical_layout: fill
---

```r setup, include=FALSE
library(flexdashboard)
```

Column .tabset
-----------------------------------------------------------------------

### Chart A1

### Chart B1

Column .tabset
-----------------------------------------------------------------------

### Chart A2

### Chart B2

注意,这是first posted on RStudio Community,但没有收到任何回复。

【问题讨论】:

【参考方案1】:

这可以用 javascript 来实现。幸运的是,Knitr 支持嵌入式 Javascript。我首先是一个R程序员,所以这可能不一定是最简洁的实现,但它确实达到了正确的效果。

    ---
    title: "Untitled"
    output: 
      flexdashboard::flex_dashboard:
        orientation: columns
        vertical_layout: fill
    ---

    ```r setup, include=FALSE
    library(flexdashboard)
    ```

    Column .tabset
    -----------------------------------------------------------------------

    ### Chart A1
    Chart A1 is Great

    ### Chart B1
    Chart B1 is Great

    Column .tabset
    -----------------------------------------------------------------------

    ### Chart A2
    Chart A2 is Great

    ### Chart B2
    Chart B2 is Great

    ```js
    // Once the Document Has Fully Loaded
    document.addEventListener("DOMContentLoaded", function()
      // Select The Tabs
      window.a1Tab = document.querySelector("#column > ul > li:nth-child(1)");
      window.b1Tab = document.querySelector("#column > ul > li:nth-child(2)");
      window.a2Tab = document.querySelector("#column-1 > ul > li:nth-child(1)");
      window.b2Tab = document.querySelector("#column-1 > ul > li:nth-child(2)");

      // Select the Panel Content
      window.a1Panel = document.getElementById('chart-a1');
      window.b1Panel = document.getElementById('chart-b1');
      window.a2Panel = document.getElementById('chart-a2');
      window.b2Panel = document.getElementById('chart-b2');

      // If We Click on B1, Open B2, Close A2
      b1Tab.addEventListener('click', function()
        a2Tab.classList.remove('active');
        a2Tab.children[0].setAttribute('aria-expanded', true);
        a2Panel.classList.remove('active');

        b2Tab.classList.add('active');
        b2Tab.children[0].setAttribute('aria-expanded', true);
        b2Panel.classList.add('active');
      , false);

      // If We Click on B2, Open B1, Close A1
      b2Tab.addEventListener('click', function()
        a1Tab.classList.remove('active');
        a1Tab.children[0].setAttribute('aria-expanded', true);
        a1Panel.classList.remove('active');

        b1Tab.classList.add('active');
        b1Tab.children[0].setAttribute('aria-expanded', true);
        b1Panel.classList.add('active');
      , false);

      // If We Click on A1, Open A2, Close B2
      a1Tab.addEventListener('click', function()
        b2Tab.classList.remove('active');
        b2Tab.children[0].setAttribute('aria-expanded', true);
        b2Panel.classList.remove('active');

        a2Tab.classList.add('active');
        a2Tab.children[0].setAttribute('aria-expanded', true);
        a2Panel.classList.add('active');
      , false);

      // If We Click on A2, Open A1, Close B1
      a2Tab.addEventListener('click', function()
        b1Tab.classList.remove('active');
        b1Tab.children[0].setAttribute('aria-expanded', true);
        b1Panel.classList.remove('active');

        a1Tab.classList.add('active');
        a1Tab.children[0].setAttribute('aria-expanded', true);
        a1Panel.classList.add('active');
      , false);
    );

    ```

编辑:对于无限数量的选项卡,假设您在第一列和第二列中始终具有相同数量的选项卡。同样的免责声明,这不一定是最简洁的实现,但达到了预期的效果。


    ---
    title: "Untitled"
    output: 
      flexdashboard::flex_dashboard:
        orientation: columns
        vertical_layout: fill
    ---

    ```r setup, include=FALSE
    library(flexdashboard)
    ```

    Column .tabset
    -----------------------------------------------------------------------

    ### Chart A1
    Chart A1 is Great

    ### Chart B1
    Chart B1 is Great

    ### Chart C1
    Chart C1 is Great

    ### Chart D1
    Chart D1 is Great

    Column .tabset
    -----------------------------------------------------------------------

    ### Chart A2
    Chart A2 is Great

    ### Chart B2
    Chart B2 is Great

    ### Chart C2
    Chart C2 is Great

    ### Chart D2
    Chart D2 is Great

    ```js
    // Once the Document Has Fully Loaded
    document.addEventListener("DOMContentLoaded", function()
      // Select The Tabs
      window.col1Tabs = document.querySelector("#column > ul");
      window.col2Tabs = document.querySelector("#column-1 > ul");

      // Select the Panel Content
      window.col1Panels = document.querySelector("#column > div");
      window.col2Panels = document.querySelector("#column-1 > div");

      // Function to Make Tabs Active
      window.handleTab = function(tabIndex)
        for(i=0;i<col1Tabs.childElementCount;i++)
          col1Tabs.children[i].classList.remove('active');
          col2Tabs.children[i].classList.remove('active');
          col1Panels.children[i].classList.remove('active');
          col2Panels.children[i].classList.remove('active');
        
        col1Tabs.children[tabIndex].classList.add('active');
        col2Tabs.children[tabIndex].classList.add('active');
        col1Panels.children[tabIndex].classList.add('active');
        col2Panels.children[tabIndex].classList.add('active');
      

      // For All Tabs, Add Event Listener
      for(i=0;i<col1Tabs.childElementCount;i++)
        col1Tabs.children[i].setAttribute('onclick', 'handleTab(' + i + ');');
        col2Tabs.children[i].setAttribute('onclick', 'handleTab(' + i + ');');
      

    );

    ```

编辑:对于以后可能会发现此问题的任何人,Github Issue. 中添加了具有更大灵活性的 JQuery 实现

【讨论】:

这太好了,谢谢!在我的真实示例中,我有更多选项卡,所以我想知道是否有某种方法可以指定哪些选项卡应该相互“链接”并让点击事件自动生成?我不懂什么JS,所以我真的不知道从哪里开始,但这真的很有用。 感谢您添加更新!我的真实示例在每列中有不同数量的选项卡,所以这不会完全有效,但你给了我足够的工作。而且,现在我要学习一些 JavaScript!【参考方案2】:

只是使用 JQuery 和 boostrap tabset JS 函数添加另一个答案。 它比其他答案更简洁,但与两列格式中任意数量的选项卡(但数量相同)的工作方式相同。

---
title: "Untitled"
output: 
  flexdashboard::flex_dashboard:
    orientation: columns
    vertical_layout: fill
---

```r setup, include=FALSE
library(flexdashboard)
```

```js
document.addEventListener("DOMContentLoaded", function()
    $('a[data-toggle="tab"]').on('click', function(e)
      // find the tab index that is click
      child = e.target.parentNode;
      tabnum = Array.from(child.parentNode.children).indexOf(child);
      // find in which column we are
      column = $(e.target).closest("div[id]");
      // show the same tab in the other column
      columnid = column.attr("id");
      if (columnid == "column") 
        columnto = "column-1";
       else 
        columnto = "column";
      
      $("div[id="+columnto+"] li:eq("+tabnum+") a").tab('show');
    )
);
```

Column .tabset
-----------------------------------------------------------------------

### Chart A1

This is a text

### Chart B1

```r
plot(iris)
```


Column .tabset
-----------------------------------------------------------------------

### Chart A2

```r
plot(mtcars)
```

### Chart B2

This is another text

【讨论】:

这也很棒,非常感谢!我想知道当每列中有不同数量的选项卡时是否会有一种方法有效,我们可以指定哪些选项卡应该在列中相互“链接”。如果 Col 1 中有 3 个选项卡,Col 2 中有 2 个选项卡,则类似于 a1 = a2, b1 = b2, c1 = a2 是的,我想您可以在 JS 中按列创建一个索引数组,然后从中选择链接的选项卡。就像你在 R linkedIndex[targetIndex, columnid] 中所做的那样。也可能有一个解决方案,我认为有关链接选项卡的信息被添加到某些选项卡节点的数据属性中,您可以在 JS 中获取此信息

以上是关于在 flexdashboard 中单击时更改第二个标签集的主要内容,如果未能解决你的问题,请参考以下文章

如何更改从第一个活动单击的按钮上的第二个活动的文本? [科特林]

单击单选按钮图像应更改

R flexdashboard 删除标题栏

PyQt5 - 第二个窗口中的按钮在单击时不执行操作

runjs 在 flexdashboard 中更改 observeEvent 的位置?

单击第二个下拉列表时,黑框应保持可见