import Vue, { PropType } from 'vue'; import { GetContainer } from './popup/type'; type PortalMixinOptions = { ref?: string; afterPortal?: () => void; }; function getElement(selector: string | GetContainer): Element | null { if (typeof selector === 'string') { return document.querySelector(selector); } return selector(); } export function PortalMixin({ ref, afterPortal }: PortalMixinOptions) { return Vue.extend({ props: { getContainer: [String, Function] as (PropType) }, watch: { getContainer: 'portal' }, mounted() { if (this.getContainer) { this.portal(); } }, methods: { portal() { const { getContainer } = this; const el = ref ? this.$refs[ref] as HTMLElement : 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); } } } }); }