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

Commit

Permalink
feat(textarea): add v-model support
Browse files Browse the repository at this point in the history
  • Loading branch information
b2nil committed Dec 6, 2020
1 parent 06ae9c1 commit 5d35ea5
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 143 deletions.
89 changes: 45 additions & 44 deletions src/components/textarea/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CommonEvent } from '@tarojs/components/types/common'
import Taro from '@tarojs/taro'
import { AtTextareaProps } from 'types/textarea'
import { pxTransform } from '../../utils/common'
import { useModelValue } from '../../composables/model'

type ExtendEvent = {
target: {
Expand Down Expand Up @@ -50,19 +51,15 @@ const AtTextarea = defineComponent({
height: { type: [String, Number], default: 100 },
cursorSpacing: { type: Number, default: 100 },
// event handlers
onChange: {
type: Function as PropType<AtTextareaProps['onChange']>,
default: () => (value: string, event?: CommonEvent) => { },
required: true
},
onChange: Function as PropType<AtTextareaProps['onChange']>,
onFocus: Function as PropType<AtTextareaProps['onFocus']>,
onBlur: Function as PropType<AtTextareaProps['onBlur']>,
onConfirm: Function as PropType<AtTextareaProps['onConfirm']>,
onLinechange: Function as PropType<AtTextareaProps['onLinechange']>,
},

setup(props: AtTextareaProps, { attrs, slots }) {
const isAlipay = Taro.getEnv() === Taro.ENV_TYPE.ALIPAY
setup(props: AtTextareaProps, { attrs, emit }) {
const inputValue = useModelValue(props, emit, 'value')

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

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

const placeholderClasses = computed(() => `placeholder ${props.placeholderClass}`)

const alipayShowCount = computed(() => isAlipay
? { showCount: props.count }
: {}
)
const placeholderClasses = computed(() => ({
'placeholder': true,
[`${props.placeholderClass}`]: Boolean(props.placeholderClass)
}))

function handleInput(event: CommonEvent & ExtendEvent): void {
props.onChange(event.target.value, event)
if (attrs['onUpdate:value']) {
inputValue.value = event.target.value
} else {
props.onChange?.(event.target.value, event)
}
}

function handleFocus(event: CommonEvent): void {
props.onFocus && props.onFocus(event)
props.onFocus?.(event)
}

function handleBlur(event: CommonEvent): void {
props.onBlur && props.onBlur(event)
props.onBlur?.(event)
}

function handleConfirm(event: CommonEvent): void {
props.onConfirm && props.onConfirm(event)
props.onConfirm?.(event)
}

function handleLinechange(event: CommonEvent): void {
props.onLinechange && props.onLinechange(event)
props.onLinechange?.(event)
}

return () => (
h(View, mergeProps(attrs, {
class: rootClasses.value
}), {
default: () => [
h(Textarea, mergeProps(alipayShowCount.value, {
class: 'at-textarea__textarea',
style: textareaStyle.value,
placeholderstyle: props.placeholderStyle,
placeholderClass: placeholderClasses.value,
cursorSpacing: props.cursorSpacing,
value: props.value,
maxlength: actualMaxLength.value,
placeholder: props.placeholder,
disabled: props.disabled,
autoFocus: props.autoFocus,
focus: props.focus,
fixed: props.fixed,
showConfirmBar: props.showConfirmBar,
selectionStart: props.selectionStart,
selectionEnd: props.selectionEnd,
onInput: handleInput,
onFocus: handleFocus,
onBlur: handleBlur,
onConfirm: handleConfirm,
onLineChange: handleLinechange,
})),

props.count && !isAlipay && (
h(Textarea, mergeProps(
process.env.TARO_ENV === 'alipay' ? { showCount: props.count } : {},
{
class: 'at-textarea__textarea',
style: textareaStyle.value,
placeholderstyle: props.placeholderStyle,
placeholderClass: placeholderClasses.value,
cursorSpacing: props.cursorSpacing,
value: inputValue.value,
maxlength: actualMaxLength.value,
placeholder: props.placeholder,
disabled: props.disabled,
autoFocus: props.autoFocus,
focus: props.focus,
fixed: props.fixed,
showConfirmBar: props.showConfirmBar,
selectionStart: props.selectionStart,
selectionEnd: props.selectionEnd,
onInput: handleInput,
onFocus: handleFocus,
onBlur: handleBlur,
onConfirm: handleConfirm,
onLineChange: handleLinechange,
})),

props.count && process.env.TARO_ENV !== 'alipay' && (
h(View, {
class: 'at-textarea__counter'
}, { default: () => `${props.value.length} / ${_maxLength.value}` })
}, { default: () => `${inputValue.value.length} / ${_maxLength.value}` })
)
]
})
Expand Down
95 changes: 0 additions & 95 deletions src/pages/form/textarea/index.ts

This file was deleted.

88 changes: 88 additions & 0 deletions src/pages/form/textarea/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<template>
<page header-title="Textarea 多行文本框">
<panel title="基础用法">
<example-item>
<at-textarea
placeholder="通过 onChange 更新 value 的值..."
:max-length="200"
:value="value1"
@change="handleChange('value1', $event)"
/>
</example-item>
</panel>

<panel title="不显示字数">
<example-item>
<at-textarea
placeholder="通过 v-model:value 更新 value 的值..."
:count="false"
:max-length="200"
v-model:value="value2"
/>
</example-item>
</panel>

<panel title="文字超出仍可输入">
<example-item>
<at-textarea
placeholder="通过 v-model:value 更新 value 的值..."
:text-overflow-forbidden="false"
:max-length="200"
v-model:value="value3"
/>
</example-item>
</panel>

<panel title="自定义高度">
<example-item>
<at-textarea
placeholder="通过 v-model:value 更新 value 的值..."
height="300"
:max-length="200"
v-model:value="value4"
/>
</example-item>
</panel>
</page>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs } from 'vue'
import { AtTextarea } from '../../../index'
import { Page, Panel, ExampleItem } from '../../components/demo-page'
import './index.scss'
interface IndexState {
[key: string]: string
}
export default defineComponent({
name: "TextareaDemo",
components: {
AtTextarea,
Page,
Panel,
ExampleItem
},
setup() {
const state = reactive<IndexState>({
value1: '',
value2: '',
value3: '',
value4: ''
})
function handleChange(stateName: string, value: string): void {
state[stateName] = value
}
return {
...toRefs(state),
handleChange
}
}
})
</script>
8 changes: 4 additions & 4 deletions types/textarea.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import AtComponent from './base'

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

0 comments on commit 5d35ea5

Please sign in to comment.