后代选择+++margin-right:auto

本文详细介绍了CSS中的:nth-child和:nth-of-type选择器的使用方法,通过实例展示了如何精确选择元素,同时提供了使子div在父div中居中的CSS技巧。

 

nth-child的使用

<div id="BorderOne">
     <span>1</span>
     <span>2</span>
     <span>3</span>
</div>

 

#BorderOne span:nth-child(1){}
#BorderOne span:nth-child(2){}
#BorderOne span:nth-child(3){}

 nth-of-type(2)的使用

<div class="div1">

  <ul>

    <li></li>

    <li></li>

    <li></li>

  </ul>

</div>

样式则为:

  .div1>ul>li:nth-of-type(2){

      写样式即可

   }

 

 

 


margin-right:none等

在一个大的div里嵌套一个div使其居中可用以下css样式给第二div设置

divTwo{margin-right:atuo;margin-left:auto}自己可根据实际情况外加padding

 

转载于:https://www.cnblogs.com/YDshuaizai/p/7055479.html

<template> <el-dialog :append-to-body="true" title="配置人员" v-if="hasLoaded" :close-on-click-modal="false" v-model="dialogVisible" width="700px" center class="dialog" @close="handleDialogVisible" > <div class="line"></div> <el-form ref="form" :model="form" label-width="140px" size="default" :rules="rules"> <div> 活动名称:【活动ID] 活动名称 </div> <!-- 树状选择区域 --> <div class="merchant-select-area"> <div style="text-align: center;position: relative"> <h3>选择人员</h3> <div class="selectablebox" style="margin-right: -2px"> <el-input placeholder="请输入名称/ID" v-model="merchantSearch" style="margin-bottom: 10px; width: 220px" class="merchant-search-input" clearable /> <Search class="small-search-icon" /> <el-tree ref="merchantTree" :data="filteredTreeData" show-checkbox node-key="id" :props="treeProps" :filter-node-method="filterNode" @check-change="handleTreeCheck" default-expand-all ></el-tree> </div> </div> <!-- 中间:穿梭箭头 --> <div class="arrow-column"> <el-button class="btn" @click="moveToSelected" :disabled="selectedTreeNodes.length === 0"> <el-icon class="icons"> <ArrowRight /> <ArrowRight /> </el-icon> </el-button> <el-button class="btn" @click="moveToSelectable" :disabled="selectedMerchantsToRemove.length === 0"> <el-icon class="icons"> <ArrowLeft /> <ArrowLeft /> </el-icon> </el-button> </div> <!-- 右侧:已选列表 --> <div style="text-align: center" class="boxes"> <h3>已选中人员</h3> <div class="selectablebox"> <div class="selected-column"> <el-checkbox-group v-model="selectedMerchantsToRemove"> <el-checkbox v-for="merchant in selectedMerchants" :key="merchant.id" :label="merchant" style="display: block; margin-bottom: 5px" class="merchant-checkbox" > {{ merchant.name }} </el-checkbox> </el-checkbox-group> </div> </div> </div> </div> <div class="dialog-footer"> <el-button @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="handleSave">保存</el-button> </div> </el-form> </el-dialog> </template> <script> import _ from 'lodash'; import { ElMessageBox, ElMessage } from 'element-plus'; import { Validator } from '/@/config/utils'; import { ArrowRight, ArrowLeft } from '@element-plus/icons-vue'; export default { components: { ArrowRight, ArrowLeft }, props: { id: { type: String, default: '', }, activeId:{ type: String, default: '', } }, data() { return { form: { signatureTime: [], templateName: '5', }, dialogVisible: true, hasLoaded: false, merchantSearch: '', treeData: [], // 原始树数据(包含所有节点) filteredTreeData: [], // 过滤后显示的树数据(隐藏已选节点) treeProps: { children: 'children', label: 'name' }, selectedMerchants: [], // 已选中的人员(右侧列表) selectedMerchantsToRemove: [], // 右侧待移除的人员 selectedTreeNodes: [], // 左侧树中勾选的节点(待右移) }; }, created() { this.getDetail(); }, watch: { merchantSearch(val) { this.$refs.merchantTree.filter(val); }, }, methods: { async getDetail() { this.$http.get(this.$api.settlement.promoteRateUserConfigDetail, { params: { promoteId: this.id }// 传递费率模板ID }).then(({ data }) => { this.treeData = [...data.noMappingUserList] this.selectedMerchants = [...(data.mappingUserList || [])] this.filterTreeData(); this.hasLoaded = true; }).catch(err => { console.error('数据加载错误:', err) }) }, // 过滤树数据(隐藏已选节点) filterTreeData() { const selectedIds = this.selectedMerchants.map((m) => m.id); this.filteredTreeData = this.deepFilterTree( JSON.parse(JSON.stringify(this.treeData)), // 深拷贝避免污染原始数据 selectedIds ); }, deepFilterTree(tree, excludedIds) { return tree .map((node) => { if (excludedIds.includes(node.id)) return null; if (node.children && node.children.length > 0) { const filteredChildren = this.deepFilterTree(node.children, excludedIds).filter((child) => child !== null); if (filteredChildren.length > 0) { return { ...node, children: filteredChildren }; } return null; // 如果子节点都被过滤掉了,返回 null 表示该节点也需要被过滤 } return node; }) .filter((node) => node !== null); }, // 树节点过滤方法(用于搜索) filterNode(value, data) { if (!value) return true; return data.name.includes(value) || (data.id && data.id.includes(value)); }, // 树节点勾选变化 handleTreeCheck(data, checked) { // 修复3:确保正确获取勾选的节点 if (this.$refs.merchantTree) { const checkedNodes = this.$refs.merchantTree.getCheckedNodes(true); this.selectedTreeNodes = checkedNodes.filter((node) => !node.children); // 只保留叶子节点(人员) } }, // 右移:选中节点到右侧 moveToSelected() { if (this.selectedTreeNodes.length === 0) return; // 合并到已选列表(去重) this.selectedMerchants = _.unionBy(this.selectedMerchants, this.selectedTreeNodes, 'id'); // 取消树中勾选 & 重新过滤树(隐藏已选节点) this.selectedTreeNodes.forEach((node) => { if (this.$refs.merchantTree) { this.$refs.merchantTree.setChecked(node.id, false, true); } }); this.selectedTreeNodes = []; this.filterTreeData(); }, // 左移:从右侧移除节点 moveToSelectable() { if (this.selectedMerchantsToRemove.length === 0) return; // 从已选列表移除 this.selectedMerchants = this.selectedMerchants.filter((m) => !this.selectedMerchantsToRemove.some((rm) => rm.id === m.id)); // 清空右侧待移除勾选 & 重新过滤树(显示移回的节点) this.selectedMerchantsToRemove = []; this.filterTreeData(); // 刷新树(显示移回的节点) }, handleSave() { let vm = this; let { form } = this; var validator = new Validator(); validator.add(vm.selectedMerchants, [{ strategy: 'isNonEmpty', errorMsg: '请至少选择一个人员' }]); const errorMsg = validator.check(); if (errorMsg) return ElMessage.error(errorMsg); console.log('最终选中的人员:', this.selectedMerchants); const submitData = { activeId:this.activeId, userIds:this.selectedMerchants.map(item => item.userId) // 已选中的人员数组 }; console.log("88888888888",submitData); this.$http.post(this.$api.settlement.comASave, submitData) .then(( data ) => { console.log('配置已保存:', data) if (data.code == 0) { this.$message.success('配置已保存') this.$emit('onSuccess', submitData) this.dialogVisible = false } else { this.$message.error(data.msg || '保存失败') } }) .catch(err => { //this.$message.error('保存失败,请重试') console.error('保存错误:', err) }) }, handleDialogVisible() { this.$emit('onClose'); }, }, }; </script> <style lang="scss" scoped> ::v-deep .el-input { width: 350px; } .dialog-footer { display: flex; justify-content: center; margin-top: 20px; } .line { margin-top: -20px; margin-bottom: 23px; border-bottom: 1px solid #3333 !important; } ::v-deep .el-dialog__title { text-align: center; font-size: 18px; } ::v-deep .el-date-editor { min-width: 350px !important; } .merchant-select-area { display: flex; justify-content: space-between; margin-top: 43px; max-height: 400px; overflow: hidden; } .boxes { margin-bottom: 10px; display: flex; flex-direction: column; align-items: center; width: 26-px; } .selectablebox { margin-top: 10px; width: 260px; border: 1px solid #3333; border-radius: 5px; padding: 10px; height: 350px; } .selectablebox > div { width: 100%; } .arrow-column { display: flex; flex-direction: column; justify-content: center; align-items: center; } .arrow-column .el-button { margin: 5px 0; } /* 树组件样式 */ ::v-deep .el-tree { width: 100%; max-height: 350px; overflow-y: auto; padding: 10px; } /* 已选列表样式 */ .selected-column { flex: 1; width: 90%; max-height: 350px; overflow-y: auto; border-radius: 5px; // padding: 10px; margin-top: 10px; } /* 优化滚动条 */ ::v-deep .el-tree::-webkit-scrollbar, .selected-column::-webkit-scrollbar { width: 6px; } ::v-deep .el-tree::-webkit-scrollbar-thumb, .selected-column::-webkit-scrollbar-thumb { background-color: #ddd; border-radius: 3px; } .merchant-search-input ::v-deep .el-input__wrapper { border-radius: 30px; } .merchant-checkbox ::v-deep.el-checkbox { // border: 1px solid #3333; width: 100%; // box-sizing: border-box; // word-wrap: break-word; // word-break: break-all; height: 37px; line-height: 37px; padding-left: 10px; margin-top: 10px; } .btn { color: var(--el-color-primary); border: 1px solid var(--el-color-primary); } :deep(.small-search-icon) { font-size: 12px !important; color: #666 !important; cursor: pointer; position: absolute; top: 52px; right: 69px; width: 12px !important; height: 12px !important; } :deep(.el-checkbox-group) { display: flex !important; flex-wrap: wrap; } :deep(.el-checkbox-group .el-checkbox) { width: 47px !important; box-sizing: border-box; } :deep(.el-button:not(.is-circle) i.el-icon), :deep(.el-button i.fa), :deep(.el-button--default i.iconfont), :deep(.el-button--default i.fa) { font-size: 32px !important; } </style> 树形结构移动到右边将父节点也要带过去,将父节点移动到右边同时移动父节点下面的所有数据到左边
10-17
<!-- src/views/PermissionApplyPage.vue --> <template> <div class="permission_apply_page"> <div class="permission-panel"> <!-- 标题 + 帮助图标 --> <div class="permission-panel-title"> {{ t('您没有当前页面的数据权限') }} <el-icon class="help-icon" @click="handleHelpClick" :size="20" style="margin-left: 8px; cursor: pointer" > <QuestionFilled /> </el-icon> </div> <!-- 内容区域 --> <div class="permission-panel-content"> <!-- Tab 按钮 --> <div class="tab-buttons" role="tablist"> <button v-for="tab in tabs" :key="tab.key" class="tab-btn" :class="{ active: currentTab === tab.key }" :aria-selected="currentTab === tab.key" tabindex="0" role="tab" @click="switchTab(tab.key)" > {{ tab.label }} </button> </div> <!-- 动态面板内容 --> <div v-for="tab in tabs" v-show="currentTab === tab.key" :id="`panel-${tab.key}`" :key="tab.key" role="tabpanel" :aria-labelledby="`tab-${tab.key}`" > <component :is="tab.component" /> </div> <div class="back-button" @click="back"> <el-icon style="color: #ffffff; font-size: 16px; font-weight: bold"> <ArrowLeft /> </el-icon> </div> </div> </div> </div> </template> <script setup lang="ts"> import { ref } from 'vue'; import { useI18n } from 'vue-i18n'; import { ArrowLeft, QuestionFilled } from '@element-plus/icons-vue'; import NotOwnedPanel from './components/NotOwnedPanel.vue'; import OwnedPanel from './components/OwnedPanel.vue'; import PendingPanel from './components/PendingPanel.vue'; import { useRouter } from 'vue-router'; const { t } = useI18n(); const router = useRouter(); // 定义 Tab 数据及对应组件 const tabs = [ { key: 'not-owned', label: '未拥有', component: NotOwnedPanel }, { key: 'owned', label: '已拥有', component: OwnedPanel }, { key: 'pending', label: '审批中', component: PendingPanel }, ] as const; const currentTab = ref<'not-owned' | 'owned' | 'pending'>('not-owned'); const switchTab = (key: typeof currentTab.value) => { currentTab.value = key; }; const handleHelpClick = () => { window.open( 'https://3ms.huawei.com/km/groups/3945222/blogs/details/18952136', '_blank', 'noopener,noreferrer' ); }; const back = () => { router.back(); }; </script> <style scoped lang="less"> @primary-color: #5e7ce0; @text-dark: #252b3a; @tab-inactive-bg: var(--btn-hover-color); .permission_apply_page { width: 100%; height: 100%; overflow: auto; border-left: 3px solid gray; background: #fff; } .permission-panel { width: 1044px; margin: 0 auto; &-title { font-size: 27px; color: @text-dark; font-weight: 600; padding-top: 11vh; display: flex; align-items: center; gap: 8px; margin-bottom: 30px; } &-content { min-height: 400px; position: relative; .back-button { position: fixed; right: 0; top: 50vh; transform: translateY(-50%); background: #1f92ff; width: 20px; height: 40px; border-bottom-left-radius: 20px; border-top-left-radius: 20px; display: flex; align-items: center; justify-content: center; cursor: pointer; } } } .tab-buttons { display: flex; margin-bottom: 20px; } .tab-btn { width: 99px; height: 31px; line-height: 31px; border: none; border-radius: 2px; cursor: pointer; font-size: 16px; font-weight: 500; background-color: @tab-inactive-bg; color: #333; border-right: 1px solid #ffffff; &:focus-visible { outline: 2px solid @primary-color; border-radius: 4px; } } .tab-btn.active { background-color: @primary-color; color: #fff; } .loading { text-align: center; padding: 40px; color: #666; font-style: italic; } </style> 点击了快捷申请按钮之后,NotOwnedPanel组件里面的列表内容要刷新一下
10-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值