vue3+elementUI實(shí)現(xiàn)懸浮多行文本輸入框效果
一、組件功能描述
點(diǎn)擊常規(guī)輸入框 可以調(diào)出懸浮大文本域輸入框,支持多行文本輸入、支持從excel復(fù)制粘貼輸入并自動(dòng)切分為符合參數(shù)的逗號(hào)拼接字符串。
組件圖例
二、組件參數(shù)說(shuō)明
1.props(屬性)
參數(shù)名 | 參數(shù)類型 | 必填 | 默認(rèn)值 | 說(shuō)明 |
---|---|---|---|---|
inputPrefix | String | 申請(qǐng)單號(hào): | 外部輸入框 提示文本 | |
inputPlaceholder | string | 請(qǐng)輸入單號(hào) | 外部輸入框 占位文本Placeholder | |
popoverWidth | number | 300 | 如果需要結(jié)合 界面適應(yīng)寬度的話,配合hook useGetElementWidthByClassName(className),參數(shù)class 是對(duì)應(yīng)元素基坑的類名 | |
showTextLength | number | 15 | 基礎(chǔ)文本框展示的字符個(gè)數(shù) | |
useTextProcess | boolean | true | 開啟文本處理 , true : 判斷長(zhǎng)度限制 切割 \r \n 字符串 ,false :不做處理 | |
overLength | number | 10 | 多行文本框最大上限,默認(rèn)上限為 10個(gè) | |
textInputLength | number | 10 | 多行文本框顯示行數(shù) 上限為 10個(gè) | |
inputInnerPlaceholder | string | 每行填寫一條申請(qǐng)單號(hào) | 懸浮輸入框 占位文本 | |
modelValue | string | 是 | 自定義V-model 綁定變量 |
2.Emits(拋出事件)
事件名 | 事件參數(shù) | 說(shuō)明 |
---|---|---|
update:modelValue | textValue | 自定義V-model 拋出事件 |
3.Expose(對(duì)外暴露事件)
外部組件需要通過(guò) $refs 來(lái)進(jìn)行調(diào)用的方法
4.是否支持屬性透?jìng)?/p>
不支持屬性與事件透?jìng)髦烈蕾嚱M件
三、組件代碼
<template> <el-popover :visible="state.visible" placement="bottom-start" :width="props.popoverWidth" > <div> <el-input ref="inputTextAreaRef" v-model="textValue" type="textarea" :placeholder="inputInnerPlaceholder" resize="none" :autosize="{ minRows: props.textInputLength + 1, maxRows: props.textInputLength + 1 }" clearable class="textInputArea" @blur="blurInputTextArea" @input="showErrorTip = false" @clear="showErrorTip = false" /> <div class="input-textarea-bottom-btn"> <div> <p v-if="showErrorTip" class="over-length-error-tip"> 超出最大行數(shù)限制{{ props.overLength }}行 </p> </div> </div> </div> <template #reference> <el-input ref="inputRef" v-model="omitText" class="base-input" :placeholder="props.inputPlaceholder" style="cursor: pointer" @focus="showLevitateWindow" > <template #prefix> {{ props.inputPrefix }} </template> </el-input> </template> </el-popover> </template> <script setup lang="ts"> import { computed } from 'vue' const props = withDefaults( defineProps<{ modelValue:string inputPrefix?: string inputPlaceholder?: string popoverWidth?: number showTextLength?:number useTextProcess?:boolean overLength?:number textInputLength?:number inputInnerPlaceholder?:string }>(), { inputPrefix: '申請(qǐng)單號(hào):', // 外部輸入框 提示文本 inputPlaceholder: '請(qǐng)輸入單號(hào)', // 外部輸入框 占位文本 inputInnerPlaceholder: '每行填寫一條申請(qǐng)單號(hào)', // 懸浮輸入框 占位文本 popoverWidth: 300, // 如果需要結(jié)合 界面適應(yīng)寬度的話,配合hook useGetElementWidthByClassName(className),參數(shù)class 是對(duì)應(yīng)元素基坑的類名 showTextLength: 15, // 基礎(chǔ)文本框展示的字符個(gè)數(shù) overLength: 10, // 多行文本框最大上限,默認(rèn)上限為 10個(gè) textInputLength: 10, // 多行文本框顯示行數(shù) 上限為 10個(gè) useTextProcess: true // 開啟文本處理 , 判斷長(zhǎng)度限制 切割 \r \n 字符串 } ) const emits = defineEmits(['update:modelValue']) const inputTextAreaRef = ref<HTMLElement | null> (null) const inputRef = ref<HTMLElement | null> (null) const showErrorTip = ref<boolean> (false) const state = reactive({ visible: false }) const omitText = computed(() => { return textValue.value.length > props.showTextLength ? textValue.value.substring(0, props.showTextLength) + '……' : textValue.value }) const textValue = ref(props.modelValue) watchEffect(() => { textValue.value = props.modelValue }) // 聚焦的時(shí)候 展示懸浮輸入框 function showLevitateWindow () { if (state.visible) { inputTextAreaRef.value?.focus() return } // 處理數(shù)據(jù),如果包含 , 需要拆開 const localValue = textValue.value if (localValue.indexOf(',') > -1) { textValue.value = localValue.split(',').join('\n') emits('update:modelValue', textValue.value) } state.visible = true nextTick(() => { inputTextAreaRef.value?.focus() }) } // 懸浮輸入失去焦點(diǎn) 傳輸數(shù)據(jù)給父組件 function blurInputTextArea () { if (props.useTextProcess) { const { overLength, val } = textProcessing(textValue.value) // textValue.value = val if (!overLength) { // 沒(méi)有超長(zhǎng)的 傳遞給父組件 console.log('emit的數(shù)據(jù)', val) emits('update:modelValue', val) state.visible = false } else { showErrorTip.value = true // 展示錯(cuò)誤信息 } } else { emits('update:modelValue', textValue.value) state.visible = false } } // 文本處理方法,切割 \r \n 字符串 const textProcessing : (val: string) => { val:string, overLength:boolean } = (val) => { const splitText = val.split(/\r?\n/).filter(i => i !== '') const overLength = splitText.length > props.overLength // 最大長(zhǎng)度 return { val: splitText.join(','), overLength } } </script> <style scoped lang="scss"> .input-textarea-bottom-btn{ margin-top: 5px; display: flex; justify-content: space-between; align-content: center; .over-length-error-tip{ color:#f56c6c; font-size: 12px; line-height: 24px; } } /* 隱藏瀏覽器默認(rèn)滾動(dòng)條 */ .textInputArea ::-webkit-scrollbar { width: 6px; /* 寬度 */ height: 6px; /* 高度 */ } /* 滾動(dòng)條滑塊 */ .textInputArea ::-webkit-scrollbar-thumb { background: #969696; /* 滑塊顏色 */ border-radius: 3px; /* 滑塊圓角 */ } /* 滾動(dòng)條軌道 */ .textInputArea ::-webkit-scrollbar-track { background: #f0f0f0; /* 軌道顏色 */ border-radius: 3px; /* 軌道圓角 */ } /* 鼠標(biāo)懸停在滾動(dòng)條上時(shí)的滑塊樣式 */ .textInputArea ::-webkit-scrollbar-thumb:hover { background: #656565; } </style>
附帶 Hook 函數(shù)
import { ref, onMounted, onBeforeUnmount } from 'vue' /** * @description 根據(jù)className 獲取懸浮輸入框的基礎(chǔ)輸入框?qū)挾? * @param className - 基礎(chǔ)元素類名 string,默認(rèn) levitateBaseInput * @param paddingWidth - 邊距寬度 number,默認(rèn) 12 * */ export default function useGetElementWidthByClassName (className = 'levitateBaseInput', paddingWidth = 12) { const elementWidth = ref(0) function getElementsClientWidth () { setTimeout(() => { const ele = document.getElementsByClassName(className) if (ele[0]) { elementWidth.value = ele[0].clientWidth - paddingWidth } else elementWidth.value = 0 }, 400) } onMounted(() => { window.addEventListener('resize', getElementsClientWidth) getElementsClientWidth() }) onBeforeUnmount(() => { window.removeEventListener('resize', getElementsClientWidth) }) return elementWidth }
四、組件使用例子
<HomeSearchItem ref="inputElementRef" prop="MultiAccounts" class="levitateBaseInput"> <levitate-multiple-input v-model="queryParams.MultiAccounts" :popover-width="levitateWidth" input-prefix="多賬戶查詢:" input-placeholder="" input-inner-placeholder="每行輸入一個(gè)賬戶,最多20行,Meta賬戶可不加act_前綴" :over-length="20" /> </HomeSearchItem> const queryParams = reactive({ MultiAccounts:'' }) const levitateWidth = useGetElementWidthByClassName()
五、其他注意事項(xiàng)
1、本組件主要是用于解決從Excel 復(fù)制粘貼多行文本,并需要單行截取的問(wèn)題。
2、props中的popoverWidth是用于設(shè)置彈出層的寬度,在搭配外層formItem使用時(shí)候,可以使用配套hook函數(shù)useGetElementWidthByClassName(默認(rèn)獲取類名為levitateBaseInput的元素的寬度,可以通過(guò)參數(shù)修改)獲取外層寬度使彈出層寬度匹配外層輸入框,否則使用固定寬度300。
3、組件設(shè)計(jì):在點(diǎn)擊外層輸入框的時(shí)候,當(dāng)懸浮框沒(méi)有展開的時(shí)候,則顯示懸浮框并自動(dòng)focus到大文本域輸入框(如果v-model的數(shù)據(jù)包含 , 則需要進(jìn)行拆分并加入\n 確??梢栽谖谋居蜉斎肟蛘7中姓故荆?,當(dāng)懸浮框是展開的狀態(tài)則默認(rèn)focus文本域輸入框防止失去焦點(diǎn)(再次點(diǎn)擊外層小輸入框的時(shí)候,防止丟失焦點(diǎn))。當(dāng)文本域失去焦點(diǎn)則進(jìn)行文本處理,見(jiàn)第四點(diǎn)。
/* <el-popover :visible="state.visible"> …………………省略其他代碼………………… </el-popover> */ // 聚焦的時(shí)候 展示懸浮輸入框 function showLevitateWindow () { if (state.visible) { inputTextAreaRef.value?.focus() return } // 處理數(shù)據(jù),如果包含 , 需要拆開, localValue 為v-model傳入數(shù)據(jù)的本地副本 const localValue = textValue.value if (localValue.indexOf(',') > -1) { textValue.value = localValue.split(',').join('\n') emits('update:modelValue', textValue.value) } state.visible = true // 在懸浮輸入框展示后立刻聚焦 nextTick(() => { inputTextAreaRef.value?.focus() }) }
4、有關(guān)文本處理的方法,props中的useTextProcess是文本處理配置,如果設(shè)置為true,即對(duì)輸入的多行文本進(jìn)行文本處理 切割 \r \n 字符串并返回切割后拼接 , 后的字符串;如果是false則不對(duì)文本處理。會(huì)在懸浮框失去焦點(diǎn)的時(shí)候觸發(fā)blurInputTextArea 方法進(jìn)而在useTextProcess為true的情況下調(diào)用textProcessing 方法進(jìn)行處理。當(dāng)前版本在false的情況下不處理超長(zhǎng)情況。
在true的情況如果文本超出行數(shù)限制,則會(huì)將showErrorTip.value = true // 展示錯(cuò)誤信息,
// 懸浮輸入失去焦點(diǎn) 傳輸數(shù)據(jù)給父組件。 function blurInputTextArea () { if (props.useTextProcess) { const { overLength, val } = textProcessing(textValue.value) // textValue.value = val if (!overLength) { // 沒(méi)有超長(zhǎng)的 傳遞給父組件 console.log('emit的數(shù)據(jù)', val) emits('update:modelValue', val) state.visible = false } else { showErrorTip.value = true // 展示錯(cuò)誤信息 } } else { emits('update:modelValue', textValue.value) state.visible = false } } // 文本處理方法,切割 \r \n 字符串 const textProcessing : (val: string) => { val:string, overLength:boolean } = (val) => { const splitText = val.split(/\r?\n/).filter(i => i !== '') const overLength = splitText.length > props.overLength // 最大長(zhǎng)度 return { val: splitText.join(','), overLength } }
以上就是vue3+elementUI實(shí)現(xiàn)懸浮多行文本輸入框效果的詳細(xì)內(nèi)容,更多關(guān)于vue3 elementUI懸浮文本輸入框的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Vue中輸入框僅支持?jǐn)?shù)字輸入的四種方法
- vue如何設(shè)置輸入框只能輸入數(shù)字且只能輸入小數(shù)點(diǎn)后兩位,并且不能輸入減號(hào)
- vue elementui 動(dòng)態(tài)追加下拉框、輸入框功能
- 基于vue3實(shí)現(xiàn)一個(gè)簡(jiǎn)單的輸入框效果
- Vue中禁止編輯的常見(jiàn)方法(以禁止編輯輸入框?yàn)槔?
- vue之input輸入框防抖debounce函數(shù)的使用方式
- vue實(shí)現(xiàn)輸入框只允許輸入數(shù)字
- 基于vue+h5實(shí)現(xiàn)車牌號(hào)輸入框功能(demo)
相關(guān)文章
nuxt 服務(wù)器渲染動(dòng)態(tài)設(shè)置 title和seo關(guān)鍵字的操作
這篇文章主要介紹了nuxt 服務(wù)器渲染動(dòng)態(tài)設(shè)置 title和seo關(guān)鍵字的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11Vant的Tabbar標(biāo)簽欄引入自定義圖標(biāo)方式
這篇文章主要介紹了Vant的Tabbar標(biāo)簽欄引入自定義圖標(biāo)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04Vue.js實(shí)現(xiàn)全屏背景圖片滑動(dòng)切換特效
本文主要介紹了Vue.js實(shí)現(xiàn)全屏背景圖片滑動(dòng)切換特效,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01Vue.js學(xué)習(xí)筆記之 helloworld
vue是法語(yǔ)中視圖的意思,Vue.js是一個(gè)輕巧、高性能、可組件化的MVVM庫(kù),同時(shí)擁有非常容易上手的API。有需要的小伙伴可以參考下2016-08-08在vue中使用防抖和節(jié)流,防止重復(fù)點(diǎn)擊或重復(fù)上拉加載實(shí)例
今天小編就為大家分享一篇在vue中使用防抖和節(jié)流,防止重復(fù)點(diǎn)擊或重復(fù)上拉加載實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11