vue 实现左右拖拽布局

使用vue 实现页面左右拖拽效果,出现了好了多点问题
问题1.自己写的第一版代码,出现了 可以console打印出来,就是视图不更新

<template>
    <div id="app">
        <div class="layout-container">
            <div class="left-panel" ref="leftPanel">
                <p>左边面板内容,可以放导航栏等元素</p>
            </div>
            <div class="resizer" @mousedown="startResize"></div>
            <div class="right-panel" ref="rightPanel">
                <p>右边面板内容,比如主体内容展示区</p>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    name: "ConfigFile",
    data() {
        return {
            isResizing: false,
            startX: 0,
            leftWidth: 0,
            rightWidth: 0
        };
    },
    mounted() {
        console.log('Component mounted successfully');
        const leftPanel = this.$refs.leftPanel;
        const rightPanel = this.$refs.rightPanel;
        this.leftWidth = leftPanel.offsetWidth;
        this.rightWidth = rightPanel.offsetWidth;
    },
    methods: {
        startResize(event) {
            event.preventDefault();
            event.stopPropagation();
            console.log(event, 'event')
            this.isResizing = true;
            this.startX = event.pageX;
            document.addEventListener("mousemove", this.resize);
            document.addEventListener("mouseup", this.stopResize);
        },
        resize(event) {
            console.log('resize method called');
            if (this.isResizing) {
                const dx = event.pageX - this.startX;
                console.log('dx value:', dx);
                const leftPanel = this.$refs.leftPanel;
                const rightPanel = this.$refs.rightPanel;
                const newLeftWidth = this.leftWidth + dx;
                const newRightWidth = this.rightWidth - dx;
                console.log('newLeftWidth:', newLeftWidth, 'newRightWidth:', newRightWidth);
                if (newLeftWidth >= leftPanel.offsetWidth && newRightWidth >= rightPanel.offsetWidth) {
                    leftPanel.style.width = newLeftWidth + "px";
                    rightPanel.style.width = newRightWidth + "px";
                    this.leftWidth = newLeftWidth;
                    this.rightWidth = newRightWidth;
                }
            }
        },
        stopResize() {
            this.isResizing = false;
            document.removeEventListener("mousemove", this.resize);
            document.removeEventListener("mouseup", this.stopResize);
        }
    }
};
</script>
<style scoped>
.layout-container {
    display: flex;
    height: 100vh;
    /* 占据整个视口高度 */
}

.left-panel {
    flex: 1;
    min-width: 200px;
    /* 左边面板最小宽度 */
    background-color: lightblue;
    overflow: auto;
}

.resizer {
    pointer-events: auto;
    width: 10px;
    cursor: col-resize;
    /* 鼠标指针样式变成左右拉伸样式 */
    background-color: gray;
    /* 检查是否有透明度等影响鼠标事件的属性,若有可尝试注释掉 */
    /* opacity: 0.5; */
    /* 检查是否有变换相关属性,若有可尝试注释掉 */
    /* transform: rotate(10deg); */
}

.right-panel {
    flex: 2;
    min-width: 300px;
    /* 右边面板最小宽度 */
    background-color: lightgreen;
    overflow: auto;
}
</style> 

解决问题1: 代码的逻辑看起来是正确的,但视图不更新可能是因为在调整面板宽度时没有正确设置 flex 属性。
由于使用了 flex 布局,直接通过 style.width 修改面板的宽度可能不会产生预期的效果。

为了确保视图更新并且实现左右拖拽的功能,可以将面板的宽度设置为 flex 的 flex-basis 属性。

(1)使用 flex-basis 代替 style.width:在调整面板宽度时,使用 flex-basis 来控制面板的初始宽度。

(2)更新 resize 方法:在 resize 方法中,调整 flex-basis 而不是 style.width。

更改好的第二版代码

问题2: 拖拽幅度太大,跟着鼠标拖拽;
问题3: 左右布局的宽度都有最大宽度和最小宽度,到达一定宽度就不能拖拽,需要设置最大宽度和最小宽度

<template>
    <div id="app">
        <div class="layout-container">
            <div class="left-panel" ref="leftPanel">
                <p>左边面板内容,可以放导航栏等元素</p>
            </div>
            <div class="resizer" @mousedown="startResize"></div>
            <div class="right-panel" ref="rightPanel">
                <p>右边面板内容,比如主体内容展示区</p>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    name: "ConfigFile",
    data() {
        return {
            isResizing: false,
            startX: 0,
            leftWidth: 0,
            rightWidth: 0,
        };
    },
    mounted() {
        const leftPanel = this.$refs.leftPanel;
        const rightPanel = this.$refs.rightPanel;
        this.leftWidth = leftPanel.offsetWidth;
        this.rightWidth = rightPanel.offsetWidth;
    },
    methods: {
        startResize(event) {
            event.preventDefault();
            this.isResizing = true;
            this.startX = event.pageX;
            document.addEventListener("mousemove", this.resize);
            document.addEventListener("mouseup", this.stopResize);
        },
        resize(event) {
            if (this.isResizing) {
                const dx = event.pageX - this.startX;
                const leftPanel = this.$refs.leftPanel;
                const rightPanel = this.$refs.rightPanel;
                const newLeftWidth = this.leftWidth + dx;
                const newRightWidth = this.rightWidth - dx;

                // 设置最小宽度限制
                if (newLeftWidth >= 200 && newRightWidth >= 300) {
                    leftPanel.style.flexBasis = newLeftWidth + "px";
                    rightPanel.style.flexBasis = newRightWidth + "px";
                    this.leftWidth = newLeftWidth;
                    this.rightWidth = newRightWidth;
                }
            }
        },
        stopResize() {
            this.isResizing = false;
            document.removeEventListener("mousemove", this.resize);
            document.removeEventListener("mouseup", this.stopResize);
        },
    },
};
</script>

<style scoped>
.layout-container {
    display: flex;
    height: 100vh;
}

.left-panel {
    flex: 0 0 auto; /* Prevents it from growing */
    min-width: 200px;
    background-color: lightblue;
    overflow: auto;
}

.resizer {
    width: 10px;
    cursor: col-resize;
    background-color: gray;
}

.right-panel {
    flex: 1; /* Allows it to grow */
    min-width: 300px;
    background-color: lightgreen;
    overflow: auto;
}
</style>

解决问题2:
为了控制拖拽幅度,使其更加平滑,可以在 resize 方法中计算相对于面板的移动量,而不是直接使用鼠标的 pageX 位置。可以通过在 startResize 方法中记录鼠标的初始位置来实现。

解决问题3:
在 resize 方法中,可以添加条件来限制面板的最大和最小宽度。

下面是完整的第三版代码

<template>
    <div id="app">
        <div class="layout-container">
            <div class="left-panel" ref="leftPanel">
                <p>左边面板内容,可以放导航栏等元素</p>
            </div>
            <div class="resizer" @mousedown="startResize"></div>
            <div class="right-panel" ref="rightPanel">
                <p>右边面板内容,比如主体内容展示区</p>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    name: "ConfigFile",
    data() {
        return {
            isResizing: false,
            startX: 0,
            leftWidth: 0,
            rightWidth: 0,
        };
    },
    mounted() {
        const leftPanel = this.$refs.leftPanel;
        const rightPanel = this.$refs.rightPanel;
        this.leftWidth = leftPanel.offsetWidth;
        this.rightWidth = rightPanel.offsetWidth;
    },
    methods: {
        startResize(event) {
            event.preventDefault();
            this.isResizing = true;
            this.startX = event.pageX; // 记录鼠标起始位置
            document.addEventListener("mousemove", this.resize);
            document.addEventListener("mouseup", this.stopResize);
        },
        resize(event) {
            if (this.isResizing) {
                const dx = event.pageX - this.startX; // 计算相对移动
                const leftPanel = this.$refs.leftPanel;
                const rightPanel = this.$refs.rightPanel;

                const newLeftWidth = this.leftWidth + dx;
                const newRightWidth = this.rightWidth - dx;

                // 设置最小和最大宽度限制
                const minLeftWidth = 200; // 左边面板最小宽度
                const minRightWidth = 300; // 右边面板最小宽度
                const maxLeftWidth = 800; // 左边面板最大宽度
                const maxRightWidth = 1200; // 右边面板最大宽度

                // 如果新的宽度在限制范围内,则更新
                if (newLeftWidth >= minLeftWidth && newLeftWidth <= maxLeftWidth &&
                    newRightWidth >= minRightWidth && newRightWidth <= maxRightWidth) {
                    leftPanel.style.flexBasis = newLeftWidth + "px";
                    rightPanel.style.flexBasis = newRightWidth + "px";
                    this.leftWidth = newLeftWidth;
                    this.rightWidth = newRightWidth;
                }

                // 更新起始位置
                this.startX = event.pageX; // 更新起始位置为当前鼠标位置
            }
        },
        stopResize() {
            this.isResizing = false;
            document.removeEventListener("mousemove", this.resize);
            document.removeEventListener("mouseup", this.stopResize);
        },
    },
};
</script>

<style scoped>
.layout-container {
    display: flex;
    height: 100vh;
}

.left-panel {
    flex: 0 0 auto;
    /* Prevents it from growing */
    min-width: 200px;
    max-width: 800px;
    /* 左边面板最大宽度 */
    background-color: lightblue;
    overflow: auto;
}

.resizer {
    width: 2px;
    cursor: col-resize;
    background-color: gray;
}

.right-panel {
    flex: 1;
    /* Allows it to grow */
    min-width: 300px;
    max-width: 1200px;
    /* 右边面板最大宽度 */
    background-color: lightgreen;
    overflow: auto;
}
</style>

实现效果

在这里插入图片描述

今天又发现几个点,进行下补充:
样式可能有点不一样,大概是一致

**问题点4:**确保左侧和右侧的宽度总和为 100%。
在鼠标拖动时,左侧宽度减少时,右侧宽度增加,反之亦然。

**问题点5:**设置左右两侧的最小和最大宽度为相对的百分比。

<template>
    <div id="app">
        <div class="layout-container">
            <div class="left-panel" ref="leftPanel" :style="{ flexBasis: leftWidth + '%' }">
                <slot name="leftCon"></slot>
            </div>
            <div class="resizer" @mousedown="startResize"></div>
            <div class="right-panel" ref="rightPanel" :style="{ flexBasis: rightWidth + '%' }">
                <slot name="rightCon"></slot>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    name: "ResizablePanelLayout",
    data() {
        return {
            isResizing: false,
            startX: 0,
            leftWidth: 50, // 初始左侧宽度为50%
            rightWidth: 50, // 初始右侧宽度为50%
        };
    },
    methods: {
        startResize(event) {
            event.preventDefault();
            this.isResizing = true;
            this.startX = event.pageX; // 记录鼠标起始位置
            document.addEventListener("mousemove", this.resize);
            document.addEventListener("mouseup", this.stopResize);
        },
        resize(event) {
            if (this.isResizing) {
                const dx = event.pageX - this.startX; // 计算相对移动
                const totalWidth = 100; // 总宽度为100%
                const minLeftWidth = 10; // 左边面板最小宽度为10%
                const minRightWidth = 10; // 右边面板最小宽度为10%

                // 计算新的宽度
                let newLeftWidth = this.leftWidth + (dx / window.innerWidth) * totalWidth;
                let newRightWidth = totalWidth - newLeftWidth;

                // 如果新的宽度在限制范围内,则更新
                if (newLeftWidth >= minLeftWidth && newRightWidth >= minRightWidth) {
                    this.leftWidth = newLeftWidth;
                    this.rightWidth = newRightWidth;
                }

                // 更新起始位置
                this.startX = event.pageX; // 更新起始位置为当前鼠标位置
            }
        },
        stopResize() {
            this.isResizing = false;
            document.removeEventListener("mousemove", this.resize);
            document.removeEventListener("mouseup", this.stopResize);
        },
    },
};
</script>

<style scoped>
.layout-container {
    display: flex;
    height: 100vh;
    border-radius: 2px;
}

.left-panel {
    flex: 0 0 auto;
    background-color: rgb(250, 250, 250);
    overflow: auto;
}

.resizer {
    width: 2px;
    cursor: col-resize;
    background-color: gray;
}

.right-panel {
    flex: 1;
    background-color: white;
    overflow: auto;
}
</style>

解决问题4:
宽度设置:将 leftWidth 和 rightWidth 的初始值设置为 50%,并在 resize 方法中根据鼠标移动计算新的宽度。
最小宽度:设置最小宽度为 10%(可以根据需要调整)。
解决问题5:
动态宽度:使用 :style 绑定来动态设置左侧和右侧面板的宽度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值