简体   繁体   English

在相同的 Javascript 上下文中创建带有附加纤细组件的 window

[英]Create window with attached svelte component and in the same Javascript context

I use the Sapper framework and I want to open my own dev tools window that should have full access to Javascript objects of the main window.我使用 Sapper 框架,我想打开我自己的开发工具 window,它应该可以完全访问主 window 的 Javascript 对象。

I'm trying to create a new window with a svelte component and with same Javascript context:我正在尝试创建一个新的 window 与一个苗条的组件和相同的 Javascript 上下文:

var win = window.open('abour:blank')
var container = win.document.createElement('div')
var win.document.body.appendChild(container)
var component = new ComponentClass({
    target: container,
})

It works but without CSS styles.它可以工作,但没有 CSS styles。

You can use this REPL for tests.您可以使用此 REPL进行测试。

How can I apply the component CSS styles for the new window?如何为新的 window 应用组件 CSS styles?

Or what is the best practices to create such windows?或者创建这样的 windows 的最佳实践是什么?

I solved this problem by simply transferring all styles from the parent window (see the appendCss function)我通过简单地从父 window 转移所有 styles 解决了这个问题(参见appendCss函数)

If you use sapper you can transfer only these styles: link[rel="stylesheet"][href^="client/"]如果您使用工兵,您只能传输这些 styles: link[rel="stylesheet"][href^="client/"]

Full solution bellow and you can also see this REPL下面是完整的解决方案,您还可以看到这个 REPL

ComponentWindow.ts组件窗口.ts

export class ComponentWindow {
    constructor({
        windowName = '',
        windowFeatures = 'width=600,height=400,resizable,scrollbars=yes,status=1',
        replace = false,
    }: {
        windowName?: string,
        windowFeatures?: string,
        replace?: boolean,
    } = {}) {
        this._windowOptions = [ 'about:blank', windowName, windowFeatures, replace ]
    }

    // region create window

    private readonly _windowOptions: any[]
    private _window
    public get window() {
        if (!this.isOpened) {
            this._window = window.open(...this._windowOptions)
            this.appendCss()
            this.appendContainer()
        }
        return this._window
    }

    private appendCss() {
        const {window: _window} = this

        const parentStyleElements = Array.from(window.document.querySelectorAll(
            'link[rel="stylesheet"][href^="client/"], style',
        ))

        for (let i = 0; i < parentStyleElements.length; i++) {
            const parentStyleElement = parentStyleElements[i]
            let styleElement
            switch (parentStyleElement.tagName) {
                case 'LINK':
                    styleElement = _window.document.createElement('link')
                    styleElement.rel = 'stylesheet'
                    styleElement.href = (parentStyleElement as any).href
                    break
                case 'STYLE':
                    styleElement = _window.document.createElement('style')
                    styleElement.id = parentStyleElement.id
                    styleElement.innerHTML = parentStyleElement.innerHTML
                    break
                default:
                    throw new Error('Unexpected style element: ' + styleElement.tagName)
            }
            _window.document.head.appendChild(styleElement)
        }
    }

    private appendContainer() {
        const {window} = this
        window.container = window.document.createElement('div')
        window.document.body.appendChild(window.container)
    }

    // endregion

    // region attachComponent

    private _component
    public attachComponent(componentClass?, options?) {
        let {_component} = this
        if (_component) {
            _component.$destroy()
            this._component = _component = null
        }

        if (!componentClass) {
            return
        }

        const {window} = this
        _component = new componentClass({
            ...options,
            target: window.container,
        })
        this._component = _component

        window.addEventListener('beforeunload', () => {
            this.attachComponent()
        })

        return _component
    }

    // endregion

    public get isOpened() {
        return this._window && !this._window.closed
    }

    public focus() {
        if (this.isOpened) {
            this._window.focus()
        }
    }

    public destroy() {
        this.attachComponent()
        if (this.isOpened) {
            this._window.close()
            this._window = null
        }
    }
}

Usage:用法:

<script>
    import {ComponentWindow} from './ComponentWindow.js'
    import ComponentClass from './ComponentClass.svelte'
    import {onMount, onDestroy} from 'svelte'

    let componentWindow = new ComponentWindow()
    let component
    let value = 10

    onDestroy(() => componentWindow.destroy())

    $: if (component) component.$set({ value })

    async function openComponentWindow() {
        if (componentWindow.isOpened) {
            componentWindow.focus()
            return
        }

        component = await componentWindow.attachComponent(ComponentClass, {
            props: {
                value               
            }
        })

        componentWindow.focus()
    }
</script>

<button on:click="{openComponentWindow}">Open component Window</button><br>
<button on:click="{() => value++}">Change value</button>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Svelte:组件上下文 - Svelte: Component context 每次点击都创建苗条的组件 - Create svelte component on every click Svelte:如何将数据从 javascript 文件传递​​回 svelte 组件 - Svelte: How to pass data back to svelte component from javascript file 创建一个像svelte:head一样工作的全局svelte组件 - Create a global svelte-component that works like svelte:head 使用 rollup 将导入的 javascript 打包到 svelte 组件中 - Packaging imported javascript into svelte component using rollup 了解 Svelte/Sveltekit 中的存储、上下文、会话和组件层次结构 - Understanding stores, context, sessions, and component hierarchy in Svelte/Sveltekit 使用 JavaScript 创建的 Svelte 组件未收到响应式更新 - Svelte component created with JavaScript not receiving reactive updates 在 Svelte 中使用 web 组件时,如何解决组件在附加监听器之前发出事件的问题? - When using a web component in Svelte, how to solve the issue that the component emits events before listeners are attached to it? 我可以在延迟加载的 Svelte 组件中访问上下文吗? - Can I access context in lazily loaded Svelte component? 如何创建一个可以在 Svelte 中的所有页面中使用的上下文? - How to create a context that can be used in all pages in Svelte?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM