perf: portal

refactor-trigger
tangjinzhou 2021-08-15 09:46:32 +08:00
parent 448e912571
commit 44acf6139d
4 changed files with 33 additions and 42 deletions

View File

@ -1,48 +1,38 @@
import PropTypes from './vue-types'; import PropTypes from './vue-types';
import { defineComponent, nextTick, Teleport } from 'vue'; import {
defineComponent,
nextTick,
onBeforeUnmount,
onMounted,
onUpdated,
ref,
Teleport,
} from 'vue';
export default defineComponent({ export default defineComponent({
name: 'Portal', name: 'Portal',
inheritAttrs: false,
props: { props: {
getContainer: PropTypes.func.isRequired, getContainer: PropTypes.func.isRequired,
children: PropTypes.any.isRequired,
didUpdate: PropTypes.func, didUpdate: PropTypes.func,
}, },
data() { setup(props, { slots }) {
this._container = null; const container = ref();
return {}; onMounted(() => {
}, container.value = props.getContainer();
mounted() { });
this.createContainer(); onUpdated(() => {
},
updated() {
const { didUpdate } = this.$props;
if (didUpdate) {
nextTick(() => { nextTick(() => {
didUpdate(this.$props); props.nextTick?.(props);
}); });
});
onBeforeUnmount(() => {
if (container.value && container.value.parentNode) {
container.value.parentNode.removeChild(container.value);
} }
}, });
return () => {
beforeUnmount() { return container.value ? <Teleport to={container.value}>{slots.default?.()}</Teleport> : null;
this.removeContainer(); };
},
methods: {
createContainer() {
this._container = this.$props.getContainer();
this.$forceUpdate();
},
removeContainer() {
if (this._container && this._container.parentNode) {
this._container.parentNode.removeChild(this._container);
}
},
},
render() {
if (this._container) {
return <Teleport to={this._container}>{this.$props.children}</Teleport>;
}
return null;
}, },
}); });

View File

@ -20,7 +20,6 @@ export default defineComponent({
wrapperClassName: PropTypes.string, wrapperClassName: PropTypes.string,
forceRender: PropTypes.looseBool, forceRender: PropTypes.looseBool,
getContainer: PropTypes.any, getContainer: PropTypes.any,
children: PropTypes.func,
visible: PropTypes.looseBool, visible: PropTypes.looseBool,
}, },
data() { data() {
@ -130,7 +129,7 @@ export default defineComponent({
}, },
render() { render() {
const { children, forceRender, visible } = this.$props; const { forceRender, visible } = this.$props;
let portal = null; let portal = null;
const childProps = { const childProps = {
getOpenCount: () => openCount, getOpenCount: () => openCount,
@ -141,8 +140,8 @@ export default defineComponent({
portal = ( portal = (
<Portal <Portal
getContainer={this.getDomContainer} getContainer={this.getDomContainer}
children={children(childProps)}
ref={this.savePortal} ref={this.savePortal}
v-slots={{ default: () => this.$slots.default?.(childProps) }}
></Portal> ></Portal>
); );
} }

View File

@ -35,9 +35,11 @@ const DialogWrap = defineComponent({
visible={visible} visible={visible}
forceRender={forceRender} forceRender={forceRender}
getContainer={getContainer} getContainer={getContainer}
children={childProps => { v-slots={{
default: childProps => {
dialogProps = { ...dialogProps, ...childProps }; dialogProps = { ...dialogProps, ...childProps };
return <Dialog {...dialogProps}>{getSlot(this)}</Dialog>; return <Dialog {...dialogProps}>{getSlot(this)}</Dialog>;
},
}} }}
/> />
); );

View File

@ -717,7 +717,7 @@ export default defineComponent({
portal = ( portal = (
<Portal <Portal
key="portal" key="portal"
children={this.getComponent()} v-slots={{ default: this.getComponent }}
getContainer={this.getContainer} getContainer={this.getContainer}
didUpdate={this.handlePortalUpdate} didUpdate={this.handlePortalUpdate}
></Portal> ></Portal>