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

Commit

Permalink
feat(input): 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 4a453f4 commit 0248c52
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 45 deletions.
52 changes: 27 additions & 25 deletions src/components/input/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
InputEventDetail,
KeyboardHeightEventDetail,
} from "types/input"
import { ENV_TYPE, getEnv } from "@tarojs/taro"
import { uuid } from "../../utils/common"
import { useModelValue } from "../../composables/model"

type PickAtInputProps = Pick<AtInputProps, 'maxLength' | 'disabled' | 'password'>
type GetInputPropsReturn = PickAtInputProps & Pick<InputProps, 'type'>
Expand Down Expand Up @@ -115,15 +115,11 @@ const AtInput = defineComponent({
},
confirmType: {
type: String as () => AtInputProps["confirmType"],
default: 'done' as AtInputProps["confirmType"],
default: 'done',
validator: (val: string) => ["done", "send", "search", "next", "go"].includes(val)
},
// events
onChange: {
type: Function as PropType<AtInputProps['onChange']>,
default: () => () => { },
required: true
},
onChange: Function as PropType<AtInputProps['onChange']>,
onBlur: Function as PropType<AtInputProps['onBlur']>,
onFocus: Function as PropType<AtInputProps['onFocus']>,
onConfirm: Function as PropType<AtInputProps['onConfirm']>,
Expand All @@ -132,11 +128,9 @@ const AtInput = defineComponent({
onErrorClick: Function as PropType<AtInputProps['onErrorClick']>
},

setup(props: AtInputProps, { attrs, slots }) {
const inputValue = ref(props.value)
setup(props: AtInputProps, { attrs, slots, emit }) {
const inputValue = useModelValue(props, emit, 'value')
const inputID = ref('weui-input' + uuid())
const isWEB = ref(getEnv() === ENV_TYPE.WEB)

const inputProps = computed(() => getInputProps(props))

const rootClasses = computed(() => ({
Expand All @@ -162,23 +156,27 @@ const AtInput = defineComponent({
'at-input__title--required': props.required
}))

watch(() => props.value, (val, preVal) => {
if (val !== preVal) {
inputValue.value = val
}
})
// watch(() => props.value, (val, preVal) => {
// if (val !== preVal) {
// inputValue.value = val
// }
// })

function handleInput(e: BaseEventOrig<InputEventDetail>) {
props.onChange(e.detail.value, e)
if (attrs['onUpdate:value']) {
inputValue.value = e.detail.value
} else {
props.onChange?.(e.detail.value, e)
}
}

function handleFocus(e: BaseEventOrig<FocusEventDetail>) {
if (typeof props.onFocus === 'function') {
props.onFocus(e.detail.value, e)
}
if (isWEB.value) {
if (process.env.TARO_ENV === 'h5') {
// hack fix: h5 点击清除按钮后,input value 在数据层被清除,但视图层仍未清除
inputID.value = 'weui-input' + String(e.timeStamp).replace('.', '')
inputID.value = 'weui-input' + uuid(10, 32)
}
}

Expand All @@ -201,14 +199,17 @@ const AtInput = defineComponent({
}

function handleClearValue(e: ITouchEvent) {
props.onChange('', e)
if (attrs['onUpdate:value']) {
inputValue.value = ''
} else {
props.onChange?.('', e)
}

// hack fix: h5 点击清除按钮后,input value 在数据层被清除,但视图层仍未清除
if (isWEB.value) {
if (process.env.TARO_ENV === 'h5') {
const inputNode = document.querySelector<HTMLInputElement>(`#${inputID.value} > .weui-input`)
inputNode!.value = ''
}

}

function handleKeyboardHeightChange(
Expand Down Expand Up @@ -247,8 +248,9 @@ const AtInput = defineComponent({
}, { default: () => props.title })
),

h(Input, mergeProps(isWEB.value ? { id: inputID.value } : {}, {
h(Input, {
class: 'at-input__input',
id: inputID.value,
name: props.name,
type: inputProps.value.type,
password: inputProps.value.password,
Expand All @@ -270,7 +272,7 @@ const AtInput = defineComponent({
onFocus: handleFocus,
onConfirm: handleConfirm,
onKeyboardHeightChange: handleKeyboardHeightChange,
})),
}),

(props.clear && props.value) && (
h(View, {
Expand Down Expand Up @@ -300,7 +302,7 @@ const AtInput = defineComponent({

h(View, {
class: 'at-input__children'
}, { default: () => slots.default && slots.default() })
}, { default: () => slots.default?.() })
]
})
]
Expand Down
43 changes: 25 additions & 18 deletions src/pages/form/input/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@
name="value1"
title="标准五个字"
type="text"
placeholder="标准五个字"
:value="value1"
@change="handleInput('value1', $event)"
placeholder="使用了 v-model:value 更新 value"
v-model:value="value1"
/>
<at-input
name="value2"
title="标题实在特别长就换行"
placeholder="其他列保持正常间距"
:value="value2"
@change="handleInput('value2', $event)"
placeholder="使用了 onChange 更新 value"
:value="value1"
@change="handleInput('value1', $event)"
/>
<at-input
name="value3"
Expand Down Expand Up @@ -137,8 +136,7 @@
title="清除按钮"
type="text"
placeholder="点击清除按钮清空内容"
:value="value13"
@change="handleInput('value13', $event)"
v-model:value="value13"
/>
<at-input
clear
Expand All @@ -148,8 +146,7 @@
title="必填项"
type="text"
placeholder="必须填写内容"
:value="value16"
@change="handleInput('value16', $event)"
v-model:value="value16"
/>
<at-input
clear
Expand All @@ -158,8 +155,7 @@
title="监听事件"
type="text"
placeholder="监听键盘高度事件"
:value="value17"
@change="handleInput('value17', $event)"
v-model:value="value17"
@keyboard-height-change="handleKeyboardHeightChange"
/>
</at-form>
Expand All @@ -181,19 +177,20 @@
type="text"
placeholder="验证码"
:maxLength="4"
:value="value14"
@change="handleInput('value14', $event)"
v-model:value="value14"
>
<image :src="verificationCode" />
<image
:src="verificationCode"
:style="imageStyle"
/>
</at-input>
<at-input
clear
name="value15"
type="phone"
placeholder="请输入手机号码"
:border="false"
:value="value15"
@change="handleInput('value15', $event)"
v-model:value="value15"
>
<view
:style="{
Expand All @@ -212,7 +209,7 @@
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs } from 'vue'
import { computed, defineComponent, reactive, toRefs } from 'vue'
import Taro from '@tarojs/taro'
import { AtForm, AtInput } from '../../../index'
Expand Down Expand Up @@ -252,6 +249,15 @@ export default defineComponent({
second: 60,
})
const imageStyle = computed(() => {
if (process.env.TARO_ENV === 'h5') {
return {
width: 'unset',
height: 'unset',
}
}
})
function showTipText() {
return state.disabled ? `${state.second}s后重试` : '发送验证码'
}
Expand Down Expand Up @@ -303,6 +309,7 @@ export default defineComponent({
return {
...toRefs(state),
imageStyle,
verificationCode,
handleInput,
showTipText,
Expand Down
4 changes: 2 additions & 2 deletions types/input.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,10 @@ export interface AtInputProps extends AtComponent, OmitInputProps {
*/
onFocus?: InputFunction<string | number, FocusEventDetail>
/**
* 输入框值改变时触发的事件,开发者需要通过 onChange 事件来更新 value 值变化,onChange 函数必填
* 输入框值改变时触发的事件,开发者可通过 onChange 事件或 v-model:value 来更新 value 值变化,使用 v-model 时,无需 onChange 函数
* 小程序中,如果想改变 value 的值,需要 return value 从而改变输入框的当前值, v2.0.3 版本可以获取 event 参数
*/
onChange: InputFunction<string | number, InputEventDetail, any>
onChange?: InputFunction<string | number, InputEventDetail, any>
/**
* 点击完成按钮时触发,v2.0.3 版本可以获取 event 参数
*/
Expand Down

0 comments on commit 0248c52

Please sign in to comment.