提交 23d75de6 编写于 作者: Q qiang

fix: 修复 input、textarea 组件快速输入(删除)光标闪烁的问题

上级 5f5a576b
......@@ -8,7 +8,7 @@
class="uni-input-wrapper"
>
<div
v-show="!(composing || inputValue.length)"
v-show="!(composing || valueSync.length)"
ref="placeholder"
:style="placeholderStyle"
:class="placeholderClass"
......@@ -17,7 +17,7 @@
/>
<input
ref="input"
v-model="inputValue"
v-model="valueSync"
:disabled="disabled"
:type="inputType"
:maxlength="maxlength"
......@@ -36,27 +36,18 @@
</template>
<script>
import {
emitter,
keyboard
baseInput
} from 'uni-mixins'
const INPUT_TYPES = ['text', 'number', 'idcard', 'digit', 'password']
const NUMBER_TYPES = ['number', 'digit']
export default {
name: 'Input',
mixins: [emitter, keyboard],
model: {
prop: 'value',
event: 'update:value'
},
mixins: [baseInput],
props: {
name: {
type: String,
default: ''
},
value: {
type: [String, Number],
default: ''
},
type: {
type: String,
default: 'text'
......@@ -96,7 +87,6 @@ export default {
},
data () {
return {
inputValue: this._getValueString(this.value),
composing: false,
wrapperHeight: 0,
cachedValue: ''
......@@ -131,15 +121,9 @@ export default {
focus (value) {
value && this._focusInput()
},
value (value) {
this.inputValue = this._getValueString(value)
},
inputValue (value) {
this.$emit('update:value', value)
},
maxlength (value) {
const realValue = this.inputValue.slice(0, parseInt(value, 10))
realValue !== this.inputValue && (this.inputValue = realValue)
const realValue = this.valueSync.slice(0, parseInt(value, 10))
realValue !== this.valueSync && (this.valueSync = realValue)
}
},
created () {
......@@ -196,11 +180,11 @@ export default {
if (~NUMBER_TYPES.indexOf(this.type)) {
if (this.$refs.input.validity && !this.$refs.input.validity.valid) {
$event.target.value = this.cachedValue
this.inputValue = $event.target.value
this.valueSync = $event.target.value
// 输入非法字符不触发 input 事件
return
} else {
this.cachedValue = this.inputValue
this.cachedValue = this.valueSync
}
}
......@@ -209,14 +193,13 @@ export default {
const maxlength = parseInt(this.maxlength, 10)
if (maxlength > 0 && $event.target.value.length > maxlength) {
$event.target.value = $event.target.value.slice(0, maxlength)
this.inputValue = $event.target.value
this.valueSync = $event.target.value
// 字符长度超出范围不触发 input 事件
return
}
}
this.$trigger('input', $event, {
value: this.inputValue
this.$triggerInput($event, {
value: this.valueSync
})
},
_onFocus ($event) {
......@@ -247,16 +230,13 @@ export default {
}
},
_resetFormData () {
this.inputValue = ''
this.valueSync = ''
},
_getFormData () {
return this.name ? {
value: this.inputValue,
value: this.valueSync,
key: this.name
} : {}
},
_getValueString (value) {
return value === null ? '' : String(value)
}
}
}
......
......@@ -49,26 +49,17 @@
</template>
<script>
import {
emitter,
keyboard
baseInput
} from 'uni-mixins'
const DARK_TEST_STRING = '(prefers-color-scheme: dark)'
export default {
name: 'Textarea',
mixins: [emitter, keyboard],
model: {
prop: 'value',
event: 'update:value'
},
mixins: [baseInput],
props: {
name: {
type: String,
default: ''
},
value: {
type: [String, Number],
default: ''
},
maxlength: {
type: [Number, String],
default: 140
......@@ -116,7 +107,6 @@ export default {
},
data () {
return {
valueSync: this._getValueString(this.value),
valueComposition: '',
composition: false,
focusSync: this.focus,
......@@ -148,19 +138,6 @@ export default {
}
},
watch: {
value (val) {
this.valueSync = this._getValueString(val)
},
valueSync (val) {
if (val !== this._oldValue) {
this._oldValue = val
this.$trigger('input', {}, {
value: val,
cursor: this.$refs.textarea.selectionEnd
})
this.$emit('update:value', val)
}
},
focus (val) {
if (val) {
this.focusChangeSource = 'focus'
......@@ -210,7 +187,6 @@ export default {
})
},
mounted () {
this._oldValue = this.$refs.textarea.value = this.valueSync
this._resize({
height: this.$refs.sensor.$el.offsetHeight
})
......@@ -283,7 +259,12 @@ export default {
_input ($event) {
if (this.composition) {
this.valueComposition = $event.target.value
return
}
this.$triggerInput($event, {
value: this.valueSync,
cursor: this.$refs.textarea.selectionEnd
})
},
_getFormData () {
return {
......@@ -293,9 +274,6 @@ export default {
},
_resetFormData () {
this.valueSync = ''
},
_getValueString (value) {
return value === null ? '' : String(value)
}
}
}
......
import {
debounce,
throttle
} from 'uni-shared'
import emitter from './emitter'
import keyboard from './keyboard'
export default {
name: 'BaseInput',
mixins: [emitter, keyboard],
model: {
prop: 'value',
event: 'update:value'
},
props: {
value: {
type: [String, Number],
default: ''
}
},
data () {
return {
valueSync: this._getValueString(this.value)
}
},
watch: {
valueSync (value) {
this.$emit('update:value', value)
}
},
created () {
const valueChange = this.__valueChange = debounce((val, oldVal) => {
this.valueSync = this._getValueString(val)
}, 100)
this.$watch('value', valueChange)
this.__triggerInput = throttle(($event, detail) => {
this.$trigger('input', $event, detail)
}, 100)
this.$triggerInput = ($event, detail) => {
this.__valueChange.cancel()
this.__triggerInput($event, detail)
}
},
beforeDestroy () {
this.__valueChange.cancel()
this.__triggerInput.cancel()
},
methods: {
_getValueString (value) {
return value === null ? '' : String(value)
}
}
}
......@@ -23,6 +23,11 @@ export {
}
from './keyboard'
export {
default as baseInput
}
from './base-input'
export {
default as interact
}
......
......@@ -86,11 +86,37 @@ export function guid () {
export function debounce (fn, delay) {
let timeout
return function () {
const newFn = function () {
clearTimeout(timeout)
const timerFn = () => fn.apply(this, arguments)
timeout = setTimeout(timerFn, delay)
}
newFn.cancel = function () {
clearTimeout(timeout)
}
return newFn
}
export function throttle (fn, wait) {
let last = 0
let timeout
const newFn = function (...arg) {
const now = Date.now()
clearTimeout(timeout)
const waitCallback = () => {
last = now
fn.apply(this, arg)
}
if (now - last < wait) {
timeout = setTimeout(waitCallback, wait - (now - last))
return
}
waitCallback()
}
newFn.cancel = function () {
clearTimeout(timeout)
}
return newFn
}
export function kebabCase (string) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册