封装原因
- 项目中有时候会要求文本域获取焦点后改变背景色、添加边框
组件属性
| 属性 | 说明 | 示例 |
|---|
| height | 文本域的高度(autoHeight为false)、最小高度(autoHeight为true) | 字符串:'200rpx' |
| textareaBoxStyle | 文本域父盒子的样式(比如设置边框、背景色、内边距等等) | 对象 |
| textareaBoxPadding | 文本域父盒子的上下padding之和(autoHeight为true、textareaBoxStyle中设置了padding则需要传入) | 字符串:'40rpx' |
| textareaStyle | 文本域的样式(比如设置字号、字体、文本颜色等等) | 对象 |
| placeholder | 未输入内容时的占位内容 | 对象 |
| placeholderStyle | 占位内容的样式(比如设置字号、字体、文本颜色等等) | 对象 |
| disabled | 文本域是否禁用 | 布尔类型:false |
| autoHeight | 文本域是否自动增高 | 布尔类型:true |
| maxlength | 最大输入长度,设置为 -1 的时候不限制最大长度 | number:150 |
| focusStyle | 文本域获得焦点时的样式 | 对象 |
注意事项
- 只封装了文本域常用的功能,如果还有其他需求可以进行二次封装
- 当autoHeight为true、textareaBoxStyle设置了padding则需要传入textareaBoxPadding
- 样式对象中的line-height行高问题:开启自动增高后行高无法生效
- 当占位内容过长(超过文本域一行的宽度后)iOS端设备无法显示除第一行外的剩余内容(Android端不会出现这个问题)
- placeholderStyle设置行高没有效果(占位内容设置行高无效,估计是textarea组件底层的运算不支持)
封装代码
<template>
<view class="textarea-box" :style="[textareaBoxStyle, isFocus ? focusStyle : '']">
<textarea
:style="[textareaStyle]"
:placeholder="props.placeholder"
:placeholder-style="props.placeholderStyle"
:maxlength="props.maxlength"
:auto-height="props.autoHeight"
:disabled="props.disabled"
@focus="isFocus = true"
@blur="isFocus = false"
@input="inputChange"
></textarea>
</view>
</template>
<script setup>
import { ref, onMounted, computed, watch, getCurrentInstance } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
const { proxy } = getCurrentInstance()
const example = proxy
const props = defineProps({
height: {
type: String,
default: '200rpx',
},
textareaBoxStyle: {
type: Object,
default: {},
},
textareaBoxPadding: {
type: String,
default: '40rpx',
},
textareaStyle: {
type: Object,
default: {},
},
placeholder: {
type: String,
default: '请输入',
},
placeholderStyle: {
type: String,
default: '',
},
disabled: {
type: Boolean,
default: false,
},
autoHeight: {
type: Boolean,
default: true,
},
maxlength: {
type: Number,
default: 150,
},
focusStyle: {
type: Object,
default: {},
},
})
const emit = defineEmits(['update:modelValue'])
onMounted(() => {
init()
})
function init() {
textareaBoxStyle.value = {
padding: '20rpx',
borderRadius: '10rpx',
backgroundColor: '
...props.textareaBoxStyle,
}
textareaStyle.value = {
...props.textareaStyle,
}
for (let key in textareaBoxStyle.value) {
if (key == 'height' || key == 'minHeight' || key == 'min-height') {
delete textareaBoxStyle.value[key]
}
}
for (let key in textareaStyle.value) {
if (key == 'height' || key == 'minHeight' || key == 'min-height') {
delete textareaStyle.value[key]
}
}
if (props.autoHeight) {
for (let key in textareaBoxStyle.value) {
if (key == 'lineHeight' || key == 'line-height') {
delete textareaBoxStyle.value[key]
}
}
for (let key in textareaStyle.value) {
if (key == 'lineHeight' || key == 'line-height') {
delete textareaStyle.value[key]
}
}
textareaBoxStyle.value.minHeight = props.height
// 处理textareaStyle的min-height
let result = extractNumberAndUnit(props.textareaBoxPadding)
let heightResult = extractNumberAndUnit(props.height)
let minHeight = ''
if (heightResult.unit == 'rpx') {
if (result.unit == 'rpx') {
minHeight = heightResult.number - result.number + 'rpx'
} else {
minHeight = heightResult.number - result.number * 2 + 'rpx'
}
} else {
if (result.unit == 'rpx') {
minHeight = heightResult.number - result.number / 2 + 'px'
} else {
minHeight = heightResult.number - result.number + 'px'
}
}
textareaStyle.value.minHeight = minHeight
} else {
textareaBoxStyle.value.height = props.height
textareaStyle.value.height = '100%'
}
focusStyle.value = {
backgroundColor: '
border: '1rpx solid
...props.focusStyle,
}
}
function extractNumberAndUnit(inputString) {
const match = inputString.match(/(\d+)([a-zA-Z]+)/)
if (match) {
const number = match[1] * 1
const unit = match[2]
return { number, unit }
} else {
return { number: null, unit: null }
}
}
let textareaBoxStyle = ref({})
let textareaStyle = ref({})
let focusStyle = ref({})
let isFocus = ref(false)
function inputChange(e) {
emit('update:modelValue', e.detail.value)
}
</script>
<style lang="scss" scoped>
textarea {
width: 100%
z-index: 99
}
</style>
页面使用
<myTextarea v-model="textarea"></myTextarea>
let textarea = ref('')