jquery 封装 bootstrap table [完善]

效果如图:
image

JS 如下:

$.fn.extend({
    pagination: function (opts) {

        // The default config
        const _defaultConfig = {
            page: 1,
            limit: 10,
            maxDisplayCount: 5,
            buttons: ['first', 'prev', 'next', 'last'],
        }
        const _config = $.extend({}, _defaultConfig, opts); // The pagination config
        const that = this; // The pagination element

        let { buttons = _defaultConfig.buttons } = opts || {} // The pagination buttons
        let availableButtons = buttons.map((v, i, arr) => buttons.includes(v) ? v : '') // The available pagination buttons
        let { change } = opts || {} // The event handler
        let {
            page = _defaultConfig.page, // The current page index
            pageCount = 1, // The total page count
            limit = _defaultConfig.limit, // The page size
        } = opts
        let { data = [] } = opts || {} // The data array

        const $rootEle = $(this)

        function init() {

            delete _config.page

            if (limit < 1)
                limit = _defaultConfig.limit

            if (Array.isArray(data) && data.length > 0)
                pageCount = Math.ceil(data.length / limit)


            renderPagination()
            initEvent()
        }

        function initEvent() {

            $rootEle.off('click', 'li.page-item')
            $rootEle.on('click', 'li.page-item', function (e) {
                const $this = $(this)

                if ($this.hasClass('disabled'))
                    return;

                if ($this.hasClass('active'))
                    return;

                if ($this.hasClass('page-item')) {
                    if ($this.hasClass('first')) {
                        page = page = 1
                    } else if ($this.hasClass('prev')) {
                        if (page > 1) {
                            page = page -= 1
                        }
                    } else if ($this.hasClass('next')) {
                        if (page < pageCount) {
                            page = page += 1
                        }
                    } else if ($this.hasClass('last')) {
                        page = page = pageCount
                    }

                    if ($this.data('index') > 0) {
                        page = $this.data('index')
                    }
                }

                renderPagination()

                if (change) {
                    change.call(that, e, {
                        page,
                        pageCount,
                        limit
                    })
                }
            })
        }

        function renderPagination() {

            let _numberButtons = ``

            for (let i = 0; i < pageCount; i++) {
                const _pageIndex = ` data-index="${i + 1}"`
                const _active = page === i + 1 ? ' active' : ''
                _numberButtons += `<li class="page-item${_active}"${_pageIndex}><a class="page-link" href="#">${i + 1}</a></li>`
            }

            const _renderJumpButton = (index, disabled = false) => {
                disabled = disabled ? ' disabled' : ''
                const jumpName = availableButtons[index] ? ` ${availableButtons[index]}` : ''
                return `<li class="page-item${jumpName}${disabled}"><a class="page-link" href="#">${availableButtons[index]}</a></li>`
            }

            const _renderButtons = () => {
                let html = ``
                if (availableButtons[0])
                    html += _renderJumpButton(0, page === 1)

                if (availableButtons[1])
                    html += _renderJumpButton(1, page === 1)

                html += _numberButtons

                if (availableButtons[2])
                    html += _renderJumpButton(2, page === pageCount)

                if (availableButtons[3])
                    html += _renderJumpButton(3, page === pageCount)

                return html
            }

            const _paginationHtml = `<ul class="pagination">${_renderButtons()}</ul>`
            $rootEle.html(_paginationHtml)
        }

        const render = function (options) {

            const _opts = $.extend({}, opts, options)
            return $rootEle.pagination.call(that, _opts)
        }

        init()

        return {
            page,
            config: _config,
            render,
        }
    },
    table: function (opts) {

        // The default config
        const _defaultConfig = {
            page: 1,
            limit: 10,
        }
        const _config = $.extend({}, _defaultConfig, opts); // The table config
        const that = this; // The table element
        let { data = [], ajax = {}, pagination } = opts || {} // The table data
        const { cols, limit = _defaultConfig.limit } = opts || {} // The table columns

        // The pagination component
        let _pagination
        const paginationOptions = pagination // The pagination options

        if (!data) {
            data = []
        }

        // Find the table elements
        const $rootEle = $(this)
        const $tHead = $rootEle.find('thead')
        const $tBody = $rootEle.find('tbody')


        function init() {

            initPagination()
            renderTableHead()
            renderTableBody()
            pullData();
        }

        function initPagination() {
            // The pagination component
            if (paginationOptions) {
                const pageEleSelector = paginationOptions.elem
                if (!_config.limit || _config.limit < 1) {
                    _config.limit = _defaultConfig.limit
                }

                const _paginationChange = paginationOptions.change;
                paginationOptions.change = (e, { page, pageCount, limit }) => {
                    if (_paginationChange)
                        _paginationChange.call(_pagination, e, { page, pageCount, limit });
                    pageChange(e, { page, pageCount, limit })
                }

                _pagination = $(pageEleSelector).pagination(paginationOptions)
            }
        }

        // #region Render

        function renderTableHead() {
            const ths = cols.map(z => {
                const sortable = z.sort ? ` sortable` : ''
                const dataField = ` data-field="${z.field}"` || ''
                return `<th scope="col"${dataField}${sortable}>${z.title || ''}</th>`
            })
            $tHead.html(`<tr>${ths.join('')}</tr>`)
        }

        function renderTableBody() {

            const renderRows = getPendingRenderRows()

            let _trs = renderRows.map((row, i) => {
                const _cols = cols.map((col, j) => {

                    if (col.type === 'index') {

                        const checkbox = col.checkbox ? `<input type="checkbox" style="margin-right: 7px;" />` : ''

                        return `<th scope="row">${checkbox}${i + 1}</th>`
                    }


                    return `<td>${row[col.field] || ''}</td>`
                })

                return `<tr data-index="${i}">${_cols.join('')}</tr>`
            })

            if (renderRows.length < 1) {
                _trs.push(`<tr><td colspan="${cols.length}" style="text-align: center;">暂无数据</td></tr>`)
            }

            $tBody.html(_trs.join(''))
        }

        function pageChange(e, { page, pageCount, limit }) {

            _config.page = page
            _config.limit = limit

            renderTableBody()
        }

        // #endregion

        // #region Utils

        const getPagedRows = (rows) => {

            const pageIndex = _config.page;
            const pageSize = _config.limit;

            const startIndex = (pageIndex - 1) * pageSize;
            const stopIndex = startIndex + pageSize;

            return (rows || data).slice(startIndex, stopIndex);
        }

        const getPendingRenderRows = () => {

            if (limit) {
                return getPagedRows()
            }

            return data
        }

        //#endregion

        // #region Interfaces

        const render = function (options) {

            const _opts = $.extend({}, opts, options)
            return $rootEle.table(_opts)
        }

        const pullData = function (options) {

            if (!ajax || !ajax.url) {
                console.error('ajax.url is required')
                return;
            }

            // The ajax options backup
            const _ajaxOptionsBackup = $.extend({}, ajax, options)
            // The ajax options
            const ajaxOptions = $.extend({}, _ajaxOptionsBackup)

            const successCallback = function (res) {

                if (_ajaxOptionsBackup.parseData && typeof _ajaxOptionsBackup.parseData === 'function') {
                    res = _ajaxOptionsBackup.parseData.call(that, res)
                }

                if (_ajaxOptionsBackup.success)
                    _ajaxOptionsBackup.success.call(that, res)

                if (_ajaxOptionsBackup.done) {
                    data = _ajaxOptionsBackup.done.call(that, res)
                }

                if (Array.isArray(data)) {
                    renderTableBody()

                    if (_pagination) {
                        _pagination = _pagination.render({ data: data })
                    }
                } else {
                    console.error('data must be array')
                }
            }
            ajaxOptions.success = successCallback

            const errorCallback = function (res) {
                if (_ajaxOptionsBackup.error)
                    _ajaxOptionsBackup.error.call(that, res)
            }
            ajaxOptions.error = errorCallback

            const completeCallback = function (res) {
                if (_ajaxOptionsBackup.complete)
                    _ajaxOptionsBackup.complete.call(that, res)
            }
            ajaxOptions.complete = completeCallback

            $.ajax(ajaxOptions)
        }

        // #endregion

        init()

        return {
            config: _config,
            render,
            pullData,
        }
    },
})

HTML:

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <title>jquery-table</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"
        integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous" />
    <style>
        body,
        #root {
            width: 100vw;
            height: 100vh;
            box-sizing: border-box;
            overflow: hidden;
        }

        #root {
            display: flex;
            place-items: center;
        }
    </style>
</head>

<body>
    <div id="root">
        <div class="container">
            <table id="jTable" class="table table-striped table-dark" style="position: relative;">
                <thead> </thead>
                <tbody> </tbody>
            </table>
            <!-- <div class="d-flex justify-content-center" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 999; background-color: rgba(255, 255, 255, 0.5);">
                <div class="spinner-border" role="status">
                  <span class="sr-only">Loading...</span>
                </div>
              </div> -->
            <nav id="jPagination" class="d-flex justify-content-center" aria-label="Page navigation example">
                <ul class="pagination">
                    <li class="page-item">
                        <a class="page-link" href="#" aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span>
                        </a>
                    </li>
                    <li class="page-item"><a class="page-link" href="#">1</a></li>
                    <li class="page-item"><a class="page-link" href="#">2</a></li>
                    <li class="page-item"><a class="page-link" href="#">3</a></li>
                    <li class="page-item">
                        <a class="page-link" href="#" aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                        </a>
                    </li>
                </ul>
            </nav>
        </div>
    </div>

    <!-- <script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script> -->
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"
        integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-7ymO4nGrkm372HoSbq1OY2DP4pEZnMiA+E0F3zPr+JQQtQ82gQ1HPY3QIVtztVua"
        crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Mock.js/1.0.1-beta1/mock-min.js"
        integrity="sha512-C6haFoe26x0I8R2daqjCKMYlOvq++RXhACOBluxWpZdScv5kuIMrQtxAVweoRqWUlvF0bKtCSEI0f561tRQhtw=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="/table.js"> </script>
    <script>

        Mock.mock(/data\.json/, {
            'data|36': [{
                'id|+1': 1,
                'name': '@cname',
                'gender|1': ['boy', 'girl'],
                'age|15-23': 15,
                'city': '@province',
                'phone': /^1((34[0-8])|(8\d{2})|(([35][0-35-9]|4[579]|66|7[35678]|9[1389])\d{1}))\d{7}$/,
                'email': '@email',
                'identity': /[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]/,
            }]
        })

        const cols = [
            {
                type: 'index',
                checkbox: true,
                title: '#'
            },
            {
                field: 'name',
                title: 'name',
                sort: true,
            },
            {
                field: 'gender',
                title: 'gender',
                sort: true,
            },
            {
                field: 'age',
                title: 'age',
                sort: true,
            },
            {
                field: 'city',
                title: 'city',
                sort: true,
            },
            {
                field: 'phone',
                title: 'phone',
                sort: true,
            },
            {
                field: 'email',
                title: 'email',
                sort: true,
            },
            {
                field: 'identity',
                title: 'identity',
                sort: true,
            },
        ]

        const table = $('#jTable').table({
            pagination: {
                elem: '#jPagination',
            },
            // data: data,
            ajax: {
                url: './data.json',
                method: 'POST',
                dataType: 'json',
                done: function (res) {
                    return res.data;
                },
            },
            cols: cols,
            limit: 10,
            events: {
                'action-delete': function (row) {

                },
                'action-check': function (row) {

                }
            }
        })

        console.log(table);
    </script>
</body>

</html>
posted @ 2024-06-09 16:03  灵火  阅读(4)  评论(0编辑  收藏  举报