fix: reduce passive event warning of touchmove event (#10975)

This commit is contained in:
neverland 2022-08-27 11:12:36 +08:00 committed by GitHub
parent 6a7376d15d
commit da3400435f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 217 additions and 136 deletions

View File

@ -26,6 +26,7 @@ import {
makeStringProp, makeStringProp,
makeNumericProp, makeNumericProp,
createNamespace, createNamespace,
type ComponentInstance,
} from '../utils'; } from '../utils';
import { import {
cutString, cutString,
@ -42,7 +43,11 @@ import {
import { cellSharedProps } from '../cell/Cell'; import { cellSharedProps } from '../cell/Cell';
// Composables // Composables
import { CUSTOM_FIELD_INJECTION_KEY, useParent } from '@vant/use'; import {
useParent,
useEventListener,
CUSTOM_FIELD_INJECTION_KEY,
} from '@vant/use';
import { useId } from '../composables/use-id'; import { useId } from '../composables/use-id';
import { useExpose } from '../composables/use-expose'; import { useExpose } from '../composables/use-expose';
@ -145,6 +150,7 @@ export default defineComponent({
}); });
const inputRef = ref<HTMLInputElement>(); const inputRef = ref<HTMLInputElement>();
const clearIconRef = ref<ComponentInstance>();
const customValue = ref<() => unknown>(); const customValue = ref<() => unknown>();
const { parent: form } = useParent(FORM_KEY); const { parent: form } = useParent(FORM_KEY);
@ -354,7 +360,7 @@ export default defineComponent({
const onClickRightIcon = (event: MouseEvent) => const onClickRightIcon = (event: MouseEvent) =>
emit('click-right-icon', event); emit('click-right-icon', event);
const onClear = (event: MouseEvent) => { const onClear = (event: TouchEvent) => {
preventDefault(event); preventDefault(event);
emit('update:modelValue', ''); emit('update:modelValue', '');
emit('clear', event); emit('clear', event);
@ -527,9 +533,9 @@ export default defineComponent({
{renderInput()} {renderInput()}
{showClear.value && ( {showClear.value && (
<Icon <Icon
ref={clearIconRef}
name={props.clearIcon} name={props.clearIcon}
class={bem('clear')} class={bem('clear')}
onTouchstart={onClear}
/> />
)} )}
{renderRightIcon()} {renderRightIcon()}
@ -569,6 +575,11 @@ export default defineComponent({
nextTick(adjustTextareaSize); nextTick(adjustTextareaSize);
}); });
// useEventListener will set passive to `false` to eliminate the warning of Chrome
useEventListener('touchstart', onClear, {
target: computed(() => clearIconRef.value?.$el),
});
return () => { return () => {
const disabled = getProp('disabled'); const disabled = getProp('disabled');
const labelAlign = getProp('labelAlign'); const labelAlign = getProp('labelAlign');

View File

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import VanField from '..'; import VanField from '..';
import VanForm from '../../form';
import VanCellGroup from '../../cell-group'; import VanCellGroup from '../../cell-group';
import { ref } from 'vue'; import { ref } from 'vue';
import { useTranslate } from '../../../docs/site'; import { useTranslate } from '../../../docs/site';
@ -43,35 +44,39 @@ const password = ref('');
<template> <template>
<demo-block :title="t('customType')"> <demo-block :title="t('customType')">
<van-cell-group inset> <van-cell-group inset>
<van-field <van-form>
v-model="text" <van-field
:label="t('text')" v-model="text"
:placeholder="t('textPlaceholder')" :label="t('text')"
/> :placeholder="t('textPlaceholder')"
<van-field autocomplete="off"
v-model="phone" />
type="tel" <van-field
:label="t('phone')" v-model="phone"
:placeholder="t('phonePlaceholder')" type="tel"
/> :label="t('phone')"
<van-field :placeholder="t('phonePlaceholder')"
v-model="digit" />
type="digit" <van-field
:label="t('digit')" v-model="digit"
:placeholder="t('digitPlaceholder')" type="digit"
/> :label="t('digit')"
<van-field :placeholder="t('digitPlaceholder')"
v-model="number" />
type="number" <van-field
:label="t('number')" v-model="number"
:placeholder="t('numberPlaceholder')" type="number"
/> :label="t('number')"
<van-field :placeholder="t('numberPlaceholder')"
v-model="password" />
type="password" <van-field
:label="t('password')" v-model="password"
:placeholder="t('passwordPlaceholder')" type="password"
/> :label="t('password')"
:placeholder="t('passwordPlaceholder')"
autocomplete="off"
/>
</van-form>
</van-cell-group> </van-cell-group>
</demo-block> </demo-block>
</template> </template>

View File

@ -26,103 +26,107 @@ exports[`should render demo and match snapshot 1`] = `
</div> </div>
<div> <div>
<div class="van-cell-group van-cell-group--inset"> <div class="van-cell-group van-cell-group--inset">
<div class="van-cell van-field"> <form class="van-form">
<div class="van-cell__title van-field__label"> <div class="van-cell van-field">
<label id="van-field-label" <div class="van-cell__title van-field__label">
for="van-field-input" <label id="van-field-label"
> for="van-field-input"
Text
</label>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<input type="text"
id="van-field-input"
class="van-field__control"
placeholder="Text"
aria-labelledby="van-field-label"
> >
Text
</label>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<input type="text"
id="van-field-input"
class="van-field__control"
placeholder="Text"
autocomplete="off"
aria-labelledby="van-field-label"
>
</div>
</div> </div>
</div> </div>
</div> <div class="van-cell van-field">
<div class="van-cell van-field"> <div class="van-cell__title van-field__label">
<div class="van-cell__title van-field__label"> <label id="van-field-label"
<label id="van-field-label" for="van-field-input"
for="van-field-input"
>
Phone
</label>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<input type="tel"
id="van-field-input"
class="van-field__control"
placeholder="Phone"
aria-labelledby="van-field-label"
> >
Phone
</label>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<input type="tel"
id="van-field-input"
class="van-field__control"
placeholder="Phone"
aria-labelledby="van-field-label"
>
</div>
</div> </div>
</div> </div>
</div> <div class="van-cell van-field">
<div class="van-cell van-field"> <div class="van-cell__title van-field__label">
<div class="van-cell__title van-field__label"> <label id="van-field-label"
<label id="van-field-label" for="van-field-input"
for="van-field-input"
>
Digit
</label>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<input type="tel"
inputmode="numeric"
id="van-field-input"
class="van-field__control"
placeholder="Digit"
aria-labelledby="van-field-label"
> >
Digit
</label>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<input type="tel"
inputmode="numeric"
id="van-field-input"
class="van-field__control"
placeholder="Digit"
aria-labelledby="van-field-label"
>
</div>
</div> </div>
</div> </div>
</div> <div class="van-cell van-field">
<div class="van-cell van-field"> <div class="van-cell__title van-field__label">
<div class="van-cell__title van-field__label"> <label id="van-field-label"
<label id="van-field-label" for="van-field-input"
for="van-field-input"
>
Number
</label>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<input type="text"
inputmode="decimal"
id="van-field-input"
class="van-field__control"
placeholder="Number"
aria-labelledby="van-field-label"
> >
Number
</label>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<input type="text"
inputmode="decimal"
id="van-field-input"
class="van-field__control"
placeholder="Number"
aria-labelledby="van-field-label"
>
</div>
</div> </div>
</div> </div>
</div> <div class="van-cell van-field">
<div class="van-cell van-field"> <div class="van-cell__title van-field__label">
<div class="van-cell__title van-field__label"> <label id="van-field-label"
<label id="van-field-label" for="van-field-input"
for="van-field-input"
>
Password
</label>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<input type="password"
id="van-field-input"
class="van-field__control"
placeholder="Password"
aria-labelledby="van-field-label"
> >
Password
</label>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<input type="password"
id="van-field-input"
class="van-field__control"
placeholder="Password"
autocomplete="off"
aria-labelledby="van-field-label"
>
</div>
</div> </div>
</div> </div>
</div> </form>
</div> </div>
</div> </div>
<div> <div>

View File

@ -1,4 +1,5 @@
import { import {
ref,
watch, watch,
computed, computed,
reactive, reactive,
@ -13,10 +14,12 @@ import {
preventDefault, preventDefault,
createNamespace, createNamespace,
makeRequiredProp, makeRequiredProp,
type ComponentInstance,
} from '../utils'; } from '../utils';
// Composables // Composables
import { useTouch } from '../composables/use-touch'; import { useTouch } from '../composables/use-touch';
import { useEventListener } from '@vant/use';
// Components // Components
import { Image } from '../image'; import { Image } from '../image';
@ -57,6 +60,7 @@ export default defineComponent({
}); });
const touch = useTouch(); const touch = useTouch();
const swipeItem = ref<ComponentInstance>();
const vertical = computed(() => { const vertical = computed(() => {
const { rootWidth, rootHeight } = props; const { rootWidth, rootHeight } = props;
@ -271,6 +275,11 @@ export default defineComponent({
} }
); );
// useEventListener will set passive to `false` to eliminate the warning of Chrome
useEventListener('touchmove', onTouchMove, {
target: computed(() => swipeItem.value?.$el),
});
return () => { return () => {
const imageSlots = { const imageSlots = {
loading: () => <Loading type="spinner" />, loading: () => <Loading type="spinner" />,
@ -278,9 +287,9 @@ export default defineComponent({
return ( return (
<SwipeItem <SwipeItem
ref={swipeItem}
class={bem('swipe-item')} class={bem('swipe-item')}
onTouchstartPassive={onTouchStart} onTouchstartPassive={onTouchStart}
onTouchmove={onTouchMove}
onTouchend={onTouchEnd} onTouchend={onTouchEnd}
onTouchcancel={onTouchEnd} onTouchcancel={onTouchEnd}
> >

View File

@ -77,6 +77,7 @@ export default defineComponent({
setup(props, { emit, slots }) { setup(props, { emit, slots }) {
const root = ref<HTMLElement>(); const root = ref<HTMLElement>();
const sidebar = ref<HTMLElement>();
const activeAnchor = ref<Numeric>(''); const activeAnchor = ref<Numeric>('');
const touch = useTouch(); const touch = useTouch();
@ -272,11 +273,11 @@ export default defineComponent({
const renderSidebar = () => ( const renderSidebar = () => (
<div <div
ref={sidebar}
class={bem('sidebar')} class={bem('sidebar')}
style={sidebarStyle.value} style={sidebarStyle.value}
onClick={onClickSidebar} onClick={onClickSidebar}
onTouchstartPassive={touch.start} onTouchstartPassive={touch.start}
onTouchmove={onTouchMove}
> >
{renderIndexes()} {renderIndexes()}
</div> </div>
@ -284,6 +285,11 @@ export default defineComponent({
useExpose({ scrollTo }); useExpose({ scrollTo });
// useEventListener will set passive to `false` to eliminate the warning of Chrome
useEventListener('touchmove', onTouchMove, {
target: sidebar,
});
return () => ( return () => (
<div ref={root} class={bem()}> <div ref={root} class={bem()}>
{props.teleport ? ( {props.teleport ? (

View File

@ -1,12 +1,14 @@
import { import {
ref,
Transition, Transition,
defineComponent, defineComponent,
type PropType, type PropType,
type CSSProperties, type CSSProperties,
type ExtractPropTypes, type ExtractPropTypes,
} from 'vue'; } from 'vue';
// Utils
import { import {
noop,
isDef, isDef,
extend, extend,
truthProp, truthProp,
@ -16,6 +18,9 @@ import {
createNamespace, createNamespace,
getZIndexStyle, getZIndexStyle,
} from '../utils'; } from '../utils';
// Composables
import { useEventListener } from '@vant/use';
import { useLazyRender } from '../composables/use-lazy-render'; import { useLazyRender } from '../composables/use-lazy-render';
const [name, bem] = createNamespace('overlay'); const [name, bem] = createNamespace('overlay');
@ -38,10 +43,13 @@ export default defineComponent({
props: overlayProps, props: overlayProps,
setup(props, { slots }) { setup(props, { slots }) {
const root = ref<HTMLElement>();
const lazyRender = useLazyRender(() => props.show || !props.lazyRender); const lazyRender = useLazyRender(() => props.show || !props.lazyRender);
const preventTouchMove = (event: TouchEvent) => { const onTouchMove = (event: TouchEvent) => {
preventDefault(event, true); if (props.lockScroll) {
preventDefault(event, true);
}
}; };
const renderOverlay = lazyRender(() => { const renderOverlay = lazyRender(() => {
@ -57,15 +65,20 @@ export default defineComponent({
return ( return (
<div <div
v-show={props.show} v-show={props.show}
ref={root}
style={style} style={style}
class={[bem(), props.className]} class={[bem(), props.className]}
onTouchmove={props.lockScroll ? preventTouchMove : noop}
> >
{slots.default?.()} {slots.default?.()}
</div> </div>
); );
}); });
// useEventListener will set passive to `false` to eliminate the warning of Chrome
useEventListener('touchmove', onTouchMove, {
target: root,
});
return () => ( return () => (
<Transition v-slots={{ default: renderOverlay }} name="van-fade" appear /> <Transition v-slots={{ default: renderOverlay }} name="van-fade" appear />
); );

View File

@ -22,7 +22,7 @@ import {
} from '../utils'; } from '../utils';
// Composables // Composables
import { useChildren } from '@vant/use'; import { useChildren, useEventListener } from '@vant/use';
import { useExpose } from '../composables/use-expose'; import { useExpose } from '../composables/use-expose';
// Components // Components
@ -88,6 +88,7 @@ export default defineComponent({
} }
const hasOptions = ref(false); const hasOptions = ref(false);
const columnsRef = ref<HTMLElement>();
const formattedColumns = ref<PickerObjectColumn[]>([]); const formattedColumns = ref<PickerObjectColumn[]>([]);
const columnsFieldNames = computed(() => { const columnsFieldNames = computed(() => {
@ -380,11 +381,7 @@ export default defineComponent({
const wrapHeight = itemHeight.value * +props.visibleItemCount; const wrapHeight = itemHeight.value * +props.visibleItemCount;
const columnsStyle = { height: `${wrapHeight}px` }; const columnsStyle = { height: `${wrapHeight}px` };
return ( return (
<div <div ref={columnsRef} class={bem('columns')} style={columnsStyle}>
class={bem('columns')}
style={columnsStyle}
onTouchmove={preventDefault}
>
{renderColumnItems()} {renderColumnItems()}
{renderMask(wrapHeight)} {renderMask(wrapHeight)}
</div> </div>
@ -393,6 +390,11 @@ export default defineComponent({
watch(() => props.columns, format, { immediate: true }); watch(() => props.columns, format, { immediate: true });
// useEventListener will set passive to `false` to eliminate the warning of Chrome
useEventListener('touchmove', preventDefault, {
target: columnsRef,
});
useExpose<PickerExpose>({ useExpose<PickerExpose>({
confirm, confirm,
getValues, getValues,

View File

@ -15,7 +15,7 @@ import {
} from '../utils'; } from '../utils';
// Composables // Composables
import { useParent } from '@vant/use'; import { useEventListener, useParent } from '@vant/use';
import { useTouch } from '../composables/use-touch'; import { useTouch } from '../composables/use-touch';
import { useExpose } from '../composables/use-expose'; import { useExpose } from '../composables/use-expose';
@ -67,6 +67,7 @@ export default defineComponent({
let momentumOffset: number; let momentumOffset: number;
let transitionEndTrigger: null | (() => void); let transitionEndTrigger: null | (() => void);
const root = ref<HTMLElement>();
const wrapper = ref<HTMLElement>(); const wrapper = ref<HTMLElement>();
const state = reactive({ const state = reactive({
@ -305,11 +306,16 @@ export default defineComponent({
(value) => setIndex(value) (value) => setIndex(value)
); );
// useEventListener will set passive to `false` to eliminate the warning of Chrome
useEventListener('touchmove', onTouchMove, {
target: root,
});
return () => ( return () => (
<div <div
ref={root}
class={[bem(), props.className]} class={[bem(), props.className]}
onTouchstartPassive={onTouchStart} onTouchstartPassive={onTouchStart}
onTouchmove={onTouchMove}
onTouchend={onTouchEnd} onTouchend={onTouchEnd}
onTouchcancel={onTouchEnd} onTouchcancel={onTouchEnd}
> >

View File

@ -13,7 +13,7 @@ import {
} from '../utils'; } from '../utils';
// Composables // Composables
import { useRect, useCustomFieldValue } from '@vant/use'; import { useRect, useCustomFieldValue, useEventListener } from '@vant/use';
import { useRefs } from '../composables/use-refs'; import { useRefs } from '../composables/use-refs';
import { useTouch } from '../composables/use-touch'; import { useTouch } from '../composables/use-touch';
@ -268,6 +268,11 @@ export default defineComponent({
useCustomFieldValue(() => props.modelValue); useCustomFieldValue(() => props.modelValue);
// useEventListener will set passive to `false` to eliminate the warning of Chrome
useEventListener('touchmove', onTouchMove, {
target: groupRef,
});
return () => ( return () => (
<div <div
ref={groupRef} ref={groupRef}
@ -280,7 +285,6 @@ export default defineComponent({
aria-disabled={props.disabled} aria-disabled={props.disabled}
aria-readonly={props.readonly} aria-readonly={props.readonly}
onTouchstartPassive={onTouchStart} onTouchstartPassive={onTouchStart}
onTouchmove={onTouchMove}
> >
{list.value.map(renderStar)} {list.value.map(renderStar)}
</div> </div>

View File

@ -21,7 +21,7 @@ import {
} from '../utils'; } from '../utils';
// Composables // Composables
import { useRect, useCustomFieldValue } from '@vant/use'; import { useRect, useCustomFieldValue, useEventListener } from '@vant/use';
import { useTouch } from '../composables/use-touch'; import { useTouch } from '../composables/use-touch';
const [name, bem] = createNamespace('slider'); const [name, bem] = createNamespace('slider');
@ -64,6 +64,7 @@ export default defineComponent({
let startValue: SliderValue; let startValue: SliderValue;
const root = ref<HTMLElement>(); const root = ref<HTMLElement>();
const slider = ref<HTMLElement>();
const dragStatus = ref<'start' | 'dragging' | ''>(); const dragStatus = ref<'start' | 'dragging' | ''>();
const touch = useTouch(); const touch = useTouch();
@ -292,6 +293,7 @@ export default defineComponent({
return ( return (
<div <div
ref={slider}
role="slider" role="slider"
class={getButtonClassName(index)} class={getButtonClassName(index)}
tabindex={props.disabled ? undefined : 0} tabindex={props.disabled ? undefined : 0}
@ -308,7 +310,6 @@ export default defineComponent({
} }
onTouchStart(event); onTouchStart(event);
}} }}
onTouchmove={onTouchMove}
onTouchend={onTouchEnd} onTouchend={onTouchEnd}
onTouchcancel={onTouchEnd} onTouchcancel={onTouchEnd}
onClick={stopPropagation} onClick={stopPropagation}
@ -322,6 +323,11 @@ export default defineComponent({
updateValue(props.modelValue); updateValue(props.modelValue);
useCustomFieldValue(() => props.modelValue); useCustomFieldValue(() => props.modelValue);
// useEventListener will set passive to `false` to eliminate the warning of Chrome
useEventListener('touchmove', onTouchMove, {
target: slider,
});
return () => ( return () => (
<div <div
ref={root} ref={root}

View File

@ -21,7 +21,7 @@ import {
} from '../utils'; } from '../utils';
// Composables // Composables
import { useRect, useClickAway } from '@vant/use'; import { useRect, useClickAway, useEventListener } from '@vant/use';
import { useTouch } from '../composables/use-touch'; import { useTouch } from '../composables/use-touch';
import { useExpose } from '../composables/use-expose'; import { useExpose } from '../composables/use-expose';
@ -209,6 +209,11 @@ export default defineComponent({
useClickAway(root, () => onClick('outside'), { eventName: 'touchstart' }); useClickAway(root, () => onClick('outside'), { eventName: 'touchstart' });
// useEventListener will set passive to `false` to eliminate the warning of Chrome
useEventListener('touchmove', onTouchMove, {
target: root,
});
return () => { return () => {
const wrapperStyle = { const wrapperStyle = {
transform: `translate3d(${state.offset}px, 0, 0)`, transform: `translate3d(${state.offset}px, 0, 0)`,
@ -221,7 +226,6 @@ export default defineComponent({
class={bem()} class={bem()}
onClick={getClickHandler('cell', lockClick)} onClick={getClickHandler('cell', lockClick)}
onTouchstartPassive={onTouchStart} onTouchstartPassive={onTouchStart}
onTouchmove={onTouchMove}
onTouchend={onTouchEnd} onTouchend={onTouchEnd}
onTouchcancel={onTouchEnd} onTouchcancel={onTouchEnd}
> >

View File

@ -28,7 +28,12 @@ import {
} from '../utils'; } from '../utils';
// Composables // Composables
import { doubleRaf, useChildren, usePageVisibility } from '@vant/use'; import {
doubleRaf,
useChildren,
useEventListener,
usePageVisibility,
} from '@vant/use';
import { useTouch } from '../composables/use-touch'; import { useTouch } from '../composables/use-touch';
import { useExpose } from '../composables/use-expose'; import { useExpose } from '../composables/use-expose';
import { onPopupReopen } from '../composables/on-popup-reopen'; import { onPopupReopen } from '../composables/on-popup-reopen';
@ -66,6 +71,7 @@ export default defineComponent({
setup(props, { emit, slots }) { setup(props, { emit, slots }) {
const root = ref<HTMLElement>(); const root = ref<HTMLElement>();
const track = ref<HTMLElement>();
const state = reactive<SwipeState>({ const state = reactive<SwipeState>({
rect: null, rect: null,
width: 0, width: 0,
@ -435,13 +441,18 @@ export default defineComponent({
onDeactivated(stopAutoplay); onDeactivated(stopAutoplay);
onBeforeUnmount(stopAutoplay); onBeforeUnmount(stopAutoplay);
// useEventListener will set passive to `false` to eliminate the warning of Chrome
useEventListener('touchmove', onTouchMove, {
target: track,
});
return () => ( return () => (
<div ref={root} class={bem()}> <div ref={root} class={bem()}>
<div <div
ref={track}
style={trackStyle.value} style={trackStyle.value}
class={bem('track', { vertical: props.vertical })} class={bem('track', { vertical: props.vertical })}
onTouchstartPassive={onTouchStart} onTouchstartPassive={onTouchStart}
onTouchmove={onTouchMove}
onTouchend={onTouchEnd} onTouchend={onTouchEnd}
onTouchcancel={onTouchEnd} onTouchcancel={onTouchEnd}
> >