如何给 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和控件的先后顺序,对于input输入框来说,一般label在前面,控件在后面。而对于checkbox来说,一般是控件在前而label在后,此时我们可以按如下方式书写html。
1 | <input type="checkbox" id="subscribe" name="subscribe"> |
或者
1 | <label> |
大多数表单控件都可以使用label标签,包括但不限于:
<input type='text'>
<input type='radio'>
<input type='checkbox'>
<select>
<textarea>
使用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"> |