如何在Angular项目中实现新版Materialize CSS?求最佳方案
我之前也碰到过和你一模一样的困扰——不想在Angular里混着用jQuery,但新版Materialize的JS功能又搞不定,找的教程还不全。分享下我亲测有效的纯Angular+无jQuery版Materialize集成方案:
第一步:安装新版Materialize CSS
先确保安装的是v1.0.0+版本的materialize-css,这个版本已经彻底移除了jQuery依赖:
npm install materialize-css@next --save
第二步:在Angular项目中全局配置
打开angular.json文件,在对应项目的styles和scripts数组中添加Materialize的资源路径:
"styles": [ "node_modules/materialize-css/dist/css/materialize.min.css", "src/styles.css" ], "scripts": [ "node_modules/materialize-css/dist/js/materialize.min.js" ]
第三步:封装Materialize JS组件为Angular指令
新版Materialize的JS基于原生DOM操作,我们可以自己写轻量的Angular指令来封装常用组件,既符合Angular开发模式,又能完整调用Materialize的交互功能。下面举几个高频组件的例子:
1. 下拉菜单(Dropdown)指令
创建dropdown.directive.ts文件:
import { Directive, ElementRef, OnInit } from '@angular/core'; declare var M: any; @Directive({ selector: '[appDropdown]' }) export class DropdownDirective implements OnInit { constructor(private el: ElementRef) {} ngOnInit() { M.Dropdown.init(this.el.nativeElement); } }
模板中使用方式:
<a class='dropdown-trigger btn' appDropdown href='#' data-target='dropdown1'>Drop Me!</a> <ul id='dropdown1' class='dropdown-content'> <li><a href="#!">First Option</a></li> <li><a href="#!">Second Option</a></li> </ul>
2. 模态框(Modal)指令
创建modal.directive.ts文件:
import { Directive, ElementRef, OnInit } from '@angular/core'; declare var M: any; @Directive({ selector: '[appModal]' }) export class ModalDirective implements OnInit { constructor(private el: ElementRef) {} ngOnInit() { M.Modal.init(this.el.nativeElement); } }
模板中使用方式:
<!-- 触发按钮 --> <a class="waves-effect waves-light btn" appModal href="#modal1">Open Modal</a> <!-- 模态框结构 --> <div id="modal1" class="modal"> <div class="modal-content"> <h4>Modal Header</h4> <p>Here's some modal content</p> </div> <div class="modal-footer"> <a href="#!" class="modal-close waves-effect waves-green btn-flat">Confirm</a> </div> </div>
3. 侧边栏(Sidenav)指令
创建sidenav.directive.ts文件:
import { Directive, ElementRef, OnInit } from '@angular/core'; declare var M: any; @Directive({ selector: '[appSidenav]' }) export class SidenavDirective implements OnInit { constructor(private el: ElementRef) {} ngOnInit() { M.Sidenav.init(this.el.nativeElement); } }
模板中使用方式:
<ul id="slide-out" class="sidenav"> <li><a href="#!">Home</a></li> <li><a href="#!">Profile</a></li> </ul> <a href="#" data-target="slide-out" appSidenav class="sidenav-trigger"><i class="material-icons">menu</i></a>
第四步:处理动态渲染的组件
如果组件是通过*ngIf或*ngFor动态生成的,直接在ngOnInit初始化会失效(因为DOM还未渲染完成)。这时候可以改用AfterViewInit配合延迟初始化:
import { Directive, ElementRef, AfterViewInit } from '@angular/core'; declare var M: any; @Directive({ selector: '[appDynamicDropdown]' }) export class DynamicDropdownDirective implements AfterViewInit { constructor(private el: ElementRef) {} ngAfterViewInit() { // 确保DOM渲染完成后初始化 setTimeout(() => { M.Dropdown.init(this.el.nativeElement); }, 0); } }
第五步:手动调用Materialize API
如果需要在组件中手动控制Materialize组件(比如主动打开/关闭模态框),可以通过ViewChild获取元素并调用实例方法:
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core'; declare var M: any; @Component({ selector: 'app-custom-modal', template: ` <button class="btn" (click)="openModal()">Open Dynamic Modal</button> <div #modalEl class="modal"> <div class="modal-content"> <h4>Dynamic Modal</h4> <p>This modal is controlled via Angular code</p> </div> </div> ` }) export class CustomModalComponent implements AfterViewInit { @ViewChild('modalEl') modalEl!: ElementRef; private modalInstance: any; ngAfterViewInit() { this.modalInstance = M.Modal.init(this.modalEl.nativeElement); } openModal() { this.modalInstance.open(); } }
关于封装库的说明
确实目前大部分旧的Materialize Angular封装都依赖jQuery,而新版的适配库要么不完善要么更新滞后。自己写指令其实非常轻量,完全可控,既符合Angular的组件化思想,又避免了不必要的依赖引入。
内容的提问来源于stack exchange,提问作者pb4now

