feat(Popup): add destroy-on-close prop (#13223)

This commit is contained in:
inottn 2024-11-24 19:52:49 +08:00 committed by GitHub
parent b41f8cd14c
commit 6dc6b4b5ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 152 additions and 28 deletions

View File

@ -13,5 +13,6 @@ export function useLazyRender(show: WatchSource<boolean | undefined>) {
{ immediate: true },
);
return (render: () => JSX.Element) => () => (inited.value ? render() : null);
return (render: () => JSX.Element | undefined) => () =>
inited.value ? render() : null;
}

View File

@ -328,8 +328,9 @@ export default {
placeholder="Select city"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-popup v-model:show="showPicker" destroy-on-close position="bottom">
<van-picker
:model-value="pickerValue"
:columns="columns"
@confirm="onConfirm"
@cancel="showPicker = false"
@ -343,6 +344,7 @@ import { ref } from 'vue';
export default {
setup() {
const result = ref('');
const pickerValue = ref([]);
const showPicker = ref(false);
const columns = [
{ text: 'Delaware', value: 'Delaware' },
@ -352,13 +354,15 @@ export default {
{ text: 'Maine', value: 'Maine' },
];
const onConfirm = ({ selectedOptions }) => {
const onConfirm = ({ selectedValues, selectedOptions }) => {
result.value = selectedOptions[0]?.text;
pickerValue.value = selectedValues;
showPicker.value = false;
};
return {
result,
pickerValue,
columns,
onConfirm,
showPicker,
@ -379,8 +383,12 @@ export default {
placeholder="Select date"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-date-picker @confirm="onConfirm" @cancel="showPicker = false" />
<van-popup v-model:show="showPicker" destroy-on-close position="bottom">
<van-date-picker
:model-value="pickerValue"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
</van-popup>
```
@ -391,13 +399,16 @@ export default {
setup() {
const result = ref('');
const showPicker = ref(false);
const pickerValue = ref<string[]>([]);
const onConfirm = ({ selectedValues }) => {
result.value = selectedValues.join('/');
pickerValue.value = selectedValues;
showPicker.value = false;
};
return {
result,
pickerValue,
onConfirm,
showPicker,
};
@ -417,9 +428,10 @@ export default {
placeholder="Select area"
@click="showArea = true"
/>
<van-popup v-model:show="showArea" position="bottom">
<van-popup v-model:show="showArea" destroy-on-close position="bottom">
<van-area
:area-list="areaList"
:model-value="pickerValue"
@confirm="onConfirm"
@cancel="showArea = false"
/>
@ -434,7 +446,11 @@ export default {
setup() {
const result = ref('');
const showArea = ref(false);
const onConfirm = ({ selectedOptions }) => {
const pickerValue = ref('');
const onConfirm = ({ selectedValues, selectedOptions }) => {
pickerValue.value = selectedValues.length
? selectedValues[selectedValues.length - 1]
: '';
showArea.value = false;
result.value = selectedOptions.map((item) => item.text).join('/');
};
@ -442,6 +458,7 @@ export default {
return {
result,
areaList,
pickerValue,
showArea,
onConfirm,
};

View File

@ -354,9 +354,10 @@ export default {
placeholder="点击选择城市"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-popup v-model:show="showPicker" destroy-on-close position="bottom">
<van-picker
:columns="columns"
:model-value="pickerValue"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
@ -369,6 +370,7 @@ import { ref } from 'vue';
export default {
setup() {
const result = ref('');
const pickerValue = ref([]);
const showPicker = ref(false);
const columns = [
{ text: '杭州', value: 'Hangzhou' },
@ -378,13 +380,15 @@ export default {
{ text: '湖州', value: 'Huzhou' },
];
const onConfirm = ({ selectedOptions }) => {
const onConfirm = ({ selectedValues, selectedOptions }) => {
result.value = selectedOptions[0]?.text;
pickerValue.value = selectedValues;
showPicker.value = false;
};
return {
result,
pickerValue,
columns,
onConfirm,
showPicker,
@ -407,8 +411,12 @@ export default {
placeholder="点击选择时间"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" position="bottom">
<van-date-picker @confirm="onConfirm" @cancel="showPicker = false" />
<van-popup v-model:show="showPicker" destroy-on-close position="bottom">
<van-date-picker
:model-value="pickerValue"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
</van-popup>
```
@ -419,13 +427,16 @@ export default {
setup() {
const result = ref('');
const showPicker = ref(false);
const pickerValue = ref([]);
const onConfirm = ({ selectedValues }) => {
result.value = selectedValues.join('/');
pickerValue.value = selectedValues;
showPicker.value = false;
};
return {
result,
pickerValue,
onConfirm,
showPicker,
};
@ -447,9 +458,10 @@ export default {
placeholder="点击选择省市区"
@click="showArea = true"
/>
<van-popup v-model:show="showArea" position="bottom">
<van-popup v-model:show="showArea" destroy-on-close position="bottom">
<van-area
:area-list="areaList"
:model-value="pickerValue"
@confirm="onConfirm"
@cancel="showArea = false"
/>
@ -464,7 +476,11 @@ export default {
setup() {
const result = ref('');
const showArea = ref(false);
const onConfirm = ({ selectedOptions }) => {
const pickerValue = ref([]);
const onConfirm = ({ selectedValues, selectedOptions }) => {
pickerValue.value = selectedValues.length
? selectedValues[selectedValues.length - 1]
: '';
showArea.value = false;
result.value = selectedOptions.map((item) => item.text).join('/');
};
@ -472,6 +488,7 @@ export default {
return {
result,
areaList,
pickerValue,
showArea,
onConfirm,
};

View File

@ -22,10 +22,17 @@ const t = useTranslate({
});
const areaCode = ref('');
const pickerValue = ref('');
const showArea = ref(false);
const onConfirm = ({ selectedOptions }: PickerConfirmEventParams) => {
const onConfirm = ({
selectedValues,
selectedOptions,
}: PickerConfirmEventParams) => {
areaCode.value = selectedOptions.map((item) => item!.text).join('/');
pickerValue.value = selectedValues.length
? (selectedValues[selectedValues.length - 1] as string)
: '';
showArea.value = false;
};
@ -44,9 +51,16 @@ const onCancel = () => {
:placeholder="t('placeholder')"
@click="showArea = true"
/>
<van-popup v-model:show="showArea" round position="bottom" teleport="body">
<van-popup
v-model:show="showArea"
destroy-on-close
round
position="bottom"
teleport="body"
>
<van-area
:area-list="t('areaList')"
:model-value="pickerValue"
@confirm="onConfirm"
@cancel="onCancel"
/>

View File

@ -18,10 +18,12 @@ const t = useTranslate({
});
const result = ref('');
const pickerValue = ref<string[]>([]);
const showPicker = ref(false);
const onConfirm = ({ selectedValues }: PickerConfirmEventParams) => {
result.value = selectedValues.join('/');
pickerValue.value = selectedValues as string[];
showPicker.value = false;
};
@ -40,7 +42,17 @@ const onCancel = () => {
:placeholder="t('placeholder')"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" round position="bottom" teleport="body">
<van-date-picker @confirm="onConfirm" @cancel="onCancel" />
<van-popup
v-model:show="showPicker"
destroy-on-close
round
position="bottom"
teleport="body"
>
<van-date-picker
:model-value="pickerValue"
@confirm="onConfirm"
@cancel="onCancel"
/>
</van-popup>
</template>

View File

@ -21,10 +21,15 @@ const t = useTranslate({
});
const result = ref<Numeric>('');
const pickerValue = ref<Numeric[]>([]);
const showPicker = ref(false);
const onConfirm = ({ selectedOptions }: PickerConfirmEventParams) => {
const onConfirm = ({
selectedValues,
selectedOptions,
}: PickerConfirmEventParams) => {
result.value = selectedOptions[0]?.text || '';
pickerValue.value = selectedValues;
showPicker.value = false;
};
@ -43,8 +48,15 @@ const onCancel = () => {
:placeholder="t('placeholder')"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" round position="bottom" teleport="body">
<van-popup
v-model:show="showPicker"
destroy-on-close
round
position="bottom"
teleport="body"
>
<van-picker
:model-value="pickerValue"
:columns="t('textColumns')"
@confirm="onConfirm"
@cancel="onCancel"

View File

@ -71,8 +71,9 @@ export default {
placeholder="Choose City"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" round position="bottom">
<van-popup v-model:show="showPicker" destroy-on-close round position="bottom">
<van-picker
:model-value="pickerValue"
title="Title"
:columns="columns"
@cancel="showPicker = false"
@ -94,10 +95,12 @@ export default {
{ text: 'Maine', value: 'Maine' },
];
const fieldValue = ref('');
const pickerValue = ref<Numeric[]>([]);
const showPicker = ref(false);
const onConfirm = ({ selectedOptions }) => {
const onConfirm = ({ selectedValues, selectedOptions }) => {
showPicker.value = false;
pickerValue.value = selectedValues;
fieldValue.value = selectedOptions[0].text;
};

View File

@ -81,8 +81,9 @@ export default {
placeholder="选择城市"
@click="showPicker = true"
/>
<van-popup v-model:show="showPicker" round position="bottom">
<van-popup v-model:show="showPicker" destroy-on-close round position="bottom">
<van-picker
:model-value="pickerValue"
:columns="columns"
@cancel="showPicker = false"
@confirm="onConfirm"
@ -104,9 +105,10 @@ export default {
];
const fieldValue = ref('');
const showPicker = ref(false);
const onConfirm = ({ selectedOptions }) => {
const pickerValue = ref<Numeric[]>([]);
const onConfirm = ({ selectedValues, selectedOptions }) => {
showPicker.value = false;
pickerValue.value = selectedValues;
fieldValue.value = selectedOptions[0].text;
};

View File

@ -6,6 +6,7 @@ import VanPopup from '../../popup';
import { basicColumns } from './data';
import { useTranslate } from '../../../docs/site';
import type { PickerConfirmEventParams } from '../types';
import type { Numeric } from '../../utils';
const t = useTranslate({
'zh-CN': {
@ -24,6 +25,7 @@ const t = useTranslate({
const showPicker = ref(false);
const fieldValue = ref('');
const pickerValue = ref<Numeric[]>([]);
const onClickField = () => {
showPicker.value = true;
@ -31,8 +33,12 @@ const onClickField = () => {
const onCancel = () => {
showPicker.value = false;
};
const onConfirm = ({ selectedOptions }: PickerConfirmEventParams) => {
const onConfirm = ({
selectedValues,
selectedOptions,
}: PickerConfirmEventParams) => {
showPicker.value = false;
pickerValue.value = selectedValues;
fieldValue.value = selectedOptions[0]!.text as string;
};
</script>
@ -47,8 +53,14 @@ const onConfirm = ({ selectedOptions }: PickerConfirmEventParams) => {
:placeholder="t('chooseCity')"
@click="onClickField"
/>
<van-popup v-model:show="showPicker" round position="bottom">
<van-popup
v-model:show="showPicker"
destroy-on-close
round
position="bottom"
>
<van-picker
:model-value="pickerValue"
:title="t('title')"
:columns="t('basicColumns')"
@cancel="onCancel"

View File

@ -50,6 +50,7 @@ export const popupProps = extend({}, popupSharedProps, {
iconPrefix: String,
closeOnPopstate: Boolean,
closeIconPosition: makeStringProp<PopupCloseIconPosition>('top-right'),
destroyOnClose: Boolean,
safeAreaInsetTop: Boolean,
safeAreaInsetBottom: Boolean,
});
@ -186,11 +187,22 @@ export default defineComponent({
const onKeydown = (event: KeyboardEvent) => emit('keydown', event);
const renderPopup = lazyRender(() => {
const { round, position, safeAreaInsetTop, safeAreaInsetBottom } = props;
const {
destroyOnClose,
round,
position,
safeAreaInsetTop,
safeAreaInsetBottom,
show,
} = props;
if (!show && destroyOnClose) {
return;
}
return (
<div
v-show={props.show}
v-show={show}
ref={popupRef}
style={style.value}
role="dialog"

View File

@ -226,6 +226,7 @@ Use `teleport` prop to specify mount location.
| duration | Transition duration, unit second | _number \| string_ | `0.3` |
| z-index | Set the z-index to a fixed value | _number \| string_ | `2000+` |
| round | Whether to show round corner | _boolean_ | `false` |
| destroy-on-close `v4.9.10` | Whether to destroy content when closed | _boolean_ | `false` |
| lock-scroll | Whether to lock background scroll | _boolean_ | `true` |
| lazy-render | Whether to lazy render util appeared | _boolean_ | `true` |
| close-on-popstate | Whether to close when popstate | _boolean_ | `false` |

View File

@ -228,6 +228,7 @@ export default {
| duration | 动画时长,单位秒,设置为 0 可以禁用动画 | _number \| string_ | `0.3` |
| z-index | 将弹窗的 z-index 层级设置为一个固定值 | _number \| string_ | `2000+` |
| round | 是否显示圆角 | _boolean_ | `false` |
| destroy-on-close `v4.9.10` | 是否在关闭时销毁内容 | _boolean_ | `false` |
| lock-scroll | 是否锁定背景滚动 | _boolean_ | `true` |
| lazy-render | 是否在显示弹层时才渲染节点 | _boolean_ | `true` |
| close-on-popstate | 是否在页面回退时自动关闭 | _boolean_ | `false` |

View File

@ -283,3 +283,23 @@ test('should have safe-area-inset-bottom class when using safe-area-inset-bottom
'van-safe-area-bottom',
);
});
test('should destroy content when using destroyOnClose prop', async () => {
const wrapper = mount(Popup, {
props: {
show: false,
destroyOnClose: true,
},
slots: {
default: () => <div class="foo" />,
},
});
expect(wrapper.find('.foo').exists()).toBeFalsy();
await wrapper.setProps({ show: true });
expect(wrapper.find('.foo').exists()).toBeTruthy();
await wrapper.setProps({ show: false });
expect(wrapper.find('.foo').exists()).toBeFalsy();
});