如何给 Checkbox 添加自定义样式?
各位老铁大家好,又是一个风和日丽的日子,人生苦短,不能总是留恋美好的风景,亦要时时刻刻学习,所谓活到老学到老。今天我们一起来学习一下如何给 html 中的 ckeckbox 添加自定义样式。
如何在 html 中实现 checkbox?
其实,html 中根本没有checkbox这种控件,也就是说,你不能这样写:
今天我们一起来学习一下html中的label标签。
现实生活中,标签无处不在,比如我们在超市买东西时,商品上都会贴有标签,标签上会标明商品的名称、成分、型号、价格等信息。
Web世界中也有自己的标签,那就是label,它的作用是为控件提供一个说明。以如下登录界面为例,这里的Username和Password就是label,他们表明右侧的输入框分别要输入用户名和密码。label标签的作用就是为控件提供一个标题以说明这个控件的作用。

当然label标签不仅可以用于输入框(input),还可以用于下拉选择框(select),单选框(radio),复选框(checkbox)等控件。
html中使用select + option来完成下拉框的功能。
1 | <div style="padding: 16px; border-radius: 4px; border: 1px solid #ccc;"> |
渲染结果如下:
对于单选框(radio button),如果要实现互斥效果(多个radio button只能选择其中一个),必须给这些radio button设置相同的name,比如下面两个radio button的name都设置为gender。
1 | <div style="padding: 16px; border-radius: 4px; border: 1px solid #ccc;"> |
渲染结果如下:
html代码如下:
1 | <div style="padding: 16px; border-radius: 4px; border: 1px solid #ccc"> |
渲染结果如下:
为控件添加label标签主要有两种方式,一种是使用for/id的方式,另一种是使用嵌套的方式。
id属性。for属性,指定其值为控件的id属性值。下面的代码中,我们定义了一个文本框控件,设置其id属性值为username,并为它提供了一个label标签,设置其for属性的值为username。这样,label和控件就关联起来了。
1 | <label for="username">Username:</label> |
如果不想使用for/id的形式,那么可以直接用label标签包裹住对应的控件
1 | <label>Username: |
无论使用哪种形式,都可以调整label和控件的先后顺序。
这样写法渲染后label在前,输入框在后。
1 | <label for="subscribe">Subscribe to newsletter:</label> |
下面的写法渲染后输入框在前,label在后。
1 | <input type="checkbox" id="subscribe" name="subscribe"> |
嵌套方式也一样,这样写选然后输入框在前,label在后。
1 | <label> |
而下面这样写选然后label在前,输入框在后。
1 | <label>Subscribe to newsletter |
在实际编程中,对于input输入框来说,一般label在前面,控件在后面。而对于checkbox来说,一般是控件在前而label在后。
使用label标签有哪些好处呢?
username控件为例,即使用户点击label标签username,input控件也能获取焦点。在Web开发中,可替换元素是指如下一类元素:
这么说可能有点抽象,我们举一个例子,下面的html中通过img标签引入了一个图片:
1 | <img src="https://example.com/image.jpg" alt="Example Image"> |
在这个例子中,img元素就是一个可替换元素,因为它的内容(图片)来自于外部资源(src属性指定的URL)。
Html中的可替换元素有如下这些:
<img>:用于显示图像。<video>:用于显示视频。<iframe>:用于嵌入其他HTML文档。<embed>:用于嵌入外部内容,如PDF文件或Flash动画。<fencedframe>:用于嵌入其他HTML文档。以下这些tag在某些情况下也可能是可替换元素:
<audio>:用于显示音频。<canvas>:用于绘制图形。<object>:用于嵌入外部内容,如PDF文件或Flash动画。<input>:用于显示表单控件。(image input types only):before和:after伪元素。? instead of &&1 | const user = { |
这种方式确实简单很多,但是处理Unit Test可能会麻烦一些。
?? instead of ||1 | const name = user.name || 'Guest'; // old way |
XSS = Cross Site Scripting, 即跨站脚本攻击为了和CSS(层叠样式表)区分开来,所以叫XSS。这种攻击方式是黑客向目标站点注入恶意代码,当用户浏览网页对应的恶意代码就会执行以窃取用户的信息,最常见的就是cookie盗取。常见的XSS攻击有三种
存储型攻击如下图所示:
在软件开发届有一句名言:永远不要相信前端传递过来的数据,后端一定要对前端传入的数据进行验证,即使前端已经验证了,后端也要验证。只要这样,才能保证安全。
现在流行的前端框架都会对用户的输入进行转义,比如React或者Angular框架,如果用户输入<script>alert('hello')</script>,这个内容会被转义成<script>alert('hello')</script>,这样就可以正常渲染,而不会被浏览器执行了。
标记为HttpOnly的cookie,浏览器只能通过HTTP协议访问,而不能通过JavaScript访问,这样就可以防范XSS攻击。
CPS = Content Security Policy, 即内容安全策略,这是一种安全策略,可以防范XSS攻击。CPS是一个HTTP头部,可以告诉浏览器只能加载指定的资源,比如只能加载指定的域名下的资源,或者只能加载指定的类型的资源。这样就可以防范XSS攻击。
CPS只是众多防范XSS攻击方式的一种,还有其他方法可以方法XSS攻击,比如output encoding, sanitization等。
关于CSP的详细内容,请看这里。
CPS也不只用于防范XSS攻击,还可以防范其他攻击,比如:
XSRF = Cross Site Request Forgery, 即开展请求伪造。与XSS攻击方式不同,这种方式需要黑客自己有一个恶意站点,然后诱导用户点击恶意链接跳转到黑客的恶意站点,黑客再根据用户的cookie和其他信息伪造一个请求发送给用户访问的正常站点。
前端性能优化有很多方面,细节很多,最近面试也经常考到这个问题,现整理如下,以便日后查阅。
今天来看看在JavaScript中如何控制对象的可访问性。对象的可访问性控制在常规业务代码中都用的并不多,一般都是底层框架在用,不过了解一下总是没有坏处的。
使用Object.preventExtensions()方法可以将一个对象设置为不可扩展,不可扩展的对象不能添加新属性,但可以修改或者删除已有属性。
1 | "use strict"; // eslint-disable-line |
使用Object.seal()方法可以将一个对象密封,密封后的对象不能添加、删除属性,但可以修改属性的值。
1 | "use strict"; // eslint-disable-line |
使用Object.freeze()方法可以冻结一个对象,冻结后的对象不能添加、修改、删除属性,也不能修改属性的可枚举性、可配置性、可写性。
1 | 'use strict'; |
| 特性 | 不可扩展对象 (Object.preventExtensions) |
密封对象 (Object.seal) |
冻结对象 (Object.freeze) |
|---|---|---|---|
| 是否可新增属性 | ❌ | ❌ | ❌ |
| 是否可修改属性值 | ✅ | ✅ | ❌ |
| 是否可删除属性 | ✅ | ❌ | ❌ |
| 是否可更改原型链 | ✅ | ✅ | ❌ |
| 是否可更改可枚举性 | ✅ | ❌ | ❌ |
| 是否可更改可配置性 | ✅ | ❌ | ❌ |
| 是否可更改可写性 | ✅ | ✅ | ❌ |
今天我们来学习一下如何在JavaScript中实现原型继承,话不多说,直接上代码。
1 | // 父类的构造函数 |
今天在HackerRank上做Angular题目,偶然遇到一个循环固定次数的问题,这里记录一下。
假设需要在template里面循环count次,每次生成一个div,而count是后台api返回的一个变量,该如何实现呢?
我能想到的最简单的方法,就是定义一个含有count个元素的数组,然后使用ngFor遍历这个数组。
1 | export class AppComponent implements OnInit { |
然后使用ngFor遍历这个数组。这样会循环生成count个div元素。
1 | <ng-container *ngFor="let n of nums; let i = index"> |
1 | <div *ngFor="let i of [].constructor(count).keys()"> |
注意:该方法会导致一个错误:需要研究一下,为什么?
1 | core.mjs:6662 ERROR RuntimeError: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '[object Array Iterator]'. Current value: '[object Array Iterator]'. Expression location: _AppComponent component. Find more at |
使用时,需要在模块或者独立组件的imports中引入RepeatDirective,否则会报错。
1 | // 自定义指令代码 |
调用自定义指令
1 | <div *appRepeat="count; let i"> |
使用时,需要在模块或者独立组件的imports中引入RangePipe,否则会报错。
1 | import { Pipe, PipeTransform } from '@angular/core'; |
使用自定义管道
1 | <div *ngFor="let i of count | range"> |