• [Vue2]实现点击下拉筛选table组件


    [Vue2]实现点击下拉筛选table组件

    /**表格组件列表 */
    Vue.component('temTable', {
        props: ['data_table'],
        computed: {
            // tableCellWidth: function () {
            //     return
            // }
            tableWidth: function () {
                if (this.$refs.tableBody) {
                    return this.$refs.tableBody.offsetWidth
                } else {
                    return 0
                }
            },
            targetBrandListText() {
                let res = publicText[this.data_table.language]['had-filtered-brand-text']
                if (this.targetBrandList.length > 0) {
                    res += ":"
                    this.targetBrandList.forEach((item, index) => {
                        if (index === 0) {
                            res += item
                        } else {
                            res += '、' + item
                        }
                    })
                }
                return res
            }
        },
        methods: {
    
            unique(arr) {
                if (!Array.isArray(arr)) {
                    console.log('type error!')
                    return
                }
                let array = [];
                for (let i = 0; i < arr.length; i++) {
                    if (array.indexOf(arr[i]) === -1) {
                        array.push(arr[i])
                    }
                }
                return array;
            },
    
            // 设置表格和表头的宽度
            setTableWidth() {
                console.log('setTableWidth')
                // let fullTableDom = document.querySelectorAll("")
                let headers = document.getElementsByClassName('hzs-table-header')
                let tableRows = document.getElementsByClassName('hzs-table-content-tr')
                console.log('setTableWidth')
    
                // 表格头的
                this.$root.tableWidthList.forEach((item, index) => {
                    console.log(item)
                    // console.log(headers)
                    let tdItem = this.data_table.theadList[index]
                    headers[index].style.width = tdItem.width ? item + 'px' : 'auto'
                    // console.log("tdItem", tdItem);
                })
    
                // 表格内容的
                // let h = "hzs-table-content-tr"
                this.$root.tableWidthList.forEach((item, index) => {
                    // [td, td, td, td]
                    for (let i = 0; i < tableRows.length; i++) {
                        let tds = tableRows[i].getElementsByTagName('td')
                        let tdItem = this.data_table.theadList[index]
                        tds[index].style.width = tdItem.width ? item + 'px' : 'auto'
                    }
                })
    
            },
    
            // 获取所有的品牌列表
            getAllBrandList() {
                // let res = new Set()
                // this.data_table.tbodyList.forEach(item => {
                //     res.add(item[0].name)
                // })
    
                let res = []
                this.data_table.tbodyList.forEach(item => {
                    res.push(item[0].name)
                })
                this.brandList = this.unique(res)
            },
    
            // 筛选功能  筛选出一个brand下的所有item 并返回列表
            filterBrand(brandList) {
                let res = []
                // console.log(res.length);
                // if (brand && brand !== '') {
                //     res = this.data_table.tbodyList.filter(item => {
                //         return item[0].name == brand
                //     })
                // }
                if (brandList.length > 0) {
                    res = this.data_table.tbodyList.filter(item => {
                        return brandList.indexOf(item[0].name) != -1
                    })
                }
                return res
            },
    
    
            // 更新选中框
            changeList(itemList) {
                // 重新筛选
                if (itemList.length < 1) {
                    this.tbodyList = this.data_table.tbodyList
                    return
                }
                let res = []
                // itemList.forEach(item => {
                //     res = res.concat(this.filterBrand(item))
                // })
                // this.tbodyList = res
                res = this.filterBrand(itemList)
                this.tbodyList = res
            },
    
            openFilterCard() {
                console.log(this.tableWidth)
                this.isShowFilterCard = true
    
            },
    
            closeCard() {
                this.isShowFilterCard = false
            },
    
            confirmBrandList(targetBrandList) {
                this.targetBrandList = targetBrandList
            },
    
            resize() {
                this.$refs.hzsConfirmBrandList.style.width = document.getElementById("table-header").offsetWidth + 'px'
            }
        },
        watch: {
            targetBrandList(newVal) {
                this.changeList(newVal)
                // 当显示筛选结果时,给table加一个上边距
            },
            // 监听 data_table 如果传入了 数据,才渲染表格
            data_table: {
                deep: true,
                immediate: true,
                handler(newVal, oldVal) {
                    let that = this
                    setTimeout(() => {
                        try {
                            that.tbodyList = newVal.tbodyList
                            // 将筛选框的高度与表格高度一致
                            let box = document.getElementsByClassName('hzs-filter-box')[0]
                            let hzsCard = document.getElementsByClassName('hzs-card')[0]
                            let hzsLetterList = document.getElementsByClassName('hzs-letter-list')[0]
    
                            let tHeight = document.getElementById('tableBody').offsetHeight
                            let containerHeight = document.getElementsByClassName('container')[0].offsetHeight
    
                            // 动态绑定height
                            if (!!containerHeight) {
                                box.style.height = containerHeight - 56 + 'px';
                                box.style.maxHeight = containerHeight - 56 + 'px';
                                hzsCard.style.height = containerHeight - 56 - 58 + 'px';
                                hzsLetterList.style.height = containerHeight - 56 - 58 - 77 + 'px';
                            } else if (!!tHeight) {
                                box.style.height = tHeight + 'px';
                                box.style.maxHeight = tHeight + 'px';
                                hzsCard.style.height = tHeight - 58 + 'px';
                                hzsLetterList.style.height = containerHeight - 58 - 77 + 'px';
                            }
                            that.$forceUpdate()
                        } catch (err) {
                            console.log(err.message);
                        }
                    }, 300);
                },
            },
        },
        data() {
            return {
                brandList: [],
                currentBrand: [],
                tbodyList: [],
                isShowFilterCard: false,
                targetBrandList: [],
            }
        },
    
        created() {
            this.getAllBrandList()
            this.tbodyList = this.data_table.tbodyList
        },
        mounted() {
            // console.log('temTable');
            // setTimeout(() => {
            //   // console.log(this.$root.tableWidthList);
            //
            //   // this.setTableWidth()
            // })
    
    
            // console.log(this.brandList)
            // this.filterTableBody()
            // console.log(this.tbodyList)
            // console.log(this.$refs.hzsConfirmBrandList)
            this.resize()
            window.addEventListener('resize', this.resize)
        },
    
        template: `
        
    {{ tdItem.name }}

    {{ targetBrandListText }}

    {{ tdItem.name }}
    `
    }) Vue.component('temFilterCard', { // watch: { // tableWidth(newVal) { // console.log("调整width") // console.log(newVal) // this.$refs.filterCard.style.width = `${newVal}px` // } // }, props: { allBrandList: { type: Array, default: () => [] }, isShow: { type: Boolean, default: false }, tableWidth: { type: Number, }, lang: { type: String, } }, computed: { // 按照首字母进行筛选 然后分组 sortBrandDict: function () { let res = {} this.allBrandList.forEach(item => { let firstLetter = item[0].toUpperCase() if (!res.hasOwnProperty(firstLetter)) { res[firstLetter] = [] } res[firstLetter].push(item) }) // 返回排序好的 return this.objKeySort(res) }, targetBrandSet: function () { if (!Array.isArray(this.targetBrandList)) { console.log('type error!') return } let array = []; for (let i = 0; i < this.targetBrandList.length; i++) { if (array.indexOf(this.targetBrandList[i]) === -1) { array.push(this.targetBrandList[i]) } } return array; // return new Set(this.targetBrandList) } }, watch: { // targetBrandSet: { // handler: function(newVal, oldVal){ // console.log("targetBrandSet") // console.log(newVal) // console.log(oldVal) // }, // deep: true // } targetBrandList: { handler: function (newVal, oldVal) { this.textIsShow = !newVal.length // if (newVal.length > 4) { // this.showCaution = true // setTimeout(() => { // this.showCaution = false // }, 3000); // } this.$forceUpdate() } }, lang(newVal) { // alert('筛选框是否显示:' + newVal) this.publicText = publicText } // width(newVal) { // console.log("宽度改变") // console.log(newVal) // this.$refs.filterCard.style.width = `${newVal}px` // } }, data() { return { // 目标brandList targetBrandList: [], currentLetter: 'A', // targetBrandSet: new Set(), textIsShow: true, showCaution: false, filterBoxHeight: 0, publicText: publicText } }, methods: { unique(arr) { if (!Array.isArray(arr)) { console.log('type error!') return } let array = []; for (let i = 0; i < arr.length; i++) { if (array.indexOf(arr[i]) === -1) { array.push(arr[i]) } } return array; }, objKeySort(obj) { //排序的函数 let newKey = Object.keys(obj).sort() // 先用Object内置类的keys方法获取要排序对象的属性名,再利用Array原型上的sort方法对获取的属性名进行排序,newkey是一个数组 let newObj = {} //创建一个新的对象,用于存放排好序的键值对 for (let i = 0; i < newKey.length; i++) { // 遍历newkey数组 newObj[newKey[i]] = obj[newKey[i]] //向新创建的对象中按照排好的顺序依次增加键值对 } return newObj //返回排好序的新对象 }, addFilterBrand(item) { let tmpList = this.unique(this.targetBrandList) if (tmpList.indexOf(item) !== -1) { // console.log(tmpList.indexOf(item)); tmpList.splice(tmpList.indexOf(item), 1) } else { tmpList.push(item) } this.targetBrandList = tmpList // 如果筛选多于四个,进行限制 if (this.targetBrandList.length > 4) { this.showCaution = true setTimeout(() => { this.showCaution = false }, 3000); tmpList.splice(tmpList.indexOf(item), 1) this.targetBrandList = tmpList } // this.targetBrandSet.add(item) // console.log(item) // console.log(this.targetBrandSet) // console.log(Array.from(this.targetBrandSet)) // console.log(this.targetBrandList) }, removeBrand(item) { let tmpList = this.unique(this.targetBrandList) tmpList.splice(tmpList.indexOf(item), 1) this.targetBrandList = tmpList // let tmpList = new Set(this.targetBrandList) // tmpList.delete(item) // this.targetBrandList = Array.from(tmpList) }, confirm() { this.$emit('confirmBrandList', this.targetBrandList) this.$emit("closeCard") }, reset() { this.targetBrandList = [] this.$emit('confirmBrandList', this.targetBrandList) }, cancel() { this.reset() this.$emit("closeCard") }, resize() { // console.log("调整size") let width = document.getElementById('table-header').offsetWidth this.$refs.filterCard.style.width = `${width}px` }, isSelected(item) { // console.log(this.targetBrandSet.has(item)); return this.targetBrandSet.indexOf(item) !== -1 }, closeCard() { this.$emit("closeCard") }, // 滚动到目标字母的位置 scrollToLetter(letter) { let name = 'letter' + letter let targetLetter = this.$refs[name][0] let targetScrollTop = targetLetter.offsetTop + this.$refs.topCard.offsetHeight // this.$refs.filterCard.scrollTop = targetScrollTop // 判断一下能否滑到 // console.log(targetScrollTop) // console.log(this.$refs.filterCard.offsetHeight) // console.log(this.$refs.filterCard.scrollHeight) // console.log(this.$refs.filterCard.scrollHeight - this.$refs.filterCard.offsetHeight) let maxScrollTop = this.$refs.filterCard.scrollHeight - this.$refs.filterCard.offsetHeight if (targetScrollTop < maxScrollTop) { // console.log("能滑到") } else { // console.log("不能滑到") targetScrollTop = maxScrollTop } this.slideAnimate(this.$refs.filterCard, targetScrollTop) }, // 滚动时判断滑到哪个字母了 handleScroll() { // 判断现在是哪个字母 // console.log("正在滚动") let letters = Object.keys(this.sortBrandDict) // 所有已经翻到的字母列表 let allList = [] letters.forEach((letter, index) => { let name = 'letter' + letter let targetLetter = this.$refs[name][0] // 判断 if (this.$refs.filterCard.scrollTop > targetLetter.offsetTop + this.$refs.topCard.offsetHeight - 1) { allList.push(letter) } }) // console.log("所有已经翻到的字母列表") // console.log(allList) if (allList.length > 0) { this.currentLetter = allList[allList.length - 1] } else { this.currentLetter = letters[0] } // console.log(this.currentLetter ) // console.log(allList) }, // 先快后慢 滑动动画封装 slideAnimate(element, targetScrollTop) { clearInterval(element.timer); //清楚历史定时器 element.timer = setInterval(function () { //获取步长 确定移动方向(正负值) 步长应该是越来越小的,缓动的算法。 let step = (targetScrollTop - element.scrollTop) / 5; //对步长进行二次加工(大于0向上取整,小于0项下取整) step = step > 0 ? Math.ceil(step) : Math.floor(step); //动画原理: 目标位置 = 当前位置 + 步长 element.scrollTop += step //检测缓动动画有没有停止 if (Math.abs(targetScrollTop - element.scrollTop) <= Math.abs(step)) { element.scrollTop = targetScrollTop //直接移动指定位置 clearInterval(element.timer); } }, 20); } }, // 生命周期 mounted() { // console.log("sortBrandDict") // console.log(this.sortBrandDict) // this.$set(this.targetBrandSet, new Set()) // 调整宽度 // let width = document.getElementById('table-header').offsetWidth // this.$refs.filterCard.style.width = `${width}px` this.resize() // 调整位置 // this.$refs.hzsFilterBox window.addEventListener('resize', this.resize) console.log(this.lang); // getBoundingClientRect() // this.$refs.filterCard.addEventListener('scroll', this.handleScroll) }, // updated() { // }, template: `

    {{publicText[lang]['had-filtered-brand-text']}}

    {{publicText[lang]['hzs-all-brand-text']}}

    {{key}}
    {{publicText[lang]['hzs-caution-text']}}
    {{publicText[lang]['btn-cancel']}}
    {{publicText[lang]['btn-reset']}}
    {{publicText[lang]['btn-confirm']}}
    `
    })

    css部分

    /* 筛选card 部分 */
    .hzs-filter-box {
        position: absolute;
        top: 0;
        overflow: hidden;
        /*opacity: 1;*/
        /* height: 85vh; */
        padding-bottom: 58px;
        /* max-height: 85vh; */
        /*left: 0;*/
    }
    .hzs-filter-icon {
        margin-left: 10px;
        cursor: pointer;
    }
    
    .hzs-card {
        position: relative;
    
        /*border: 1px solid black;*/
        background: #ffffff;
        box-shadow: 0 5px 5px rgba(0, 0, 0, 0.3);
        font-family: Roboto-Medium;
        /*height: 400px;*/
        /* height: 100%; */
        overflow: auto;
        z-index: 999; /* 这个必须要加 */
        /*transition: height 2s;*/
    }
    
    .brand-tag {
        display: inline-block;
    
        border-radius: 4px;
        border: 1px solid #ebebeb;
    }
    
    .hzs-button-group {
        width: 100%;
        position: absolute;
        bottom: 0;
        /*left: 0;*/
        display: flex;
        padding: 10px;
        justify-content: space-between;
        /*background: url('../img/grey60.png');*/
        border-top: 1px solid #C7C7C7;
        background: linear-gradient(180deg, #F3F3F3, #C7C7C7);
        z-index: 9999;
    }
    
    .hzs-button-group .greyButton {
        padding-left: 20px;
        padding-right: 20px;
        font-weight: 600;
        font-size: 16px;
    }
    
    .hzs-confirm {
        padding: 10px 25px;
        z-index: 1;
        display: inline-flex;
        justify-content: center;
        align-items: center;
        height: 38px;
        min-width: 60px;
        font-family: SourceHanSansCN-Medium;
        font-size: 16px;
        font-weight: 600;
        letter-spacing: 1px;
        outline: none;
    
        white-space: nowrap;
        color: white;
        cursor: pointer;
        border-radius: 5px;
        /*border-image-source: url('../img/grey60.png');*/
    
        background-image: linear-gradient(180deg, #7BBAFF 10%, #0072EE 76%, #007AFF 100%);
        /*box-shadow: 0 2px 0 0 #FFFFFF;*/
        /*border-radius: 14px;*/
    }
    
    .hzs-confirm:active {
        background: linear-gradient(180deg, #007AFF 100%, #0072EE 76%, #7BBAFF 10%);
    }
    
    .hzs-top-card {
        padding: 10px;
    }
    
    .hzs-all-brand-card {
        position: relative;
        padding-right: 30px;
        /*background: #EBEBEB;*/
        background: white;
    
    }
    
    .hzs-first-letter {
        background: #EBEBEB;
        padding: 0 10px;
        font-weight: 600;
        font-size: 17px;
    }
    
    
    .hzs-a-brand {
        background: white;
        padding: 10px;
        font-size: 17px;
        border-bottom: 2px solid #dcdcdc;
        display: flex;
        justify-content: space-between;
    }
    
    .hzs-caution {
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.3);
        z-index: 99999;
    }
    
    .hzs-caution-text {
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        padding: 40px 40px;
        max-width: 450px;
        line-height: 28px;
        background-color: #fff;
        border-radius: 4px;
        font-size: 18px;
        text-align: center;
        white-space: normal
    }
    
    
    /*  已筛选品牌 */
    .had-filtered-brand-text {
        font-size: 20px;
        font-weight: 600;
    }
    
    .hzs-target-brand-list {
        /*min-height: 100px;*/
        /*display: flex;*/
        /*flex-wrap: wrap;*/
        /*justify-content: flex-start;*/
    }
    
    .hzs-brand-tag {
        border: 1px solid gray;
        display: inline-block;
        padding: 5px;
        border-radius: 4px;
        font-size: 18px;
        /*font-weight: 600;*/
        margin-right: 10px;
        margin-top: 10px;
    }
    
    .hzs-brand-tag span:nth-child(1) {
        color: #007AFF;
        padding: 0 5px;
        text-transform: capitalize;
    }
    
    
    .hzs-brand-tag span:nth-child(2) {
        color: rgba(0, 0, 0, 0.3);
    }
    
    .hzs-brand-tag .shanchu {
        display: inline-block;
        width: 12px;
        height: 12px;
        background-image: url(../img/shanchu.png);
        background-size: cover;
        margin-left: 5px;
        margin-right: 5px;
        cursor: pointer;
    }
    
    /* .hzs-brand-tag span:nth-child(3) {
        font-weight: 1000;
        padding: 0 5px;
        font-size: 4px
        font-size: 14px;
        color: brown;
    } */
    
    .hzs-all-brand-text {
        margin: 20px 0 0;
        font-size: 20px;
        font-weight: 600;
    }
    
    .hzs-please-choose {
        text-align: center;
        padding: 20px 0 0;
        font-size: 16px;
        font-weight: 600;
        color: hsl(0, 2%, 50%);
    }
    
    .hzs-letter-list {
        width: 24px;
        position: fixed;
        right: 18px;
        top: 140px;
        font-size: 14px;
        font-weight: 500;
        color: #8C8C8C;
        /* border: 1px solid #000; */
        overflow-y: scroll;
        /*display: flex;*/
        /*flex-flow: column;*/
        /*justify-items: flex-start;*/
    }
    
    .hzs-letter-list::-webkit-scrollbar {
        width: 3px;
    
        height: 18px;
    
        -webkit-border-radius: 5px;
    
        -moz-border-radius: 5px;
    
        border-radius: 5px;
    }
    
    .hzs-letter-list div {
        padding: 0;
        margin-bottom: 4px;
        text-align: center;
    }
    
    .hzs-letter-current {
        font-size: 18px;
        font-weight: 700;
        color: black;
    }
    
    
    .hzs-up {
        /*position: absolute;*/
        /*top: 10px;*/
        /*right: 20px;*/
        /*z-index: 9999;*/
        font-weight: 1000;
        font-size: 20px;
    }
    
    .hzs-up .xiangshang {
        display: inline-block;
        width: 25px;
        height: 25px;
        vertical-align: middle;
        background-image: url(../img/xiangshang.png);
        background-size: cover;
        margin-left: 10px;
        cursor: pointer;
    }
    
    .hzs-confirm-brand-list {
        position: absolute;
        padding: 10px;
        font-size: 16px;
        font-weight: 500;
        border: 1px solid #ccc;
        background: #E1E1E1;
    }
    
    .hzs-gouxuan {
        color: green;
        font-weight: 1000;
    }
    
    .hzs-up-and-had-filtered {
        display: flex;
        justify-content: space-between;
        margin-right: 10px;
    }
    
    .hzs-enter, .hzs-leave-to {
        /*opacity: 0; !*点击按钮页面即将被显示,此时div标签处于隐藏状态*!*/
        height: 0;
    }
    
    /* .hzs-enter-active, .hzs-leave-active  { */
        /*transition: opacity 2s; !* 对该CSS样式进行transition的监控,有2s的过渡*!*/
        /* transition: height 0.4s ease-in-out; */
    /* } */
    
  • 相关阅读:
    IO密集型线程和CPU密集型线程
    搭建solidity开发环境(以太坊)
    【图像分类】Swin Transformer理论解读+实践测试
    【数据结构】二叉搜索树
    mysql分区表的增删改查操作
    Qt+Win10使用QAxWidget控件实现远程桌面控制
    哈希思想的应用 - 位图,布隆过滤器
    C++11 智能指针 已完成未发布
    SQLlabs46关
    pytorch 实现线性回归(Pytorch 03)
  • 原文地址:https://blog.csdn.net/qq_41996454/article/details/126942701