08335 / hivui-platform-template
hivui平台项目模板
Newer
Older
hivui-platform-template / project / hivuiMain / components / tabpanel / panel.vue
<template>
    <div class="pl-tabs-panel" :title="title" :style="tabStyle">
        <div class="pl-loading pl-loading-fixed" v-show="url && !loaded" ref="dom-loader">
            <span></span>
            <span></span>
            <span></span>
            <span></span>
            <span></span>
        </div>
        <iframe v-if="hasUrl" ref="iframe" :name="'iframe' + name" @load="handleIframeLoad"></iframe>
        <slot v-else></slot>
    </div>
</template>

<script>
import { getUrlValue, setUrlValue } from "@main/utils";
import { getToken } from '@main/utils/auth'

export default {
    name: 'PTabpanel',
    props: {
        close: [String, Number, Boolean],
        itemData: Object,
        title: {
            type: String,
            default: ""
        },
        name: {
            type: [String, Number],
            default: ""
        },
        url: {
            type: String,
            default: ""
        },
        index: [String, Number]
    },
    data() {
        return {
            scrollTop: 0,
            loaded: false,
            hasUrl: !!this.url
        }
    },
    computed: {
        active() {
            return this.$parent.currentName === this.name
        },
        tabStyle() {
            return {
                position: "absolute",
                width: "100%",
                height: "100%",
                top: this.active ? 0 : "-200%",
                left: 0,
                opacity: this.active ? 1 : 0,
                visibility: this.active ? "visible" : "hidden",
            };
        }
    },
    watch: {
        active(val) {
            const iframe = this.getIframe();
            if (!iframe) return

            if (val) {
                // 面板激活,加载地址 + 恢复滚动位置
                this.setIframeSrc();
                this.$nextTick(() => {
                    this.restoreScrollTop();
                })
            } else {
                // 面板隐藏,保存当前滚动位置
                this.saveScrollTop();
            }
        }
    },
    updated() {
        this.$parent.$emit('tab-nav-update');
    },
    mounted() {
        if (this.active) {
            this.setIframeSrc();
        }
    },
    methods: {
        getIframe() {
            return this.$refs.iframe || null;
        },

        // 保存iframe滚动位置(增加异常捕获,跨域页面防止报错)
        saveScrollTop() {
            try {
                const iframe = this.getIframe();
                if (iframe && iframe.contentDocument) {
                    this.scrollTop = iframe.contentDocument.documentElement.scrollTop || 0;
                }
            } catch (e) {
                // 跨域iframe无法访问内部dom,直接忽略
            }
        },

        // 恢复滚动位置
        restoreScrollTop() {
            try {
                const iframe = this.getIframe();
                if (iframe && iframe.contentDocument) {
                    iframe.contentDocument.documentElement.scrollTop = this.scrollTop;
                }
            } catch (e) { }
        },

        // 设置iframe地址核心方法
        setIframeSrc() {
            const iframe = this.getIframe();
            if (!this.hasUrl || !iframe) return;

            // 地址为空不需要刷新
            if (this.url === 'about:blank') {
                this.loaded = true;
                return;
            }

            // ⭐关键:赋值src前强制开启loading
            this.loaded = false;
            if (iframe.src !== this.url) {
                iframe.setAttribute('src', this.url);
            } else {
                // src没有变化,不会触发load事件,手动关闭loading
                this.loaded = true;
            }
        },

        // 刷新当前iframe
        reload() {
            const iframe = this.getIframe();
            if (!iframe) return;

            this.loaded = false;
            try {
                const urlToken = getUrlValue(iframe.contentWindow.location.href, "access_token");
                const nowToken = getToken();
                // 原有false开关保留,按需开启
                if (false && !window._global && urlToken && nowToken && urlToken !== nowToken) {
                    iframe.contentWindow.location = setUrlValue(decodeURIComponent(iframe.contentWindow.location.href), "access_token", nowToken);
                } else {
                    iframe.contentWindow.location.reload();
                }
            } catch (e) {
                // 跨域页面reload捕获异常
                this.loaded = true;
            }
        },

        // iframe加载完成事件
        handleIframeLoad(evt) {
            const iframe = this.getIframe();
            if (!iframe) return;

            try {
                if (!this.title && iframe.contentWindow?.document.title) {
                    this.$emit("update:title", iframe.contentWindow.document.title);
                }
            } catch (e) { }

            this.loaded = true;

            this.$emit('onIframeLoad', this, evt);
        },
    }
}
</script>