收藏
回答

uniapp 微信小程序,iOS14,iOS14.1,递归组件,scroll-view无法滚动?

<template>
    <div class="eo-cascader-panel" :style="[panelStyle()]">
        <view
            v-if="multiple && incrementCount > 1"
            class="flex-row row-column-center row-between"
            :style="[selectBtnStyle(), { height: '80rpx' }]"
            @click.stop="selectAll"
        >
            <text class="option ellipsis_one" style="padding:0;">全选</text>
            <view v-if="multiple" class="checkbox" :style="{ backgroundColor: checkedAll ? '#0092ff' : 'transparent' }">
                <view class="gou"></view>
            </view>
        </view>


        <scroll-view scroll-y class="eo-cascader-menu" :style="[menuStyle()]">
            <li class="has-child" v-for="(item, index) in list" :key="index">
                <view
                    class="option flex-row row-column-center row-between"
                    :style="{ backgroundColor: item.childVisible ? '#ffffff' : '' }"
                    @click="changeList(item, index)"
                >
                    <view v-if="item.childVisible && incrementCount === 1 && line" class="vertical-line"></view>
                    <text :style="[optionStyle(item)]" class="list-name ellipsis_one">{{ item.name }}</text>
                    <image
                        v-if="incrementCount === deep && item.childVisible && !multiple && selectBtnVisible"
                        src="@/static/icon/check.png"
                        class="radio-img"
                    ></image>
                    <view
                        v-if="incrementCount === deep && multiple && selectBtnVisible"
                        class="checkbox"
                        @click.stop="multipleSelect(item, index)"
                        :style="{ backgroundColor: item.selected ? '#0092ff' : 'transparent' }"
                    >
                        <view class="gou"></view>
                    </view>
                </view>
            </li>
        </scroll-view>
        <cascade-option
            ref="CascadeOption"
            v-if="currentOption.childVisible && currentOption.children"
            :options="currentOption.children"
            :cascadeWidth="cascadeWidth"
            :treeWidth="treeWidth"
            :selectBtnWidth="cascadeWidth - firstUlWidth"
            :incrementCount="count"
            :deep="deep"
        ></cascade-option>
    </div>
</template>


<script>
import CascadeOption from "@/pages/templates/CascadeSelection/CascadeOptions.vue";
import Bus from "./bus"; // 总线通信


export default {
    name: "CascadeOption",
    components: {
        CascadeOption
    },
    props: {
        options: {
            // 选择器列表
            type: Array,
            default: []
        },
        firstUlWidth: {
            // 第一级选择器宽度
            type: Number,
            default: 100
        },
        firstUlBackgroundColor: {
            // 第一级选择器背景色
            type: String,
            default: "#fff"
        },
        treeWidth: {
            // 其它级宽度
            type: Number,
            default: 142
        },
        cascadeWidth: {
            // 级联选择器宽度
            type: Number,
            default: 0
        },
        multiple: {
            // 是否支持多选
            type: Boolean,
            default: false
        },
        selectBtnWidth: {
            // 全选按钮的宽度,递归传递,保证子级联能够取到
            type: Number,
            default: 0
        },
        incrementCount: {
            // 当前所属树的哪一层
            type: Number,
            default: 1
        },
        deep: {
            // 当前级联树的深度
            type: Number,
            default: 1
        },
        line: {
            // 是否第一级竖直横线
            type: Boolean,
            default: true
        }
    },
    data() {
        return {
            list: [], // 当前递归组件的列表
            currentOption: null, // 当前递归组件的选中项
            selectBtnVisible: true, // 是否显示全选按钮或单选按钮
            checkedAll: false, // 是否全选
            multipleOperate: true // 是否进行多选框点击操作
        };
    },
    computed: {
        count() {
            let c = this.incrementCount;
            return ++c;
        }
    },
    created() {
        this.init(this.options);
    },
    methods: {
        update(props) {
            this.init(props);
        },
        init(options) {
            this.list = options;


            // 控制全选按钮的显示
            this.selectBtnVisible = true;
            this.$parent.selectBtnVisible = false;
            this.$parent.checkedAll = false;


            if (this.$parent.list) {
                this.$parent.list.forEach(item => {
                    item.selected = false;
                });
            }


            for (let i = 0; i < this.list.length; i++) {
                if (this.list[i].childVisible) {
                    this.currentOption = this.list[i];
                }
            }


            // 手动更新子级联菜单
            this.$nextTick(() => {
                if (Object.keys(this.$refs).length) {
                    this.$refs.CascadeOption.update(this.currentOption.children);
                }
            });
        },
        changeList(item, index) {
            this.multipleOperate = false;


            if (!item.childVisible) {
                for (let i = 0; i < this.list.length; i++) {
                    this.list[i].childVisible = false;
                    this.changeChildVisible(this.list, false);
                }


                item.childVisible = true;
                this.selectBtnVisible = true;
            }


            this.currentOption = item;


            // 手动更新子级联菜单
            this.$nextTick(() => {
                if (Object.keys(this.$refs).length) {
                    this.$refs.CascadeOption.update(this.currentOption.children);
                }
            });


            Bus.$emit("getValue", item, this.incrementCount); // 递归组件使用总线通信,否则会导致递归的子组件无法触发多个emit
        },
        // 递归调用,所以这里是不能直接取到this.currrentOption的值的
        selectAll() {
            this.checkedAll = !this.checkedAll;


            if (this.checkedAll) {
                this.changeTree(this.list, true);
            } else {
                this.changeTree(this.list, false);
            }
        },
        changeChildVisible(data, visible) {
            if (data) {
                data.forEach(item => {
                    item.childVisible = visible;
                    if (item.children) {
                        this.changeChildVisible(item.children, visible);
                    }
                });
            }
        },
        changeTree(data, selected) {
            if (data) {
                data.forEach(item => {
                    item.selected = selected;
                });
            }
        },
        // 复选框操作
        multipleSelect(item, index) {
            this.multipleOperate = true;
            this.currentOption = item;
            item.selected = !item.selected;


            if (this.judgeSelectedAll()) {
                this.checkedAll = true;
            } else {
                this.checkedAll = false;
            }


            Bus.$emit("getValue", item);
        },
        judgeSelectedAll() {
            let flag = false;


            this.list.forEach(item => {
                if (!item.selected) flag = false;
                if (item.selected) flag = true;
            });


            return flag;
        },
        panelStyle() {
            let style = {};


            if (this.incrementCount === 1) {
                style.width = `${this.firstUlWidth}px`;
                style.backgroundColor = `${this.firstUlBackgroundColor} !important`;
            } else {
                style.width = `${this.treeWidth}px`;
            }


            if (this.incrementCount <= 2) {
                style.left = `${this.firstUlWidth * (this.incrementCount - 1)}px`;
            } else {
                style.left = `${this.treeWidth}px`;
            }


            return style;
        },
        optionStyle(item) {
            let style = {};


            if (item.childVisible) {
                style.color = "rgba(0, 146, 255, 1)";
                style.fontWeight = "bold";
            }


            return style;
        },
        selectBtnStyle() {
            let style = {
                position: "relative",
                boxSizing: "border-box",
                padding: "0 28rpx"
            };


            style.width = `${this.selectBtnWidth}px`;


            if (!this.selectBtnVisible) {
                style.visibility = "hidden";
            }


            if (this.incrementCount > 1) {
                style.top = "0";
                style.left = `-${this.treeWidth * (this.incrementCount - 2)}px`;
            }


            return style;
        },
        menuStyle() {
            let style = {};


            if (this.multiple && this.incrementCount > 1) {
                style.height = "calc(100% - 44px)";
            }


            if (this.incrementCount === 1) {
                style.border = "none";
            }


            return style;
        }
    }
};
</script>
<style lang="scss" scoped>
.eo-cascader-panel {
    height: 100%;
    position: absolute;
    background: #fff;
    top: 0;
    left: 0;
}
.eo-cascader-menu {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    color: #606266;
    border-right: 2rpx solid rgba(240, 240, 240, 1);
    -webkit-overflow-scrolling: auto !important;
}
.eo-cascader-menu li {
    width: 100%;
    height: 30px;
    line-height: 30px;
    box-sizing: border-box;
}
.option {
    position: relative;
    box-sizing: border-box;
    padding: 0 14px;
}
.vertical-line {
    width: 8rpx;
    height: 38rpx;
    background: #0092ff;
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
}
.eo-cascader-menu li.has-child:after {
    content: "";
    position: absolute;
    right: 10px;
    top: -2px;
    transform: scaleY(1.8);
    font-size: 12px;
    color: #606266;
}
.radio-img {
    width: 42rpx;
    height: 42rpx;
    position: absolute;
    right: 28rpx;
}
.list-name {
    max-width: 280rpx;
    font-size: 28rpx;
    font-weight: 400;
    font-family: PingFangSC-Medium, PingFang SC;
    color: rgba(89, 89, 89, 1);
}
.checkbox {
    width: 28rpx;
    height: 28rpx;
    border: 2rpx solid #bfbfbf;
    border-radius: 4rpx;
    position: relative;
}
.gou {
    width: 9rpx;
    height: 18rpx;
    border-right: 2rpx solid #fff;
    border-bottom: 2rpx solid #fff;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: rotate(40deg) translate(-120%, -38%);
}
</style>


回答关注问题邀请回答
收藏

3 个回答

  • 崔丛丛
    崔丛丛
    2021-11-02

    请移步uni-app官方社区

    2021-11-02
    有用
    回复
  • 谋谋谋
    谋谋谋
    2021-11-02

    请移步uni-app官方社区

    2021-11-02
    有用
    回复
  • 微喵网络
    微喵网络
    2021-11-02

    请移步uni-app官方社区

    2021-11-02
    有用
    回复
登录 后发表内容