Skip to content
This repository was archived by the owner on Dec 6, 2021. It is now read-only.

Commit 5d35ea5

Browse files
committed
feat(textarea): add v-model support
1 parent 06ae9c1 commit 5d35ea5

File tree

4 files changed

+137
-143
lines changed

4 files changed

+137
-143
lines changed

src/components/textarea/index.ts

+45-44
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { CommonEvent } from '@tarojs/components/types/common'
44
import Taro from '@tarojs/taro'
55
import { AtTextareaProps } from 'types/textarea'
66
import { pxTransform } from '../../utils/common'
7+
import { useModelValue } from '../../composables/model'
78

89
type ExtendEvent = {
910
target: {
@@ -50,19 +51,15 @@ const AtTextarea = defineComponent({
5051
height: { type: [String, Number], default: 100 },
5152
cursorSpacing: { type: Number, default: 100 },
5253
// event handlers
53-
onChange: {
54-
type: Function as PropType<AtTextareaProps['onChange']>,
55-
default: () => (value: string, event?: CommonEvent) => { },
56-
required: true
57-
},
54+
onChange: Function as PropType<AtTextareaProps['onChange']>,
5855
onFocus: Function as PropType<AtTextareaProps['onFocus']>,
5956
onBlur: Function as PropType<AtTextareaProps['onBlur']>,
6057
onConfirm: Function as PropType<AtTextareaProps['onConfirm']>,
6158
onLinechange: Function as PropType<AtTextareaProps['onLinechange']>,
6259
},
6360

64-
setup(props: AtTextareaProps, { attrs, slots }) {
65-
const isAlipay = Taro.getEnv() === Taro.ENV_TYPE.ALIPAY
61+
setup(props: AtTextareaProps, { attrs, emit }) {
62+
const inputValue = useModelValue(props, emit, 'value')
6663

6764
const _maxLength = computed(() => parseInt(props.maxLength!.toString()))
6865

@@ -79,68 +76,72 @@ const AtTextarea = defineComponent({
7976
const rootClasses = computed(() => ({
8077
'at-textarea': true,
8178
[`at-textarea--${ENV}`]: true,
82-
'at-textarea--error': _maxLength.value < props.value.length
79+
'at-textarea--error': _maxLength.value < inputValue.value.length
8380
}))
8481

85-
const placeholderClasses = computed(() => `placeholder ${props.placeholderClass}`)
86-
87-
const alipayShowCount = computed(() => isAlipay
88-
? { showCount: props.count }
89-
: {}
90-
)
82+
const placeholderClasses = computed(() => ({
83+
'placeholder': true,
84+
[`${props.placeholderClass}`]: Boolean(props.placeholderClass)
85+
}))
9186

9287
function handleInput(event: CommonEvent & ExtendEvent): void {
93-
props.onChange(event.target.value, event)
88+
if (attrs['onUpdate:value']) {
89+
inputValue.value = event.target.value
90+
} else {
91+
props.onChange?.(event.target.value, event)
92+
}
9493
}
9594

9695
function handleFocus(event: CommonEvent): void {
97-
props.onFocus && props.onFocus(event)
96+
props.onFocus?.(event)
9897
}
9998

10099
function handleBlur(event: CommonEvent): void {
101-
props.onBlur && props.onBlur(event)
100+
props.onBlur?.(event)
102101
}
103102

104103
function handleConfirm(event: CommonEvent): void {
105-
props.onConfirm && props.onConfirm(event)
104+
props.onConfirm?.(event)
106105
}
107106

108107
function handleLinechange(event: CommonEvent): void {
109-
props.onLinechange && props.onLinechange(event)
108+
props.onLinechange?.(event)
110109
}
111110

112111
return () => (
113112
h(View, mergeProps(attrs, {
114113
class: rootClasses.value
115114
}), {
116115
default: () => [
117-
h(Textarea, mergeProps(alipayShowCount.value, {
118-
class: 'at-textarea__textarea',
119-
style: textareaStyle.value,
120-
placeholderstyle: props.placeholderStyle,
121-
placeholderClass: placeholderClasses.value,
122-
cursorSpacing: props.cursorSpacing,
123-
value: props.value,
124-
maxlength: actualMaxLength.value,
125-
placeholder: props.placeholder,
126-
disabled: props.disabled,
127-
autoFocus: props.autoFocus,
128-
focus: props.focus,
129-
fixed: props.fixed,
130-
showConfirmBar: props.showConfirmBar,
131-
selectionStart: props.selectionStart,
132-
selectionEnd: props.selectionEnd,
133-
onInput: handleInput,
134-
onFocus: handleFocus,
135-
onBlur: handleBlur,
136-
onConfirm: handleConfirm,
137-
onLineChange: handleLinechange,
138-
})),
139-
140-
props.count && !isAlipay && (
116+
h(Textarea, mergeProps(
117+
process.env.TARO_ENV === 'alipay' ? { showCount: props.count } : {},
118+
{
119+
class: 'at-textarea__textarea',
120+
style: textareaStyle.value,
121+
placeholderstyle: props.placeholderStyle,
122+
placeholderClass: placeholderClasses.value,
123+
cursorSpacing: props.cursorSpacing,
124+
value: inputValue.value,
125+
maxlength: actualMaxLength.value,
126+
placeholder: props.placeholder,
127+
disabled: props.disabled,
128+
autoFocus: props.autoFocus,
129+
focus: props.focus,
130+
fixed: props.fixed,
131+
showConfirmBar: props.showConfirmBar,
132+
selectionStart: props.selectionStart,
133+
selectionEnd: props.selectionEnd,
134+
onInput: handleInput,
135+
onFocus: handleFocus,
136+
onBlur: handleBlur,
137+
onConfirm: handleConfirm,
138+
onLineChange: handleLinechange,
139+
})),
140+
141+
props.count && process.env.TARO_ENV !== 'alipay' && (
141142
h(View, {
142143
class: 'at-textarea__counter'
143-
}, { default: () => `${props.value.length} / ${_maxLength.value}` })
144+
}, { default: () => `${inputValue.value.length} / ${_maxLength.value}` })
144145
)
145146
]
146147
})

src/pages/form/textarea/index.ts

-95
This file was deleted.

src/pages/form/textarea/index.vue

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<template>
2+
<page header-title="Textarea 多行文本框">
3+
<panel title="基础用法">
4+
<example-item>
5+
<at-textarea
6+
placeholder="通过 onChange 更新 value 的值..."
7+
:max-length="200"
8+
:value="value1"
9+
@change="handleChange('value1', $event)"
10+
/>
11+
</example-item>
12+
</panel>
13+
14+
<panel title="不显示字数">
15+
<example-item>
16+
<at-textarea
17+
placeholder="通过 v-model:value 更新 value 的值..."
18+
:count="false"
19+
:max-length="200"
20+
v-model:value="value2"
21+
/>
22+
</example-item>
23+
</panel>
24+
25+
<panel title="文字超出仍可输入">
26+
<example-item>
27+
<at-textarea
28+
placeholder="通过 v-model:value 更新 value 的值..."
29+
:text-overflow-forbidden="false"
30+
:max-length="200"
31+
v-model:value="value3"
32+
/>
33+
</example-item>
34+
</panel>
35+
36+
<panel title="自定义高度">
37+
<example-item>
38+
<at-textarea
39+
placeholder="通过 v-model:value 更新 value 的值..."
40+
height="300"
41+
:max-length="200"
42+
v-model:value="value4"
43+
/>
44+
</example-item>
45+
</panel>
46+
</page>
47+
</template>
48+
49+
<script lang="ts">
50+
import { defineComponent, reactive, toRefs } from 'vue'
51+
import { AtTextarea } from '../../../index'
52+
import { Page, Panel, ExampleItem } from '../../components/demo-page'
53+
import './index.scss'
54+
55+
interface IndexState {
56+
[key: string]: string
57+
}
58+
59+
export default defineComponent({
60+
name: "TextareaDemo",
61+
62+
components: {
63+
AtTextarea,
64+
Page,
65+
Panel,
66+
ExampleItem
67+
},
68+
69+
setup() {
70+
const state = reactive<IndexState>({
71+
value1: '',
72+
value2: '',
73+
value3: '',
74+
value4: ''
75+
})
76+
77+
function handleChange(stateName: string, value: string): void {
78+
state[stateName] = value
79+
}
80+
81+
return {
82+
...toRefs(state),
83+
handleChange
84+
}
85+
}
86+
})
87+
88+
</script>

types/textarea.d.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import AtComponent from './base'
77

88
export interface AtTextareaProps extends AtComponent {
99
/**
10-
* 输入框当前值,用户需要通过 onChange 事件的 event.target.value 来更新 value 值,必填
10+
* 输入框当前值,支持 v-model,用户可通过 onChange 事件的 event.target.value 或 v-model:value 来更新 value 值,必填
1111
*/
1212
value: string
1313
/**
@@ -86,10 +86,10 @@ export interface AtTextareaProps extends AtComponent {
8686
cursorSpacing?: number
8787
/**
8888
* 输入框值改变时触发的事件,
89-
* 开发者需要通过 onChange 事件来更新 value 值变化,
90-
* onChange 函数必填
89+
* 开发者可通过 onChange 事件或 v-model:value 来更新 value 值变化,
90+
* 不使用 v-model 时,onChange 函数必填
9191
*/
92-
onChange: (value: string, event?: CommonEvent) => void
92+
onChange?: (value: string, event?: CommonEvent) => void
9393
/**
9494
* 输入框获得焦点时触发,height 为键盘高度,在基础库 1.9.90 起支持
9595
*/

0 commit comments

Comments
 (0)