[工具] 前端 excel - Handsontable

Ref : https://handsontable.com/

最近有需要在網頁上用到類似 excel 的功能
於是使用 Handsontable 這個套件

這個套件有分 CE 跟 Pro 版本
CE也就是 Community Edition, 通常是免費的
Pro 則是有額外強大的功能, 要收費的
這邊就簡單筆記一下我用到的部分 (CE)

<!-- 需要一個裝 handsontable 的容器 -->
<div id="handsome-table">

<button class="btn btn-success pull-right" id="export-btn">匯出EXCEL</button>

底下是 js 的部分
// 定義好欄位名稱
const COL_HEADER = [
    'Permalink',
    '觸及',
    '點擊',
    '點擊率',
    '負評',
    '負評率'
];
let container = document.getElementById('handsome-table');
// 裝 handsontable 的 data array
// handsontable 是直接操控 data, 也就是 data-binding
// 這個到後面很好用
let data = [];
// 定義匯出 handsontable 的按鈕
let $exportBtn = $('#export-btn');
// 初始化 handsontable
let hot = new Handsontable(container, {
    data: data,
    // 定義資料的 schema, 讓資料不要只是用陣列呈現, 而是物件
    dataSchema: {
        permalink: null,
        impression: null,
        click: null,
        clickRate: null,
        negative: null,
        negativeRate: null
    },
    // 是否滿版
    stretchH: "all",
    // 要不要加上欄位名稱
    colHeaders: true,
    // 欄位名稱的值
    colHeaders: COL_HEADER,
    // 是否允許複製貼上
    copyPaste: true,
    contextMenu: true,
    // 定義每一個欄位的屬性, ex: 型態是 number or text, number的話要到小數點後幾位, 欄位寬度等
    columns: [
        { 
            data: 'permalink',
            type: 'text',
            width: 800
        }, {
            data: 'impression',
            type: 'numeric',
            width: 80
        }, {
            data: 'click',
            type: 'numeric',
            width: 80
        }, {
            data: 'clickRate',
            type: 'numeric',
            numericFormat: {
                pattern: '0.0000'
            },
            width: 80
        }, {
            data: 'negative',
            type: 'numeric',
            width: 80
        }, {
            data: 'negativeRate',
            type: 'numeric',
            numericFormat: {
                pattern: '0.0000'
            },
            width: 80
        }
    ],
    // 定義貼上後觸發的 function
    afterPaste: async function () {
        $exportBtn.removeClass('btn-success').addClass('btn-warning').attr('disabled', true).text('處理中');
        let processes = [];
        // trim space
        data.map(d => {
            if (d.permalink) {
                d.permalink = d.permalink.trim();
            }
            return d;
        });
        for (let x in data) {
            if (!data[x].permalink) {
                continue;
            }
            let result = await sendRequestAsync('POST', API_URL, { url: data[x].permalink });
            let { 
                clicks, clicks_rate,
                impressions, negative_feedback,
                negative_feedback_rate
            } = result.response;
            data[x].impression = impressions;
            data[x].click = clicks;
            data[x].clickRate = clicks_rate * 100;
            data[x].negative = negative_feedback;
            data[x].negativeRate = negative_feedback_rate * 100;
            // 刷新頁面
            this.render();
        }
        // sort by negative rate descending
        data.sort((a, b) => {
            if (a.negativeRate === null) {
                return 1;
            } else if (b.negativeRate === null) {
                return -1;
            } else {
                return b.negativeRate - a.negativeRate;
            }
        });
        // 刷新頁面
        this.render();
            
        $exportBtn.removeClass('btn-warning').addClass('btn-success').removeAttr('disabled').text('匯出');
    },
    // 最少要幾個 rows
    minRows: 30,
    minSpareRows: 1
});

// 匯出 excel 
$exportBtn.click(function () {
    let rows = data.filter(d=>d.permalink);
    let content = `data:text/csv;charset=utf-8,`;
    rows.forEach((r, idx)=> {
        if (idx === 0) {
            content += `${COL_HEADER.join(',')}\r\n`;
        }
        let _c = [];
        for (let key in r) {
            _c.push(r[key]);
        }
        content += `${_c.join(',')}\r\n`;
    });
    let date = new Date();
    let encodedUri = encodeURI(content);
    let link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", `insight_${getyyyymmdd()}.csv`);
    link.innerHTML= "Click Here to download";
    document.body.appendChild(link); // Required for FF
    link.click();
});





留言

這個網誌中的熱門文章

[MySQL] schema 與資料類型優化

[翻譯] 介紹現代網路負載平衡與代理伺服器