资讯动态

Material Components for the Web(MDC Web)快速上手:从 CDN 到 npm + Webpack 的完整实践指南

发布时间:2026/9/21 17:59:41 来源:尧图企业网站定制
Material Components for the WebMDC Web快速上手从 CDN 到 npm Webpack 的完整实践指南【免费下载链接】material-components-webModular and customizable Material Design UI components for the web项目地址: https://gitcode.com/gh_mirrors/ma/material-components-webMaterial Components for the WebMDC Web是 Google 核心工程师与 UX 设计师团队开发的 Material Design 官方 Web 组件库旨在帮助开发者以可靠的开发流程构建美观、功能完整的 Web 项目。本文以仓库根目录 README.md 为主线系统讲解 MDC Web 的模块化架构、两种快速上手路径CDN 与 npm并深入 Webpack Sass ES2015 的完整构建配置、多种 JavaScript 导入方式与组件实例化技巧让你既能5 分钟跑起来也能在生产环境中按需定制。MDC Web 是什么模块化、可定制的 Material Design Web 组件库MDC Web 是 Material Design Lite 的说明可以看到它被特意设计为可适配多种主流 Web 框架的架构详见 docs/framework-wrappers.md。MDC Web 致力于无缝融入更广泛的适用场景从简单的静态网站到复杂的 JavaScript 重度应用再到混合的客户端/服务端渲染系统。无论你是否已经深度使用某个框架都能以轻量、惯用的方式将 Material Components 集成到你的站点中。适用场景一览静态站点 / 原型使用 CDN 引入预编译产物即可工程化项目通过 npm 安装并按需引入组件包配合 Sass 与 ES2015 模块参与构建框架集成底层采用 Foundation / Adapter 分层为 React、Angular 等框架封装提供了接口基础。维护状态提示重要根据仓库 README 的声明该项目已不再积极维护——虽然自动化更新可能仍会发生但团队不再优先规划新特性或缺陷修复且这些自动更新未来也会被关闭。在选择新项目技术栈时请结合这一现状评估本文面向的是希望使用或理解 MDC Web 既有能力的开发者。版本与发布节奏来自 README 的官方说明遵循 semver 语义化版本控制你可以控制何时引入破坏性变更典型的发布节奏为2 周一次每月包含一次带破坏性变更的 major 版本中间穿插带缺陷修复的 patch 版本当前仓库中 packages/material-components-web/package.json 记录的版本为14.0.0。核心架构包划分与 Foundation / Adapter 模式要理解 MDC Web 的模块化首先要看它的包结构。根据 docs/code/architecture.mdMDC Web 被拆分为多个包package每个包要么是子系统Subsystem要么是组件Component子系统被众多组件复用通常描述样式如颜色、主题或动效如动画。例如mdc-animation、mdc-theme、mdc-ripple、mdc-elevation、mdc-shape、mdc-typography等组件如mdc-button、mdc-textfield、mdc-dialog组件包往往依赖多个子系统包但组件之间很少互相依赖每个组件都可独立于其他组件单独使用这是模块化设计的基本原则。仓库根目录下packages/目录查看全部组件包正是这一设计的落地每个包自带 README、Sass 源文件、TypeScript 源文件与 package.json。三层技术栈Sass / HTML / JavaScript层MDC Web 的做法Sass所有 CSS 均由 Sass 生成。子系统通过 Sass mixin 暴露可复用的样式声明组组件在其 Sass 文件中导入这些 mixin最终每个包将自己的 Sass 文件编译为单个 CSS 文件HTMLMDC Web不提供任何 HTML 模板只通过文档给出组件所必需的 HTML 结构。这保证了它在任何框架、任何服务端渲染方案下都不抢走你的标记控制权JavaScript每个动态组件拆分为 Foundation 与 Adapter 两部分便于将业务逻辑复用到 React、Angular 等多种 Web 平台Foundation / Adapter / Vanilla Component 三层 JS 结构这是 MDC Web 最值得理解的设计。每个动态组件由三部分协作Foundation基础承载最能代表 Material Design 的业务逻辑完全不引用任何 DOM 元素。凡涉及 DOM 操作的逻辑都委托给 Adapter 方法完成。Adapter适配器一个接口声明 Foundation 实现业务逻辑所需的全部方法。因为可以存在多种 Adapter 实现所以组件能跨框架互操作。目前仓库只实现了原生 JavaScript 版本的 Adapter。Vanilla Component原生组件以一个根 Element 实例化通过覆写MDCComponent的getDefaultFoundation方法创建带 Vanilla Adapter 的 Foundation 实例Vanilla Adapter 实现 Adapter API 并直接引用根元素。组件同时对外暴露开发者需要访问的 Foundation 方法的代理。仓库中 packages/mdc-base/component.ts 给出了MDCComponent的骨架构造函数依次调用initialize(...args)、通过getDefaultFoundation()创建 Foundation 并执行this.foundation.init()再调用initialSyncWithDOM()完成与 DOM 的初始同步destroy()则委托给foundation.destroy()释放资源。而 packages/mdc-base/foundation.ts 中的MDCFoundation基类定义了cssClasses、strings、numbers、defaultAdapter四个静态钩子与init()/destroy()生命周期方法子类在此基础上实现具体业务逻辑。对只想消费 MDC Web而不是编写封装库的开发者而言只需要与Component交互不必直接访问 Foundation 或 Adapter 的 API。TypeScript 与发布产物MDC Web 组件使用 TypeScript 编写见 docs/code/architecture.md以提升开发效率并减少错误。npm 发布产物包括UMD JavaScript 包仅含 ES5 语法的 ES Module面向 TypeScript 用户的.d.ts类型声明文件。快速开始一CDN 一行引入零构建跑起来如果你想以最小的配置快速体验 MDC Web直接通过 CDN 加载预编译的一体化 CSS 与 JS 包即可以下代码来自仓库 README.md 的 Quick Start 示例以文本输入框组件为例!-- Required styles for Material Web -- link relstylesheet hrefhttps://unpkg.com/material-components-weblatest/dist/material-components-web.min.css !-- Render textfield component -- label classmdc-text-field mdc-text-field--filled span classmdc-text-field__ripple/span span classmdc-floating-label idmy-labelLabel/span input typetext classmdc-text-field__input aria-labelledbymy-label span classmdc-line-ripple/span /label !-- Required Material Web JavaScript library -- script srchttps://unpkg.com/material-components-weblatest/dist/material-components-web.min.js/script !-- Instantiate single textfield component rendered in the document -- script mdc.textField.MDCTextField.attachTo(document.querySelectorHTMLElement(.mdc-text-field)); /script几个要点CSS 与 JS 分离加载material-components-web.min.css提供全部组件样式material-components-web.min.js提供全部组件逻辑全局命名空间mdcUMD 产物将组件挂载在window.mdc下mdc.textField.MDCTextField即可取到文本输入框组件类attachTo静态方法这是MDCComponent提供的统一入口见 packages/mdc-base/component.ts子类覆写后即可用根元素一键实例化组件标记结构即文档结构mdc-text-field--filled是填充型变体mdc-text-field__ripple、mdc-floating-label、mdc-line-ripple分别是涟漪、浮动标签与底线波纹的必需子元素。快速开始二npm 安装单个组件以 textfield 为例工程化场景下更推荐按需安装单个组件包。以下是 README.md 中 NPM 快速开始部分的完整复现假设你已配置 webpack 将 Sass 编译为 CSS完整配置见下一节与 docs/getting-started.md。安装 textfield 模块npm install material/textfieldHTML文本输入框的标准标记更多选项见 packages/mdc-textfield 组件页label classmdc-text-field mdc-text-field--filled span classmdc-text-field__ripple/span input typetext classmdc-text-field__input aria-labelledbymy-label span classmdc-floating-label idmy-labelLabel/span span classmdc-line-ripple/span /labelCSS在 Sass 入口中引入组件所需样式并调用core-stylesuse material/floating-label/mdc-floating-label; use material/line-ripple/mdc-line-ripple; use material/notched-outline/mdc-notched-outline; use material/textfield; include textfield.core-styles;这里可以看到架构设计中子系统的体现textfield 依赖 floating-label浮动标签、line-ripple底线波纹、notched-outline缺口描边三个子系统各自以mdc-*入口文件的形式被单独引入。与 packages/mdc-textfield/README.md 中 Styles 一节的写法完全一致。JavaScript导入MDCTextField并实例化import {MDCTextField} from material/textfield; const textField new MDCTextField(document.querySelectorHTMLElement(.mdc-text-field));这会在页面中第一个.mdc-text-field元素上初始化文本输入框组件。从零搭建完整构建环境Webpack Sass ES2015上一节的 npm 用法依赖一个能编译 Sass 与 ES2015 的构建环境。仓库 docs/getting-started.md 给出了从零开始的完整五步流程这里完整继承并给出可直接复制的配置。Step 1Webpack 编译 Sass先执行npm init创建package.json并在scripts中添加启动命令{ scripts: { start: webpack serve } }安装以下开发依赖各司其职webpack打包 Sass 与 JavaScriptwebpack-dev-server开发服务器sass-loaderWebpack 中预处理 Sass 文件的 loadersassSass 编译器Dart Sasscss-loader解析 CSS 的import与url()路径extract-loader将 CSS 提取为.css文件file-loader将.css文件作为公共 URL 提供。npm install --save-dev webpack webpack-cli webpack-dev-server css-loader sass-loader sass extract-loader file-loader创建引用bundle.css的index.html!DOCTYPE html html head link relstylesheet hrefbundle.css /head bodyHello World/body /html创建app.scssbody { color: blue; }配置webpack.config.js将app.scss编译为bundle.cssmodule.exports [{ entry: ./app.scss, output: { // This is necessary for webpack to compile // But we never use style-bundle.js filename: style-bundle.js, }, module: { rules: [ { test: /\.scss$/, use: [ { loader: file-loader, options: { name: bundle.css, }, }, { loader: extract-loader }, { loader: css-loader }, { loader: sass-loader, options: { // Prefer Dart Sass implementation: require(sass), // See https://github.com/webpack-contrib/sass-loader/issues/804 webpackImporter: false, }, }, ] } ] }, }];运行npm start并打开 http://localhost:8080即可看到蓝色的 Hello World。Step 2接入组件样式与主题 mixin安装按钮组件npm install material/button用以下内容替换app.scss——它同时演示了 MDC Web 的主题定制能力通过 Sass mixin 覆写容器填充色use material/button/mdc-button; use material/button; .foo-button { include button.container-fill-color(darksalmon); }要让 sass-loader 理解material开头的导入需要为sass-loader配置includePaths: [./node_modules]{ loader: sass-loader, options: { // Prefer Dart Sass implementation: require(sass), // See https://github.com/webpack-contrib/sass-loader/issues/804 webpackImporter: false, sassOptions: { includePaths: [./node_modules] }, } }只要所有 MDC Web 包保持同步更新配置includePaths通常就足够了若因嵌套node_modules出现编译问题见文末附录的自定义 importer 方案。为了给 Sass 产物补充浏览器厂商前缀还需通过 PostCSS 接入autoprefixernpm install --save-dev autoprefixer postcss-loader在webpack.config.js顶部引入并在 loader 链中加入postcss-loaderconst autoprefixer require(autoprefixer);{ loader: extract-loader }, { loader: css-loader }, { loader: postcss-loader, options: { postcssOptions: { plugins: [ autoprefixer() ] } } }, { loader: sass-loader, options: { sassOptions: { includePaths: [./node_modules] }, // Prefer Dart Sass implementation: require(sass), // See https://github.com/webpack-contrib/sass-loader/issues/804 webpackImporter: false, } },material/button的必需 HTML 结构见 packages/mdc-button/README.md更新index.html加入按钮标记与foo-button类body button classfoo-button mdc-button div classmdc-button__ripple/div span classmdc-button__labelButton/span /button /body再次运行npm start打开 http://localhost:8080即可看到一个被darksalmon填充的 Material Design 按钮Step 3Webpack 编译 ES2015通过 Babel 将 ES2015 编译为标准 JavaScript安装依赖npm install --save-dev babel/core babel-loader babel/preset-env在index.html的/body前加入脚本引用script srcbundle.js async/script创建app.jsconsole.log(hello world);修改webpack.config.js三处将 entry 改为同时包含app.scss与app.jsentry: [./app.scss, ./app.js]将output.filename改为bundle.jsoutput: { filename: bundle.js, }在 rules 数组中追加babel-loader{ test: /\.js$/, loader: babel-loader, query: { presets: [babel/preset-env], }, }合并后的完整webpack.config.js如下可直接复制使用const autoprefixer require(autoprefixer); module.exports { entry: [./app.scss, ./app.js], output: { filename: bundle.js, }, module: { rules: [ { test: /\.scss$/, use: [ { loader: file-loader, options: { name: bundle.css, }, }, {loader: extract-loader}, {loader: css-loader}, { loader: postcss-loader, options: { postcssOptions: { plugins: [ autoprefixer() ] } } }, { loader: sass-loader, options: { // Prefer Dart Sass implementation: require(sass), // See https://github.com/webpack-contrib/sass-loader/issues/804 webpackImporter: false, sassOptions: { includePaths: [./node_modules], }, }, } ], }, { test: /\.js$/, loader: babel-loader, query: { presets: [babel/preset-env], }, } ], }, };再次npm start控制台应输出 hello world。Step 4接入组件 JavaScript以 ripple 为例安装涟漪组件npm install material/ripple在app.js中导入MDCRipple并初始化import {MDCRipple} from material/ripple/index; const ripple new MDCRipple(document.querySelectorHTMLElement(.foo-button));为什么要显式引用/index文档说明显式引用index是为了直接导入每个包内的 ES2015 源码从而支持 tree-shaking并避免公共依赖如 Ripple产生重复代码代价是你的构建工具链需要先转译这些 MDC Web 模块即 Step 3 中安装的 Babel 工具链。再次npm start按钮上就会出现 Material Design 的水波纹交互效果Step 5构建生产产物webpack-dev-server只适合开发预览不适合生产环境。在package.json中新增构建脚本scripts: { build: webpack, start: webpack serve }执行npm run build这会在项目目录下生成bundle.js与bundle.css——即编译后的 CSS 与转译后的 JS可直接复制到任意 Web 服务器托管的目录中。附录为嵌套 node_modules 配置 Sass importer如果安装了冲突版本的各 MDC Web 包可能出现嵌套的node_modules目录导致上面的includePaths方案失效Sass 只会在顶层node_modules中查找material包。此时可实现一个基于 Node 模块解析算法的自定义 importer在webpack.config.js顶部exports之前添加const path require(path); function tryResolve_(url, sourceFilename) { // Put require.resolve in a try/catch to avoid node-sass failing with cryptic libsass errors // when the importer throws try { return require.resolve(url, {paths: [path.dirname(sourceFilename)]}); } catch (e) { return ; } } function tryResolveScss(url, sourceFilename) { // Support omission of .scss and leading _ const normalizedUrl url.endsWith(.scss) ? url : ${url}.scss; return tryResolve_(normalizedUrl, sourceFilename) || tryResolve_(path.join(path.dirname(normalizedUrl), _${path.basename(normalizedUrl)}), sourceFilename); } function materialImporter(url, prev) { if (url.startsWith(material)) { const resolved tryResolveScss(url, prev); return {file: resolved || url}; } return {file: url}; }再将sass-loader配置更新为{ loader: sass-loader, options: { // Prefer Dart Sass implementation: require(sass), // See https://github.com/webpack-contrib/sass-loader/issues/804 webpackImporter: false, sassOptions: { importer: materialImporter, includePaths: [./node_modules], }, }, }该 importer 会从发起导入的文件所在目录开始按 Node 模块解析规则向上查找依赖从而找到离导入文件最近的material包。JavaScript 的多种导入方式与实例化技巧除了上文用到的 ES Module 导入MDC Web 还支持多种模块消费方式详见 docs/importing-js.md。每种方式的适用场景不同可按技术栈选择ES Modules推荐用于现代构建链import {MDCFoo, MDCFooFoundation} from material/foo;MDC Web 包的main字段指向dist下的预编译 UMD 模块以最大化兼容性——构建工具通常默认node_modules中的依赖已是 ES5 而跳过转译。如果你想利用 tree-shaking 与 MDC Web 内部的依赖共享来减小产物体积可以显式引用包的index.jsimport {MDCFoo, MDCFooFoundation} from material/foo/index;如果你的构建工具支持读取package.json的module字段指向仅含 ES5 语法的 ES Module使用 Webpack 或 Rollup 时无需写/index继续用简短的material/foo即可——但要确保工具链会像处理你自己的代码一样处理 MDC Web 的模块。CommonJSNode 环境const mdcFoo require(material/foo); const MDCFoo mdcFoo.MDCFoo; const MDCFooFoundation mdcFoo.MDCFooFoundation;AMDRequireJS 类加载器require([path/to/material/foo], mdcFoo { const MDCFoo mdcFoo.MDCFoo; const MDCFooFoundation mdcFoo.MDCFooFoundation; });Global / CDN浏览器直用const MDCFoo mdc.foo.MDCFoo; const MDCFooFoundation mdc.foo.MDCFooFoundation;TypeScript 类型支持若使用 TypeScriptMDC Web 包自带.d.ts文件。大多数情况下无需显式引用——编译器会通过package.json的types属性自动找到它们dist目录下的.d.ts对应 UMD 模块包内还有与每个 foundation/component/adapter 一一对应的.d.ts。需要说明的是发布包中刻意省略了.ts源文件因为.d.ts与转译后的.jsUMD 或 ES Module 格式已被广泛接受。一次实例化多个元素文档示例中常见的new MDCFoo(document.querySelector(.mdc-foo))只会命中页面中第一个匹配元素querySelector最多返回一个元素。要为多个元素同时实例化使用querySelectorAllconst foos [].map.call(document.querySelectorAll(.mdc-foo), function(el) { return new MDCFoo(el); });声明式初始化mdc-auto-init对于静态网站、原型等追求简单便捷的场景mdc-auto-init提供了一种基于 DOM 的声明式初始化方式见 packages/mdc-auto-init/README.md在组件根元素上添加data-mdc-auto-init属性并赋值为组件类名页面底部调用mdc.autoInit()即可label classmdc-text-field mdc-text-field--filled contenteditable="false">【免费下载链接】material-components-webModular and customizable Material Design UI components for the web项目地址: https://gitcode.com/gh_mirrors/ma/material-components-web创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价