From 6995bcc8a385bd0d10739901c25e9d2c27f59a23 Mon Sep 17 00:00:00 2001
From: chenjiahan <chenjiahan@youzan.com>
Date: Mon, 6 Jul 2020 15:12:56 +0800
Subject: [PATCH] fix(Popup): teleport

---
 src-next/mixins/popup/index.js |  4 +--
 src-next/mixins/portal.js      | 47 ---------------------------
 src-next/popup/index.js        | 59 +++++++++++++++++++++++-----------
 3 files changed, 43 insertions(+), 67 deletions(-)
 delete mode 100644 src-next/mixins/portal.js

diff --git a/src-next/mixins/popup/index.js b/src-next/mixins/popup/index.js
index 436eb909d..b626fbbe8 100644
--- a/src-next/mixins/popup/index.js
+++ b/src-next/mixins/popup/index.js
@@ -8,7 +8,6 @@ import { getScroller } from '../../utils/dom/scroll';
 
 // Mixins
 import { TouchMixin } from '../touch';
-import { PortalMixin } from '../portal';
 import { CloseOnPopstateMixin } from '../close-on-popstate';
 
 export const popupMixinProps = {
@@ -20,6 +19,8 @@ export const popupMixinProps = {
   overlayStyle: Object,
   // overlay custom class name
   overlayClass: String,
+  // teleport
+  getContainer: [String, Function],
   // whether to close popup when click overlay
   closeOnClickOverlay: Boolean,
   // z-index
@@ -41,7 +42,6 @@ export function PopupMixin(options = {}) {
     mixins: [
       TouchMixin,
       CloseOnPopstateMixin,
-      PortalMixin({}),
     ],
 
     props: popupMixinProps,
diff --git a/src-next/mixins/portal.js b/src-next/mixins/portal.js
deleted file mode 100644
index 3ed88ef2d..000000000
--- a/src-next/mixins/portal.js
+++ /dev/null
@@ -1,47 +0,0 @@
-function getElement(selector) {
-  if (typeof selector === 'string') {
-    return document.querySelector(selector);
-  }
-
-  return selector();
-}
-
-export function PortalMixin({ ref, afterPortal }) {
-  return {
-    props: {
-      getContainer: [String, Function],
-    },
-
-    watch: {
-      getContainer: 'portal',
-    },
-
-    mounted() {
-      if (this.getContainer) {
-        this.portal();
-      }
-    },
-
-    methods: {
-      portal() {
-        const { getContainer } = this;
-        const el = ref ? this.$refs[ref] : this.$el;
-
-        let container;
-        if (getContainer) {
-          container = getElement(getContainer);
-        } else if (this.$parent) {
-          container = this.$parent.$el;
-        }
-
-        if (container && container !== el.parentNode) {
-          container.appendChild(el);
-        }
-
-        if (afterPortal) {
-          afterPortal.call(this);
-        }
-      },
-    },
-  };
-}
diff --git a/src-next/popup/index.js b/src-next/popup/index.js
index 23b900006..df2dfe120 100644
--- a/src-next/popup/index.js
+++ b/src-next/popup/index.js
@@ -1,5 +1,5 @@
-import { Transition } from 'vue';
-import { createNamespace, isDef } from '../utils';
+import { Teleport, Transition } from 'vue';
+import { createNamespace, isDef, isFunction } from '../utils';
 import { PopupMixin } from '../mixins/popup';
 import Icon from '../icon';
 import Overlay from '../overlay';
@@ -48,25 +48,28 @@ export default createComponent({
     this.onClosed = createEmitter('closed');
   },
 
-  render() {
-    const { round, position, duration } = this;
-    const isCenter = position === 'center';
+  methods: {
+    genOverlay() {
+      if (this.overlay) {
+        return <Overlay show={this.show} onClick={this.onClickOverlay} />;
+      }
+    },
 
-    const transitionName =
-      this.transition ||
-      (isCenter ? 'van-fade' : `van-popup-slide-${position}`);
+    genPopup() {
+      const { round, position, duration } = this;
+      const isCenter = position === 'center';
 
-    const style = {};
-    if (isDef(duration)) {
-      const key = isCenter ? 'animationDuration' : 'transitionDuration';
-      style[key] = `${duration}s`;
-    }
+      const transitionName =
+        this.transition ||
+        (isCenter ? 'van-fade' : `van-popup-slide-${position}`);
 
-    return (
-      <>
-        {this.overlay && (
-          <Overlay show={this.show} onClick={this.onClickOverlay} />
-        )}
+      const style = {};
+      if (isDef(duration)) {
+        const key = isCenter ? 'animationDuration' : 'transitionDuration';
+        style[key] = `${duration}s`;
+      }
+
+      return (
         <Transition
           name={transitionName}
           onAfterEnter={this.onOpened}
@@ -98,6 +101,26 @@ export default createComponent({
             </div>
           ) : null}
         </Transition>
+      );
+    },
+  },
+
+  render() {
+    const { getContainer } = this;
+    if (getContainer) {
+      const to = isFunction(getContainer) ? getContainer() : getContainer;
+      return (
+        <Teleport to={to}>
+          {this.genOverlay()}
+          {this.genPopup()}
+        </Teleport>
+      );
+    }
+
+    return (
+      <>
+        {this.genOverlay()}
+        {this.genPopup()}
       </>
     );
   },