9.4 Getters[35]
9.5 Actions[36]
9.6 Devtools[37]
10.基于 mitt 处理组件间事件联动[38]
10.1 为什么选择 mitt ?[39]
10.2 严重警告[40]
10.3 如何使用 mitt ?[41]
11.异步请求[42]
11.1 基于 axios 的封装[43]
11.2 为 axios 增加泛型的支持[44]
11.3 封装更方便的 useRequest[45]
11.4 统一的 API 接口管理[46]
11.5 mock[47]
12.路由[48]
12.1 创建路由三部曲[49]
12.2 使用 meta 丰富你的路由[50]
13.项目性能与细节优化[51]
13.1 开启 gzip[52]
13.2 页面载入进度条[53]
13.3 Title[54]
13.4 解决移动端使用 vh 的问题[55]
13.5 可以常驻的 JavaScript 库[56]
14.代码风格与流程规范[57]
14.1 ESLint[58]
14.2 StyleLint[59]
14.3 代码提交规范[60]
15.编写使用文档[61]
15.1 使用 vitepress 搭建文档[62]
15.2 文档部署[63]
16.插件[64]
16.1 VSCode 插件[65]
16.2 Chrome 插件[66]
源码[67]
参考[68]
1.搭建脚手架
使用 vue-cli
或 vite
,通过一系列的配置,初始化一个开发模板,无需从零开始搭建开发环境,可以有效的提升开发效率,相信也是大多数开发者接手一个新项目所使用的一种方式。尽管官方提供的脚手架已经足够优秀,但未必是真正符合我们自己团队的使用习惯,所以从官方的基础上,开发一款属于我们自己的脚手架,能更多的提升开发效率。
1.1 前端脚手架应具备哪些功能?
减少重复的初始化工作,不需要再复制其他类似的项目删除无关代码,或从零搭建一个项目。
可以根据团队需求,使用简单的交互操作生成相应的目录结构和文件。
统一团队的开发习惯、代码风格,保证构建结果的一致性。
完整的使用文档,降低新人上手、开发和后期维护成本。
1.2 如何开发一款自己的脚手架?
提到构建前端工程化中脚手架,相信大家已经看过不少文章,几年前我也曾经写过一篇关于脚手架构建的文章[69],随便搜一下关键词可以看到很多相关的文章,在这里不做太多的介绍,主要讲一些这些文章中很少提到的如何根据选项生成文件。
1.3 如何根据选项生成文件?
说实话我也不知道大佬们是怎么根据各种配置编译成相应的文件,这块希望大家踊跃发言,寻求一种更佳高效简洁的方式。在这里跟大家分享一下我的方案:
交互方面,搭建过脚手架的同学一定知道 inquirer[70],这个库可以很方便的通过交互式操作获取到我们选择的一些自定义配置参数。那么问题来了,如何通过这些配置相应的创建对应的文件呢?
这里我推荐使用 EJS[71] + Prettier[72] 生成代码,通过 fs-extra[73] 写入最终的文件。
EJS 是一款 JavaScript 模板引擎,我们可以通过传入参数,生成对应的代码串,例如创建一个 package.ejs
用来生成 package.json
中,如果我们选择使用了 scss
作为 CSS 预处理器,然后将 sass
和 stylelint-scss
作为项目的安装依赖:
<% if (precss === ‘scss’) { -%>
“sass”: “1.26.5”,
“stylelint-scss”: “^3.20.1”,
<% } -%>
复制代码
模板引擎可以帮你通过参数生成代码,它并不会限制你生成任何类型的代码文件,因为我们生成的是纯代码,最后通过读取 .ejs
文件对应生成相应的类型文件即可。
Prettier 是一款代码格式化工具,相信大家对它并不陌生。使用 EJS 生成的目的还是给开发人员阅读和编辑,所以生成的代码应该符合最终的格式要求,因为后续我们会为脚手架添加 ESLint 和 StyleLint 等工具,刚刚创建的项目里面一堆红线报错可是十分不友好的。
import prettier = require(“prettier”);
prettier.format(code, { parser: ‘json’ }))
复制代码
parser
是 prettier 的解析器,常见的 typescript、css、less、json 等文件都可以进行格式化。
2.基于 vite 的搭建基础模板
最早搭建 vue3 脚手架的时候,我选择的用 vue/cli 搭建,因为生态不健全,有些基于 webpack 的功能无法使用,但现在 vite 生态已经比较完善了,所以重构脚手架,由 webpack 转向 vite,这一步极大的提升了开发体验。
2.1 创建基本模板项目
npm init vite@latest
yarn create vite
pnpm create vite
复制代码
然后按照提示操作即可,vite 提供的选项很少,只有 vue 或 vue + ts,不像 vue/cli 提供那么多的配置方式,所以剩下的东西需要我们手动配置。
当然 vite 也提供了很多模板,但是我认为做加法比做减法更加容易,在众多的模板中很难找到适合我们自己的。
2.2 常用插件推荐
这里先简单了解几个好用的 vite 插件:
unplugin-vue-components[74]:组件的按需自动导入。
vite-plugin-svg-icons[75]:用于生成 svg 雪碧图。
vite-plugin-compression[76]:使用 gzip 或者 brotli 来压缩资源。
为什么只推荐这么几个插件?因为 vite
对许多 webpack
需要安装的 loader
或 plugin
都有着天生的支持,比如 less、sass、typescript,后续会在相应的章节说明用法。
3.使用 Typescript
vue2.x 版本对 TypeScript 的支持是硬伤 ,而 TypeScript 对大型项目的保障能力是被普遍认可的。这一点在 vue3.x 版本中得到了非常友好的支持。
Vite 天然支持引入 .ts
文件。
这里对 tsconfig.json 做了一些修改:
{
“compilerOptions”: {
“types”: [“vite/client”],
“baseUrl”: “src”,
“paths”: {
“@/“: [”./ ”]
}
},
“exclude”: [“node_modules”]
}
复制代码
在初期使用 typeScript 的时候,很多人都很喜欢使用 any 类型,把 typeScript 写成了 anyScript ,虽然使用起来很方便,但是这就失去了 typeScript 的类型检查意义了,当然写类型的习惯是需要慢慢去养成的,不用急于一时。
4.配置环境变量
vite 提供了两种模式:具有开发服务器的开发模式(development)和生产模式(production)。
这里我们可以建立 4 个 .env
文件,一个通用配置和三种环境:开发、测试、生产。
4.1 配置模式
NODE_ENV=development # 开发模式
NODE_ENV=production # 生产模式
复制代码
.env 通用配置,我个人喜欢把他当作项目的配置文件,例如项目的 title,此文件不对应任何模式。
.env.development 开发环境,使用 development 模式。
.env.staging 测试环境,因为要部署到测试服务器,或本地使用 serve 命令预览,所以使用 production 模式。
.env.production 生产环境,因为要部署到测试服务器,或本地使用 serve 命令预览,所以使用 production 模式。
package.json 内 script 需要增加 staging 命令
“script”: {
“build”: “vue-tsc --noEmit && vite build”,
“staging”: “vue-tsc --noEmit && vite build --mode staging”,
“serve”: “vite preview --host”
}
复制代码
4.2 常用的环境变量
推荐使用以下常见的三个变量:
接口请求地址。
通常后端会区分三种环境,部署在不同的地址下。
静态资源地址。
静态资源我是不建议你直接放在项目中,这会导致项目仓库变得巨大。
本地开发和测试环境我会选在使用本地搭建的静态资源服务器,你可以找后端运维的同学帮你搭建,或者你使用 http-server 在本地启动一个服务器也可以。生产环境建议上传至 OSS。
构建资源公共路径。
这个与 vue/cli 中的 publicPath 同理,有的时候你构建的项目并不是存放在跟路径下,例如 http://ip:port/{项目名}
。
4.3 封装静态资源文件
如果你配置了 VITE_APP_STATIC_URL 静态资源环境变量,那么你需要封装以下两个东西:
根据环境返回实际的资源地址函数。
方便使用的静态资源组件。
baseStaticUrl.ts
// 处理静态资源链接
export default function baseStaticUrl(src = ‘’) {
const { VITE_APP_STATIC_URL } = import.meta.env;
if (src) {
return ${VITE_APP_STATIC_URL}${src}
;
}
return VITE_APP_STATIC_URL as string;
}
复制代码
静态资源组件
静态资源主要有图片、音频和视频三种常见的形式。
复制代码
4.4 封装 SVG
的图标组件
svg 图标比较小,而且都是可读的 xml 文本,所以我们把它直接放在项目中即可,通过 vite-plugin-svg-icons
插件,实现自动引入 svg 图标。
配置 vite.config.ts:
plugins: [
viteSvgIcons({
iconDirs: [resolve(process.cwd(), ‘src/assets/icons’)],
symbolId: ‘icon-[dir]-[name]’,
}),
]
复制代码
封装一个 vue 组件:
复制代码
首先将下载的 .svg 图标放入 @/assets/icons 文件夹下
复制代码
5.按需自动引入组件
unplugin-vue-components[77] 是一款非常强大的插件(极力推荐),核心功能就是帮助你自动按需引入组件,Tree-shakable,只注册你使用的组件。这里说一下他的两个核心使用方式和配置方式。
此插件不仅支持 vue3,同时也支持 vue2,并且支持 Vite、Webpack、Vue CLI、Rollup。
5.1 安装与配置
安装:
npm i unplugin-vue-components -D
复制代码
配置:
// vite.config.ts
import Components from ‘unplugin-vue-components/vite’
export default defineConfig({
plugins: [
Components({ /* options */ }),
],
})
复制代码
这里的 options 可以配置一些选项,后面提到的组件库注册会使用到。
5.2 改变全局组件注册方式
我们通常将全局的组件封装在 @/src/components
中,然后通过 app.component()
注册全局组件。使用此插件后,无需手写注册,直接在模板中使用组件即可:
这里引入官方的示例:
复制代码
自动编译为:
复制代码
5.3 自动引入组件库
在使用组件库时,常规组件我们也会注册到全局,如果使用局部注册由于页面中会使用到多个组件,会非常麻烦,所以这个功能绝佳,例如我们使用 ant-design-vue 组件库。
直接在模板中使用即可,无需手动注册或局部引用:
按钮
复制代码
当然,你还需要在 vite 中引入它的解析器:
import Components from ‘unplugin-vue-components/vite’
import { AntDesignVueResolver } from ‘unplugin-vue-components/resolvers’
export default defineConfig({
plugins: [
Components({
resolvers: [
AntDesignVueResolver(),
]
})
],
})
复制代码
目前支持的解析器,根据你的喜好去选择:
Ant Design Vue[78]
Element Plus[79]
Element UI[80]
Headless UI[81]
IDux[82]
Naive UI[83]
Prime Vue[84]
Vant[85]
VEUI[86]
Varlet UI[87]
View UI[88]
Vuetify[89]
VueUse Components[90]
Quasar[91]
6.样式
项目中最好使用通用样式,可以创建 src/styles
目录存放,这里推荐一些分类:
styles
├── antd # 组件库样式覆盖,命名自取,这里以 ant design 为例
├── color.less # 颜色
├── index.less # 入口
├── global.less # 公共类
├── transition.less # 动画相关
└── variable.less # 变量
复制代码
6.1 预设基础样式
相信用过 normalize[92] 的同学不在少数,它可以重置 css 样式,使各浏览器效果保持一致。后面的章节会提到 tailwind.css,它内置了预设样式重置的功能,与 normalize 还是有一定的区别,有兴趣的同学可以了解一下[93]。
6.2 CSS 预处理器
虽然 vite 原生支持 less/sass/scss/stylus,但是你必须手动安装他们的预处理器依赖,例如:
npm install -D less
复制代码
如何选择预处理器?
推荐使用你是所使用的组件库的样式语言,因为 css 预处理器学会一种后,入手其他几乎没有学习成本。
6.3 开启 scoped
没有加 scoped 属性,会编译成全局样式,造成全局污染。
复制代码
6.4 深度选择器
有时我们可能想明确地制定一个针对子组件的规则。
如果你希望 scoped 样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 >>> 操作符。有些像 Sass 之类的预处理器无法正确解析 >>>。这种情况下你可以使用 /deep/ 或 ::v-deep 操作符取而代之——两者都是 >>> 的别名,同样可以正常工作。
7.布局
页面整体布局是一个产品最外层的框架结构,往往会包含导航、页脚、侧边栏等。在页面之中,也有很多区块的布局结构。在真实项目中,页面布局通常统领整个应用的界面,有非常重要的作用,所以单独拆分出来也是非常有必要的。
在脚手架中,所有的通用布局组件都应该放在 src/layouts 中,这种封装比较简单,这里就不贴代码了,大家按照自己实际情况自行发挥,在此仅提供一下封装思路。
7.1 常规的布局
BasicLayout
基础页面布局,包含了头部导航,侧边栏等。
BlankLayout
空白的布局。
7.2 特殊的布局
RouteLayout
如果你的项目在路由切换中需要对某些二级页面进行缓存,那么推荐你创建一个 RouteLayout,通过路由 meta
中的配置,返回 router-view
或者使用 keep-alive
包裹的 router-view
。
UserLayout
用于用户登录注册等页面抽离出来。
PageLayout
基础布局,包含了面包屑等信息,内含 slot。
8.集成 Tailwind.css
Tailwind.css[94] 在我第一次看到它的时候,内心是比较反感的,但实际上手之后又觉得真香。从 vue2 项目中,我已经引入了 tailwind,整体的开发结果就是,基本很少再使用 <style>
标签去转本定义一些 class 和样式,毕竟起名字这种事,一个是涉及到规范,一个是涉及到英语。如果你选择 tailwind,CSS 预处理器的作用就会显得微乎其微,因为你无需再自定定义各种变量和 mixins。
总体来说,学习成本并不高,花上两个小时足够上手,记住不用死记硬背那些类名。
8.1 效率提升
很多人总是说样式要与 HTML 分离,现在为什么又要提倡 tailwind 这种与 HTML 紧密结合的工具?这是因为现在使用 vue 这类框架已经高度组件化,样式分离是为了方便复用和维护,但在组件化面前样式分离只能是降低开发效率。
下面介绍一下 tailwind 提供了哪些提升效率的功能:
提供了大量的功能类,极大的提高了可维护性。
响应式设计,各种设备一把梭。
悬停、焦点和其它状态。
深色模式。
支持配置,例如颜色方面很难做到跟你的设计师统一。
不用为起名字而纠结???
8.2 JIT 模式
如果你的环境支持 postcss8( vue/cli 构建的 vue2 项目是 postcss7 ),那么 JIT 模式直接带你起飞。
超快的构建速度。
支持变体,你甚至可以这么写 sm:hover:active:disabled:opacity-75
。
支持任意样式,例如 md:top-[-113px]
。
开发和生产环境结果是一致的,(我在 vue2 项目中就遇到过组件库构建结果不一致的问题)。
如果你使用 vscode 那你一定要安装 Tailwind CSS IntelliSense[95] 插件,它可以自动补全类名,显著降低学习成本。
8.3 关于打包体积
使用默认配置,未压缩是 3739.4kB ,Gzip压缩 是 293.9kB,Brotli压缩 是 73.2kB。这似乎看起来很大,这是因为 tailwind 提供了成千上万的功能类,其中绝大部分你不会使用到。
当构建生产时,你应该使用 purge 选项来 tree-shake 优化未使用的样式,并优化您的最终构建大小当使用 Tailwind 删除未使用的样式时,很难最终得到超过 10kb 的压缩 CSS。
还有一点,Atom CSS
极大的提升了样式的复用程度,从而直接降低了构建体积。
9.vuex 替代方案 pinia
由于 vuex 4
对 typescript 的支持让人感到难过,所以状态管理弃用了 vuex 而采取了 pinia[96]。
忘记在哪看到,尤大好像说 pinia[97] 可能会代替 vuex,所以请放心使用。
9.1 为什么采用 Pinia ?
Pinia 的 API 设计非常接近 Vuex 5
的提案[98]。(作者是 Vue 核心团队成员)
无需像 Vuex 4
自定义复杂的类型来支持 typescript,天生具备完美的类型推断。
模块化设计,你引入的每一个 store 在打包时都可以自动拆分他们。
无嵌套结构,但你可以在任意的 store 之间交叉组合使用。
Pinia 与 Vue devtools 挂钩,不会影响 Vue 3 开发体验。
下面简单的介绍一下如何使用 Pinia,并对比 vuex 有哪些区别与注意事项,具体请参考官方文档[99]。
9.2 创建 Store
Pinia 已经内置在脚手架中,并且与 vue 已经做好了关联,你可以在任何位置创建一个 store:
import { defineStore } from ‘pinia’
export const useUserStore = defineStore({
id: ‘user’,
state: () =>({}),
getters: {},
actions: {}
})
复制代码
这与 Vuex 有很大不同,它是标准的 Javascript 模块导出,这种方式也让开发人员和你的 IDE 更加清楚 store 来自哪里。
Pinia 与 Vuex 的区别:
id 是必要的,它将所使用 store 连接到 devtools。
创建方式:new Vuex.Store(...)
(vuex3),createStore(...)
(vuex4)。
对比于 vuex3 ,state 现在是一个函数返回对象 。
没有 mutations ,不用担心,state 的变化依然记录在 devtools 中。
9.3 State
创建好 store 之后,可以在 state 中创建一些属性了:
state: () => ({ name: ‘codexu’, age: 18 })
复制代码
将 store 中的 state 属性设置为一个函数,该函数返回一个包含不同状态值的对象,这与我们在组件中定义数据的方式非常相似。
在模板中使用 store:
现在我们想从 store 中获取到 name 的状态,我们只需要使用以下的方式即可:
{{userStore.name}}
const userStore = useUserStore()
return { userStore }
复制代码
注意这里并不需要 userStore.state.name
。
虽然上面的写法很舒适,但是你一定不要用解构的方式去提取它内部的值,这样做的话,会失去它的响应式:
const { name, email } = useUserStore()
复制代码
9.4 Getters
Pinia 中的 getter 与 Vuex 中的 getter 、组件中的计算属性具有相同的功能,传统的函数声明使用 this 代替了 state 的传参方法,但箭头函数还是要使用函数的第一个参数来获取 state ,因为箭头函数处理 this 的作用范围:
getters: {
nameLength() {
return this.name.length
},
nameLength: state => state.name.length,
nameLength: ()=> this.name.length ❌
}
复制代码
9.5 Actions
这里与 Vuex 有极大的不同,Pinia 仅提供了一种方法来定义如何更改状态的规则,放弃 mutations 只依靠 Actions ,这是一项重大的改变。
Pinia 让 Actions 更加的灵活:
actions: {
async insertPost(data){
await doAjaxRequest(data);
this.name = ‘…’;
}
}
复制代码
9.6 Devtools
脚手架已内置下面的代码,这将添加 devtools 支持:
import { createPinia, PiniaPlugin } from ‘pinia’
Vue.use(PiniaPlugin)
const pinia = createPinia()
复制代码
时间旅行功能貌似已经可以使用了,这块后续会关注。
10.基于 mitt 处理组件间事件联动
如果你曾经是 Vue2.x 的开发者,那么请阅读下面引用官方文档[100]的一段话:
我们从实例中完全移除了 $on
、$off
和 $once
方法。$emit
仍然包含于现有的 API 中,因为它用于触发由父组件声明式添加的事件处理函数。
在 Vue 3 中,已经不可能使用这些 API 从组件内部监听组件自己发出的事件了,该用例暂没有迁移的方法。但是该 eventHub 模式可以被替换为实现了事件触发器接口的外部库,例如 mitt
或 tiny-emitter
。
10.1 为什么选择 mitt ?
足够小,仅有 200bytes。
支持全部事件的监听和批量移除。
无依赖,不论是什么框架都可以直接使用。
10.2 严重警告
我们已经无法在项目中使用 eventBus ,仅推荐你在特殊场合 下使用 mitt,它并不是开发的常态 ,你一定要确保知道自己在做什么?否则你的项目将难以维护!!!
10.3 如何使用 mitt ?
在使用 mitt 前建议请阅读官方文档[101]:
脚手架默认提供一个可以直接使用的对象:
import emitter from ‘@/libs/emitter’;
复制代码
当然你也可以引入已经安装好的 mitt:
import mitt from ‘mitt’
const emitter = mitt()
复制代码
mitt 提供了非常简单的 API,下面代码是官方演示:
// listen to an event
emitter.on(‘foo’, e => console.log(‘foo’, e) )
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
结尾
学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。
资料领取方式:戳这里免费获取
如果你曾经是 Vue2.x 的开发者,那么请阅读下面引用官方文档[100]的一段话:
我们从实例中完全移除了 $on
、$off
和 $once
方法。$emit
仍然包含于现有的 API 中,因为它用于触发由父组件声明式添加的事件处理函数。
在 Vue 3 中,已经不可能使用这些 API 从组件内部监听组件自己发出的事件了,该用例暂没有迁移的方法。但是该 eventHub 模式可以被替换为实现了事件触发器接口的外部库,例如 mitt
或 tiny-emitter
。
10.1 为什么选择 mitt ?
足够小,仅有 200bytes。
支持全部事件的监听和批量移除。
无依赖,不论是什么框架都可以直接使用。
10.2 严重警告
我们已经无法在项目中使用 eventBus ,仅推荐你在特殊场合 下使用 mitt,它并不是开发的常态 ,你一定要确保知道自己在做什么?否则你的项目将难以维护!!!
10.3 如何使用 mitt ?
在使用 mitt 前建议请阅读官方文档[101]:
脚手架默认提供一个可以直接使用的对象:
import emitter from ‘@/libs/emitter’;
复制代码
当然你也可以引入已经安装好的 mitt:
import mitt from ‘mitt’
const emitter = mitt()
复制代码
mitt 提供了非常简单的 API,下面代码是官方演示:
// listen to an event
emitter.on(‘foo’, e => console.log(‘foo’, e) )
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-SdsaRNGH-1713691864114)]
[外链图片转存中…(img-QhV81BfL-1713691864114)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
[外链图片转存中…(img-YYYGR8P5-1713691864115)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
[外链图片转存中…(img-UyQ5fFHP-1713691864115)]
结尾
学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。
资料领取方式:戳这里免费获取