繁体   English   中英

使用响应式布局的制表符渲染问题

[英]Tabulator rendering issue using responsive layout

问题:如果我坚持布局:“fitColumns”,我尝试的任何其他内容似乎都会导致渲染(如果这是正确的术语)问题。 我没有使用框架(时间范围内的桥梁)。 当页面完全加载后显示表格时,无论我选择何种布局 - 它总是像“fitColumns”一样开始显示。 例如,如果我将它设置为“fitDataFill”,它将加载并显示为“fitColumns”。 当我单击另一个选项卡并再次返回时,它会显示 fitDataFill 应有的数据。

修改:

粗略的步骤顺序:

  • 加载一个特定文件,其中包含有关要加载到表中的文件 rest 的元数据、这些表的名称、每个表中的列以及在列标题上显示为浮动帮助的文本
  • 加载数据的 rest 并构建包含元数据的表配置 object
  • 为每个表和 append 添加一个表特定的 div 到 csv-tab-buttons div
  • 在新创建的 div 上构建表
  • 添加按钮,该按钮将通过 css active class 和 setTab function 切换显示哪个表

setTab function 包含两次重绘(to be sure, to be sure)。

如果您看到的代码类似于您在此处编写的代码,那么多亏了您,我编写的大部分内容都是从其他人那里收集来的。

Tabulator 版本是 4.8 代码是使用 Visual Studio Code 创建的,使用 Live Server 扩展在每次保存后重新加载页面浏览器是 Chrome 版本 85.0.4183.121(官方构建)(64 位)

  • 我根据@mirza 的建议重写,以确保在构建表之前完全读取数据,并且每个表都独立于其他表存储,因此我不会每次都将同一个表传递给 setTab
  • fitColumns 有效但不允许我单独调整列的大小(这可能是设计使然)
  • fitData 似乎工作正常
  • fitDataFill 和 fitDataStretch 在第一次渲染或同一表格的后续渲染上不起作用,直到我点击离开并再次返回
  • 我试图通过调试器遵循 tabulator.js 中的逻辑,虽然我可以看到发生了什么,但那里发生的事情太多了,我无法理解问题出在哪里

HTML:

    <!DOCTYPE html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <meta http-equiv="X-UA-Compatible" content="ie=edge" />
            <!-- CSS -->
            <link rel="stylesheet" href="./scripts/dist/css/tabulator.min.css">
            <link rel="stylesheet" href="./styles/style.css">
            <!-- Scripts -->
            <script type="text/javascript" src="./scripts/dist/js/tabulator.min.js"></script>
            <script type="text/javascript" src="./scripts/dist/js/papaparse.min.js"></script>
            <title>My Team</title>
        </head>
    
        <body>
            <!-- Wrapper -->
            <div class="wrapper">
                <section class="container">
                    <!-- Header -->
                    <header id="header" class="header">
                        <h1>Reporting</h1>
                    </header>
    
                    <!-- Tabs -->
                    <div id="csv-tab-buttons" class="tab">
                    </div>
    
                    <!-- Tables on each tab -->
                    <div id="csv-tabs">
                    </div>
    
                    <!-- Footer -->
                    <footer class="footer">
                        <p>My Team &copy; 2020</p>
                    </footer>
    
                </section>
            </div><!-- Wrapper Ends-->
            <script src="./scripts/dist/js/miscsv.min.js"></script>
        </body>
    </html>

修订版 Javascript:

 //*******************************************************************************************************
// Global variables
//*******************************************************************************************************

var file = 'DS.PPTE.DB2.VIARACF.VARLEGND.CSV'
var tables = []
var tableDivs = []
var tabConfig = {}

//*******************************************************************************************************
// Global functions
//*******************************************************************************************************

let onlyUnique = (value, index, self) => {
    return self.indexOf(value) === index
}

//*******************************************************************************************************
// Async functions
//*******************************************************************************************************

// Set the tab to whichever button was clicked
async function activateTab(target) {
    // hides all tabs
    document.querySelectorAll(".tabcontent").forEach(tabContent => tabContent.style.display = "none");
    // Remove the active class from all tab links
    document.querySelectorAll('.tablinks').forEach(tabLink => tabLink.className.replace("active", ""));
    // Remove the active class from the active tab
    document.querySelectorAll(".active").forEach(activeTab => activeTab.classList.remove("active"))
    // Activate the selected tab
    document.querySelector(`#${target.textContent}`).style.display = "block"
    target.classList.add("active");
}

async function setTab(target) {
    console.log("Activate the tab")
    await activateTab(target)
    console.log("Redraw the table")
    // Redraw the table
    tableDivs[`${target.textContent}`].redraw(true);
}

// Read a CSV file
const readCSV = async (file) => {
    return new Promise(resolve => {
        Papa.parse(`data/${file}`, {
            header: true,
            download: true,
            skipEmptyLines: true,
            complete: results => {
                console.log(`${file} loaded - ${results.data.length} records.`)
                resolve(results)
            }
        })
    })
}

// Get all the data first
async function getData() {
    // Read the meta data file with the data and table config
    let parseMeta = await readCSV(file)
    tabConfig = {
        // Get the names of the tables to present
        tabs: parseMeta.data.map((data) => data['TABLE-NAME']).filter(onlyUnique).sort(), 
        // Find the file name for each table
        files: parseMeta.data.map((data) => `${data['TABLE-NAME']}-${data['CSV-FILE-NAME']}`).filter(onlyUnique)
            .map((entry) => {
                let tmpEntry = entry.split('-')
                return { table: `${tmpEntry[0]}`, file: `${tmpEntry[1]}` }
            }), 
        // Save the float over help for each column by table name
        help: parseMeta.data.map((data) => {
            return { key: `${data['TABLE-NAME']}-${data['VARIABLE']}`, helpText: data['VAR-DESCRIPTION'] != '' ? data['VAR-DESCRIPTION'] : data['VARIABLE'] }
            }), 
        data: tables,
        divs: tableDivs,
    }
    // Read in the files which contain the table data
    for (const tabName of tabConfig.tabs) {
        let file = tabConfig.files.filter(entry => entry.table == tabName)[0].file
        tables[tabName] = await readCSV(file)
        tableDivs[tabName] = `csv-table-${tabName}`
    }
}

// Master function to do everything in the right order
async function doAll() {
    // Get all the data and build the table config
    await getData()

    // Store the buttons and tabs anchor divs
    let buttonsDiv = document.getElementById("csv-tab-buttons")
    let tabsDiv = document.getElementById("csv-tabs")

    // Add the buttons and tables
    for ([idx, tabName] of tabConfig.tabs.entries()) {
        // Add tabs to hold the tables to the page
        const elemTabDiv = document.createElement('div')
        const elemTableDiv = document.createElement('div')
        elemTabDiv.id = tabName
        elemTabDiv.className = "tabcontent"
        elemTableDiv.id = `csv-table-${tabName}`
        elemTableDiv.className = "table"
        elemTabDiv.appendChild(elemTableDiv)
        tabsDiv.appendChild(elemTabDiv)

        // Define header context menu
        let headerMenu = [
            {
                label:"Hide Column",
                action:function(e, column){
                    column.hide()
                },
            },
        ]
        // Create the table
        tableDivs[tabName] = new Tabulator(`#csv-table-${tabName}`, {
            data:tabConfig.data[tabName].data,
            layout:"fitData",
            responsiveLayout:"collapse",
            tooltips:true,
            pagination:"local",
            paginationSize:20,
            resizableColumns:true,
            movableColumns:true,
            resizableRows:true,
            autoColumns: true,
            autoColumnsDefinitions: function(definitions) {
                definitions.forEach((column) => {
                    let helpText = tabConfig.help.find(key => key.key === `${tabName}-${column.field}`).help
                    // Add float over help based on column name
                    column.headerTooltip = helpText
                    column.headerMenu = headerMenu
                    column.headerFilter = true
                    column.headerSort = true
                    column.headerFilterLiveFilter = false
                })
                return definitions
            },
            renderStarted:function(){
                console.log("Render started")
            },
            renderComplete:function(){
                console.log("Render complete")
            },
        })
        // Add tab buttons to page
        const elemTabButton = document.createElement('button')
        elemTabButton.id = `button-${tabName}`
        if ( idx == 0 ) {
            elemTabButton.className = "tablinks active"
        } else {
            elemTabButton.className = "tablinks"
        }
        elemTabButton.onclick = function() { setTab(this) }
        elemTabButton.textContent = tabName
        buttonsDiv.appendChild(elemTabButton)
    }
    document.querySelector(".active").click();
}

doAll()



CSS:

:root {
    --shadow: 0 1px 5px rgba(104, 104, 104, 0.8);
    --raisin: #262730;
    --vermillion: #d33f49;
    --cadet: #576c75;
    --navyboy: #8db2c2;
    --space-cadet: #363457;
    --baby-powder: #f0f4ef;
    --ice: rgb(245, 247, 253);
}

html {
    box-sizing: border-box;
    font-family: Arial, Helvetica, sans-serif;
    color: var(--dark);
}

body {
    background: var(--baby-powder);
    margin: 10px 10px;
    line-height: 1.4;
}

/* .wrapper {
    display: grid;
    grid-gap: 10px;
} */

.container {
    display: grid;
    grid-gap: 10px;
    grid-template-areas: 
        'header'
        'csv-tab-buttons'
        'footer';

    margin: auto;
    width: 98%;
    overflow: auto;
    padding: 1rem 1rem;
}

header {
    background: var(--raisin);
    color: var(--vermillion);
    font-size: 150%;
    line-height: 1;
    padding: 0.1rem;
    text-align: center;
    box-shadow: var(--shadow);
}

.tab {
    background-color: var(--ice);
    box-shadow: var(--shadow);
}

/* Style the buttons that are used to open the tab content */
.tab button {
    background-color: inherit;
    /* float: left; */
    border: none;
    outline: none;
    cursor: pointer;
    /* padding: 14px 16px; */
    padding: 1rem 1.1rem;
    transition: 0.3s;
}

/* Change background color of buttons on hover */
.tab button:hover {
    background-color: var(--cadet);
    color: var(--ice);
}

/* Create an active/current tablink class */
.tab button.active {
    background-color: var(--vermillion);
    color: var(--ice);
}

/* Style the tab content */
.tabcontent {
    /* overflow: hidden; */
    display: none;
    /* padding: 6px 12px; */
    /* border-top: none; */
}

/* Override Tabulator header background */
.tabulator-col-content {
    background-color: var(--ice);
}

.table {
    overflow: hidden;
    box-shadow: var(--shadow);
}

.footer {
    background: var(--cadet);
    color: white;
    padding: 0rem 2rem;
    line-height: 1;
    box-shadow: var(--shadow);
}

编辑:我对所有内容的顺序进行了一些更改,以便在调用setTab function 时可以将表 object 保留在 scope 中,并且可以在单击选项卡按钮时发出重绘。 我第一次点击每个选项卡时,它似乎填充到数据的宽度。 当我再次单击每个选项卡时,它会正确地将屏幕外的列换行到下一行。 我在 setTab 例程中放置了多个表格重绘,这对表格的呈现没有影响。 然而,它确实以某种方式改变了表的属性。 我在调试器中观察到 tableWidth 从第一次重绘前的 0 变为 2734,在第二次重绘后变为 2786,并保持该值不变。 如果我点击离开并再次返回,它会按预期换行。

如果在创建表格时元素不可见,制表符表格将无法正确呈现。

要正确呈现表格,您必须在元素可见时重新绘制表格。

这里

来自网站:

如果包含 Tabulator 的元素的大小发生变化(并且您无法使用内置的自动调整大小功能)或者您在其包含元素可见之前创建了一个表格,则需要重绘表格以确保行和列正确呈现。

您可以通过重绘表格

table.redraw();

要么

table.redraw(true); //trigger full rerender including all data and rows

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM