如何在Laravel+Vue项目中正确加载tw-elements?
Laravel + Vue 3 集成 TW Elements 问题解决
问题概述
- 已通过npm安装tw-elements,在app.js中导入后,使用带
data-te-*属性的组件时无法正常渲染,无控制台报错 - 出现TypeScript类型警告:
No declaration file found for module 'tw-elements'. 'index.min.js' in 'c:/sites/ReservationSystem/node_modules/tw-elements/dist/js/' has an implicitly 'any' type.
解决步骤
1. 补全TW Elements资源引入
TW Elements需要同时引入CSS和JS资源,在app.js开头添加CSS导入:
import 'tw-elements/dist/css/tw-elements.min.css';
2. 正确初始化TW Elements
TW Elements不能直接通过Vue的use()方法注册,需要手动调用初始化方法,同时适配Inertia单页应用的页面切换场景:
修改app.js中的应用初始化部分,替换原有的.use(te),改为全局初始化+页面切换监听:
// 全局初始化TW Elements te.default.init(); // 监听Inertia页面切换完成事件,重新初始化组件 document.addEventListener('inertia:page:finish', () => { te.default.init(); });
3. 消除TypeScript类型警告
在项目根目录创建resources/js/types/tw-elements.d.ts文件,添加如下内容:
declare module 'tw-elements' { const te: any; export default te; }
然后在项目的tsconfig.json中更新include字段,确保类型文件被识别:
"include": [ "resources/js/**/*", "resources/js/types/**/*" ]
4. 页面组件内确保初始化
在使用TW Elements组件的Vue页面的mounted钩子中,再次调用初始化方法,确保当前页面的组件被正确渲染:
mounted() { te.default.init(); }
修改后完整代码
app.js
import './bootstrap'; import '../css/app.css'; // 导入TW Elements样式文件 import 'tw-elements/dist/css/tw-elements.min.css'; import { createApp, h } from 'vue'; import { createInertiaApp } from '@inertiajs/inertia-vue3'; import { InertiaProgress } from '@inertiajs/progress'; import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'; import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m'; import { autoAnimatePlugin } from '@formkit/auto-animate/vue'; import VueClickAway from "vue3-click-away"; import * as te from 'tw-elements'; const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel'; createInertiaApp({ title: (title) => `${title} - ${appName}`, resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')), setup({ el, app, props, plugin }) { const vueApp = createApp({ render: () => h(app, props) }) .use(plugin) .use(autoAnimatePlugin) .use(VueClickAway) .use(ZiggyVue, Ziggy) .mount(el); // 全局初始化TW Elements te.default.init(); // Inertia页面切换后重新初始化 document.addEventListener('inertia:page:finish', () => { te.default.init(); }); return vueApp; }, }); InertiaProgress.init({ color: '#4B5563' });
Vue页面组件
<template> <div class="flex justify-center"> <div class="mb-3 xl:w-96"> <select data-te-select-init data-te-select-filter="true"> <option value="1">One</option> <option value="2">Two</option> <option value="3">Three</option> </select> </div> </div> </template> <script> import AppLayout from "@/Layouts/AppLayout.vue"; import { defineComponent } from "vue"; import { directive } from "vue3-click-away"; import { Inertia } from "@inertiajs/inertia"; import JetInputError from "@/Components/InputError.vue"; import { Link } from "@inertiajs/inertia-vue3"; import { reactive } from "vue"; import { useAutoAnimate } from '@formkit/auto-animate/vue'; import * as te from 'tw-elements'; export default defineComponent({ directives: { ClickAway: directive }, props: { plans: Array, }, components: { AppLayout, JetInputError, Link, }, data() { return {} }, setup() { const form = reactive({}); function submit() { Inertia.post(route("reservas.store"), form, { onSuccess: () => { this.openForm = false; } }); } return { form, submit }; }, mounted() { // 初始化当前页面的TW Elements组件 te.default.init(); }, methods: { } }); </script>
内容的提问来源于stack exchange,提问作者Andrés Felipe
相关产品推荐
相关产品推荐

