vue2:关于页面布局-行内列间间隔的调整

59 篇文章 ¥19.90 ¥99.00

如下图三行

有些控件之间需要有间隔,表示虽是同一行,但是相互之间并没有关系;

有些控件之间没有间隔,表示互相关联。

1、同行没有关系,需要有间隔的列

每一个el-col中添加一个el-form-item即可,每个el-form-item之间会有间隔

<el-col :lg="12" :sm="24">
   <el-form-item  label="相关研发需求:" prop="requirementUnid">
      <!--添加控件-->
      <el-select style="width: 100%"/>    
   </el-form-item>
</el-col>
<el-col :lg="12" :sm="24">            
   <el-form-item  label="所属模块:" prop="moduleUnid">
        <!--添加控件-->
        <el-cascader></el-cascader>
    </el-form-item>            
</el-col>

2、相互之间没有间隔,且第二个控件不需要额

uniapp 以下代码 内置浏览器样式运行到手机上样式有偏差 小车距离不一致<template> <view class="wapper"> <!-- <view class="bg-image"></view> --> <image class="bg-image" src="/static/home/bus/bg-image.png" mode="widthFix" style="width: 100%;" /> <!-- 自定义导航栏 --> <view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }"> <view class="navbar-content"> <!-- 左侧返回按钮 --> <view class="back-btn" @click="handleBack"> <image src="/static/home/bus/back-icon.png" mode="aspectFit" style="width: 48rpx;height: 48rpx;" /> </view> <!--标题 --> <text class="title">{{busLineBase.name}}</text> </view> </view> <view class="wapper-content" :style="{ paddingTop: statusBarHeight +50 + 'px' }"> <view class="line_info"> <view class="site"> <text class="from">{{busLineBase.startSn}}</text> <view class="arrow"> <text class="to">{{busLineBase.endSn}}</text> </view> </view> <view class="tit"> <view class="time_s"> <text class="time-text">{{busLineBase.firstTime}}</text> </view> <view class="time_e"> <text class="time-text">{{busLineBase.lastTime}}</text> </view> <text class="price">票价: {{busLineBase.price}}</text> </view> </view> <view class="distance-class"> <view class="station"> <view class="station-title"> <view class="station-name">候车站</view> <view class="station-content"> <view class="active">动漫大厦</view> <view class="underline"></view> </view> </view> </view> <view class="distance"> <view class="time"> <text class="time_title" v-if="haveBus">12分钟</text> <text v-else>暂无车辆时</text> </view> <text class="arr">5站/2.4km</text> </view> </view> </view> <view class="site_list"> <scroll-view class="wapper_sitelist" scroll-x="true"> <view v-for="(item, index) in stateBus"> <div class="bus_road" :style="{marginLeft:item.order*48+'px'}"></div> </view> <view class="road"> <view class='part' v-for="(item, index) in siteList" @click="showActive(index, item.siteName)"> <view class='name'> <view> <view class="dot_p" :class="{'dot_p_show': ind === index}"></view> <view class='dot_r' v-if="index!=siteList.length-1"></view> </view> <view class='dot_d' :class="{'dot_d_show': ind === index}"></view> <text class='text' :class="{'text_show': ind === index}"> {{index +1}} <text class="text-dir"> {{item.sn}} </text> </text> </view> </view> </view> </scroll-view> </view> </view> </template> <script> import { getRealTimeBusLine } from '@/request/bus.js' export default { data() { return { ind: 5, siteId: "", lineName: "二号线", siteName: "动漫园站", siteList: [], busLineBase: [], stateBus: [], time_s: '', time_e: '', from: '', busPosition: [0, 5, 11], to: '', isActive: false, lineId: '', siteNum: '0', haveBus: true, // 保留原有数据项... } }, onLoad(options) { // 获取路由参数 const { statusBarHeight } = uni.getSystemInfoSync() this.statusBarHeight = statusBarHeight this.lineId = options.lineId this.lat = options.lat this.lng = options.lng this.getLineDetail() // 使用uni-app地图API // this.loadLineInfo() }, methods: { async getLineDetail() { var res = await getRealTimeBusLine({ lineId: this.lineId, lat: this.lat, lng: this.lng }) if (res.code == 0) { console.log(res) this.siteList = res.data.busInfStop this.busLineBase = res.data.busLineBase this.stateBus = res.data.stateBus this.ind = res.data.targetOrder } }, showActive(index, siteName) { this.ind = index this.text = siteName var TF = false for (let i = 0; i <= this.busPosition.length; i++) { if (index + 1 > this.busPosition[i]) { // this.haveBus = true this.siteNum = index + 1 - this.busPosition[i] TF = true } } if (TF === false) { // this.haveBus = false } }, handleBack() { uni.navigateBack() }, async loadLineInfo() { try { // 使用uni-app请求API const res = await uni.request({ url: `https://restapi.amap.com/v3/bus/linename`, data: { key: 'cd0bbe150380e1263de209abf425745b', city: '天津', keywords: this.lineName, extensions: 'all' } }) if (res.data.status === '1') { this.processLineData(res.data.lineinfo[0]) } } catch (e) { console.error('公交线路加载失败', e) } }, processLineData(tips) { // 数据处理逻辑(与Vue版相同) this.from = tips.start_stop + '-' this.to = tips.end_stop this.lineId = tips.id // 其他数据处理... }, // 保留showActivechangeDirect方法... } } </script> <style> page { background-color: #f5f5f5; } </style> <style scoped> .bg-image { position: absolute; } .custom-navbar { position: fixed; top: 0; left: 0; width: 100%; z-index: 1000; /* 自定义背景色 */ /* 自定义阴影 */ } .navbar-content { height: 44px; /* 标准导航栏高度 */ display: flex; align-items: center; padding: 0 15px; } .title { flex: 1; text-align: center; font-size: 17px; font-weight: bold; color: #333; /* 标题颜色 */ } .back-btn { width: 24px; height: 24px; } .right-area { width: 40px; text-align: right; } .info_wapper { height: 156px; /* background: #36A3F9; */ /* background: url(@/static/home/bus/detail-bg.png) left no-repeat; */ padding: 15px; color: black; position: absolute; z-index: 9; width: 100%; } .line_info { position: relative; /* display: flex; */ } .site { font-size: 32rpx; color: black; margin-bottom: 10px; text-align: left; display: flex; margin-left: 30px; } .from { /* padding-left: 52rpx; */ color: black; } .arrow { background: url(@/static/home/bus/single.png) left no-repeat; background-size: 14px 5px; margin-left: 10px; color: black; } .to { padding-left: 26px; color: black; } .time_s { background: url(@/static/home/bus/start.png) left no-repeat; background-size: 18px 18px; justify-self: baseline; } .time_e { background: url(@/static/home/bus/end.png) left no-repeat; background-size: 18px 18px; margin-left: 15px; } .price { margin-left: 15px; } .tit { color: #fff; font-size: 26rpx; /* padding-left: 52rpx; */ margin-bottom: 10px; height: 21px; color: #333; display: flex; align-items: baseline; margin-left: 30px; } .distance-class { border-radius: 15px; /* box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); */ background: url(@/static/home/bus/distance-bg.png) center no-repeat; background-size: cover; height: 160px; position: absolute; z-index: 999; left: 20px; right: 20px; } .distance { color: #B7BABB; line-height: 20px; text-align: center; display: flex; flex-direction: column; align-items: center; position: relative; z-index: 99; /* align-items: baseline; */ } .time { color: aquamarine; } .station { margin-left: 20px; color: #353738; padding: 10px; } .station-title { display: flex; align-items: baseline; } .station-name { margin-right: 15px; } .station-content { padding-top: 10px; /* padding-left: 20rpx; */ position: relative; /* padding-right: 50rpx; */ /* 确保文字在下划线上方 */ z-index: 2; justify-content: center; display: flex; align-items: center; /* 文字在上层 */ } .underline { position: absolute; bottom: 2px; height: 3px; background: linear-gradient(to right, rgb(110, 207, 169), rgb(110, 224, 176)); /* 下划线颜色 */ border-radius: 3px; z-index: -1; width: 80%; align-items: center; justify-content: center; display: flex; /* margin-left: 30rpx; */ /* width: 60rpx; */ /* 下划线在文字下方 */ } .active { color: black; /* 激活状态文字颜色 */ font-weight: bold; /* font-size: 36rpx; */ } .time { float: left; width: 40%; font-size: 26rpx; /* height: 130rpx; */ line-height: 40px; } .time { font-size: 36rpx; color: #353738; } .time-text { margin-left: 25px; } .time_title { color: rgb(14, 170, 112); font-weight: bold; } .arr { float: left; /* width: 20%; */ font-size: 30rpx; color: rgb(14, 170, 112); } .site_list { /* margin: 15px; */ /* box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); */ background-color: white; border-radius: 15px; margin-top: 150px; padding-left: 15px; padding-right: 15px; padding-top: 15px; padding-bottom: 10px; background: url(@/static/home/bus/site-bg.png) center no-repeat; position: absolute; z-index: 999; left: 20px; right: 20px; background-size: cover; /* 让背景图片覆盖整个视口 */ } .site_list .wapper_sitelist { width: 100%; overflow-x: scroll; position: relative; -webkit-overflow-scrolling: touch; display: flex; } .bus_road { background: url(@/static/home/bus/bus.png) no-repeat center; background-size: 28px 28px; width: 28px; height: 14px; position: absolute; z-index: 1; margin-top: 4px; left: 14px; } .road { display: flex; } .wapper_sitelist::-webkit-scrollbar { display: none; } /deep/::-webkit-scrollbar { display: none; width: 0; height: 0; } .part { padding: 10px; display: flex; flex-direction: row; text-align: center; justify-content: center; } .site_list .dot_r { margin-top: 25px; position: absolute; top: 3px; height: 3px; background: linear-gradient(to right, rgb(110, 207, 169), rgb(110, 224, 176)); /* 下划线颜色 */ border-radius: 3rpx; z-index: 1; width: 48px; align-items: center; justify-content: center; display: flex; } .site_list .name { margin-top: 28px; display: flex; flex-direction: column; align-items: center; } .site_list .text { display: flex; text-align: center; margin-left: 5px; } .site_list .text_show { display: flex; text-align: center; margin-left: 5px; color: rgb(14, 170, 112); font-weight: bold; } .site_list .dot_show { background: url(@/static/home/bus/position_red.png) no-repeat center; background-size: 14px 18px; } .site_list .dot_d_show { border-radius: 50%; width: 16px; height: 16px; background-color: rgba(110, 207, 169, 0.5); position: absolute; z-index: 99999; top: 21px; margin-left: 8px; display: flex; align-items: center; justify-content: center; } .road-class { display: flex; } .dot_p { border-radius: 50%; width: 8px; height: 8px; background-color: rgb(110, 207, 169); position: absolute; z-index: 99999; top: 25px; display: flex; align-items: center; justify-content: center; /* margin-left: 10rpx; */ } .dot_p_show { border-radius: 50%; width: 8px; height: 8px; background-color: rgb(14, 170, 112); position: absolute; z-index: 99999; top: 25px; display: flex; align-items: center; justify-content: center; } .text-dir{ margin-top: 5px; writing-mode: vertical-rl; letter-spacing: 3px; } </style>
最新发布
07-02
<think>好的,用户想了解如何使用Vue3Element-Plus实现双菜单的功能。首先,我需要回忆一下Element-Plus的组件库,是否有现成的双菜单组件。Element-Plus的菜单组件通常是单的,但用户可能需要通过布局来实现双。可能需要使用布局组件如el-rowel-col来分。 接下来,考虑数据结构。双菜单通常是将菜单项分成两部分显示,所以可能需要将数据分成两组,或者根据屏幕宽度动态分。例如,将菜单数组按索引分成前半部分后半部分,分别显示在两中。 然后,用户交互方面,可能需要处理菜单的点击事件,保持选中状态的一致性。使用Vue3的响应式系统,比如ref或reactive来管理当前选中的菜单项,并在两同步状态。 另外,样式调整也很重要。需要确保两菜单的布局美观,可能使用Flex布局或者Grid布局来分配空,并添加适当的内边距间隔。 还需要参考用户提供的引用内容,其中提到了在表格中实现行内编辑,虽然场景不同,但组件通信状态管理的思路可能有借鉴之处。比如,使用v-model传递值,触发事件更新父组件状态。 最后,考虑示例代码的结构,使用el-menu组件包裹两个el-col,每个内再使用el-menu-item展示菜单项。通过计算属性分割数据,处理点击事件更新激活的菜单。 可能还需要处理响应式布局,确保在不同屏幕尺寸下双显示合理。此外,添加样式让两有分隔线,提升视觉效果。 总结步骤:搭建布局结构,处理数据分,状态管理,事件处理,样式调整。然后根据这些步骤编写示例代码,并解释关键点。</think># Vue3 + Element-Plus 双菜单实现方法 ## 一、实现步骤 ### 1. 布局结构搭建 使用$el-row$$el-col$组件实现响应式双布局: ```html <el-row :gutter="20"> <el-col :span="12"> <!-- 左侧菜单 --> </el-col> <el-col :span="12"> <!-- 右侧菜单 --> </el-col> </el-row> ``` ### 2. 菜单数据分割 通过计算属性分割菜单数据: ```javascript const menuItems = ref([ { id: 1, name: '菜单1' }, { id: 2, name: '菜单2' }, // ...更多菜单项 ]); const leftMenus = computed(() => menuItems.value.slice(0, Math.ceil(menuItems.value.length / 2)) ); const rightMenus = computed(() => menuItems.value.slice(Math.ceil(menuItems.value.length / 2)) ); ``` ### 3. 双菜单实现 ```html <el-menu mode="vertical" :default-active="activeIndex" @select="handleSelect" > <el-row :gutter="20"> <el-col :span="12"> <template v-for="item in leftMenus" :key="item.id"> <el-menu-item :index="item.id.toString()"> {{ item.name }} </el-menu-item> </template> </el-col> <el-col :span="12"> <template v-for="item in rightMenus" :key="item.id"> <el-menu-item :index="item.id.toString()"> {{ item.name }} </el-menu-item> </template> </el-col> </el-row> </el-menu> ``` ### 4. 状态管理 ```javascript const activeIndex = ref('1'); const handleSelect = (index) => { activeIndex.value = index; // 触发菜单切换逻辑 } ``` ## 二、关键功能说明 1. **响应式分割**:通过计算属性自动根据菜单项数量平分到两 2. **状态同步**:使用统一的$activeIndex$管理两菜单选中状态 3. **样式优化**:添加自定义CSS实现视觉分隔 ```css .el-col { border-right: 1px solid #eee; &:last-child { border-right: none; } } ``` ## 三、完整示例 参考Element-Plus的菜单组件封装方式[^2],可创建可复用的双菜单组件: ```vue <template> <div class="dual-column-menu"> <el-menu ...> <!-- 上述双结构 --> </el-menu> </div> </template> <script setup> // 上述逻辑代码 </script> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值