前置文章
一、vue使用element-ui自定義樣式思路分享【實操】
二、vue3&ts&el-tabs多個tab表單校驗
現狀確認
- 點擊添加按鈕,沒有點擊樣式,用戶感知不明顯
- 沒有限制最大的tab添加數量,可以無限添加
調整目標&代碼編寫
調整目標
- 點擊添加按鈕,按鈕背景變成藍色,加號圖標變成白色
- 限制最大的tab添加數量為
10
,超過10
添加按鈕設置為灰色不可點擊
代碼編寫
點擊添加按鈕,按鈕背景變成藍色
在vue使用element-ui自定義樣式思路分享【實操】提到了如何給el-tabs按鈕自定義樣式,文本在按鈕已經設置了自定義樣式的基礎上進行,首先實現點擊按鈕時,背景顏色變成藍色,考慮使用偽類選擇器active
來實現。
藍色保持與element框架默認提供的一致,可以通過Snipaste來拾取:F1開啟截屏,鼠標移動到藍色區域,Shift切換顏色數據類型,按C完整復制。
代碼調整如下
/*添加按鈕點擊顯示藍色*/
.asset-tab :deep(.el-tabs__new-tab):active {background: #409eff;
}
效果
點擊添加按鈕,加號圖標變成白色
觀察svg的樣式選擇器,觀察到通過fill
設置顏色不生效,修改color
顏色才生效,例如下圖中設置為紅色
添加代碼
/*設置svg點擊顏色顯示白色*/
.asset-tab :deep(.el-tabs__new-tab):active .is-icon-plus svg {color: white;
}
效果
js動態禁止按鈕點擊&設置按鈕禁止樣式
添加禁止樣式(主要關注前面三行)
/*禁止樣式*/
.asset-tab :deep(.el-tabs__new-tab.disabled) {pointer-events: none;opacity: 0.8;background: lightgray;height: 30px;width: 30px;border-radius: 15px;font-size: 16px;
}
操作document動態添加或去除禁止樣式,注意document.querySelector()
選擇器不需要加:deep()
,并將修改邏輯抽取成方法setAddBtnStatus
,在增減tab邏輯后調用即可
const setAddBtnStatus = function () {const newTab = document.querySelector('.asset-tab .el-tabs__new-tab')console.log('newTab', newTab)const index = tabs.value.lengthif (index >= 10) {newTab?.classList.add('disabled')} else {newTab?.classList.remove('disabled')}
}
最終效果&完整代碼
完整代碼:
<!--AssetCreate.vue-->
<template><div style="margin-bottom: 10px"><h3>數據源選擇:</h3><el-switch v-model="isUseLocalFlag" active-text="使用本地服務數據" inactive-text="使用mock數據"/><el-button @click="setTabData" style="margin-left: 10px;">給tab賦值</el-button><el-button @click="clearTabData" >清空tab賦值</el-button></div><div class="asset-tab"><el-tabs v-model="activeTab" type="card" editable class="demo-tabs" @edit="handleTabsEdit"><el-tab-pane v-for="tab in tabs" :key="tab.name" :label="tab.label" :name="tab.name"><AssetItem ref="assetItemRefs" :insertForm="tab.insertForm"/></el-tab-pane></el-tabs></div><div class="bottom-btn"><el-button @click="submitAsset" type="primary">提交</el-button></div>
</template><script setup lang="ts">
import { ref } from 'vue'
import axios from 'axios'
import type { TabPaneName } from 'element-plus'
import { removeRedundantFields } from '@/utils/methodUtil'
import AssetItem from '@/components/asset/AssetItem.vue'
import type { AssetFormData } from '@/types'
import { ElMessage } from 'element-plus'
// 當前激活的tab
const activeTab = ref('表單 1')
// tabs初始數據
const tabs = ref([{ label: '表單 1', name: '表單 1', insertForm: {} }
])
const isUseLocalFlag = ref(true)
const clearTabData = function () {tabs.value = [{ label: '表單 1', name: '表單 1', insertForm: {} }]activeTab.value = '表單 1'setAddBtnStatus()
}
const setTabData = async function () {const bizId = '0777c40218114c35a29b0d4d84355668'if (isUseLocalFlag.value) {await axios.post(`/asset/assetInfo/${bizId}/byBizId`).then(result => {if (result.status === 200) {tabs.value = []const assetInfoList = result?.data?.data?.assetInfoListconst removeResult = removeRedundantFields(assetInfoList, ['extAttribute11', 'extAttribute12','extAttribute13', 'extAttribute14', 'extAttribute15', 'extAttribute16', 'extAttribute17', 'extAttribute18','extAttribute19', 'extAttribute20'])removeResult.forEach((item, index) => {const newTabName = `表單 ${index + 1}`tabs.value.push({label: newTabName,name: newTabName,insertForm: item})setAddBtnStatus()activeTab.value = newTabName})}})} else {// 請求mock數據await axios.post('/mock/asset/assetInfo', { bizId }).then(result => {const assetInfoList: Array<AssetFormData> = result?.data?.data?.assetInfoListtabs.value = []assetInfoList.forEach((asset, idx) => {const newTabName = `表單 ${idx + 1}`tabs.value.push({label: newTabName,name: newTabName,insertForm: asset})setAddBtnStatus()activeTab.value = newTabName})})}
}
const assetItemRefs = ref<InstanceType<typeof AssetItem>[]>([])
const handleTabsEdit = (targetName: TabPaneName | undefined,action: 'remove' | 'add'
) => {if (action === 'add') {let index = tabs.value.lengthif (index >= 10) returnconst newTabName = `表單 ${++index}`tabs.value.push({label: newTabName,name: newTabName,insertForm: {}})activeTab.value = newTabName} else if (action === 'remove') {const activeName = activeTab.valueif (tabs.value.length === 1) returntabs.value = tabs.value.filter((tab) => tab.name !== targetName)tabs.value.forEach((item, index) => {item.name = `表單 ${++index}`item.label = item.name})const currentExist = tabs.value.some((item, index) => {if (item.name === activeName) {return index}return false})if (!currentExist) activeTab.value = tabs.value[tabs.value.length - 1].name}setAddBtnStatus()
}
const setAddBtnStatus = function () {const newTab = document.querySelector('.asset-tab .el-tabs__new-tab')const index = tabs.value.lengthif (index >= 10) {newTab?.classList.add('disabled')} else {newTab?.classList.remove('disabled')}
}
const verifyPass = ref(true)
const submitAsset = async function () {for (const index in assetItemRefs.value) {const verifyResult = await assetItemRefs.value[index].submitForm()// 定位到第一個校驗失敗的tabif (!verifyResult) {verifyPass.value = falseactiveTab.value = `表單 ${Number(index) + 1}`break} else {verifyPass.value = true}}if (verifyPass.value) ElMessage({ message: '表單校驗通過', type: 'success' })
}
</script><style scoped>
/*禁止樣式*/
.asset-tab :deep(.el-tabs__new-tab.disabled) {pointer-events: none;opacity: 0.8;background: lightgray;height: 30px;width: 30px;border-radius: 15px;font-size: 16px;
}
.asset-tab :deep(.el-tabs__new-tab) {height: 30px;width: 30px;border-radius: 15px;font-size: 16px;
}/*添加按鈕點擊顯示藍色*/
.asset-tab :deep(.el-tabs__new-tab):active {background: #409eff;
}
/*設置svg點擊顏色顯示白色*/
.asset-tab :deep(.el-tabs__new-tab):active .is-icon-plus svg {color: white;
}
.bottom-btn {text-align: center;margin-bottom: 10px;
}
</style>
代碼倉:hello_vue3