vue3+elementUI實現(xiàn)懸浮多行文本輸入框效果
一、組件功能描述
點擊常規(guī)輸入框 可以調(diào)出懸浮大文本域輸入框,支持多行文本輸入、支持從excel復(fù)制粘貼輸入并自動切分為符合參數(shù)的逗號拼接字符串。
組件圖例
二、組件參數(shù)說明
1.props(屬性)
參數(shù)名 | 參數(shù)類型 | 必填 | 默認值 | 說明 |
---|---|---|---|---|
inputPrefix | String | 申請單號: | 外部輸入框 提示文本 | |
inputPlaceholder | string | 請輸入單號 | 外部輸入框 占位文本Placeholder | |
popoverWidth | number | 300 | 如果需要結(jié)合 界面適應(yīng)寬度的話,配合hook useGetElementWidthByClassName(className),參數(shù)class 是對應(yīng)元素基坑的類名 | |
showTextLength | number | 15 | 基礎(chǔ)文本框展示的字符個數(shù) | |
useTextProcess | boolean | true | 開啟文本處理 , true : 判斷長度限制 切割 \r \n 字符串 ,false :不做處理 | |
overLength | number | 10 | 多行文本框最大上限,默認上限為 10個 | |
textInputLength | number | 10 | 多行文本框顯示行數(shù) 上限為 10個 | |
inputInnerPlaceholder | string | 每行填寫一條申請單號 | 懸浮輸入框 占位文本 | |
modelValue | string | 是 | 自定義V-model 綁定變量 |
2.Emits(拋出事件)
事件名 | 事件參數(shù) | 說明 |
---|---|---|
update:modelValue | textValue | 自定義V-model 拋出事件 |
3.Expose(對外暴露事件)
外部組件需要通過 $refs 來進行調(diào)用的方法
4.是否支持屬性透傳
不支持屬性與事件透傳至依賴組件
三、組件代碼
<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: '申請單號:', // 外部輸入框 提示文本 inputPlaceholder: '請輸入單號', // 外部輸入框 占位文本 inputInnerPlaceholder: '每行填寫一條申請單號', // 懸浮輸入框 占位文本 popoverWidth: 300, // 如果需要結(jié)合 界面適應(yīng)寬度的話,配合hook useGetElementWidthByClassName(className),參數(shù)class 是對應(yīng)元素基坑的類名 showTextLength: 15, // 基礎(chǔ)文本框展示的字符個數(shù) overLength: 10, // 多行文本框最大上限,默認上限為 10個 textInputLength: 10, // 多行文本框顯示行數(shù) 上限為 10個 useTextProcess: true // 開啟文本處理 , 判斷長度限制 切割 \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 }) // 聚焦的時候 展示懸浮輸入框 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() }) } // 懸浮輸入失去焦點 傳輸數(shù)據(jù)給父組件 function blurInputTextArea () { if (props.useTextProcess) { const { overLength, val } = textProcessing(textValue.value) // textValue.value = val if (!overLength) { // 沒有超長的 傳遞給父組件 console.log('emit的數(shù)據(jù)', val) emits('update:modelValue', val) state.visible = false } else { showErrorTip.value = true // 展示錯誤信息 } } 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 // 最大長度 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; } } /* 隱藏瀏覽器默認滾動條 */ .textInputArea ::-webkit-scrollbar { width: 6px; /* 寬度 */ height: 6px; /* 高度 */ } /* 滾動條滑塊 */ .textInputArea ::-webkit-scrollbar-thumb { background: #969696; /* 滑塊顏色 */ border-radius: 3px; /* 滑塊圓角 */ } /* 滾動條軌道 */ .textInputArea ::-webkit-scrollbar-track { background: #f0f0f0; /* 軌道顏色 */ border-radius: 3px; /* 軌道圓角 */ } /* 鼠標懸停在滾動條上時的滑塊樣式 */ .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,默認 levitateBaseInput * @param paddingWidth - 邊距寬度 number,默認 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="每行輸入一個賬戶,最多20行,Meta賬戶可不加act_前綴" :over-length="20" /> </HomeSearchItem> const queryParams = reactive({ MultiAccounts:'' }) const levitateWidth = useGetElementWidthByClassName()
五、其他注意事項
1、本組件主要是用于解決從Excel 復(fù)制粘貼多行文本,并需要單行截取的問題。
2、props中的popoverWidth是用于設(shè)置彈出層的寬度,在搭配外層formItem使用時候,可以使用配套hook函數(shù)useGetElementWidthByClassName(默認獲取類名為levitateBaseInput的元素的寬度,可以通過參數(shù)修改)獲取外層寬度使彈出層寬度匹配外層輸入框,否則使用固定寬度300。
3、組件設(shè)計:在點擊外層輸入框的時候,當懸浮框沒有展開的時候,則顯示懸浮框并自動focus到大文本域輸入框(如果v-model的數(shù)據(jù)包含 , 則需要進行拆分并加入\n 確保可以在文本域輸入框正常分行展示),當懸浮框是展開的狀態(tài)則默認focus文本域輸入框防止失去焦點(再次點擊外層小輸入框的時候,防止丟失焦點)。當文本域失去焦點則進行文本處理,見第四點。
/* <el-popover :visible="state.visible"> …………………省略其他代碼………………… </el-popover> */ // 聚焦的時候 展示懸浮輸入框 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,即對輸入的多行文本進行文本處理 切割 \r \n 字符串并返回切割后拼接 , 后的字符串;如果是false則不對文本處理。會在懸浮框失去焦點的時候觸發(fā)blurInputTextArea 方法進而在useTextProcess為true的情況下調(diào)用textProcessing 方法進行處理。當前版本在false的情況下不處理超長情況。
在true的情況如果文本超出行數(shù)限制,則會將showErrorTip.value = true // 展示錯誤信息,
// 懸浮輸入失去焦點 傳輸數(shù)據(jù)給父組件。 function blurInputTextArea () { if (props.useTextProcess) { const { overLength, val } = textProcessing(textValue.value) // textValue.value = val if (!overLength) { // 沒有超長的 傳遞給父組件 console.log('emit的數(shù)據(jù)', val) emits('update:modelValue', val) state.visible = false } else { showErrorTip.value = true // 展示錯誤信息 } } 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 // 最大長度 return { val: splitText.join(','), overLength } }
以上就是vue3+elementUI實現(xiàn)懸浮多行文本輸入框效果的詳細內(nèi)容,更多關(guān)于vue3 elementUI懸浮文本輸入框的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
nuxt 服務(wù)器渲染動態(tài)設(shè)置 title和seo關(guān)鍵字的操作
這篇文章主要介紹了nuxt 服務(wù)器渲染動態(tài)設(shè)置 title和seo關(guān)鍵字的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11在vue中使用防抖和節(jié)流,防止重復(fù)點擊或重復(fù)上拉加載實例
今天小編就為大家分享一篇在vue中使用防抖和節(jié)流,防止重復(fù)點擊或重復(fù)上拉加載實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11