You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Livewire wire:navigate时JS与@frostui/tailwind功能失效

Livewire wire:navigate无刷新跳转后FrostUI及自定义JS功能失效问题

使用Livewire的wire:navigate在侧边栏、顶部栏等区域实现无刷新页面跳转时,出现@frostui/tailwind CSS框架及自定义app.js中的功能失效问题。已尝试监听wire:navigate、wire:navigating、wire:navigated事件,以及使用wire:key属性,但均未解决,尤其@frostui/tailwind功能在跳转后无法再次触发。相关代码如下:

app.js代码

import "@frostui/tailwindcss"
import axios from 'axios';
import feather from 'feather-icons';

window.axios = axios;

import.meta.glob([
    "../images/**",
]);

class App {
    initComponents() {
        feather.replace()

        const myButton = document.querySelector('[data-toggle="back-to-top"]');

        if (myButton) {
            window.addEventListener('scroll', function () {
                if (window.pageYOffset > 72) {
                    myButton.classList.add('flex');
                    myButton.classList.remove('hidden');

                } else {
                    myButton.classList.remove('flex');
                    myButton.classList.add('hidden');

                }
            });

            myButton.addEventListener('click', function (e) {
                e.preventDefault();
                window.scrollTo({ top: 0, behavior: 'smooth' });
            });
        }
    }

    init() {
        this.initComponents();
    }
}

class ThemeCustomizer {

    constructor() {
        this.html = document.getElementsByTagName('html')[0]
        this.config = {};
        this.defaultConfig = window.config;
    }

    initConfig() {
        this.defaultConfig = JSON.parse(JSON.stringify(window.defaultConfig));
        this.config = JSON.parse(JSON.stringify(window.config));
        this.setSwitchFromConfig();
    }

    initSidenav() {
        let self = this;
        let pageUrl = window.location.href.split(/[?#]/)[0];
        document.querySelectorAll('ul.menu a.menu-link').forEach((element) => {
            if (element.href === pageUrl) {
                element.classList.add('active');
                let parentMenu = element.parentElement.parentElement.parentElement;
                if (parentMenu && parentMenu.classList.contains('menu-item')) {
                    const collapseElement = parentMenu.querySelector('[data-fc-type="collapse"]');
                    if (collapseElement && frost != null) {
                        const collapse = frost.Collapse.getInstanceOrCreate(collapseElement);
                        collapse.show();
                    }
                }
            }
        })

        setTimeout(function () {
            let activatedItem = document.querySelector('ul.menu .active');
            if (activatedItem != null) {
                let simpleBarContent = document.querySelector('.app-menu .simplebar-content-wrapper');
                let offset = activatedItem.offsetTop - 300;
                if (simpleBarContent && offset > 100) {
                    scrollTo(simpleBarContent, offset, 600);
                }
            }
        }, 200);

        // scrollTo (Sidenav Active Menu)
        function easeInOutQuad(t, b, c, d) {
            t /= d / 2;
            if (t < 1) return c / 2 * t * t + b;
            t--;
            return -c / 2 * (t * (t - 2) - 1) + b;
        }

        function scrollTo(element, to, duration) {
            let start = element.scrollTop, change = to - start, currentTime = 0, increment = 20;
            let animateScroll = function () {
                currentTime += increment;
                element.scrollTop = easeInOutQuad(currentTime, start, change, duration);
                if (currentTime < duration) {
                    setTimeout(animateScroll, increment);
                }
            };
            animateScroll();
        }
    }

    changeThemeMode(color) {
        this.config.theme = color;
        this.html.setAttribute('data-mode', color);
        this.setSwitchFromConfig();
    }

    changeTopbarColor(color) {
        this.config.topbar.color = color;
        this.html.setAttribute('data-topbar-color', color);
        this.setSwitchFromConfig();
    }

    changeMenuColor(color) {
        this.config.menu.color = color;
        this.html.setAttribute('data-menu-color', color);
        this.setSwitchFromConfig();
    }

    changeSidenavView(view, save = true) {
        this.html.setAttribute('data-sidenav-view', view);
        if (save) {
            this.config.sidenav.view = view;
            this.setSwitchFromConfig();
        }
    }
    initSwitchListener() {
        let self = this;

        document.querySelectorAll('input[name=data-mode]').forEach(function (element) {
            element.addEventListener('change', function (e) {
                self.changeThemeMode(element.value);
            })
        });

        document.querySelectorAll('input[name=data-topbar-color]').forEach(function (element) {
            element.addEventListener('change', function (e) {
                self.changeTopbarColor(element.value);
            })
        });

        document.querySelectorAll('input[name=data-menu-color]').forEach(function (element) {
            element.addEventListener('change', function (e) {
                self.changeMenuColor(element.value);
            })
        });

        document.querySelectorAll('input[name=data-sidenav-view]').forEach(function (element) {
            element.addEventListener('change', function (e) {
                self.changeSidenavView(element.value);
            })
        });

        // 明暗切换按钮
        let themeColorToggle = document.getElementById('light-dark-mode');
        if (themeColorToggle) {
            themeColorToggle.addEventListener('click', function (e) {

                if (self.config.theme === 'light') {
                    self.changeThemeMode('dark');
                } else {
                    self.changeThemeMode('light');
                }
            });
        }

        // 菜单切换按钮(位于顶部栏)
        let menuToggleBtn = document.querySelector('#button-toggle-menu');
        if (menuToggleBtn) {
            menuToggleBtn.addEventListener('click', function () {
                let configView = self.config.sidenav.view;
                let view = self.html.getAttribute('data-sidenav-view', configView);

                if (view === 'mobile') {
                    self.showBackdrop();
                    self.html.classList.toggle('sidenav-enable');
                } else {
                    if (configView == 'hidden') {
                        if (view === 'hidden') {
                            self.changeSidenavView(configView == 'hidden' ? 'default' : configView, false);
                        } else {
                            self.changeSidenavView('hidden', false);
                        }
                    } else {
                        if (view === 'sm') {
                            self.changeSidenavView(configView == 'sm' ? 'default' : configView, false);
                        } else {
                            self.changeSidenavView('sm', false);
                        }
                    }
                }
            });
        }

    }

    showBackdrop() {
        const backdrop = document.createElement('div');
        backdrop.id = 'backdrop';
        backdrop.classList = 'transition-all fixed inset-0 z-40 bg-gray-900 bg-opacity-50 dark:bg-opacity-80';
        document.body.appendChild(backdrop);

        if (document.getElementsByTagName('html')[0]) {
            document.body.style.overflow = "hidden";
            if (window.innerWidth > 1140) {
                document.body.style.paddingRight = "15px";
            }
        }

        const self = this
        backdrop.addEventListener('click', function (e) {
            self.html.classList.remove('sidenav-enable');
            self.hideBackdrop();
        })
    }

    hideBackdrop() {
        let backdrop = document.getElementById('backdrop');
        if (backdrop) {
            document.body.removeChild(backdrop);
            document.body.style.overflow = null;
            document.body.style.paddingRight = null;
        }
    }

    initWindowSize() {
        let self = this;
        window.addEventListener('resize', function (e) {
            self.adjustLayout();
        })
    }

    adjustLayout() {
        let self = this;

        if (window.innerWidth <= 1140) {
            self.changeSidenavView('mobile', false);
        } else {
            self.changeSidenavView(self.config.sidenav.view);
        }
    }

    setSwitchFromConfig() {
        sessionStorage.setItem('__CONFIG__', JSON.stringify(this.config));

        document.querySelectorAll('#theme-customization input[type=radio]').forEach(function (radio) {
            radio.checked = false;
        })

        let config = this.config;
        if (config) {
            let layoutModeSwitch = document.querySelector('input[type=radio][name=data-mode][value=' + config.theme + ']');
            let topbarColorSwitch = document.querySelector('input[type=radio][name=data-topbar-color][value=' + config.topbar.color + ']');
            let menuColorSwitch = document.querySelector('input[type=radio][name=data-menu-color][value=' + config.menu.color + ']');
            let sidenavViewSwitch = document.querySelector('input[type=radio][name=data-sidenav-view][value=' + config.sidenav.view + ']');

            if (layoutModeSwitch) layoutModeSwitch.checked = true;
            if (topbarColorSwitch) topbarColorSwitch.checked = true;
            if (menuColorSwitch) menuColorSwitch.checked = true;
            if (sidenavViewSwitch) sidenavViewSwitch.checked = true;
        }
    }

    init() {
        this.initConfig();
        this.initSidenav();
        this.initSwitchListener();
        this.initWindowSize();
        this.adjustLayout();
        this.setSwitchFromConfig();
    }
}

new App().init();
new ThemeCustomizer().init();

config.js代码

(function () {

    let savedConfig = sessionStorage.getItem("__CONFIG__");
    // let savedConfig = localStorage.getItem("__CONFIG__");

    let defaultConfig = {
        theme: "dark",
        topbar: {
            color: "dark",
        },
        menu: {
            color: "dark",
        },
        sidenav: {
            view: "default"
        },
    };

    const html = document.getElementsByTagName("html")[0];

    let config = Object.assign(JSON.parse(JSON.stringify(defaultConfig)), {});

    config.theme = html.getAttribute("data-mode") || defaultConfig.theme;
    config.topbar.color = html.getAttribute("data-topbar-color") || defaultConfig.topbar.color;
    config.menu.color = html.getAttribute("data-menu-color") || defaultConfig.menu.color;
    config.sidenav.view = html.getAttribute("data-sidenav-view") || defaultConfig.sidenav.view;

    window.defaultConfig = JSON.parse(JSON.stringify(config));

    if (savedConfig !== null) {
        config = JSON.parse(savedConfig);
        config.sidenav.view = html.getAttribute("data-sidenav-view") || defaultConfig.sidenav.view;
    }

    window.config = config;


    if (config) {
        html.setAttribute("data-mode", config.theme);
        html.setAttribute("data-topbar-color", config.topbar.color);
        html.setAttribute("data-menu-color", config.menu.color);

        if (window.innerWidth <= 1140) {
            html.setAttribute("data-sidenav-view", "mobile");
        } else {
            html.setAttribute("data-sidenav-view", config.sidenav.view);
        }
    }
})();

wire:navigate示例标签

<a wire:navigate class="flex items-center py-2 px-3 rounded-md text-sm text-gray-800 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-300" href="{{ route('profile.edit') }}">
    <i class="mgc_pic_2_line  me-2"></i>
    <span>@lang('Profile')</span>
</a>

包含Livewire组件的视图

<x-app-layout :title="__('Profile')">
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
            {{ __('Profile') }}
        </h2>
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
            <div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
                <div class="max-w-xl">
                    <livewire:admin.profile.update-profile-information />
                </div>
            </div>

            <div class="p-4 sm:p-8 bg-white dark:bg-gray-800 shadow sm:rounded-lg">
                <div class="max-w-xl">
                    <livewire:admin.profile.update-password />
                </div>
            </div>

        </div>
    </div>
</x-app-layout>

内容的提问来源于stack exchange,提问作者Nikola Main

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 05:47:03