text-align-last: justify 使用方法,对齐字段交互

这篇文章展示了在HTML页面中使用CSS样式创建了一个简单的表单,包含身份证号和密码输入框,用于演示前端用户验证的过程。

在这里插入图片描述

<html>
<style>
  .label {
    display: inline-block;
    width: 100px;
    text-align-last: justify;
  }
</style>

<body>
  <div class="l-content">
    <div>
      <div class="label">身份证:</div>
      <div class="label">xxxx</div>
    </div>
    <div>
      <div class="label">密码:</div>
      <div class="label">xxxx111</div>
    </div>
  </div>
</body>

</html>

<template> <view class="next-tree-view-bottom" :style="{ minHeight: height, paddingLeft: '12px', paddingRight: '12px', backgroundColor: bgColor, paddingBottom: safePaddingBottom }" > <!-- 包裹层控制居中或右对齐 --> <view class="btn-wrapper"> <zy-button v-for="(btn, index) in buttons" :key="index" :class="[ 'next-tree-view-bottom-btn', `next-tree-view-bottom-${btn.type || 'default'}`, btn.disabled ? 'disabled' : '' ]" :loading="loading || btn.loading" :disabled="loading || btn.loading || btn.disabled" :text="btn.text" :type="btn.type || 'primary'" :size="btn.size || 'lg'" @click="handleClick(btn)" > </zy-button> </view> </view> </template> <script setup> import { ref } from 'vue' // 定义 props const props = defineProps({ width: { type: String, default: '100vw' }, height: { type: String, default: '50px' }, bgColor: { type: String, default: '#FFF' }, safeAreaInsetBottom: { type: Boolean, default: true }, safePadding: { type: String, default: '12px' }, buttons: { type: Array, required: true, validator: buttons => Array.isArray(buttons) && buttons.every(btn => typeof btn.text === 'string') }, loading: { type: Boolean, default: false }, debounceTime: { type: Number, default: 0 } }) const emit = defineEmits(['click']) const safePaddingBottom = props.safeAreaInsetBottom ? `max(${props.safePadding}, calc(${props.safePadding} + env(safe-area-inset-bottom)))` : props.safePadding const timers = ref({}) const handleClick = button => { const btnId = button.id ?? button.text if (timers.value[btnId]) clearTimeout(timers.value[btnId]) timers.value[btnId] = setTimeout(() => { emit('click', button) if (typeof button.click === 'function') button.click() }, props.debounceTime) } </script> <style scoped> .next-tree-view-bottom { position: fixed; bottom: 0; left: 0; width: v-bind(width); min-height: 50px; background: #ffffff; z-index: 9999999999; box-sizing: border-box; padding: 12px; /* 安全区已在上面注入 */ } /* 按钮容器:控制对齐方式 */ .btn-wrapper { display: flex; gap: 12px; height: 50px; justify-content: center; /* 默认居中 */ width: 100%; /* 👈 关键:必须占满父容器宽度 */ } /* 大于 600px 时:靠右对齐 */ @media (min-width: 601px) { .btn-wrapper { float: right; width: 30%; } /* 固定按钮宽度 */ .next-tree-view-bottom-btn { width: 200px !important; flex: none !important; } } /* 按钮通用样式 */ .next-tree-view-bottom-btn { height: 50px; line-height: 50px; font-size: 18px; display: flex; justify-content: center; align-items: center; border-radius: 2px; border: none; cursor: pointer; transition: all 0.2s ease; position: relative; } /* 单个按钮:最多占满可用空间(减去间隙) */ .next-tree-view-bottom-btn:first-child:last-child { flex: 1; max-width: calc(100% - 0px); /* 允许撑满 .btn-wrapper */ } /* 两个按钮:每个最多占 (100% - gap)/2 */ .next-tree-view-bottom-btn:nth-child(1):nth-last-child(2), .next-tree-view-bottom-btn:nth-child(2):nth-last-child(1) { flex: 1; max-width: calc((100% - 12px) / 2); } /* 三个及以上:flex: 1 自动均分 */ .next-tree-view-bottom-btn { flex: 1; min-width: 0; } /* 类型化样式 */ .next-tree-view-bottom-default { background: #ffffff; border: 1px solid #e5e5e5; color: #333333; } .next-tree-view-bottom-default:hover:not(:disabled) { background: #f8f8f8; } .next-tree-view-bottom-confirm { background: #0f56d5; color: #ffffff; } .next-tree-view-bottom-confirm:hover:not(:disabled) { background: #0c46b0; } .next-tree-view-bottom-cancel { background: #ffffff; border: 1px solid #e5e5e5; color: #333333; } .next-tree-view-bottom-cancel:hover:not(:disabled) { background: #f8f8f8; } /* 禁用状态 */ .next-tree-view-bottom-btn.disabled, .next-tree-view-bottom-btn:disabled { opacity: 0.6; cursor: not-allowed; } /* 加载动画 */ .spinner { display: inline-block; width: 16px; height: 16px; border: 2px solid #ffffff80; border-top-color: #fff; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } </style> 当前组件直接在<template> <zy-sticky-bottom :buttons="buttons" :safe-area-inset-bottom="true" :safe-padding="'12px'" @click="onButtonClick" /> </template> <script setup> const buttons = [ { text: '取消', type: 'cancel', click: () => console.log('取消被点击') }, { text: '确定', type: 'confirm', click: () => console.log('确定被点击') } ] const onButtonClick = button => { if (button.text == '确定') { console.log('🚀 ~ button.text:', button.text) button.loading = true } } </script> onButtonClick 中修改加载的值没有生效
最新发布
10-21
<template> <!-- 报警自动转工单预案 --> <div class="alarm-work-order"> <template v-if="companyInfo.companyCode"> <a-spin :spinning="isLoading" :delay="500" :tip="$t('加载中...')"> <div class="edit-view"> <div class="input-item"> <div class="input-lable text-bold"> <span>{{ $t('预案是否启用') }}</span> </div> <div class="input-content"> <a-radio-group v-model="formData.enabled" :default-value="1"> <a-radio :value="1">{{ $t('启用') }}</a-radio> <a-radio :value="0">{{ $t('禁用') }}</a-radio> </a-radio-group> </div> </div> <div class="input-item"> <div class="input-lable text-align"> <span> {{ $t('报警类型:') }}</span> </div> <div class="input-content"> <a-select collapseTags mode="multiple" :maxTagCount="2" v-model="formData.type" allowClear placeholder="请选择" optionFilterProp="label" > <a-select-option v-for="(item, index) in typeOptions" :value="item.value" :key="index"> {{ item.label }} </a-select-option> </a-select> </div> </div> <div class="input-item"> <div class="input-lable"> <span> {{ $t('工单派发配置:') }}</span> </div> <div class="table-box" id="tableBox"> <a-table rowKey="department" :columns="columns" :dataSource="displayTableList" :scroll="{ x: '100%' }" :pagination="false" > <template slot="staff" slot-scope="text, record, index"> <a-select v-model="record.staffConfig" mode="multiple" placeholder="选择人员" optionFilterProp="label" :maxTagCount="2" allowClear @change="val => handleStaffChange(val, 'staffConfig', index)" > <a-select-option v-for="person in availableStaffMap[index]" :key="person.id" :label="person.name" :value="person.id" > {{ person.name }} </a-select-option> </a-select> </template> <template slot="time" slot-scope="text, record, index"> <a-select v-model="record.timeConfig" @change="val => changeTime(val, 'timeConfig', index)" placeholder="选择期望完成时间" > <a-select-option v-for="option in timeOptions" :key="option.value" :value="option.value"> {{ option.label }} </a-select-option> </a-select> </template> </a-table> </div> </div> <div class="btn-view action-list"> <a-button @click="onSave" type="primary">{{ $t('确定') }}</a-button> <a-button @click="onCancel" type="normal">{{ $t('取消') }}</a-button> </div> </div> </a-spin> </template> </div> </template> <script> export default { props: { orgInfo: { type: Object, default: () => { return {}; }, }, companyInfo: { type: Object, default: () => { return {}; }, }, }, data() { return { isLoading: false, formData: {}, typeOptions: [ { label: '选项1', value: 1, }, { label: '选项2', value: 2, }, { label: '选项3', value: 3, }, { label: '选项4', value: 4, }, ], columns: [ { title: '部门', key: 'department', dataIndex: 'department', ellipsis: true, }, { title: '用户', dataIndex: 'staff', scopedSlots: { customRender: 'staff' }, key: 'staff', }, { title: '期望完成时间设定', dataIndex: 'time', scopedSlots: { customRender: 'time' }, key: 'time', }, ], tableList: [ { department: '技术部', staffConfig: ['001', '002'], timeConfig: '24h' }, { department: '运维部', staffConfig: ['003'], timeConfig: '48h' }, { department: '安全部', staffConfig: [], timeConfig: '7d' }, { department: '网络部', staffConfig: [], timeConfig: '24h' }, { department: '数据库部', staffConfig: [], timeConfig: '12h' }, ], timeOptions: [ { label: '报警后12小时', value: '12h' }, { label: '报警后24小时', value: '24h' }, { label: '报警后48小时', value: '48h' }, { label: '报警后7日内', value: '7d' }, ], staffList: [ { id: '001', name: '张三' }, { id: '002', name: '李四' }, { id: '003', name: '王五' }, { id: '004', name: '赵六' }, ], }; }, computed: { // 所有被选中的用户ID(整个表格) allSelectedStaffIds() { const selected = new Set(); this.tableList.forEach(row => { if (Array.isArray(row.staffConfig)) { row.staffConfig.forEach(id => selected.add(id)); } }); return selected; }, // 为每一行生成可用人员列表 availableStaffMap() { const map = {}; const allSelected = this.allSelectedStaffIds; this.tableList.forEach((row, index) => { // 当前行已选的人员ID集合 const currentSelected = row.staffConfig ? new Set(row.staffConfig) : new Set(); // 过滤出当前行可用的人员 map[index] = this.staffList.filter(person => !allSelected.has(person.id) || currentSelected.has(person.id)); }); return map; }, // 用于显示的表数据(包含过滤后的人员显示) displayTableList() { return this.tableList.map((row, index) => { const availableStaff = this.availableStaffMap[index] || []; return { ...row, // 仅用于显示,不修改原始数据 displayStaffConfig: row.staffConfig.filter(id => availableStaff.some(p => p.id === id)), }; }); }, }, mounted() { console.log(this.allSelectedStaffIds, 'allSelectedStaffIdsallSelectedStaffIds'); console.log(this.availableStaffMap, 'availableStaffMap'); console.log(this.displayTableList, 'displayTableList'); // this.updateStatus(); }, methods: { changeTime(value, key, index) { this.$set(this.tableList[index], key, value); }, handleStaffChange(value, key, index) { // 人员只能选择两位 if (value && value.length > 2) { this.$message.destroy(); this.$message.warning('人员最多选择2位'); value = value.slice(0, 2); } this.$set(this.tableList[index], key, value); // this.updateStatus(); console.log(this.allSelectedStaffIds, 'allSelectedStaffIdsallSelectedStaffIds'); console.log(this.availableStaffMap, 'availableStaffMap'); console.log(this.displayTableList, 'displayTableList'); }, updateStatus() { const selectedIds = new Set(); this.tableList.forEach(row => { if (Array.isArray(row.staffConfig)) { row.staffConfig.forEach(id => selectedIds.add(id)); } }); this.staffList.forEach((person, index) => { const shouldDisable = selectedIds.has(person.id); if (person.disabled !== shouldDisable) { this.$set(this.staffList, index, { ...person, disabled: shouldDisable, }); } }); }, updateData(value, key, index) { this.$set(this.tableList[index], key, value); }, // 确定 onSave() { console.log('保存的数据:', { tableList: this.tableList, }); }, // 取消 onCancel() {}, }, }; </script> <style lang="less" scoped> .alarm-work-order { height: 100%; width: 100%; position: relative; box-sizing: border-box; .edit-view { width: 100%; padding: 46px 32px 24px 32px; .input-item { width: 100%; display: flex; margin-bottom: 22px; &:last-child { margin-bottom: 0 !important; } } .input-lable { width: 88px; min-width: 88px; justify-content: start; display: flex; color: #808e9d; font-size: 14px; line-height: 19px; margin-right: 24px; span { white-space: nowrap; } } .text-bold { font-weight: bold; color: #4e5c6b; } .text-align { align-items: center; } .btn-view { display: flex; align-items: center; justify-content: flex-start; padding-left: 112px; margin-top: 24px; & > button { margin-right: 12px; } } } } </style> 代码评审
07-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值