Angular 初学者快速上手教程

  • 2-3 模板
  • 2-4 组件间通讯
  • 2-5 生命周期钩子
  • 2-6 动效
  • 2-7 动态组件
  • 2-8 ShadowDOM
  • 2-9 内容投影
  • 2-10 @ContentChild@ContentChildren
  • 2-11 @ViewChild 与 @ViewChildren
  • 2-12 与 Polymer 封装组件的方式简单对比
  • 2-13 封装并发布你自己的组件库
  • 3-1 指令简介
  • 3-2 自定义指令
  • 3-3 直接在组件里面操作 DOM
  • 4 模块 @NgModule
  • 5-1 路由概述
  • 5-2 路由基本用法
  • 5-3 模块预加载
  • 5-4 路由守卫
  • 5-5 多重出口
  • 6-1 表单快速上手
  • 6-2 双向数据绑定
  • 6-3 表单校验
  • 6-4 模型驱动型表单
  • 6-5 动态表单
  • 7 服务
  • 8 RxJS 快速上手教程
  • 9 国际化
  • 10 自动化测试
  • 11 参考资源

本系列课程对应的所有示例项目列表:

  1. https://gitee.com/mumu-osc/learn-component
  2. https://gitee.com/mumu-osc/learn-directive
  3. https://gitee.com/mumu-osc/learn-router
  4. https://gitee.com/mumu-osc/learn-module
  5. https://gitee.com/mumu-osc/learn-form
  6. https://gitee.com/mumu-osc/learn-service
  7. https://gitee.com/mumu-osc/learn-test
  8. https://gitee.com/mumu-osc/learn-webpack
  9. https://github.com/damoqiongqiu/angular-seo

最后是那一句套话:水平有限,错漏难免,欢迎指正。可以在我的读者圈里跟我沟通交流。

第1课:搭建开发环境
NodeJS

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2009年,NodeJS 发布了第一个版本,标志着前端开发正式告别了刀耕火种的原始状态,开始进入工业化时代。

在 NodeJS 出现之前,前端开发领域有很多事情我们是做不到的,例如:

  • JS 代码的合并、压缩、混淆。
  • CSS 预处理。
  • 前端自动化测试。

而这一切在 NodeJS 出现之后都得到了很好的解决:

  • 对 JS 代码的预处理经历了 Grunt、Gulp 的短暂辉煌之后,终于在 webpack 这里形成了事实标准的局面。
  • CSS 的预处理也从 LESS 发展到了 SASS。
  • 自动化测试一直是前端开发中的一个巨大痛点,由于前端在运行时严重依赖浏览器环境,导致我们一直无法像测试后端代码那样可以去编写测试用例。在有了 NodeJS 之后,我们终于有了 Karma+Jasmine 这样的单元测试组合,也有了基于 WebDriverJS 这样的可以和浏览器进行通讯的集成测试神器。

就前端开发目前整体的状态来说,无论你使用什么框架,NodeJS、webpack、SASS、Karma+Jasmine、WebDriverJS 这个组合是无论如何绕不过去的。

@angular/cli

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在开发 Angular 应用的时候,当然也离不开大量基于 NodeJS 的工具,我们需要 TypeScript compiler、webpack、Karma、Jasmine、Protracter 等模块。

有相关经验的开发者都知道,自己从头开始去搭建一套基于 webpack 的开发环境是一件非常麻烦的事情。很多初学者在搭建环境这一步上面消耗了过多的精力,导致学习热情受到了沉重的打击。

当团队规模比较大的时候,在每个人的机器上配置环境需要消耗大量的时间。有一些团队为了避开这个坑,利用 Docker 来做开发环境的同步和版本升级,看起来也是一个非常不错的方案。

Angular 项目组从一开始就注意到了这个问题,所以有了 @angular/cli 这个神器,它的底层基于 webpack,集成了以上提到的所有 NodeJS 组件。你只要装好 @angular/cli 就够了,而不需要自己从头一步一步安装那些 NodeJS 插件。

当然,在安装 @angular/cli 之前你需要先把 NodeJS 安装好,请到官方网站下载安装包: https://nodejs.org/ ,安装过程和普通软件没有区别。装好 NodeJS 之后就可以安装 @angular/cli 了,由于 npm 会自动访问海外的服务器,所以强烈推荐使用 cnpm 进行安装:

npm i -g cnpm --registry=https://registry.npm.taobao.orgcnpm i -g @angular/cli

cnpm 是淘宝发布的一款工具,会自动把 npm 上面的所有包定时同步到国内的服务器上来,cnpm 本身也是一款 NodeJS 模块。

@angular/cli 安装成功之后你的终端里面将会多出一个名叫 ng 的命令,敲下 ng,将会显示完整的帮助文档:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建第一个项目

我们来创建第一个入门项目 HelloAngular,请在你的终端里面运行:

ng new HelloAngular

@angular/cli 将会自动帮你把目录结构创建好,并且会自动生成一些模板化的文件,就像这样:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请特别注意:@angular/cli 在自动生成好项目骨架之后,会立即自动使用 npm 来安装所依赖的 Node 模块,所以这里我们要 Ctrl+C 终止掉,然后自己进入项目的根目录,使用 cnpm 来进行安装。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

安装完成之后,使用 ng serve 命令启动项目:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

打开你的浏览器,访问默认的4200端口,看到以下界面说明环境 OK 了:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意:

  • 这里是 serve,不是 server,我看到一些初学者经常坑在这个地方。
  • 如果你需要修改端口号,可以用 ng serve --port ****来进行指定。
  • 如果你想让编译的包更小一些,可以使用 ng serve --prod,@angular/cli 会启用 TreeShaking 特性,加了参数之后编译的过程也会慢很多。所以,在正常的开发过程里面请不要加 --prod 参数。
  • ng serve 是在内存里面生成项目,如果你想看到项目编译之后的产物,请运行 ng build。构建最终产品版本可以加参数,ng build --prod。

ng 提供了很多非常好用的工具,除了可以利用 ng new 来自动创建项目骨架之外,它还可以帮助我们创建 Angular 里面所涉及到的很多模块,最常用的几个如下:

  • 自动创建组件:ng generate component MyComponent,可以简写成 ng g c MyComponent。创建组件的时候也可以带路径,比如:ng generate component mydir/MyComponent
  • 自动创建指令:ng g d MyDirective
  • 自动创建服务:ng g s MyService
  • 构建项目:ng build,如果你想构建最终的产品版本,可以用 ng build --prod

更多的命令和参数请在终端里面敲 ng 仔细查看,尽快熟悉这些工具可以非常显著地提升你的编码效率。

一些常见的坑

@angular/cli 这种“全家桶”式的设计带来了很大的方便,同时也有一些人不太喜欢,因为很多底层的东西被屏蔽掉了,开发者不能天马行空地自由发挥。比如:@angular/cli 把底层 webpack 的配置文件屏蔽掉了,很多喜欢自己手动配 webpack 的开发者就感到很不爽。

对于国内的开发者来说,上面这些其实不是最重要的,国内开发者碰到的坑主要是由两点引起的:

  1. 第一点是网络问题:比如 node-sass 这个模块你很有可能就装不上,原因你懂的。
  2. 第二点是开发环境导致的问题:国内使用 Windows 平台的开发者比例依然巨大,而 @angular/cli 在 Windows 平台上有一些非常恶心的依赖,比如它需要依赖 python 环境、Visual Studio 环境。

所以,如果你的开发平台是 Windows,请特别注意:

  1. 如果你知道如何给 npm 配置代理,也知道如何翻墙,请首选 npm 来安装 @angular/cli。
  2. 否则,请使用 cnpm 来安装 @angular/cli,原因有三:1、cnpm 的缓存服务器在国内,你装东西的速度会快很多;2、用 cnpm 可以帮你避开某些模块装不上的问题,因为它在服务器上面做了缓存;3、cnpm 还把一些包都预编译好了缓存在服务端,不需要把源码下载到你本地去编译,所以你的机器上可以没有那一大堆麻烦的环境。
  3. 如果安装失败,请手动把 node_modules 目录删掉重试一遍,全局的@angular/cli 也需要删掉重装,cnpm uninstall -g @angular/cli。
  4. 如果 node_modules 删不掉,爆出路径过长之类的错误,请尝试用一些文件粉碎机之类的工具强行删除。
  5. 最新版本的 @angular/cli 经常会有 bug,尤其是在 Windows 平台上面,所以请不要追新版本追太紧。如果你发现了莫名其妙的问题,请尝试降低一个主版本试试。这一点非常重要,很多初学者会非常困惑,代码什么都没改,就升级了一下环境,然后就各种编译报错。
  6. 对于 Mac 用户或者 *nix 用户,请特别注意权限问题,命令前面最好加上 sudo,保证有 root 权限。
  7. 无论你用什么开发环境,安装的过程中请仔细看 log。很多朋友没有看 log 的习惯,报错的时候直接懵掉,根本不知道发生了什么。
VS Code

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如你所知,一直以来,前端开发领域并没有一款特别好用的开发和调试工具。

  • WebStorm 很强大,但是吃资源很严重。
  • Sublime Text 插件很多,可惜要收费,而国内的企业还没有养成花钱购买开发工具的习惯。
  • Chrome 的开发者工具很好用,但是要直接调试 TypeScript 很麻烦。

所以,Visual Studio Code(简称 VS Code)才会呈现出爆炸性增长的趋势。它是微软开发的一款前端编辑器,完全开源免费。VS Code 底层是 Electron,界面本身是用 TypeScript 开发的。对于 Angular 开发者来说,当然要强烈推荐 VS Code。最值得一提的是,从1.14开始,可以直接在 VS Code 里面调试 TypeScript 代码。

第一步:环境配置
  • 确保你的 Chrome 安装在默认位置。
  • 确保你的 VS Code 里面安装了 Debugger for Chrome 这个插件。
  • 把 @angular/cli 安装到全局空间 npm install -g @angular/cli,国内用户请使用 cnpm 进行安装。注意,你最好升级到最新版本的 @angular/cli,避免版本兼容问题。
  • 用 @angular/cli 创建新项目 ng new my-app,本来就已经用 @angular/cli 创建的项目请忽略这一步,继续往下走,因为只要是 cli 创建的项目,后面的步骤都是有效的。
  • 用 VS Code 打开项目,进入项目根目录
第二步:配置 launch.json

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请参照以上步骤打开 launch.json 配置文件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请把你本地 launch.json 文件里面的内容改成这样:

{    "version": "0.2.0",    "configurations": [        {            "type": "chrome",            "request": "launch",            "name": "Chrome",            "url": "http://localhost:4200",            "webRoot": "${workspaceRoot}"        }    ]}
第三步:开始 Debug

在你的 app.component.ts 的构造函数里面打个断点,我本地是这样打断点的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

打开终端,进入项目根目录,运行 ng serve 启动项目,然后从 VS Code 的 debug 界面启动 Chrome

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意,你可能需要 F5 刷新一下 Chrome 才能进入断点!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

小结

目前,无论你使用什么前端框架,都必然要使用到各种 NodeJS 工具,Angular 也不例外。与其它框架不同,Angular 从一开始就走的“全家桶”式的设计思路,因此 @angular/cli 这款工具里面集成了日常开发需要使用的所有 Node 模块,使用 @angular/cli 可以大幅度降低搭建开发环境的难度。

第2-1课:组件:概述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

几乎所有前端框架都在玩“组件化”,而且最近都不约而同地选择了“标签化”这种思路,Angular 也不例外。

对新版本的 Angular 来说,一切都是围绕着“组件化”展开的,组件是 Angular 的核心概念模型。

以下是一个最简单的 Angular 组件定义:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • @Component:这是一个 Decorator(装饰器),其作用类似于 Java 里面的注解。Decorator 这个语言特性目前(2017-10)处于 Stage 2(草稿)状态,还不是 ECMA 的正式规范。
  • selector:组件的标签名,外部使用者可以这样来使用这个组件:。默认情况下,ng 命令生成出来的组件都会带上一个 app 前缀,如果你不喜欢,可以在 angular-cli.json 里面修改 prefix 配置项,设置为空字符串将会不带任何前缀。
  • templateUrl:引用外部的 HTML 模板。如果你想直接编写内联模板,可以使用 template,支持 ES6 引入的“模板字符串”写法
  • styleUrls:引用外部 CSS 样式文件,这是一个数组,也就意味着可以引用多份 CSS 文件。
  • export class AppComponent:这是 ES6 里面引入的模块和 class 定义方式。

本节完整的实例代码请参见这里

第2-2课:组件:把 CSS 预编译器改成 SASS

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

SASS 是一款非常好用的 CSS 预编译器,Bootstrap 官方从4.0开始已经切换到了 SASS。

目前(2017-10),@angular/cli 创建项目的时候没有自动使用 SASS 作为预编译器,我们需要自己手动修改一些配置文件,请按照以下步骤依次修改:

  • angular-cli.json 里面的 styles.css 后缀改成 .scss外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传当你后面再使用 ng g c *** 自动创建组件的时候,默认就会生成 .scss 后缀的样式文件了。
  • angular-cli.json 里面的 styleExt 改成 .scss外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  • src 下面 style.css 改成 style.scss外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  • app.component.scss外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  • app.component.ts 里面对应修改外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

改完之后,重新 ng serve,打开浏览器查看效果。

小结

本节完整的实例代码请参见这里

SASS 的 API 请参考官方网站

SASS 只是一个预编译器,它支持所有 CSS 原生语法。利用 SASS 可以提升你的 CSS 编码效率,增强 CSS 代码的可维护性,但是千万不要幻想从此就可以不用学习 CSS 基础知识了。

第2-3课:组件:模板

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

模板是编写 Angular 组件最重要的一环,你至少需要深入理解以下知识点才能玩转 Angular 模板:

  1. 对比各种 JS 模板引擎的设计思路
  2. Mustache(八字胡)语法
  3. 模板内的局部变量
  4. 属性绑定、事件绑定、双向绑定
  5. 在模板里面使用结构型指令 *ngIf、*ngFor、ngSwitch
  6. 在模板里面使用属性型指令 NgClass、NgStyle、NgModel
  7. 在模板里面使用管道格式化数据
对比各种 JS 模板引擎的设计思路

几乎每一款前端框架都会提供自己的模板语法,在 jQuery 如日中天的时代,有 Handlebars 那种功能超强的模板。最近有 React 推崇的 JSX 模板写法,当然还有 Angular 提供的那种与“指令”紧密结合的模板语法。

综合来说,无论是哪一种前端模板,大家都比较推崇“轻逻辑”( logic-less )的设计思路。

何为“轻逻辑”?

简而言之,所谓“轻逻辑”就是说,你不能在模板里面编写非常复杂的 JavaScript 表达式。比如,Angular 的模板语法就有规定:

  • 你不能在模板里面 new 对象
  • 不能使用=、+=、-=这类的表达式
  • 不能用++、–运算符
  • 不能使用位运算符
为什么要“轻逻辑”?

有一个非常重要的原因,比如你编写了以下 Angular 模板:

<ul>    <li *ngFor="let race of races">        {{race.name}}    </li></ul>

很明显,浏览器不认识 *ngFor 和 {{…}} 这种语法,所以必须在浏览器里面进行“编译”,获得对应的模板函数,然后再把数据传递给模板函数,最终结合起来获得一堆 HTML 标签,然后才能把这一堆标签插入到 DOM 树里面去。

如果启用了 AOT,处理的步骤有一些变化,@angular/cli 会对模板进行“静态编译”,避免在浏览器里面动态编译的过程。

而 Handlebars 这种模板引擎完全是运行时编译模板字符串的,你可以编写以下代码:

//定义模板字符串var source=`<ul>    {{#each races}}        <li>{{name}}</li>    {{/each}}</ul>`;//在运行时把模板字符串编译成JS函数var templateFn=Handlebars.compile(source);//把数据传给模板函数,获得最终的HTMLvar html=templateFn([    {name:'人族'},    {name:'神族'},    {name:'虫族'}]);

注意到 Handlebars.compile 这个调用了吧?这个地方的本质是在运行时把模板字符串“编译”成了一个 JS 函数。

鉴于 JS 解释执行的特性,你可能会担忧这里会有性能问题。这种担忧是合理的,但是 Handlebars 是一款非常优秀的模板引擎,它在内部做了各种优化和缓存处理。模板字符串一般只会在第一次被调用的时候编译一次,Handlebars 会把编译好的函数缓存起来,后面再次调用的时候会从缓存里面获取,而不会多次进行“编译”。

上面我们多次提到了“编译”这个词,所以很显然这里有一个东西是无法避免的,那就是我们必须提供一个 JS 版的“编译器”,让这个“编译器”运行在浏览器里面,这样才能在运行时把用户编写的模板字符串“编译”成模板函数。

有一些模板引擎会真的去用 JS 编写一款“编译器”出来,比如 Angular 和 Handlebars,它们都真的编写了一款 JS( TS )版的编译器。而有一些简单的模板引擎只是用正则表达式做了字符串替换而已,显得特别简陋。这种简陋的模板引擎对模板的写法有非常多的限制,因为它不是真正的编译器,能支持的语法特性非常有限。

所以,评估一款模板引擎的强弱,最核心的东西就是评估它的“编译器”做得怎么样。但是不管怎么说,毕竟是 JS 版的“编译器”,我们不可能把它做得像 g++ 那么强大,也没有必要做得那么强大,因为这个 JS 版的编译器需要在浏览器里面运行,搞得太复杂浏览器拖不动!

以上就是为什么大多数模板引擎都要强调“轻逻辑”的最根本原因。

对于 Angular 来说,强调“轻逻辑”还有另一个原因:在组件的整个生命周期里面,模板函数会被执行很多次。你可以想象, Angular 每次要刷新组件的外观的时候,都需要去调用一下模板函数,如果你在模板里面编写了非常复杂的代码,一定会增加渲染时间,用户一定会感到界面有“卡顿”。

人眼的视觉延迟大约是100ms到400ms之间,如果整个页面的渲染时间超过400ms,界面基本上就卡得没法用了。有一些做游戏的开发者会追求60fps刷新率的细腻感觉,60分之1秒约等于16.7ms,如果 UI 整体的渲染时间超过了16.7ms,就没法达到这个要求了。

轻逻辑( logic-less )带来了效率的提升,也带来了一些不方便,比如很多模板引擎都实现了 if 语句,但是没有实现 else,所以开发者们在编写复杂业务逻辑的时候模板代码会显得非常啰嗦。

目前来说,并没有完美的方案能同时兼顾运行效率和语法表现能力,这里只能取一个平衡。

Mustache 语法

Mustache 语法也就是你们说的双花括号语法{{…}},老外觉得它像八字胡子,很奇怪啊,难道老外喜欢侧着头看东西?

好消息是,很多模板引擎都接受了 Mustache 语法,这样一来学习量又降低了不少,开心吧?

关于 Mustache 语法,你需要掌握3点:

  1. 它可以获取到组件里面定义的属性值。
  2. 它可以自动计算简单的数学表达式,例如:加减乘除、取模。
  3. 它可以获得方法的返回值。

请依次看例子:

插值语法关键代码实例:

<h3>    欢迎来到{{title}}!</h3>
public title = '假的星际争霸2'; 

简单的数学表达式求值:

<h3>1+1={{1+1}}</h3>

调用组件里面定义的方法:

<h3>可以调用方法{{getVal()}}</h3>
public getVal():any{    return 65535;}
模板内的局部变量
<input #heroInput><p>{{heroInput.value}}</p>

有一些朋友会追问,如果我在模板里面定义的局部变量和组件内部的属性重名会怎么样呢?

如果真的出现了重名,Angular 会按照以下优先级来进行处理:

模板局部变量 > 指令中的同名变量 > 组件中的同名属性。

这种优先级规则和 JSP 里面的变量取值规则非常类似,对比一下很好理解对不对?你可以自己写代码测试一下。

属性绑定

属性绑定是用方括号来做的,写法:

<img [src]="imgSrc" />
public imgSrc:string="./assets/imgs/1.jpg";

很明显,这种绑定是单向的。

事件绑定

事件绑定是用圆括号来做的,写法:

<button class="btn btn-success" (click)="btnClick($event)">测试事件</button>

对应 Component 内部的方法定义:

public btnClick(event):void{    alert("测试事件绑定!");}
双向绑定

双向绑定是通过方括号里面套一个圆括号来做的,模板写法:

<font-resizer [(size)]="fontSizePx"></font-resizer>

对应组件内部的属性定义:

public fontSizePx:number=14;

AngularJS 是第一个把“双向数据绑定”这个特性带到前端来的框架,这也是 AngularJS 当年最受开发者追捧的特性,之一。

根据 AngularJS 团队当年讲的故事,“双向数据绑定”这个特性可以大幅度压缩前端代码的规模。大家可以回想一下 jQuery 时代的做法,如果要实现类似的效果,是不是要自己去编写大量的代码?尤其是那种大规模的表单,一大堆的赋值和取值操作,都是非常丑陋的“面条”代码,而有了“双向数据绑定”特性之后,一个绑定表达式就搞定。

目前,主流的几款前端框架都已经接受了“双向数据绑定”这个特性。

当然,也有一些人不喜欢“双向数据绑定”,还有人专门写了文章来进行批判,也算是前端一景。

在模板里面使用结构型指令

Angular 有3个内置的结构型指令:*ngIf、*ngFor、ngSwitch。ngSwitch 的语法比较啰嗦,使用频率小一些。

*ngIf 代码实例:

<p *ngIf="isShow" style="background-color:#ff3300">显示还是不显示?</p><button class="btn btn-success" (click)="toggleShow()">控制显示隐藏</button>
public isShow:boolean=true;public toggleShow():void{    this.isShow=!this.isShow;}

*ngFor 代码实例:

<li *ngFor="let race of races;let i=index;">    {{i+1}}-{{race.name}}</li>
public races:Array<any>=[    {name:"人族"},    {name:"虫族"},    {name:"神族"}];

*ngSwitch 代码实例:

<div [ngSwitch]="mapStatus">    <p *ngSwitchCase="0">下载中...</p>    <p *ngSwitchCase="1">正在读取...</p>    <p *ngSwitchDefault>系统繁忙...</p></div>
public mapStatus:number=1;

特别注意:一个 HTML 标签上只能同时使用一个结构型的指令。

因为“结构型”指令会修改 DOM 结构,如果在一个标签上使用多个结构型指令,大家都一起去修改 DOM 结构,到时候到底谁说了算?

那么需要在同一个 HTML 上使用多个结构型指令应该怎么办呢?有两个办法:

  • 加一层空的 div 标签
  • 加一层
在模板里面使用属性型指令

使用频率比较高的3个内置指令是:NgClass、NgStyle、NgModel。

NgClass 使用案例代码:

<div [ngClass]="currentClasses">同时批量设置多个样式</div><button class="btn btn-success" (click)="setCurrentClasses()">设置</button>
public currentClasses: {};public canSave: boolean = true;public isUnchanged: boolean = true;public isSpecial: boolean = true;setCurrentClasses() {    this.currentClasses = {        'saveable': this.canSave,        'modified': this.isUnchanged,        'special': this.isSpecial    };}

最后

前端CSS面试题文档,JavaScript面试题文档,Vue面试题文档,大厂面试题文档

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

lass]=“currentClasses”>同时批量设置多个样式<button class=“btn btn-success” (click)=“setCurrentClasses()”>设置



public currentClasses: {};public canSave: boolean = true;public isUnchanged: boolean = true;public isSpecial: boolean = true;setCurrentClasses() { this.currentClasses = { ‘saveable’: this.canSave, ‘modified’: this.isUnchanged, ‘special’: this.isSpecial };}




### 最后

**前端CSS面试题文档,JavaScript面试题文档,Vue面试题文档,大厂面试题文档**

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**

[外链图片转存中...(img-JqhFe1T6-1714250293249)]

[外链图片转存中...(img-LYrnN1PZ-1714250293250)]

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值