【J客时间——C学前端 】笔记

1、利用Promise封装setTimeout
    function sleep(duration) {
        return new Promise(function(resolve, reject) {
            console.log("b");
            setTimeout(resolve,duration);
        })
    }
    console.log("a");
    sleep(5000).then(()=>console.log("c"));
2、利用async和await
function sleep(duration) {
    return new Promise(function(resolve, reject) {
        setTimeout(resolve,duration);
    })
}
async function foo(){
    console.log("a")
    await sleep(2000).then(()=>console.log("b"))
    console.log("c")
}
foo()
function sleep(duration) {
    return new Promise(function(resolve, reject) {
        setTimeout(resolve,duration);
    })
}
async function foo(name){
    await sleep(2000)
    console.log(name)
}
async function foo2(){
    await foo("a");
    await foo("b");
}
foo2()	// 每两秒输出 a, b
// 应避免使用generator/iterator实现异步
	const _this = this
    let iterator = generator()
    async function init() {
      // console.log(await initData(this, "中国", false))
      _this.$store.commit("setChinaValue", await initData(_this, "中国"))
      iterator.next()	// 进下一个yield
    }
    function* generator() {
      yield init()
      yield _this.isLoading = false
    }
    iterator.next()
3、立即执行函数的代替
// 可以避免()前不加分号 导致上一行的函数执行
void function(){
    var a;
    console.log(a,1111111)
    //code
}();
4、改变this
// 注意: 箭头、class 不接受 this 的函数类型。使用call、apply、bind无效,但不报错
function foo(a, b, c){
    console.log(this);
    console.log(a, b, c);
}
foo.call({}, 1, 2, 3);	// 函数.call, 改变函数内的this指向 参数对象;同时会传参,执行函数
foo.apply({}, [1, 2, 3]);

foo.bind({}, 1, 2, 3)();	// bind不会执行函数,需要自己执行
5、try return finally
// Completion Record
function foo(){
  try{
    return 0;	
  } catch(err) {

  } finally {	// finally 先执行, 如果在这里return,会覆盖try中的return
    console.log("a")
  }
}

console.log(foo());	//  a  0

// Completion Record 表示一个语句执行完之后的结果,它有三个字段:
// - [[type]] 表示完成的类型,有 break continue return throw 和 normal 几种类型;
// - [[value]] 表示语句的返回值,如果语句没有,则是 empty;** Chrome显示的就是它 **
// - [[target]] 表示语句的目标,通常是一个 JavaScript 标签

// 利用Completion Record 的target,可以用于声明语句 跳出多层循环
    outer: while(true) {
      inner: while(true) {
          break outer;
      }
    }
    console.log("finished")
6、异步的 for of
// for..of 用于可迭代对象,如Array、Set等,也包括generator
// 如下 异步生成器函数配备了异步的 for of


function sleep(duration) {
    return new Promise(function(resolve, reject) {
        setTimeout(resolve,duration);
    })
}
async function* foo(){	// 异步生成器函数每隔一秒生成一个数字
    i = 0;
    while(true) {
        await sleep(1000);
        yield i++;
    }
        
}
for await(let e of foo())	// 使用 for await of 来访问这个异步生成器函数的结果
    console.log(e);			// 形成了一个每隔一秒打印一个数字的无限循环
7、try 配合 throw
// try 部分用于标识捕获异常的代码段
// catch 部分则用于捕获异常后做一些处理
// finally 则是用于执行后做一些必须执行的清理工作。
try {
    throw new Error("error");
} catch(e) {
    console.log(e);
} finally {
    console.log("finally");
}

8、html语义化标签
// em 斜体, 表示重音,与strong不同
今天我吃了一个<em>苹果</em>。
今天我吃了<em>一个</em>苹果。

// ruby rt rp 这是汉字 上面加注释
<ruby><rt>zhe</rt><rt>shi</rt><rt>han</rt><rt>zi</rt>
</ruby>

// p标签是block的*

// 典型组织结构
<body>
    <header>
        <nav>
            ……
        </nav>
    </header>
    <aside>
        <nav>
            ……
        </nav>
    </aside>
    <section>……</section>
    <section>……</section>
    <section>……</section>
    <footer>
        <address>……</address>
    </footer>
</body>

// 多文章结构
<body>
    <header>……</header>
    <article>
        <header>……</header>
        <section>……</section>
        <section>……</section>
        <section>……</section>
        <footer>……</footer>
    </article>
    <article>
        ……
    </article>
    <article>
        ……
    </article>
    <footer>
        <address></address>
    </footer>
</body>
9、css的 at 规则(即高级用法)
// charset 用于提示 CSS 文件使用的字符编码方式,必须出现在最前面
@charset "utf-8";

// import 用于引入一个 CSS 文件
@import "mystyle.css";
@import url("mystyle.css");

// media 就是大名鼎鼎的 media query 使用的规则了,它能够对设备的类型进行一些判断
@media print {
    body { font-size: 10pt }
}

// page 用于分页媒体访问网页时的表现设置,设置周围的结构
@page {
  size: 8.5in 11in;
  margin: 10%;

  @top-left {
    content: "Hamlet";
  }
  @top-right {
    content: "Page " counter(page);
  }
}

// counter-style 产生一种数据,用于定义列表项的表现。
@counter-style triangle {
  system: cyclic;
  symbols:;
  suffix: " ";
}

// keyframes 产生一种数据,用于定义动画关键帧
@keyframes diagonal-slide {
  from {
    left: 0;
    top: 0;
  }

  to {
    left: 100px;
    top: 100px;
  }
}

// fontface 用于定义一种字体,icon font 技术就是利用这个特性来实现的。
@font-face {
  font-family: Gentium;
  src: url(http://example.com/fonts/Gentium.woff);
}

p { font-family: Gentium, serif; }

// @support 检查环境的特性,它与 media 比较类似。
// @namespace 用于跟 XML 命名空间配合的一个规则,表示内部的 CSS 选择器全都带上特定命名空间。
// @viewport 用于设置视口的一些特性,不过兼容性目前不是很好,多数时候被 HTML 的 meta 代替

除去 at 规则 就是 qualified 规则(普通规则),由 选择器 和 声明列表 组成

  • 选择器:标签,id、class、属性和伪类
  • 选择器连接符号:空格、>、+、~、||
  • 声明属性值——函数:calc(), min(), max(), clamp()可选范围, toggle()可切换
10、head html元信息类标签

meta 标签是一组键值对,它是一种通用的元信息表示标签

一般的 meta 标签由 name 和 content 两个属性来定义。name 表示元信息的名,content 则用于表示元信息的值。 name 是一种比较自由的约定,HTTP 标准规定了一些 name 作为大家使用的共识,也鼓励大家发明自己的 name 来使用。

charset: 添加了 charset 属性的 meta 标签无需再有 name 和 content。

一般情况下,HTTP 服务端会通过 http 请求头来指定正确的编码方式,但是有些特殊的情况如使用 file 协议打开一个 HTML 文件,则没有 http 头,这种时候,charset meta 就非常重要了。

<meta charset="UTF-8">

http-equiv:具有 http-equiv 属性的 meta 标签,表示执行一个命令,这样的 meta 标签可以不需要 name 属性了。

接收的值:

content-type 添加http 请求头,并指定编码方式;

x-ua-compatible 模拟 http 头 x-ua-compatible,声明 ua 兼容性;

content-language 指定内容的语言;

default-style 指定默认样式表;

refresh 刷新;

set-cookie 模拟 http 头 set-cookie,设置 cookie;

content-security-policy 模拟 http 头 content-security-policy,声明内容安全策略。

<meta http-equiv="content-type" content="text/html; charset=UTF-8">

name 为 viewport 的 meta:用于 移动端开发标准 key-value形式

如下指定了 宽度和缩放。width 可以是device-width,跟设备宽度相等;height,device-height;initial-scale:初始缩放比例;minimum-scale:最小缩放比例;maximum-scale:最大缩放比例;user-scalable:是否允许用户缩放。

<meta name="viewport" content="width=500, initial-scale=1">

对于已经做好了移动端适配的网页,应该把用户缩放功能禁止掉,宽度设为设备宽度,一个标准的 meta 如下:

<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">

meta 标签可以被自由定义,只要写入和读取的双方约定好 name 和 content 的格式就可以了。

11、css选择器

“根据 id 选单个元素”“class 和 class 的组合选成组元素”“tag 选择器确定页面风格”这样的简单原则来使用选择器,不要搞出过于复杂的选择器。

类型选择器

// svg的a标签 和 a标签 用namespace 区分
@namespace svg url(http://www.w3.org/2000/svg);
@namespace html url(http://www.w3.org/1999/xhtml);
svg|a { stroke:blue; stroke-width:1;}
html|a { font-size:40px}

属性选择器

1. [att] 直接在方括号中放入属性名,是检查元素是否具有这个属性,只要元素有这个属性,不论属性是什么值,都可以被选中。
2. [att=val] 精确匹配,检查一个元素属性的值是否是 val。
3. [att~=val]多种匹配,检查一个元素的值是否是若干值之一,这里的 val 不是一个单一的值了,可以是用空格分隔的一个序列。
4. [att|=val]开头匹配,检查一个元素的值是否是以 val 开头,它跟精确匹配的区别是属性只要以 val 开头即可,后面内容不管。

html中的特殊字符,可以把 val 用引号括起来,形成一个 CSS 字符串。CSS 字符串允许使用单双引号来规避特殊字符,也可以用反斜杠转义

伪类选择器 以冒号开头

// 树结构关系
:empty 伪类表示没有子节点的元素,空白文本也行
:nth-child 和 :nth-last-child, :nth-child(even)选偶数,:nth-child(4n)选4的倍数
:first-child :last-child
:only-child
of-type 系列 变形的语法糖,S:nth-of-type(An+B) 是:nth-child(|An+B| of S) 的另一种写法。

// 链接与行为
:any-link 表示任意的链接,包括 a、area 和 link 标签
:link 表示未访问过的链接, :visited 表示已经访问过的链接
:hover 表示鼠标悬停在上的元素
:active 表示用户正在激活这个元素,如用户按下按钮,鼠标还未抬起时,这个按钮就处于激活状态。
:focus 表示焦点落在这个元素之上。
:target 用于选中浏览器 URL 的 hash 部分所指示的元素。

// 逻辑伪类
:not 支持不好

// 其他
12、伪元素

兼容好的只有四种

::first-line::first-letter 是比较类似的伪元素,一个表示元素的第一行,一个表示元素的第一个字母。

// 可用于首字母大写,并向左浮动
p::first-letter { 
    text-transform: uppercase;
	font-size:2em; 
    float:left;    
}

// CSS 标准规定了 first-line 必须出现在最内层的块级元素之内, 一些坑https://time.geekbang.org/column/article/84633

::before 表示在元素内容之前插入一个虚拟的元素,::after 则表示在元素内容之后插入。

// 这两个伪元素 必须指定 content 属性才会生效
p.classname::before {
    display: block;
    content: "pseudo! ";
}

// content 可以为 counter  ,实现在前面加序号
<p class="special">I'm real element</p>
p.special::before {
    display: block;
    content: counter(chapno, upper-roman) ". ";
}

有了这两个伪元素,一些修饰性元素,可以使用纯粹的 CSS 代码添加进去,这能够很好地保持 HTML 代码中的语义,既完成了显示效果,又不会让 DOM 中出现很多无语义的空元素。

13、iframe

iframe,这个标签能够嵌入一个完整的网页。

不过,在移动端,iframe 受到了相当多的限制,它无法指定大小,里面的内容会被完全平铺到父级页面上。

同时很多网页也会通过 http 协议头禁止自己被放入 iframe 中。

iframe 标签也是各种安全问题的重灾区。opener、window.name、甚至 css 的 opacity 都是黑客可以利用的漏洞。

// 以前的用法
<iframe src="http://time.geekbang.org"></iframe>

// 在新标准中,为 iframe 加入了 sandbox 模式和 srcdoc 属性。解决跨域
<iframe sandbox srcdoc="<p>Yeah, you can see it <a href="/gallery?mode=cover&amp;amp;page=1">in my gallery</a>."></iframe>

使用 srcdoc 属性创建了一个新的文档,嵌入在 iframe 中展示,并且使用了 sandbox 来隔离。这样,这个 iframe 就不涉及任何跨域问题了。

14、CSS 三大经典问题:垂直居中,两列等高,自适应宽

flex实现

// 两列等高,即一列定高,使另一列高度相同
// 路是创建一个只有一行的 flexbox,然后用 stretch 属性让每个元素高度都等于行高。
<div class="parent">
  <div class="child" style="height:300px;">
  </div>
  <div class="child">
  </div>
</div>
<br/>
<div class="parent">
  <div class="child" >
  </div>
  <div class="child" style="height:300px;">
  </div>
</div>

.parent {
  display:flex;
  width:300px;
  justify-content:center;
  align-content:center;
  align-items:stretch;
}
.child {
  width:100px;
  outline:solid 1px;
}

// 自适应宽
// 给要自适应的元素添加 flex 属性即可
<div class="parent">
  <div class="child1">
  </div>
  <div class="child2">
  </div>
</div>

.parent {
  display:flex;
  width:300px;
  height:200px;
  background-color:pink;
}
.child1 {
  width:100px;
  background-color:lightblue;
}
.child2 {
  width:100px;
  flex:1;
  outline:solid 1px;
}
15、!DOCTYPE html

其他参考:https://time.geekbang.org/column/article/92227

这些复杂的 DTD 写法并没有什么实际作用(浏览器根本不会用 SGML 引擎解析它们),因此,到了 HTML5,干脆放弃了 SGML 子集这项坚持,规定了一个简单的,大家都能记住的 DTD

<!DOCTYPE html>
16、aria 无障碍

ARIA 全称为 Accessible Rich Internet Applications,它表现为一组属性,是用于可访问性的一份标准。

可访问性其实是一个相当大的课题,它的定义包含了各种设备访问、各种环境、各种人群访问的友好性。不单单是永久性的残障人士需要用到可访问性,健康的人也可能在特定时刻处于需要可访问性的环境。

ARIA 给 HTML 元素添加的一个核心属性就是 role

// 给一个 span 添加了 checkbox 角色,这样,表示我们这个 span 被用于 checkbox,这意味着,我们可能已经用 JS 代码绑定了这个 span 的 click 事件,并且以 checkbox 的交互方式来处理用户操作。
<span role="checkbox" aria-checked="false" tabindex="0" aria-labelledby="chk1-label">
</span> <label id="chk1-label">Remember my preferences</label>

// 同时,ARIA 系统还提供了一系列 ARIA 属性给 checkbox 这个 role,这意味着,我们可以通过 HTML 属性变化来理解这个 JavaScript 组件的状态,读屏软件等三方客户端,就可以理解我们的 UI 变化,这正是 ARIA 标准的意义。

role 的定义是一个树形的继承关系:widget 表示一些可交互的组件,structure 表示文档中的结构,window 则代表窗体

17、浏览器工作

img

HTTP 请求, DOM 树构建、CSS 计算、渲染、合成、绘制 是一条流水线

即不需要等到上一步骤完全结束,就开始处理上一步的输出,这样我们在浏览网页时,才会看到逐步出现的页面。

构建DOM树:(具体见 https://time.geekbang.org/column/article/80260)

栈顶元素就是当前节点;

遇到属性,就添加到当前节点;

遇到文本节点,如果当前节点是文本节点,则跟文本节点合并,否则入栈成为当前节点的子节点;

遇到注释节点,作为当前节点的子节点;

遇到 tag start 就入栈一个节点,当前节点就是这个节点的父节点;遇到 tag end 就出栈一个节点(还可以检查是否匹配)。

18、DOM API

节点:DOM 树形结构中的节点相关 API:

Document , DocumentFrangment ,Element,..;表示在 DOM 树中的关系:parentNode childNodes firstChild lastChild nextSibling previousSibling;操作 DOM 树的 API:appendChild insertBefore removeChild replaceChild;其他高级 API:compareDocumentPosition 是一个用于比较两个节点中关系的函数,contains 检查一个节点是否包含另一个节点的函数,isEqualNode 检查两个节点是否完全相同,isSameNode 检查两个节点是否是同一个节点,实际上在 JavaScript 中可以用“===”,cloneNode 复制一个节点,如果传入参数 true,则会连同子元素做深拷贝。

元素和属性API:可以把元素的 Attribute 当作字符串来看待,这样就有以下的 API:getAttribute setAttribute removeAttribute hasAttribute;如果你追求极致的性能,还可以把 Attribute 当作节点:getAttributeNodeset AttributeNode

查找元素:querySelector 系列的 API 不如 getElement 系列的 API。

事件:触发和监听事件相关 API

Range:操作文字范围相关 API:

Range API 是一个比较专业的领域,如果不做富文本编辑类的业务,不需要太深入

// 创建 Range 一般是通过设置它的起止来实现
var range = new Range(),
    firstText = p.childNodes[1],
    secondText = em.firstChild
range.setStart(firstText, 9) // do not forget the leading space
range.setEnd(secondText, 4)

// 此外,通过 Range 也可以从用户选中区域创建,这样的 Range 用于处理用户选中区域:
var range = document.getSelection().getRangeAt(0);

// 更改 Range 选中区段内容的方式主要是取出和插入,分别由 extractContents 和 insertNode 来实现。
var fragment = range.extractContents()
range.insertNode(document.createTextNode("aaaa"))


// 下面完整的例子 展示了如何使用 range 来取出元素和在特定位置添加新元素
var range = new Range(),
    firstText = p.childNodes[1],
    secondText = em.firstChild
range.setStart(firstText, 9) // do not forget the leading space
range.setEnd(secondText, 4)

var fragment = range.extractContents()
range.insertNode(document.createTextNode("aaaa"))

遍历:遍历 DOM 需要的 API:

DOM API 中还提供了 NodeIterator 和 TreeWalker 来遍历树,比起直接用属性来遍历,NodeIterator 和 TreeWalker 提供了过滤功能,还可以把属性节点也包含在遍历之内。

// NodeIterator用法 不常用
// 第二个参数是掩码,这两个设计都是传统 C 语言里比较常见的用法。
var iterator = document.createNodeIterator(document.body, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT, null, false);
var node;
while(node = iterator.nextNode())	// 以 nextNode 返回 null 来标志结束
{
    console.log(node);
}

// TreeWalker 的用法 
// 比起 NodeIterator,TreeWalker 多了在 DOM 树上自由移动当前节点的能力,一般来说,这种 API 用于“跳过”某些节点,或者重复遍历某些节点。
var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, null, false)
var node;
while(node = walker.nextNode())
{
    if(node.tagName === "p")
        node.nextSibling();
    console.log(node);
}

// 这两个用起来不太方便,建议需要遍历 DOM 的时候,直接使用递归和 Node 的属性。
19、CSSOM View的 API

没有element.width这样的DOM API,是因为正如 HTML 和 CSS 分别承担了语义和表现的分工,DOM 和 CSSOM 也有语义和表现的分工。

CSSOM 是 CSS 的对象模型,在 W3C 标准中,它包含两个部分:描述样式表和规则等 CSS 的模型部分(CSSOM),和跟元素视图相关的 View 部分(CSSOM View)。

// CSSOM API 
// document 的 styleSheets 属性表示文档中的所有样式表,这是一个只读的列表
// 样式表只能使用 style 标签或者 link 标签创建
// 虽然无法用 CSSOM API 来创建样式表,但是我们可以修改样式表中的内容
document.styleSheets[0].insertRule("p { color:pink; }", 0)
document.styleSheets[0].removeRule(0)

// 更进一步,我们可以获取样式表中特定的规则(Rule),并且对它进行一定的操作,具体来说,就是使用它的 cssRules 属性来实现
document.styleSheets[0].cssRules

CSSOM View这一部分的 API,可以视为 DOM API 的扩展(BOM?),添加了三个部分功能:窗口部分 window,滚动部分和布局部分

// 窗口 API 用于操作浏览器窗口的位置、尺寸等
// 一些浏览器出于安全考虑没有实现,也不适用于移动端浏览器
// moveTo(x, y) 窗口移动到屏幕的特定坐标;
// moveBy(x, y) 窗口移动特定距离;
// resizeTo(x, y) 改变窗口大小到特定尺寸;
// resizeBy(x, y) 改变窗口大小特定尺寸。
window.open("about:blank", "_blank" ,"width=100,height=100,left=100,right=100" )
// 滚动API
// scrollX 是视口的属性,表示 X 方向上的当前滚动距离,有别名 pageXOffset;
// scroll(x, y) 使得页面滚动到特定的位置,有别名 scrollTo,支持传入配置型参数 {top, left};
// ..
// 通过这些属性和方法,我们可以读取视口的滚动位置和操纵视口滚动。不过,要想监听视口滚动事件,我们需要在 document 对象上绑定事件监听函数:
document.addEventListener("scroll", function(event){
  //......
})

// 视口滚动 API 是页面的顶层容器的滚动,大部分移动端浏览器都会采用一些性能优化,它和元素滚动不完全一样

// 元素滚动 API
// scrollTop 元素的属性,表示 Y 方向上的当前滚动距离。
// ...
// 可滚动的元素也支持 scroll 事件,我们在元素上监听它的事件即可
element.addEventListener("scroll", function(event){
  //......
})
// 布局 API
// 是整个 CSSOM 中最常用到的部分,我们同样要分成全局 API 和元素上的 API
// 如下图 window.screen等等,主要使用的是 innerHeight、innerWidth 和 devicePixelRatio 三个属性

img

20、浏览器事件:捕获和冒泡

事件来自输入设备,键盘;鼠标;触摸屏。

我们现代的 UI 系统,都源自 WIMP 系统。WIMP 即 Window Icon Menu Pointer 四个要素,它最初由施乐公司研发,后来被微软和苹果两家公司应用在了自己的操作系统上。

一般认为我们能够“点击一个按钮”,实际上并非如此,我们只能够点击鼠标上的按钮或者触摸屏,是操作系统和浏览器把这个信息对应到了一个逻辑上的按钮,再使得它的视图对点击事件有反应。

实际上点击事件来自触摸屏或者鼠标,鼠标点击并没有位置信息,但是一般操作系统会根据位移的累积计算出来,跟触摸屏一样,提供一个坐标给浏览器。那么,把这个坐标转换为具体的元素上事件的过程,就是捕获过程了。而冒泡过程,则是符合人类理解逻辑的:当你按电视机开关时,你也按到了电视机。

// 捕获和冒泡 示例
<body>
  <input id="i"/>
</body>


document.body.addEventListener("mousedown", () => {
  console.log("key1")
}, true)

document.getElementById("i").addEventListener("mousedown", () => {
  console.log("key2")
}, true)

document.body.addEventListener("mousedown", () => {
  console.log("key11")
}, false)

document.getElementById("i").addEventListener("mousedown", () => {
  console.log("key22")
}, false)

// 输出:“key1”“key2”“key22”“key11”

// addEventListener 有三个参数:事件名称;事件处理函数;捕获还是冒泡。

// 第三个参数不一定是 bool 值,也可以是个对象,它提供了更多选项。once:只执行一次。passive:承诺此事件监听不会调用 preventDefault,这有助于性能。useCapture:是否捕获(否则冒泡)。

// 建议默认不传第三个参数, 除非是开发 组件 或者 库

焦点 focues

// Tab 键被用来切换到下一个可聚焦的元素,焦点系统占用了 Tab 键,但是可以用 JavaScript 来阻止这个行为。
document.body.focus();

document.body.blur();

自定义事件

var evt = new Event("look", {"bubbles":true, "cancelable":false});
document.dispatchEvent(evt);

// 旧的自定义事件方法(使用 document.createEvent 和 initEvent)已经被废弃。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值