Demand background

Because of the number of columns in the item table, the table must have a horizontal scroll bar. However, if the page itself has a lot of content and vertical scroll bars appear, it will be necessary to scroll to the bottom of the table (the horizontal scroll bar of table is at the bottom of the container by default) before pulling left and right, which brings inconvenience to some users.

Conventional scheme

  1. Since the list page generally has no other content at the bottom, it can be set dynamicallytabletheheightTo avoid the appearance of the vertical scroll bar, so that the horizontal scroll bar is always at the bottom of the viewport. The disadvantage is that on some small screens, such as laptops, the table can display too few items.
  2. Tell the user to use the keyboard,el-tableThe accessibility is excellent and can be passedPlease -Shortcut keys to scroll horizontally. Or hold down the middle mouse button and swipe. The disadvantage is that many users do not know or are not used to this mode of operation. Personally, I think we can also do guidance, but we should consider the design of friendly interaction and user acceptance. (PS: manual dog head.jpg)

Realization of effect

Take a look at the final result, as shown below:

In short, the horizontal scroll bar is fixed at the bottom of the viewport when the bottom of the table container is not in the viewport area.

Thinking a

Implement a horizontal scroll bar fixed at the bottom of the viewport and synchronize the scroll bar with the Scroll event of the EL-table. Hide the custom scroll bar when el-Table’s native horizontal scroll bar is in the viewable area.

Idea 2

Generate a custom horizontal scroll bar inside the EL-Table. When the el-Table native horizontal scroll bar does not appear in the viewport range, adjust the custom scroll bar to the bottom of the viewport, otherwise hide the custom scroll bar.

I followed idea two. Since Vue is used and Dom manipulation is involved, this function is encapsulated in the form of an instruction, which can be used to add instructions to the EL-Table.

The core code is as follows:

Custom scrollbar import PerfectScrollbar from'perfect-scrollbar'; // The corresponding CSS import"perfect-scrollbar/css/perfect-scrollbar.css";


const updateScrollBar = (el) => {
    const railX = el.querySelector(".ps__rail-x"); const _tbody = el; / / if I have any scroll bar within the table need to add _tbody scrollTop const _top = window. The innerHeight - _tbody. GetBoundingClientRect (). The top - railX.clientHeight; railX.style.top = `${_top}px`;
    railX.style.opacity = "1";
    railX.style.display = "block";
}

const el_scrollBar = (el) => {
    if (el._ps_ instanceof PerfectScrollbar) {
        el._ps_.update();
    } else {
        el._ps_ = new PerfectScrollbar(el, {
            suppressScrollX: false,
            suppressScrollY: true}); //setTimeout(() => { // el._ps_.update(); / /}, 17); }};let isScrolling = false;
let _scrollHander = null;
let _resizeHander = null;

const directive = {
    inserted(el) {
        el = el.querySelector(".el-table__body-wrapper");
        if(! el) {return console.warn("Dom with className el-table__body-wrapper not found");
        }
        const rules = ["fixed"."absolute"."relative"];
        if(! Rules.includes (window.getComputedstyle (el, null).position)) {console.error(' perfect-scrollbar 'the position property of the container must be one of the following:The ${rules. Join (", ")}`) } el_scrollBar(el); updateScrollBar(el); // Register scroll and resize events _scrollHander = () => {if(! isScrolling) { window.requestAnimationFrame(() => { updateScrollBar(el); isScrolling =false;
                });
            }
            isScrolling = true;
        };
        
        _resizeHander = () => {
            updateScrollBar(el)
        }

        document.addEventListener("scroll", _scrollHander)
        window.addEventListener("resize", _resizeHander)
    },
    componentUpdated(el, binding, vnode) {
        const {
            expression
        } = binding;

        el = el.querySelector(".el-table__body-wrapper");
        if(! el) {return console.warn("Dom with className el-table__body-wrapper not found");
        }

        const handler = () => vnode.context[expression].apply();

        vnode.context.$nextTick(
            () => {
                try {
                    el_scrollBar(el);
                    updateScrollBar(el);
                    if(expression) { handler() } } catch (error) { console.error(error); }})},unbind() {
        document.removeEventListener("scroll", _scrollHander)
        window.removeEventListener("resize", _resizeHander)
    }
}

export default directive;
Copy the code

Initialize the custom scroll bar while inserted, using the PerfectScrollbar. PerfectScrollbar actually generates a horizontal scrollbar

that keeps the scrollbar at the bottom of the viewport by dynamically setting the top value of the scrollbar.

A simple geometric formula:

// The height of the viewport - tbody is based on the top value of the viewport - the height of the horizontal scrollbar container const _top = window.innerheight - _tbody.getBoundingClientRect().top - railX.clientHeight;Copy the code

Re-initialize the scroll bar after the update of the EL-Table component, and update the scroll bar position when the Scroll and resize events are triggered.

If the table has fixed columns, set z-index:4 for the fixed column of the EL-Table, so you need to set a larger Z-index for the scroll bar container.

.ps__rail-x { display: block; z-index: 99; /* > fixed table z-index*/}Copy the code

After the horizontal scroll bar of the table itself appears in the visible area, the position of the custom scroll bar is already under the table and part of it is in the area of the original scroll bar, and the original scroll bar will overwrite the custom scroll bar. Part of the overflow is outside the table (el-Table sets overflow:hidden); Neither part is visible, so the custom scroll bar is not hidden.

If you need to hide the scroll bar, you can listen for the visibility of the last TR in the table.

limitations

In the implementation process, it was found that the vertical scroll bar of PerfectScrollbar would affect the scroll synchronization of EL-Table with fixed columns (the fixed column is realized based on multiple tables), so the scroll in the Y direction was prohibited. However, this will cause the el-Table to fail to scroll vertically.

Given that you don’t typically have a double scrollbar, that is, a scroll inside the body and a scroll inside the table, I didn’t delve into the solution.

If you do have a double scrollbar, consider using the first idea above.

reference

Use perfect-scrollbar under VUE

Vue official website # Custom instructions

The project address

Github.com/juenanfeng/…