GithubHelp home page GithubHelp logo

learning's People

Contributors

harleywang93 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

learning's Issues

函数与作用域

函数是什么?

  • JavaScript函数是指一个特定代码块,可能包含多条语句,可以通过名字来供其它语句调用以执行函数包含的代码语句。

函数声明和函数表达式有什么区别?

ECMAScript 规定了三种声明函数方式

  • 构造函数(不推荐使用)
    首先函数也是对象的一种,我们可以通过其构造函数,使用new来创建一个函数对象
var sayHello = new Function("console.log('hello world');");
  • 函数声明
    使用 function 关键字可以声明一个函数
  //函数声明
  function sayHello(){
    console.log('hello')
  }

  //函数调用
  sayHello()

声明不必放到调用的前面

  • 函数表达式
var sayHello = function(){
    console.log('hello');
  }

  sayHello()

声明必须放到调用的前面

  • 来看一个经典问题
getName()//oaoafly
var getName = function() {
	console.log('wscat')
}
getName()//wscat
function getName() {
	console.log('oaoafly')
}
getName()//wscat

因为变量提升,上面的代码等同于下面的形式

var getName//undefined
function getName() {
	console.log('oaoafly')
}//虽然函数声明在最后,但是被提升到前面了
getName()//oaoafly
var getName = function() {
	console.log('wscat')
}//此时函数表达式覆盖了函数声明的值
getName()//wscat
getName()//wscat
  • 函数声明和函数表达式的区别总结
    函数声明在 JS 解析时进行函数提升,因此在同一个作用域内,不管函数声明在哪里定义,该函数都可以进行调用。而函数表达式的值是在JS运行时确定,并且在表达式赋值完成后,该函数才能调用。

什么是变量的声明前置?什么是函数的声明前置?

  • 变量的声明前置:指的是 JavaScript 解析器将当前作用域内声明的所有变量放到作用域的开始处,但是,只有变量的声明被前置了(值都为undefined),而赋值操作被保留在原处。

  • 函数的声明前置:JavaScript 解释器允许在函数声明之前使用函数,此时不仅仅是函数名被前置了,整个函数定义也被前置了,所以可以直接调用函数。

arguments 是什么?

  • arguments 是一个类数组对象。通过比如arguments[1、2、3],我们可以获取到相应的传入参数。

函数的"重载"怎样实现?

  • 在 JS 中没有重载,同名函数会覆盖。但可以在函数体针对不同的参数调用执行相应的逻辑。
  function printPeopleInfo(name, age, sex){
    if(name){
      console.log(name);
    }

    if(age){
      console.log(age);
    }

    if(sex){
      console.log(sex);
    }
  }


  printPeopleInfo('Byron', 26);
  printPeopleInfo('Byron', 26, 'male');

立即执行函数表达式是什么?有什么作用?

  • 立即执行函数表达式(Immediately-Invoked Function Expression),简称IIFE。表示定义函数之后,立即调用该函数。
(function(){
  var a  = 1;
})()
console.log(a); //undefined

其他写法:

[function fn2() {
  alert(22)
}()];// 在数组初始化器内只能是表达式
1, function fn3() {
     alert(33)
}();// 逗号也只能操作表达式
  • 作用:隔离作用域。

求n!,用递归来实现

function factor(n){
	if( n === 1 || n ===0 ) {
		return 1;
	} else if ( n < 0 ){
		return;
	} else {
		return n*factor(n-1);
	}
}

以下代码输出什么?

	function getInfo(name, age, sex){
		console.log('name:',name);
		console.log('age:', age);
		console.log('sex:', sex);
		console.log(arguments);
		arguments[0] = 'valley';
		console.log('name', name);
	}

    getInfo('饥人谷', 2, '男');
    getInfo('小谷', 3);
    getInfo('男');
name:饥人谷 age:2 sex:男 ['饥人谷',2,'男'] name vally
name:小谷 age:3 sex:undefined ['小谷',3] name vally
name:男 age:undefined sex:undefined ['男'] name vally

写一个函数,返回参数的平方和?

   function sumOfSquares(){
        var result = 0;
        for (var i = 0; i < arguments.length; i++) {
        result = result + arguments[i] * arguments[i];
        }
        console.log(result)
   }
   var result = sumOfSquares(2,3,4)
   var result2 = sumOfSquares(1,3)
   console.log(result)  //29
   console.log(result2)  //10

如下代码的输出?为什么?

	console.log(a);
	var a = 1;
	console.log(b);

由于变量的声明前置,上面的代码等同于下面的形式:

var a;//undefined
console.log(a);//undefined
a=1;
console.log(b);//报错,b没有进行变量声明。

如下代码的输出?为什么?

sayName('world');
sayAge(10);
function sayName(name){
	console.log('hello ', name);
}
var sayAge = function(age){
	console.log(age);
}

因为函数的声明前置,上面的代码等同于下面的形式:

function sayName(name){
	console.log('hello ', name);
}
sayName('world');//hello,world
sayAge(10);//报错,因为函数表达式放必须在调用前面
var sayAge = function(age){
	console.log(age);
}

如下代码输出什么? 写出作用域链查找过程伪代码

var x = 10
bar() 
function foo() {
  console.log(x)
}
function bar(){
  var x = 30
  foo()
}
globalContext = {
	AO: {
		x: 10
		foo: function
		bar: function
	}
}

f00.[[scope]] = globalContext.AO
bar.[[scope]] = globalContext.AO

barContext = {
	AO: {
		x: 30
	},
	Scope: bar.[[scope]] = globalContext.AO
}

fooContext = {
	AO : {},
	Scope: foo.[[scope]] = globalContext.AO
}

输出 10

如下代码输出什么? 写出作用域链查找过程伪代码

var x = 10;
bar() 
function bar(){
  var x = 30;
  function foo(){
    console.log(x) 
  }
  foo();
}	
globalContext = {
	AO: {
		x: 10
		bar: function
	}
}

bar.[[scope]] = globalContext.AO

barContext = {
	AO: {
		x: 30
		foo: function
	},
	Scope: bar.[[scope]] = globalContext.AO
}

foo.[[scope]] = barContext.AO

fooContext = {
	AO: {},
	Scope: foo.[[scope]] = barContext.AO
}

输出 30

以下代码输出什么? 写出作用域链的查找过程伪代码

var x = 10;
bar() 
function bar(){
  var x = 30;
  (function (){
    console.log(x)
  })()
}
globalContext = {
	AO: {
		x: 10
		bar: function(){}
	}
}

bar.[[scope]] = globalContext.AO

barContext = {
	AO: {
		x: 30
		IIFE: function(){}
	},
	Scope: barContext.AO
}

IIFE.[[scope]] = barContext.AO

IIFEContext = {
	AO: {}
	Scope: barContext.AO
}

输出 30

以下代码输出什么? 写出作用域链查找过程伪代码

var a = 1;

function fn(){
  console.log(a)
  var a = 5
  console.log(a)
  a++
  var a
  fn3()
  fn2()
  console.log(a)

  function fn2(){
    console.log(a)
    a = 20
  }
}

function fn3(){
  console.log(a)
  a = 200
}

fn()
console.log(a)
globalContext = {
	AO: {
		a: 200
		fn: function(){}
		fn3: function(){}
	}
}

fn.[[scope]] = globalContext.AO
fn3.[[scope]] = globalContext.AO

fnContext = {
	AO: {
		a: 20
		fn2: function(){}
	},
	Scope: globalContext.AO
}

fn2.[[scope]] = fnContext.AO

fn3Context = {
	AO: {},
	Scope: globalContext.AO
}

fn2Context = {
	AO: {},
	Scope: fnContext.AO
}

输出 undefined 5 1 6 20 200

字符串与 JSON

对于 HTTP 协议而言,HTML、CSS、JS、JSON 的本质都是什么?

  • 对于HTTP协议而言,html、css、js、json是符合相应语法的字符串
  • 用户访问页面时,浏览器根据用户请求的路径,向服务器发起请求,服务器根据路判断径返回给浏览器对应的字符串,同时也返回给浏览器Content-Type值。
  • Content-Type=text/html,浏览器就把字符串当HTML进行解析;
    当 HTML 中有<link rel="stylesheet" href="" />,浏览器再向服务器发起请求,服务器返回字符串和Content-Type=text/css,浏览器就把返回的字符串当 CSS 进行解析;
    当HTML中有<script src="" />,浏览器向服务器发起请求,服务器返回字符串和Content-Type=text/javascript,浏览器就把字符串当 JS 进行解析,返回给用户。

使用数组拼接出如下字符串 ,其中styles数组里的个数不定

var prod = {
    name: '女装',
    styles: ['短款', '冬季', '春装']
};
function getTpl(data){
//todo...
};
var result = getTplStr(prod);  //result为下面的字符串
<dl class="product"><dt>女装</dt><dd>短款</dd><dd>冬季</dd><dd>春装</dd></dl>

方法一:

var product = {
  name: '女装',
  styles: ['短款', '冬季', '春装']
}

function getTpl(product) {
  var str = '<dl class="product">'
  str += '    <dt>' + product.name + '</dt>'
  for(var i = 0; i < product.styles.length; i++) {
    str += '  <dd>' + product.styles[i] + '</dd>'
  }
  str += '    </dl>'
  return str;
}

var result = getTpl(product)
console.log(result)

方法二:

var product = {
  name: '女装',
  styles: ['短款', '冬季', '春装']
}

function getTpl(product) {
  var html = []
  html.push('<dl class="product">')
  html.push('    <dt>' + product.name + '</dt>')
  for(var i = 0; i < product.styles.length; i++) {
    html.push('  <dd>' + product.styles + '</dd>')
  }
  html.push('    <dl>')
  return html.join('');
}
var result = getTpl(product)
console.log(result)

写出两种以上声明多行字符串的方法

例如:

var str = 'abcdeabcdeabcdeancdeabcdeabcdeabcdeancdeabcdeabcdeabcdeancdeabcdeabcdeabcdeancde'

方法一(不推荐使用)

var str = 'abcdeabcdeabcdeancde\
abcdeabcdeabcdeancde\
abcdeabcdeabcdeancde\
abcdeabcdeabcdeancde';

方法二

var str = 'abcdeabcdeabcdeancde\nabcdeabcdeabcdeancde\nabcdeabcdeabcdeancde\nabcdeabcdeabcdeancde'

方法三

var str = 'abcdeabcdeabcdeancde\n'
+ 'abcdeabcdeabcdeancde\n'
+ 'abcdeabcdeabcdeancde\n'
+ 'abcdeabcdeabcdeancde\n'

方法四

(function (){/*
abcdeabcdeabcdeancde
abcdeabcdeabcdeancde
abcdeabcdeabcdeancde
abcdeabcdeabcdeancde
*/}).toString().split('\n').slice(1,-1).join('\n');

补全如下代码,让输出结果为字符串: hello\饥人谷

var str = 'hello\\\\饥人谷'
console.log(str)

以下代码输出什么?为什么

var str = 'jirengu\nruoyu'
console.log(str.length)//13  \n 为转义字符,转义字符只占据一个字符,且空格不算在字符长度里。

写一个函数,判断一个字符串是回文字符串,如 abcdcba是回文字符串, abcdcbb不是

function isPalindrome(str) {
  return str === str.split('').reverse().join('')
}
var str1 = 'abcdcba'
var str2 = 'abcdcbb'
isPalindrome(str1)//true
isPalindrome(str2)//false

写一个函数,统计字符串里出现出现频率最多的字符

var str = 'I must find a fucking nooooooooooob job in autumn!'
var dict = {}
var count = 0
var maxValue
for(var i = 0; i < str.length; i++){
  if(dict[str[i]]){
    ++dict[str[i]]
  }else{
    dict[str[i]] = 1
  }
}
for(key in dict){
  if(dict[key] > count){
    maxValue = key
    count = dict[key]
  }
}
console.log(count,maxValue)

写一个camelize函数,把my-short-string形式的字符串转化成myShortString形式的字符串,如

camelize("background-color") == 'backgroundColor'
camelize("list-style-image") == 'listStyleImage'
function camelize(str) {
  var arr = str.split('-')
  for(var i = 1; i < arr.length; i++){
    arr[i] = arr[i][0].toUpperCase() + arr[i].substr(1)
  }
  return arr.join('')
}
console.log( camelize("background-color"))
console.log( camelize("list-style-image"))

写一个 ucFirst函数,返回第一个字母为大写的字符 (***)

ucFirst("hunger") == "Hunger"
function ucFirst(str){
  return str[0].toUpperCase() + str.substr(1)
}

写一个函数truncate(str, maxlength), 如果str的长度大于maxlength,会把str截断到maxlength长,并加上...,如

truncate("hello, this is hunger valley,", 10) == "hello, thi...";
truncate("hello world", 20) == "hello world"
function truncate(str,maxlength){
  if(str.length <= maxlength){
    return str
  }else{
    return str.substr(0,maxlength) + '...'
  }
}
console.log(truncate("hello, this is hunger valley,", 10))
console.log(truncate("hello world", 20))

什么是 JSON格式数据?JSON格式数据如何表示对象?window.JSON 是什么?

JSON(JavaScript Object Notation)

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它基于JavaScript(Standard ECMA-262 3rd Edition - December 1999)的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成(网络传输速度)。

语法

JSON 语法是 JavaScript 对象表示语法的子集。

  1. 数据在名称/值对中
  2. 数据由逗号分隔
  3. 花括号保存对象
  4. 方括号保存数组

JSON 数据的书写格式是:名称/值对,名称/值对组合中的名称写在前面(在双引号中),值对写在后面(同样在双引号中),中间用冒号隔开:

var json1 = {"name": "Byron", "age": "24"}

var json2 = [
    {"name": "Byron", "age": "24"}, 
    {"name": "Byron2", "age": "25"}
]

window.JSON

  • window.JSON 是浏览器内置对象,用来检测对JSON的支持情况。
  • JSON对象内置了JSON.parse()、JSON.stringify()。
  • IE8版本以上才内置支持JSON.parse()函数方法。

如何把JSON 格式的字符串转换为 JS 对象?如何把 JS 对象转换为 JSON 格式的字符串?

IE8以上浏览器都支持了一个对象JSON,JSON对象主要有两个『静态』函数

  • parse:把字符串转化为JSON对象
  • stringify:把JSON对象转化为字符串

JSON 格式的字符串转换为 JS 对象:

var str = '{"name": "jirengu", "age": "24"}'
var json=JSON.parse(str);    //{name: "jirengu", age: "24"}

JS 对象转换为 JSON 格式的字符串:

var obj={name:"jirengu",  age:24,  "128":"blahblah"}
var str=JSON.stringify(obj);//"{"128":"blahblah","name":"jirengu","age":24}"

CSS 基础

CSS 是什么?

  • Cascading Style Sheets 层叠样式表
  • 用来为结构化文档(如 HTML 文档或 XML 应用)添加样式(字体、间距和颜色等)

CSS 如何使用?有几种引入方式? link 和 @import 有什么区别?

image
eg:

@charset "utf-8";
h1 {
  color: red;
  font-size: 20px;
  /*这是注释*/
}
a:hover{
  color: red;
}
  • 内联样式

也叫行内样式,样式直接写在HTML标签中。但现在按照“内容 样式 行为 分离”的原则,基本不再使用。
<h1 style="color: red; font-size: 20px;"></h1>

  • 内部样式

在 HTML 的 head 部分,加入一个 style 标签,在其中书写样式,称为内部样式。

<style type="text/css">
  h1 {
    color: red;
    font-size: 20px;
  }
</style>
<h1>...</h1>
  • 外部样式

目前最常用的 CSS 引入方式,即单独一个 css 文件来写样式,HTML 文件在执行的时候,通过外部引用的方式来获取 CSS 。外部引用有 link 和 @import 两种方式。

<head>
  <link rel="stylesheet" type="text/css" href="index.css">
</head>
<style>
  @import url("hello.css");
  @import "world.css";
</style>
  • 浏览器默认样式

在外观和预想不一样的时候,要考虑到这一点。

  • link 和 @import 的区别

  • link 是 XHTML 标签,除了加载 CSS 外,还可以定义RSS等其他事务;@import是 CSS 的一个语法,只能加载 CSS 。
  • link 引用 CSS 时,在页面载入时同时加载;@import 需要页面网页完全载入以后加载。
  • link是 XHTML 标签,无兼容问题;@import 是在 CSS2.1 提出的,低版本的浏览器不支持,只有IE5以上才能识别。
  • link 支持使用 Javascript 控制 DOM 去改变样式;而 @import 不支持。

以下这几种文件路径分别用在什么地方,代表什么意思?

  • 相对路径

css/a.css
当前目录下 css 文件夹中的 a.css 文件

./css/a.css
等价于css/a.css./代表当前文件夹

b.css
当前文件夹下的 b.css

../imgs/a.png
上一级文件夹下的 imgs 文件夹中的 a.png 文件

  • 绝对路径

/Users/hunger/project/css/a.css
本地文件的绝对地址

  • 网站路径

/static/css/a.css
网站路径,此时寻找的是根目录下 static 文件夹下 css 文件夹中 a.css 文件

css/a.css
在网页打开时为相对路径,为和 HTML 页面同级下 css 文件夹下的 a.css 文件

http://cdn.jirengu.com/kejian1/8-1.png
网络路径,表示cdn.jirengu.com上面的图片地址

如果我想在js.jirengu.com上展示一个图片,需要怎么操作?

  • 把图片上传服务器,引用相对路径
  • 直接引用网站上的图片地址(比如把本地照片上传到 极简图床,会生成一个网络地址)

列出5条以上html和 css 的书写规范

  • 语法不区分大小写,但建议统一使用小写
  • 不使用内联的style属性定义样式
  • id和class使用有意义的单词,分隔符建议使用-
  • 有可能就是用缩写
  • 属性值是0的省略单位
  • 块内容缩进
  • 属性名冒号后面添加一个空格

Chrome 开发者工具的功能区

image

  1. 不同设备的模拟演示
  2. Elements:查找网页源代码HTML中的任一元素,手动修改任一元素的属性和样式且能实时在浏览器里面得到反馈。
  3. Network:从发起网页页面请求Request后分析HTTP请求后得到的各个请求资源信息(包括状态、资源类型、大小、所用时间等),可以根据这个进行网络性能优化。
  4. Sources:断点调试JS。
  5. Timeline:记录并分析在网站的生命周期内所发生的各类事件,以此可以提高网页的运行时间的性能。
  6. Profiles:如果你需要Timeline所能提供的更多信息时,可以尝试一下Profiles,比如记录JS CPU执行时间细节、显示JS对象和相关的DOM节点的内存消耗、记录内存的分配细节。
  7. Application:记录网站加载的所有资源信息,包括存储数据(Local Storage、Session Storage、IndexedDB、Web SQL、Cookies)、缓存数据、字体、图片、脚本、样式表等。
  8. Security:判断当前网页是否安全。
  9. 样式
  10. Audits:对当前网页进行网络利用情况、网页性能方面的诊断,并给出一些优化建议。比如列出所有没有用到的CSS文件等。
  11. Console:记录开发者开发过程中的日志信息,且可以作为与JS进行交互的命令行Shell。

推荐阅读

CSS 编码规范

Math 数组 Date

Math

1. 写一个函数,返回从min到max之间的 随机整数,包括min不包括max

function random(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

2. 写一个函数,返回从min都max之间的 随机整数,包括min包括max

function random(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

3. 写一个函数,生成一个长度为 n 的随机字符串,字符串字符的取值范围包括0到9,a到 z,A到Z。

function random(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}
function getRandStr(length){
  var dict = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
  var str = ''
  for(var i = 0; i < length; i++) {
  	str += dict[random(0, 62)]
  }
  return str
}

4. 写一个函数,生成一个随机 IP 地址,一个合法的 IP 地址为 0.0.0.0~255.255.255.255

function random(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

function getRandIP() {
  var arr = []
  for(var i = 0; i < 4; i++) {
  	arr.push(random(0, 256))
  }
  return arr.join('.')
}
var ip = getRandIP()
console.log(ip)

5. 写一个函数,生成一个随机颜色字符串,合法的颜色为#000000~ #ffffff

function random(min, max) {
  return Math.floor(Math.random() * (max - min)) + min
}

function getRandColor() {
  var color = '#'
  var dict = '0123456789abcdef'
  for(var i = 0; i < 6; i++) {
  	color += dict[random(0, 16)]
  }
  return color
}
var color = getRandColor()
console.log(color)

数组

1. 数组方法里push、pop、shift、unshift、join、splice分别是什么作用?用 splice函数分别实现push、pop、shift、unshift方法

  • push
    push 方法用于在数组的末端添加一个或多个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。

  • pop
    pop 方法用于删除数组的最后一个元素,并返回该元素。注意,该方法会改变原数组。

  • join
    join 方法以参数作为分隔符,将所有数组成员组成一个字符串返回。如果不提供参数,默认用逗号分隔。

  • shift
    shift 方法用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组。

  • unshift
    unshift 方法用于在数组的第一个位置添加元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。

  • splice
    splice 方法用于删除原数组的一部分成员,并可以在被删除的位置添加入新的数组成员,返回值是被删除的元素。注意,该方法会改变原数组。

splice 的第一个参数是删除的起始位置,第二个参数是被删除的元素个数。如果后面还有更多的参数,则表示这些就是要被插入数组的新元素。

// 格式
arr.splice(index, count_to_remove, addElement1, addElement2, ...);

// 用法
var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(4, 2) // ["e", "f"]
a // ["a", "b", "c", "d"]

上面代码从原数组4号位置,删除了两个数组成员。

var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(4, 2, 1, 2) // ["e", "f"]
a // ["a", "b", "c", "d", 1, 2]

上面代码除了删除成员,还插入了两个新成员。

起始位置如果是负数,就表示从倒数位置开始删除。

var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(-4, 2) // ["c", "d"]

上面代码表示,从倒数第四个位置c开始删除两个成员。

如果只是单纯地插入元素,splice方法的第二个参数可以设为0。

var a = [1, 1, 1];

a.splice(1, 0, 2) // []
a // [1, 2, 1, 1]

如果只提供第一个参数,等同于将原数组在指定位置拆分成两个数组。

var a = [1, 2, 3, 4];
a.splice(2) // [3, 4]
a // [1, 2]

用 splice函数分别实现push、pop、shift、unshift方法

//push
function spliceToPush(arr, elements) {
  arr.splice(arr.length, 0, elements)
  return arr
}
//pop
function spliceToPop(arr) {
  arr.splice(arr.length - 1, 1)
  return arr
}
//shift
function spliceToShift(arr) {
  arr.splice(0, 1)
  return arr
}
//unshift
function spliceToUnshift(arr, elements) {
  arr.splice(0, 0, elements)
  return arr
}

var arr = [1, 2, 3]
console.log(spliceToPush(arr, 'Deadpool'))//[1, 2, 3, "Deadpool"]
console.log(spliceToPop(arr))//[1, 2, 3]
console.log(spliceToShift(arr))//[2, 3]
console.log(spliceToUnshift(arr, 'Deadpool'))//["Deadpool", 2, 3]

2. 写一个函数,操作数组,数组中的每一项变为原来的平方,在原数组上操作

function squareArr(arr){
  for(var i = 0; i < arr.length; i++) {
  	arr.splice(i, 1, (arr[i] * arr[i]))
  }
}
var arr = [2, 4, 6]
squareArr(arr)
console.log(arr) // [4, 16, 36]

3. 写一个函数,操作数组,返回一个新数组,新数组中只包含正数,原数组不变

function filterPositive(arr){
  var newArr = []
  for(var i = 0; i < arr.length; i++) {
  	if(typeof arr[i] === 'number' && arr[i] > 0) {
  	  newArr.push(arr[i])
  	}
  }
  return newArr
}
var arr = [3, -1,  2,  '饥人谷', true]
var newArr = filterPositive(arr)
console.log(newArr) //[3, 2]
console.log(arr) //[3, -1,  2,  '饥人谷', true]

Date

1. 写一个函数getChIntv,获取从当前时间到指定日期的间隔时间

function getChIntv(dateStr) {
  var targetDate = new Date(dateStr)
  var curDate = new Date()
  var offset = Math.abs(targetDate - curDate)
  var totalSeconds = Math.floor(offset / 1000)
  var second = totalSeconds % 60
  var totalMinutes = Math.floor(totalSeconds / 60)
  var minutes = totalMinutes % 60
  var totalHours = Math.floor(totalMinutes / 60)
  var hours = totalHours % 24
  var totalDays = Math.floor(totalHours / 24)
  return totalDays + ' 天 ' + hours + ' 小时 ' + minutes + ' 分 ' + second + ' 秒 '
}
var str = getChIntv("2017-09-01");
console.log(str)

2. 把hh-mm-dd格式数字日期改成中文日期

function getChsDate(str) {
  var dict = ["零","一","二","三","四","五","六","七","八","九","十","十一","十二","十三","十四","十五","十六","十七","十八","十九","二十","二十一","二十二","二十三","二十四","二十五","二十六","二十七","二十八","二十九","三十","三十一"]
  var arr = str.split('-')
  var year = arr[0]
  var month = arr[1]
  var day = arr[2]
  var yearStr = ''
  for(var i = 0; i < year.length; i++) {
  	yearStr += dict[year[i]]
  }
  var monthStr = dict[parseInt(month)]
  var dayStr = dict[parseInt(day)]
  return yearStr + "年" + monthStr + "月" + dayStr + "日"
}

var str = getChsDate('2015-01-08');
console.log(str);  // 二零一五年一月八日

3.写一个函数,参数为时间对象毫秒数的字符串格式,返回值为字符串。假设参数为时间对象毫秒数t,根据t的时间分别返回如下字符串:

刚刚( t 距当前时间不到1分钟时间间隔)
3分钟前 (t距当前时间大于等于1分钟,小于1小时)
8小时前 (t 距离当前时间大于等于1小时,小于24小时)
3天前 (t 距离当前时间大于等于24小时,小于30天)
2个月前 (t 距离当前时间大于等于30天小于12个月)
8年前 (t 距离当前时间大于等于12个月)
function friendlyDate(time){
  var curDate = new Date().getTime()
  var offset = Math.abs(curDate - time)
  var seconds = Math.floor(offset / 1000)
  var minutes = Math.floor(seconds / 60)
  var hours = Math.floor(minutes / 60)
  var days = Math.floor(hours / 24)
  var months = Math.floor(days / 30)//这里有一个问题,每个月的天数不同,有28、29、30、31天,怎样能够精确的计算呢?
  var years = Math.floor(months / 12)
  if(seconds < 60) {
  	return "刚刚"
  }else if(1 <= minutes && minutes < 60) {
  	return "3分钟前"
  }else if(1 <= hours && hours < 24) {
  	return "8小时前"
  }else if(1 <= days && days < 30) {
  	return "3天前"
  }else if(1 <= months && months < 12) {
  	return "2个月前"
  }else if(1 <= years) {
  	return "8年前"
  }
}

var str = friendlyDate('1484286699422') //2个月前
var str2 = friendlyDate('1483941245793') //2个月前

事件

题目1: DOM0 事件和DOM2级在事件监听使用方式上有什么区别?

DOM0

  • Dom0级事件处理程序是将一个函数赋值给一个事件处理程序属性,而通过将事件处理程序设置为null删除绑定在元素上的事件处理程序。
  • 这种方法无法给一个事件添加多个事件处理程序,后面的程序会覆盖前面的程序。
var button = documen.getElementById('button')
button.onclick = function(){}   // on+事件名称
button.onclick = null
button.onclick = function(){
  console.log(1)
}
button.onclick = function(){
  console.log(2)    // 会覆盖
}

DOM2

  • DOM2级事件定义了两个方法用于处理指定和删除事件处理程序的操作:
    addEventListener()removeEventListener()
  • 所有的DOM节点都包含这两个方法,并且它们都接受三个参数
  1. 事件类型
  2. 事件处理方法
  3. 布尔参数 如果是true表示在捕获阶段调用事件处理程序,如果是false,则是在事件冒泡阶段处理(如果不写,默认是false 在冒泡阶段处理)
var button = documen.getElementById('button')
button.addEventListener('click',fn)
button.removeEventListener('click',fn)
  • DOM2级不会出现DOM0级事件处理程序覆盖的问题,它可以给同一个元素添加多个事件处理程序。

题目2: attachEvent与addEventListener的区别?

button.attachEvent('onclick',fn)
button.addEventListener('click',fn)
  1. 参数个数不相同,这个最直观,addEventListener有三个参数,attachEvent只有两个,attachEvent添加的事件处理程序只能发生在冒泡阶段,addEventListener第三个参数可以决定添加的事件处理程序是在捕获阶段还是冒泡阶段处理(我们一般为了浏览器兼容性都设置为冒泡阶段)

  2. 第一个参数意义不同,addEventListener第一个参数是事件类型(比如click,load),而attachEvent第一个参数指明的是事件处理函数名称(onclick,onload)

  3. 事件处理程序的作用域不相同,addEventListener的作用域是元素本身,this是指的触发元素,而attachEvent事件处理程序会在全局变量内运行,this是window,所以刚才例子才会返回undefined,而不是元素id

  4. 为一个事件添加多个事件处理程序时,执行顺序不同,addEventListener添加会按照添加顺序执行,而attachEvent添加多个事件处理程序时顺序无规律(添加的方法少的时候大多是按添加顺序的反顺序执行的,但是添加的多了就无规律了),所以添加多个的时候,不依赖执行顺序的还好,若是依赖于函数执行顺序,最好自己处理,不要指望浏览器。

题目3: 解释IE事件冒泡和DOM2事件传播机制?

  • IE的事件冒泡:事件从目标节点逐级往上层节点传播
  • DOM事件流:DOM2级事件规定事件流包括三个阶段,先捕获,处于目标阶段,再冒泡。捕获指事件从顶层节点一级一级往下层传播,最后到达目标节点,冒泡指事件从目标节点逐级往上层节点传播。

img

题目4:如何阻止事件冒泡? 如何阻止默认事件?

阻止冒泡

  • DOM0级
var button = documen.getElementById('button')
button.onclick = function(e){
  console.log('hello')
  e.stopPropagation()     //  标准
} 
button.onclick = function(){
  console.log('hello')
  window.event.cancelBubble = true   // IE
} 
  • DOM2级
button.addEventListener('click',function(){
   console.log('world')
},false)         // 标准  第三个参数为false或者不写

button.attachEvent('onclick',function(e){
  e.cancelBubble = true   // IE
})

阻止默认事件

  • W3C标准
button.onclick = function(e){
  e.preventDefault()     
} 
// 或者
button.onclick = function(e){
  return false     
} 
// 或者HTML中
<button onclick="return false;"></button>
  • IE
button.onclick = function(event){
  window.event.returnValue = false    
}

题目5:有如下代码,要求当点击每一个元素li时控制台展示该元素的文本内容。不考虑兼容

<ul class="container">
    <li>这里是</li>
    <li>饥人谷</li>
    <li>前端6班</li>
</ul>
<script>
var container = document.querySelector('.container');
container.addEventListener('click', function(e) {
  console.log(e.target.innerText);
});
</script>

题目6: 补全代码,要求:

  • 当点击按钮开头添加时在
  • 这里是
  • 元素前添加一个新元素,内容为用户输入的非空字符串;当点击结尾添加时在最后一个 li 元素后添加用户输入的非空字符串.
  • 当点击每一个元素li时控制台展示该元素的文本内容。
<ul class="ct">
    <li>这里是</li>
    <li>饥人谷</li>
    <li>任务班</li>
</ul>
<input class="ipt-add-content" placeholder="添加内容"/>
<button id="btn-add-start">开头添加</button>
<button id="btn-add-end">结尾添加</button>
<script>
function $(str) {
  return document.querySelector(str)
}

var ct = $('.ct')
var addStart = $('#btn-add-start')
var addEnd = $('#btn-add-end')
var input = $('.ipt-add-content')

ct.addEventListener('click',function(e){
  console.log(e.target.innerText)
})
addStart.addEventListener('click',function(){
  var li = document.createElement('li')
  if(/\S/.test(input.value)){
    li.innerText = input.value
    ct.insertBefore(li,ct.firstChild)
  }else{
    alert('请输入内容')
  }
})
addEnd.addEventListener('click',function(){
  var li = document.createElement('li')
  if(/\S/.test(input.value)){
    li.innerText = input.value
    ct.appendChild(li)
  }else{
    alert('请输入内容')
  }
})
</script>

题目7: 补全代码,要求:当鼠标放置在li元素上,会在img-preview里展示当前li元素的data-img对应的图片。

<ul class="ct">
    <li data-img="1.png">鼠标放置查看图片1</li>
    <li data-img="2.png">鼠标放置查看图片2</li>
    <li data-img="3.png">鼠标放置查看图片3</li>
</ul>
<div class="img-preview"></div>
<script>
var ct = document.querySelector('.ct')
var preview = document.querySelector('.img-preview')

ct.addEventListener('mouseover',function(e){
  var dataImg = e.target.getAttribute('data-img')
  preview.innerHTML = '<img src="' + dataImg + '">'
})
</script>

Markdown 基础语法

什么是Markdown?

Markdown是一个简单的标记语言,这些标记和 HTML 的一些标签对应
通过一些转换库可以把 Markdown 转换成 HTML 或者把 HTML 转换成 Markdown

Markdown有什么作用?

用来在网页上展示文章,省去排版布局的烦恼

基本语法

1.标题

# 一级标题 h1
## 二级标题 h2
### 三级标题 h3
#### 四级标题 h4
##### 五级标题 h5

2.列表

有序列表

1. 有序列表
2. 有序列表
3. 有序列表

无序列表

- 无序列表
- 无序列表
- 无序列表

3.超链接

插入连接

[显示文本](链接地址)

插入图片

![](图片链接地址)

4.引用

单行

> 引用测试

> > 引用内引用测试

效果

引用测试

引用内引用测试

多行

```
var a = 1
var b = 2
```

效果

var a = 1
var b = 2

5.强调

**粗体测试**
*斜体测试*
~~删除线测试~~

效果

粗体测试
斜体测试
删除线测试

6.表格

Markdown使用|-来绘制表格,:可控制左对齐、居中及右对齐。

| 表头测试 | 表头测试 | 表头测试 |
| :--- | :---: | ---: |
| 内容 | 内容 | 内容 |
| 内容 | 内容 | 内容 |

效果

表头测试 表头测试 表头测试
内容 内容 内容
内容 内容 内容

7.特殊符号

Markdown利用\字符来转义一些在语法中有特殊意义的符号。

推荐阅读

Markdown 语法说明 (简体中文版)
Markdown 语法手册

jQuery 动画与 AJAX

jQuery 中,$(document).ready()是什么意思?

当 DOM 准备就绪时,指定一个函数来执行。

虽然 JavaScript 提供了 load 事件,当页面呈现时用来执行这个事件,直到所有的东西,如图像已被完全接收前,此事件不会被触发。

在大多数情况下,只要 DOM 结构已完全加载时,脚本就可以运行。传递处理函数给.ready() 方法,能保证 DOM 准备好后就执行这个函数,因此,这里是进行所有其它事件绑定及运行其它 jQuery 代码的最佳地方。

如果执行的代码需要在元素被加载之后才能使用时,(例如,取得图片的大小需要在图片被加载完后才能知道),就需要将这样的代码放到 load 事件中。

下面两种语法全部是等价的:

  • $(document).ready(handler)
  • $(handler)

经常这么使用

$(function(){
    console.log('ready');
});

$node.html()$node.text() 的区别?

  • $node.html()

返回所有选择元素内的 HTML 内容,包含 html 标签和文本内容。

如果选择器匹配多个元素,那么只有第一个匹配元素的 HTML 内容会被获取。

  • $node.text()

返回所选择元素内的文本内容,包括他们的后代,不包含 html 标签。

eg:

<div class="wrapper">
  <p>1</p>
  <p>2</p>
  <p>3</p>
</div>

console.log($('.wrapper').html()) // <p>1</p>  <p>2</p>  <p>3</p>
console.log($('p').html()) // 1
console.log($('.wrapper').text()) // 1 2 3

$.extend 的作用和用法?

  • $.extend()可以将多个对象合并到一起,可以传入多个参数。
  1. 当我们提供两个或多个对象给$.extend(),对象的所有属性都添加到目标对象( target 参数)。

  2. 如果只有一个参数提供给$.extend(),这意味着目标参数被省略。在这种情况下, jQuery 对象本身被默认为目标对象。这样,我们可以在 jQuery 的命名空间下添加新的功能。这对于插件开发者希望向 jQuery 中添加新函数时是很有用的。

eg:

var obj1 = {a:1}
var obj2 = {b:2, c:3}
var obj3 = {b:3, d:5}
var obj4 = {}
$extend(obj1, obj2) // {a:1, b:2, c:3}
$extend(obj1, obj2, obj3) //{a:1, b:3, c:3, d:5}
$extend(obj4, obj1, obj2, obj3) //{a:1, b:3, c:3, d:5}  

var obj5 = $extend({}, obj1, obj2, obj3)  // {a:1, b:3, c:3, d:5}

jQuery 的链式调用是什么?

  • 分步骤的对 jQuery 对象使用方法后继续调用方法, 而不用再次选择 jQuery 对象。

  • 原理:通过对象上的方法最后 return this 把对象再返回回来,对象就可以继续调用方法。

  • 作用:使代码排版更清晰,便于查看执行流程。

eg:

$(#test).css('color', 'blue').show(400).fadeOut(200);

jQuery 中 data 函数的作用

作用

  • data()函数用于在当前 jQuery 对象所匹配的所有元素上存取数据。
  • 通过data()函数存取的数据都是临时数据,一旦页面刷新,之前存放的数据都将不复存在。
  • 该函数属于 jQuery 对象(实例); 如果需要移除通过data()函数存放的数据, 请使用removeData()函数。

用法

  1. .data(key, value)
  2. .data(key)

eg:

$("body").data("foo", 52);
$("body").data("bar", { myType: "test", count: 40 });
$("body").data({ baz: [ 1, 2, 3 ] });
 
$("body").data("foo"); // 52
$("body").data(); // { foo: 52, bar: { myType: "test", count: 40 }, baz: [ 1, 2, 3 ] }

写出以下功能对应的 jQuery 方法:

  • 给元素 $node 添加 class active,给元素 $node 删除 class active
$node.addClass('active');
$node.removeClass('active');
  • 展示元素$node, 隐藏元素$node
$node.show();
$node.hide();
  • 获取元素 $node 的 属性: idsrctitle, 修改以上属性
//获取属性
$node.attr('id')
$node.attr('src')
$node.attr('title')
//修改属性
$node.attr('id','newId')
$node.attr('src','newSrc')
$node.attr('title','newTitle')
  • $node 添加自定义属性 data-src
$node.attr('data-src', 'src')
  • $ct 内部最开头添加元素 $node
$ct.prepend($node)
//or
$node.prependTo($ct)
  • $ct 内部最末尾添加元素 $node
$ct.append($node)
//or
$node.appendTo($ct)
  • 删除 $node
$node.remove()
  • $ct 里内容清空
$ct.empty()
  • $ct 里设置 html <div class="btn"></div>
$ct.html('<div class="btn"></div>')
  • 获取、设置 $node 的宽度、高度(分别不包括内边距、包括内边距、包括边框、包括外边距)
//不包括内边距
$node.width();//获取宽度
$node.height();//获取高度
$node.width('100');//设置宽度,如果没有规定长度单位,默认 px
$node.height('200');//设置高度
$node.css({width:'100px',height:'300px'})//设置宽度、高度

//包括内边距
$node.innerWidth();//获取包括内边距的宽度
$node.innerHeight();//获取包括内边距的高度
$node.innerWidth('100');//设置包括内边距的宽度
$node.innerHeight('300');//设置包括内边距的高度

//包括边框
$node.outerWidth();//获取包括边框宽度
$node.outerHeight();//获取包括边框高度
$node.outerWidth('50');//设置包括边框宽度
$node.outerHeight('100');//设置包括边框高度

//包括外边距
$node.outerWidth(true);//获取包括外边距宽度
$node.outerHeight(true);//获取包括外边距高度
$node.outerWidth(60,true)//设置包括外边距宽度
$node.outerHeight(80,true)//设置包括外边距高度
  • 获取窗口滚动条垂直滚动距离
$(window).scrollTop()
  • 获取 $node 到根节点水平、垂直偏移距离
$node.offset().left
$node.offset().top
  • 修改 $node 的样式,字体颜色设置红色,字体大小设置 14 px
$node.css({
 'color': 'red',
 'font-size': '14px';
})
  • 遍历节点,把每个节点里面的文本内容重复一遍
$node.each(function(){
  let str = $(this).text();
  $(this).text(str + str);
})
  • $ct 里查找 class 为 .item 的子元素
$ct.find('.item')
  • 获取 $ct 里面的所有孩子
$ct.children()
  • 对于 $node,向上找到 class 为.ct的父亲,在从该父亲找到.panel的孩子
$node.parents('.ct').find('.panel')
  • 获取选择元素的数量
$node.length
  • 获取当前元素在兄弟中的排行
$node.index()

题目7:用jQuery实现以下操作

  • 当点击 $btn 时,让 $btn 的背景色变为红色再变为蓝色

预览链接

  • 当窗口滚动时,获取垂直滚动距离

预览链接

  • 当鼠标放置到 $div 上,把 $div 背景色改为红色,移出鼠标背景色变为白色

预览链接

  • 当鼠标激活 input 输入框时让输入框边框变为蓝色,当输入框内容改变时把输入框里的文字小写变为大写,当输入框失去焦点时去掉边框蓝色,控制台展示输入框里的文字

预览链接

  • 当选择 select 后,获取用户选择的内容

预览链接

题目8: 用 jQuery ajax 实现如下效果。`当点击加载更多会加载数据展示到页面效果预览467

预览链接

正则表达式

1: \d,\w,\s,[a-zA-Z0-9],\b,.,*,+,?,x{3},^,$分别是什么?

字符 含义
\d 数字字符
\w 单词字符,包括字母(小写、大写)、数字和下划线
\s 空白字符
[a-zA-Z0-9] 字母(小写、大写)、数字
\b 单词边界
. 除了回车符和换行符之外的所有字符
* 出现零次或多次(任意次)
+ 出现一次或多次(至少出现一次)
? 出现零次或一次(最多出现一次)
x{3} 出现3次
^ 以xxx开头
$ 以xxx结尾

2: 写一个函数trim(str),去除字符串两边的空白字符

function trim(str) {
  return str.replace(/^\s+|\s+$/g, '')
}

3: 写一个函数isEmail(str),判断用户输入的是不是邮箱

function isEmail(str){
  var reg = /^\w+@\w+[.]\w+$/;
  return reg.test(str);
}

4: 写一个函数isPhoneNum(str),判断用户输入的是不是手机号

function isPhoneNumber(str) {
  return /^1\d{10}$/.test(str)
}

5: 写一个函数isValidUsername(str),判断用户输入的是不是合法的用户名(长度6-20个字符,只能包括字母、数字、下划线)

function isValidUsername(str) {
  var reg = /^\w{6,20}$/
  return reg.test(str)
}

6: 写一个函数isValidPassword(str), 判断用户输入的是不是合法密码(长度6-20个字符,只包括大写字母、小写字母、数字、下划线,且至少至少包括两种)

function isValidPassword(str) {
  if(!/^\w{6,20}$/.test(str)) return false
  if(/^[a-z]{6,20}$/.test(str)) return false
  if(/^[A-Z]{6,20}$/.test(str)) return false
  if(/^\d{6,20}$/.test(str)) return false
  if(/^_{6,20}$/.test(str)) return false
  return true
}

7: 写一个正则表达式,得到如下字符串里所有的颜色

var subj = "color: #121212; background-color: #AA00ef; width: 12px; bad-colors: f#fddee "
var colorReg = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})(?=;)/g
console.log( subj.match(colorReg) )  // ['#121212', '#AA00ef']

8: 下面代码输出什么? 为什么? 改写代码,让其输出[""hunger"", ""world""].

var str = 'hello  "hunger" , hello "world"';
var pat =  /".*"/g;
str.match(pat);//[""hunger" , hello "world""]
//字符 . 的含义是除了回车符和换行符之外的所有字符。
//量词在默认下是尽可能多的匹配的,也就是贪婪模式。
//首先从 " 开始匹配 ,所以 " 之前的 'hello  并没有匹配到。
//然后匹配除了回车符和换行符之外的所有字符
//但是仍有剩余的正则需要匹配,即 " 
//因此正则开始倒回来回溯,换句话说,就是一个字符一个字符缩减匹配。
//回溯遇到的第一个字符就是 "
//所以最终匹配到的是 '"hunger" , hello "world"'

总结:在贪婪(默认)模式下,正则引擎尽可能多的重复匹配字符。

//改写
var str = 'hello  "hunger" , hello "world"';
var pat =  /".*?"/g;
//首先 " 被匹配上
//之后是重点:正则引擎尝试用最小可能的重复次数来进行匹配。
//因此在.匹配了 h 后,它立即尝试 " 的匹配
//但可惜下个字符是 u ,并没有匹配上
//所以继续向后面匹配,一直到 "hunger" 才匹配上了。
//又因为是global全局匹配的,所以匹配上了 "world"
str.match(pat);//[""hunger"", ""world""]

总结:在非贪婪模式下,正则引擎尽可能少的重复匹配字符。

推荐阅读

正则表达式贪婪与非贪婪模式

JS 数据类型&运算符&流程控制语句

JavaScript 定义了几种数据类型?

JavaScript 语言的每一个值,都属于某一种数据类型。JavaScript 的数据类型:

  • 数值(number):整数和小数(比如1和3.14)
  • 字符串(string):字符组成的文本(比如"Hello World")
  • 布尔值(boolean):true(真)和false(假)两个特定值
  • undefined:表示“未定义”或不存在,即此处目前没有任何值
  • null:表示空缺,即此处应该有一个值,但目前为空
  • 对象(object):各种值组成的集合
  • symbol

哪些是原始类型?哪些是复杂类型?原始类型和复杂类型的区别是什么?

  • 原始类型(primitive type)
    通常,我们将数值、字符串、布尔值称为原始类型(primitive type)的值,即它们是最基本的数据类型,不能再细分了。

  • 复杂类型(合成类型 complex type)
    将对象称为合成类型(complex type)的值,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。

  • 对象的细分

  1. 狭义的对象(object)
  2. 数组(array)
  3. 函数(function)
  4. 正则表达式 (regexp)

typeofinstanceof 的作用和区别?

首先,JavaScript 有三种方法,可以确定一个值到底是什么类型。

typeof 运算符
instanceof 运算符
Object.prototype.toString 方法
  • typeof 运算符

typeof运算符可以返回一个值的数据类型,可能有以下结果。

(1)原始类型

数值、字符串、布尔值分别返回numberstringboolean

typeof 123 // "number"
typeof '123' // "string"
typeof false // "boolean"

(2)函数

函数返回function

function f() {}
typeof f
// "function"

(3)undefined

undefined返回undefined

typeof undefined
// "undefined"

利用这一点,typeof可以用来检查一个没有声明的变量,而不报错。

v
// ReferenceError: v is not defined

typeof v
// "undefined"

上面代码中,变量v没有用var命令声明,直接使用就会报错。但是,放在typeof后面,就不报错了,而是返回undefined

实际编程中,这个特点通常用在判断语句。

// 错误的写法
if (v) {
  // ...
}
// ReferenceError: v is not defined

// 正确的写法
if (typeof v === "undefined") {
  // ...
}

(4)其他

除此以外,其他情况都返回object

typeof window // "object"
typeof {} // "object"
typeof [] // "object"
typeof null // "object"

那么这里就有个问题了,既然typeof对数组(array)和对象(object)的显示结果都是object,那么怎么区分它们呢?instanceof运算符可以做到。

  • instanceof 运算符

区分数组和对象

var o = {};
var a = [];

o instanceof Array // false
a instanceof Array // true

如何判断一个变量是否是数字、字符串、布尔、函数

  • 运用typeof来判断

eg:

typeof 123 // "number"
typeof '123' // "string"
typeof false // "boolean"

NaN 是什么? 有什么特别之处?

  • NaN含义是Not a Number,表示非数字,NaN和任何值都不相等,包括自己。

如何把非数值转化为数值?

有三个函数可以把非数值转换为数值

Number()
parseInt()
parseFloat()
  • 使用Number函数(强制转换),可以将任意类型的值转化成数值。Number函数将字符串转为数值,要比parseInt函数严格很多。基本上,只要有一个字符无法转成数值,整个字符串就会被转为NaN
  • parseInt方法用于将字符串转为整数。
  • parseFloat方法用于将一个字符串转为浮点数。

==与===有什么区别

  • ==近似相等,会将两边的值,转换成同一数据类型,再比较。
  • ===是严格意义上的相等,不会转换数据类型,数据类型不一样,会直接返回false 。(实际工作中尽量使用===)

breakcontinue 有什么区别

  • break 用于强制退出循环体,执行循环后面的语句
  • continue 用于退出本次循环,继续执行下次循环

void 0undefined 在使用场景上有什么区别

  • undefined可以在局部作用域中被覆写,而void运算返回都是undefined

以下代码的输出结果是?为什么?

console.log(1+1);  // 1 的类型为数值,所以做加法运算,结果为 2 。
console.log("2"+"4");  // "2""4" 的类型为字符串,所以将两个字符拼接起来,结果为 "24" 。
console.log(2+"4");  // 2 的类型为数值,"4" 的类型为字符串。所以会先将 2 的类型强制转换为字符串类型 "2",再与 4 拼接,结果为 "24" 。
console.log(+"4");  // 参数中只有字符串"4",会将字符串强制转化为数字 4,结果为 4 。
  • 总结:
    字符串的自动转换,主要发生在加法运算时。当一个值为字符串,另一个值为非字符串,则后者转为字符串。
    除了加法运算符有可能把运算子转为字符串,其他运算符都会把运算子自动转成数值。
    一元运算符也会把运算子转成数值。

以下代码的输出结果是?

var a = 1;  
a+++a;  // (a++)+a  首先是 (a++) 的运算:这里 (a++) 的值为 1 ,a 的值为 2 。那么 (a++)+a 的运算为 1+2 ,所以这里的结果为 3 。
typeof a+2;  // (typeof a)+2  首先是 (typeof a) 的运算:a 的值为 2,数据类型为 number,那么 (typeof a) 的结果为 number。 (typeof a)+2 的结果为 "number2" 。

以下代码的输出结果是? 为什么?

 var a = 1;
 var b = 3;
 console.log( a+++b );  //首先是 a+++b 的运算: (a++)+b 。 (a++) 的运算:a 的值为 2,但 (a++) 的值为 1。 所以 (a++)+b 的运算为 1+3 ,结果为 4

遍历数组,把数组里的打印数组每一项的平方

var arr = [3,4,5];
for (i=0;i<arr.length;i+=1) {
    console.log(arr[i]*arr[i]); //console.log(Math.pow(arr[i],2));
}

遍历 JSON, 打印里面的值

var obj = {
 name: 'hunger', 
 sex: 'male', 
 age: 28 
}
for (i in obj) {
  console.log(i,":",obj[i])
}

以下代码输出结果是? 为什么 ?

var a = 1, b = 2, c = 3;  //赋值
var val = typeof a + b || c >0  //"="的优先级最低,那么整体来看就是赋值。根据优先级,typeof a + b || c > 0 的运算:先进行(typeof a) + b的运算,结果为"number2";由于逻辑或的运算规则:如果第一个运算子的布尔值为 true ,则返回第一个运算子的值,且不再对第二个运算子求值;如果第一个运算子的布尔值为 false ,则返回第二个运算子的值。所以 typeof a + b || c >0 输出的结果为"number2" ;最后赋值给 val ;所以结果为"number2"。
console.log(val)   // "number2"
var d = 5;  //赋值
var data = d ==5 && console.log('bb')  // "="优先级最低,那么整体来看就是赋值。d ==5 && console.log('bb') 的运算:由于逻辑与的运算规则:如果第一个运算子的布尔值为 true,则返回第二个运算子的值(注意是值,不是布尔值);如果第一个运算子的布尔值为 false,则直接返回第一个运算子的值,且不再对第二个运算子求值。d==5 的值为 true;console.log('bb')的值为 undefined,所以 d ==5 && console.log('bb') 的值为 undefined;最后赋值给 data;所以结果为 undefined 。
console.log(data)  // undefined
var data2 = d = 0 || console.log('haha')  //整体为两次赋值。0 || console.log('haha')的运算:由于逻辑或,第一个运算子是 false,则返回第二个运算子的值,也就是 console.log('haha')的值  undefined,所以 undefined 赋值给 d,d 再 赋值给 data2,所以结果为 undefined 。
console.log(data2)  // undefined
var x = !!"Hello" + (!"world", !!"from here!!");  //整体来看为一次赋值。!!"Hello" + (!"world", !!"from here!!") 的运算: !!"Hello" 的值为 true;!"world" 的值为 flase, !!"from here!!" 的值为 true,而逗号运算符用于对两个表达式求值,并返回后一个表达式的值,所以 (!"world", !!"from here!!") 的值为 true;然后 true+true 的值为2,最后赋值给x。
console.log(x)  // 2

取反运算符形式上是一个感叹号,用于将布尔值变为相反值,即 true 变成 false,false 变成 true。
对于非布尔值的数据,取反运算符会自动将其转为布尔值。规则是,以下六个值取反后为 true,其他值取反后都为 false 。

undefined
null
false
0(包括+0和-0)
NaN
空字符串('')

浏览器兼容

什么是浏览器兼容问题?

同一份代码,有的浏览器效果正常,有的不正常

  • 不正常的原因是什么?(不支持? bug?)
  • 如何让它展示正常?(条件注释? 单独Hack?)

为什么会有浏览器兼容问题?

  • 同一产品,版本越老 bug 越多
  • 同一产品,版本越新,功能越多
  • 不同产品,不同标准,不同实现方式

什么是 CSS hack?

  • 由于不同厂商的浏览器,比如Internet Explorer,Safari,Mozilla Firefox,Chrome等,或者是同一厂商的浏览器的不同版本,如IE6和IE7,对CSS的解析认识不完全一样,因此会导致生成的页面效果不一样,得不到我们所需要的页面效果。
    这个时候我们就需要针对不同的浏览器去写不同的CSS,让它能在不同的浏览器中也能得到我们想要的页面效果。

谈一谈浏览器兼容的思路

要不要做

  • 产品的角度(产品的受众、受众的浏览器比例、效果优先还是基本功能优先)
  • 成本的角度 (有无必要做某件事)

做到什么程度

  • 让哪些浏览器支持哪些效果

如何做

渐进增强和优雅降级
渐进增强(progressive enhancement): 针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验
优雅降级 (graceful degradation): 一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。

stackoverflow-渐进增强和优雅降级的区别

#几种浏览器兼容的写法

  • 条件注释
    eg:
<!--[if IE 6]-->
<p>You are using Internet Explorer 6.</p>
<![endif]-->
  • CSS 属性前缀
    eg:
div{
            color:blue;
            *color:red; /*如果在IE6或者7中,字体颜色为红色,否则为蓝色*/
}
  • 选择器前缀(即选择器 Hack)
    eg:
div\9{
                color:yellow
}
  • 条件注释结合选择器
    eg:
<!DOCTYPE html>
    <!--[if IEMobile 7 ]> <html dir="ltr" lang="en-US"class="no-js iem7"> <![endif]-->
    <!--[if lt IE 7 ]> <html dir="ltr" lang="en-US" class="no-js ie6 oldie"> <![endif]-->
    <!--[if IE 7 ]> <html dir="ltr" lang="en-US" class="no-js ie7 oldie"> <![endif]-->
    <!--[if IE 8 ]> <html dir="ltr" lang="en-US" class="no-js ie8 oldie"> <![endif]-->
    <!--[if (gte IE 9)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html dir="ltr" lang="en-US" class="no-js"><!--<![endif]-->
  • Modernizr工具
<html class=" js no-flexbox canvas canvastext no-webgl no-touch geolocation 
         postmessage no-websqldatabase no-indexeddb hashchange no-history 
   draganddrop no-websockets rgba hsla multiplebgs backgroundsize 
   no-borderimage borderradius boxshadow no-textshadow opacity 
   no-cssanimations no-csscolumns no-cssgradients no-cssreflections
   csstransforms no-csstransforms3d no-csstransitions fontface 
   generatedcontent video audio localstorage sessionstorage 
   no-webworkers no-applicationcache svg inlinesvg smil svgclippaths">
  • 浏览器兼容写法
transition: transform 1s;
-moz-transition: transform 1s; /* Firefox 4 */
-webkit-transition: transform 1s; /* Safari 和 Chrome */
-o-transition: transform 1s; /* Opera */

常见属性的兼容情况

inline-block: >=ie8
min-width/min-height: >=ie8
:before,:after: >=ie8
div:hover: >=ie7
inline-block: >=ie8
background-size: >=ie9
圆角: >= ie9
阴影: >= ie9
动画/渐变: >= ie10

以下工具/名词是做什么的?

  • 条件注释

  • 条件注释 (conditional comment) 是于HTML源码中被IE有条件解释的语句。条件注释可被用来向IE提供及隐藏代码。
        <!--[if IE 6]>
        <p>You are using Internet Explorer 6.</p>
        <![endif]-->
        <!--[if !IE]><!-->
        <script>alert(1);</script>
        <!--<![endif]-->
        <!--[if IE 8]>
        <link href="ie8only.css" rel="stylesheet">
        <![endif]-->
  • 使用了条件注释的页面在 Windows Internet Explorer 9 中可正常工作,但在 Internet Explorer 10 中无法正常工作。
  • IE10不再支持条件注释
项目 范例 说明
[if !IE] 非IE
lt [if lt IE 5.5] 小于IE 5.5
lte [if lte IE 6] 小于等于IE6
gt [if gt IE 5] 大于 IE5
gte [if gte IE 7] 大于等于IE7
  • IE Hack

针对IE浏览器编写不同的CSS,使得在IE浏览器中也能得到我们想要的页面效果

  • js 能力检测

能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力。使用这种方式无需顾及浏览器如何如何,只需确定浏览器是否支持特定的能力,就可以给出相关的方案。

用于解决IE9以下版本浏览器对HTML5新增标签不识别,并导致CSS不起作用的问题,使用Javascript来使不支持HTML5的浏览器支持HTML标签。

让不支持 css3 Media Query 的浏览器包括 IE6-IE8 等其他浏览器支持查询。

早期的 CSS Reset 的作用就是清除所有浏览器默认样式,这样更易于保持各浏览器渲染的一致性。
这样暴力清零会带来一些问题,eg:

  1. *{ margin:0; padding:0; }会带来性能问题
  2. 使用通配符存在隐性问题
  3. 过渡的标签重置等于画蛇添足
  4. 过渡的标签重置导致语言元素失效

是一个可定制的 CSS 文件,使浏览器呈现的所有元素,更一致和符合现代标准;是在现代浏览器环境下对于CSS reset的替代。
该项目依赖于研究浏览器默认元素风格之间的差异,精确定位需要重置的样式。相比于传统的CSS Reset,Normalize.css是一种现代的、为HTML5准备的优质替代方案。Normalize.css现在已经被用于Twitter Bootstrap、HTML5 Boilerplate、GOV.UK、Rdio、CSS Tricks 以及许许多多其他框架、工具和网站上。
作用:

  1. 保护有用的浏览器默认样式而不是完全去掉它们
  2. 为大部分HTML元素提供一般化的样式
  3. 修复浏览器自身的bug并保证各浏览器的一致性
  4. 用一些小技巧优化CSS可用性
  5. 用注释和详细的文档来解释代码

一个 JavaScript 库,用于检测用户浏览器的 HTML5 与 CSS3 特性。Modernizr 会在页面加载后立即检测特性;然后创建一个包含检测结果的 JavaScript 对象,同时在 html 元素加入方便你调整 CSS 的 class 名。

PostCSS 是一个使用 JS 插件来转换 CSS 的工具。这些插件可以支持使用变量,混入(mixin),转换未来的 CSS 语法,内联图片等操作。

一般在哪个网站查询属性兼容性?

浮动 定位 BFC 边距合并

浮动元素有什么特征?对父容器、其他浮动元素、普通元素、文字分别有什么影响?

浮动元素是什么?

  • 浮动模型也是一种可视化格式模型,浮动的框可以左右移动(根据float属性值而定),直到它的外边缘碰到包含框或者另一个浮动元素的框的边缘。浮动元素不在文档的普通流中,文档的普通流中的元素表现的就像浮动元素不存在一样。

浮动元素的特征

  1. 不占据普通文档流的空间。
  2. 浮动元素的左(右)外边界不能超过其包含块的左(右)内边界。
  3. 浮动元素的左(右)外边界必须是源文档中之前出现的左浮动(右浮动)的元素的右(左)边界,除非后出现浮动元素的顶端在先出现浮动元素的底端下面。
  4. 左浮动元素的右外边界不会在其右边浮动元素的左外边界的右边。一个右浮动元素的左外边界不会在其左边任何左浮动元素的右外边界的左边。
  5. 一个浮动元素的顶端不能比其父元素的内顶端更高。
  6. 浮动元素的顶端不能比之前所有浮动元素或块级元素的顶端更高。
  7. 如果文档中一个浮动元素之前出现另一个元素,浮动元素的顶端不能比包含该元素所生成的框的任何行框的顶端更高。
  8. 如果浮动元素出现在另一个浮动元素的旁边,而因此可能导致超出包含块的话,这个浮动元素会向下浮动到之前浮动元素下面的某一点。
  9. 浮动元素必须尽可能高地放置。
  10. 左浮动元素必须向左尽可能远,右浮动元素必须向右尽可能远。
  11. inline 元素设置浮动,改变 inlinedisplay使得它像个block-level
  12. 在重叠上,浮动元素会遮盖block-level元素的背景,不会遮盖inline元素。

内边界:指盒模型中的content边界。外边界:指盒模型中的margin边界。

影响

  • 非BFC的正常文档流父元素会"感受"不到浮动元素的存在,从而产生"高度塌陷"。
  • 其他浮动元素会"察觉"到浮动元素的存在按照从左到右的"正常文档流"排列。
  • 普通元素(非inline-level)会无视浮动元素的存在,从而占据浮动元素的"原来的位置"。
  • 文字(也既inline-level)级的元素会环绕浮动元素,表现的像是察觉到浮动元素一样。

清除浮动指什么? 如何清除浮动?

  • 清除浮动指元素的侧边不允许出现浮动元素,从而使得浮动元素的不占据普通文档流空间的使得父元素的高度塌陷问题得到解决,主要通过clear属性实现。

  • clear:指定一个元素是否可以在它之前的浮动元素旁边,或者必须向下移动(清除浮动) 在它的下面。clear 属性适用于浮动和非浮动元素。

  • 当应用于非浮动块时,它将非浮动块的边框边界移动到所有相关浮动元素外边界的下方。这个行为作用时会导致margin collapsing不起作用。

  • 当应用于浮动元素时,它将元素的外边界移动到所有相关的浮动元素外边界的下方。这会影响后面浮动元素的布局,后面的浮动元素的位置无法高于它之前的元素。

方法:

  • 设置浮动包含块的父元素height
  • 使得含块的父元素变成 BFC
  • 通过添加:after伪元素,然后在伪元素上设置clear属性来实现

利用伪类:after清除 (推荐使用)

.clearfix{ *zoom:1; } /*兼容IE6、7 (现在基本上不用写这行了,基本淘汰了)*/    
.clearfix:after { 
    content:"";
    display: block;
    clear: both;
}

利用空标签清除

  • 在 HTML 中,在浮动元素的后面添加一个空的块标签,并设置clear属性
  • 缺点:会增加一个无意义的 HTML 标签

利用 BFC 清除浮动

  • 使用 css 属性为父元素创建新的 BFC,利用 BFC 可包含浮动元素的特性来清除浮动
  • 缺点:BFC 并不是专门用来清除浮动的,创建 BFC 时,还会有各种副作用。例如:float影响整体布局,overflow:hidden影响内容的展示等等

有几种定位方式,分别是如何实现定位的,参考点是什么,使用场景是什么?

  • inherit
    从父元素继承position属性的值
    一般不用
  • static默认值,没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)
  • relative
    生成相对定位的元素,相对于元素本身正常位置进行定位
    属性值:left, top,right ,bottom
    应用于对其自身进行细微调整
  • absolute
    生成绝对定位的元素,相对于static定位以外的第一个祖先元素(offset parent)进行定位
    属性值:left, top,right ,bottom
  • fixed
    生成绝对定位的元素,相对于浏览器窗口进行定位。
    属性值:left, top,right ,bottom
    需要一直停留在窗口的元素,例如
  • sticky
    兼容性较差,一般用 JS 实现
    新的 CSS3 属性,它的表现类似``position:relativeposition:fixed`的合体,目标区域在屏幕中可见时,它的行为就像`position:relative;` 而当页面滚动超出目标区域时,它的表现就像`position:fixed`,它会固定在目标位置。
    注意:如果同时定义了`left`和`right`值,且`width`和`height`有值,那么`left`生效,`right`无效。同样的,同时定义了`top`和`bottom`,`top`生效。

z-index 有什么作用? 如何使用?

  • z-index规定了元素在 Z 轴(距离用户远近)上的顺序,值越大则越靠近用户,表现就是元素在最上面。

  • z-index仅在设置了positionstatic属性的元素生效,且z-index的值只能在兄弟元素之间比较。

  • Z-index默认值为auto,则不建立层叠上下文。设置为 0 则会建立层叠上下文。

深入理解CSS中的层叠上下文和层叠顺序

position:relative和负margin都可以使元素位置发生偏移?二者有什么区别

  • position:relative相对自己原本的位置偏移,不影响其它普通流中元素的位置。
  • margin:除了让元素自身发生偏移还影响其它普通流中的元素。

BFC 是什么?如何生成 BFC?BFC 有什么作用?

BFC: 块格式化上下文 ( block formatting context 、Block Format Content ) 是 Web 页面的可视 CSS 渲染的一部分,是一种显示渲染规则。它是块盒子的布局发生及浮动体彼此交互的区域。

首先 BFC 是一个名词,是一个独立的布局环境,我们可以理解为一个箱子(实际上是看不见摸不着的),箱子里面物品的摆放是不受外界的影响的。

形成条件:

  • 根元素或其它包含它的元素
  • 浮动 (元素的 float 不是 none)
  • 绝对定位的元素 (元素具有 positionabsolutefixed)
  • 内联块 inline-block (元素具有 display: inline-block)
  • 表格单元格 (元素具有 display: table-cell,HTML 表格单元格默认属性)
  • 表格标题 (元素具有 display: table-caption, HTML 表格标题默认属性)
  • 块元素具有overflow ,且值不是 visible
  • display: flow-root

简而言之

  • 设置float:left|right
  • 设置overflow:hidden|auto|scroll
  • 设置display:inline-block|table-caption|table-cell
  • 设置position:absolute|fiexd
  • 上面都是比较常见的,也就是说,每次看到这些属性的时候,就代表了该元素已经创建了一个 BFC 了。

注意:浮动不会影响其它块格式化上下文中元素的布局,并且清除浮动只能清除同一块格式化上下文中在它前面的元素的浮动。

作用

  • “清除浮动”,这里其实说清除浮动已经不再合适,应该说包含浮动。也就是说只要父容器形成 BFC 就可以为父元素创建 BFC,可以让父元素包含子浮动元素
  • 解决外边距合并问题
  • 消除文字围绕float元素的效果

应用

  • 自适应的两栏布局。
  • 清除元素内部浮动。
  • 嵌套元素margin边距合并问题的解决。

在什么场景下会出现外边距合并?如何合并?如何不让相邻元素外边距合并?

场景

  • 同一个 BFC,且同处于普通流中的垂直相邻元素外边距合并。
  • 父子元素的外边距合并。
  • 空元素的外边距合并。

合并规则:

  • 两个margin都是正值的时候,取两者的最大值;
  • margin 都是负值的时候,取的是其中绝对值较大的,然后,从0位置,负向位移;
  • 当有正有负的时候,先取出负 margin 中绝对值中最大的,然后,和正 margin 值中最大的 margin 相加。
  • 所有毗邻的margin要一起参与运算,不能分步进行。

不让相邻元素外边距合并的方法:

  • 被非空内容、paddingborderclear 分隔开。
  • 不在一个普通流中或一个 BFC 中。
  • margin在垂直方向上不毗邻。

总结:

  • 这些margin都处于普通流中,并在同一个BFC中;
  • 这些margin没有被非空内容、padding、border 或 clear 分隔开;
  • 这些margin在垂直方向上是毗邻的,包括以下几种情况:
  1. 一个 box 的top margin与第一个子box的top margin
  2. 一个box的bottom margin与最后一个子box的bottom margin,但须在该box的heightauto的情况下
  3. 一个box的bottom margin与紧接着的下一个box的top margin
  4. 一个box的top margin与其自身的bottom margin,但须满足没创建BFC、零min-height、零或者“auto”的height、没有普通流的子元素。
  • 例外的情况
  1. 根元素的外边距不会参与折叠
  2. 不设置任何属性的空span和空div不影响任何布局,可以无视之。

参考

CSS 外边距合并

跨域

同源策略(Same origin Policy)

说起跨域,我们就要先了解一下同源策略。同源策略是针对浏览器的,不是针对 JS。

同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。

换句话说,浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。

本域

同协议:如都是http或者https
同域名:如都是http://github.com/ahttp://github.com/b
同端口:如都是80端口

http://harleywang93.com/为例
该 url 的协议为 http,域名是 harleywang93.com,端口为443,默认端口可以省略。

http://harleywang93.com/http://harleywang93.com/about (同源,协议、域名、端口都相同)
http://harleywang93.com/https://harleywang93.com (不同源,协议不同)
http://harleywang93.com/http://other.harleywang93.com (不同源,域名不同)
http://harleywang93.com/http://harleywang93.com:442 (不同源,端口不同)

需要注意的是: 对于当前页面来说页面存放的 JS 文件的域不重要,重要的是加载该 JS 页面所在什么域

那么,我就是想访问其他域(非同源)的资源 — 即跨域,该怎么做呢?

常见的跨域方法

  • JSONP
  • CORS
  • 降域
  • window.postMessage

JSONP(JSON Padding)

HTML 中 Script 通过 src 属性可以引入其他域下的 JS,比如引入线上的 jQuery库。也可以引入非 JS 的文件,利用这个特性,可实现跨域访问接口。该方法需要后端支持。

  1. 定义数据处理函数 _fun
  2. 创建 Script 标签,src 的地址执行后端接口,最后加个参数 callback=_fun
  3. 服务端在收到请求后,解析参数,计算返还数据,输出 fun(data) 字符串。
  4. fun(data)会放到 Script 标签做为 JS 执行。此时会调用 fun 函数,将 data 做为参数。

实现方式

//b.html
<ul>
  <li>十九大10月18日在北京召开 喜迎十九大</li>
  <li>***欢迎塔吉克斯坦总统 世界之问的**答案</li>
  <li>丁来杭中将履新空军司令员 接替马晓天上将</li>
</ul>
<button>换一组</button>
<script>
  var $ = function (str) {
    return document.querySelector(str);
  };
  $('button').addEventListener('click', function () {
    var script = document.createElement('script');
    script.src = 'http://a.jrg.com:8080/getNews?callback=fn';
    document.head.appendChild(script);
    document.head.removeChild(script);
  });

  var fn = function (news) {
    for(var i=0; i<3; i++)
      $('ul>li').remove();
    for(var i=0; i<news.length; i++){
      var li = document.createElement('li');
      li.innerText = news[i];
      $('ul').appendChild(li);
    }
  };
</script>
//router.js
app.get('/getNews', function (req, res) {
    var news = [
        '**公民在美购敏感材料获刑3年 疑遭钓鱼执法',
        '十九大10月18日在北京召开 喜迎十九大',
        '***欢迎塔吉克斯坦总统 世界之问的**答案',
        '丁来杭中将履新空军司令员 接替马晓天上将',
        '上海警察"一招擒拿"抱娃妇女摔落孩子 已被停职',
        '技校学生拳击玻璃致身亡 家属抬棺材堵校门',
        '女博士被人推下几十级台阶 男子自首称"想听尖叫"'
    ];

    var data = [];
    for(var i=0; i<3; i++){
        var index = parseInt(Math.random()*news.length);
        data.push(news[index]);
        news.splice(index, 1);
    }

    var cb = req.query.callback;
    if(cb)
        res.send(cb + '(' + JSON.stringify(data) + ')');
    else
        res.send(data);
});

CORS(Cross-Origin Resource Sharing)

CORS 全称是跨域资源共享(Cross-Origin Resource Sharing),是一种 ajax 跨域请求资源的方式,支持现代浏览器,IE支持10以上。 实现方式很简单,当你使用 XMLHttpRequest 发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin; 浏览器判断该相应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。所以 CORS 的表象是让你觉得它与同源的 ajax 请求没啥区别,代码完全一样。

CORS 有简单请求和复杂请求之分

  • 简单请求
    比如发送了一个 origin 的头部
    Origin : http://www.nczonline.net
    如果服务器认为这个请求可以接受,就在Access-Control-Allow-Origin头部回发相同的源信息
    Access-Control-Allow-Origin : http://www.nczonline.net

  • 复杂请求
    复杂请求是那种对服务器有特殊要求的请求,比如请求方法是 PUT 或 DELETE ,或者Content-Type 字段的类型是 application/json 。
    复杂请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为“预检”请求(preflight)。
    浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest 请求,否则就报错。

实现方式

//a.html
<ul>
  <li>十九大10月18日在北京召开 喜迎十九大</li>
  <li>***欢迎塔吉克斯坦总统 世界之问的**答案</li>
  <li>丁来杭中将履新空军司令员 接替马晓天上将</li>
</ul>
<button>换一组</button>
<script>
    var $ = function (str) {
        return document.querySelector(str);
    };
    $('button').addEventListener('click', function () {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            if(xhr.readyState === 4 && xhr.status === 200)
                fn(JSON.parse(xhr.responseText));
        };
        xhr.open('get', 'http://b.jrg.com:8080/getNews', true);
        xhr.send();
    });
    var fn = function (news) {
        for(var i=0; i<3; i++)
            $('ul>li').remove();
        for(var i=0; i<news.length; i++){
            var li = document.createElement('li');
            li.innerText = news[i];
            $('ul').appendChild(li);
        }
    };
</script>
//router.js
app.get('/getNews', function (req, res) {
    var news = [
        '**公民在美购敏感材料获刑3年 疑遭钓鱼执法',
        '十九大10月18日在北京召开 喜迎十九大',
        '***欢迎塔吉克斯坦总统 世界之问的**答案',
        '丁来杭中将履新空军司令员 接替马晓天上将',
        '上海警察"一招擒拿"抱娃妇女摔落孩子 已被停职',
        '技校学生拳击玻璃致身亡 家属抬棺材堵校门',
        '女博士被人推下几十级台阶 男子自首称"想听尖叫"'
    ];

    var data = [];
    for(var i=0; i<3; i++){
        var index = parseInt(Math.random()*news.length);
        data.push(news[index]);
        news.splice(index, 1);
    }

    res.header('Access-Control-Allow-Origin', 'http://a.jrg.com:8080');
    res.send(data);
});

降域

当两个页面不同域,但是它们的父域之上都相同(端口),那么可以使用降域的方法来实现跨域。
对于主域相同而子域不同的情况下,可以通过设置 document.domain 的办法来解决,
具体做法是可以在 url 为 a.github.com:8080 下的 a.htmlb.github.com:8080 下的 b.html 两个文件分别加上 document.domain = “github.com”;然后通过 a.html 文件创建一个 iframe,去控制 iframewindow,从而进行交互,当然这种方法只能解决主域相同、而二级域名不同的情况。

实现方式

//a.html
<input type="text">
<iframe src="http://b.jrg.com:8080/b.html" frameborder="0"></iframe>
<script>
    var $ = function (str) {
        return document.querySelector(str);
    };
    $('input').addEventListener('input', function () {
        window.frames[0].$('input').value = this.value;
    });

    document.domain = 'jrg.com';
</script>
//b.html
<input type="text">
<script>
    var $ = function (str) {
        return document.querySelector(str);
    };
    $('input').addEventListener('input',function () {
        window.parent.$('input').value = this.value;
    });
    document.domain = 'jrg.com';
</script>

window.postMessage

window.postMessage 是一个安全的跨源通信的方法。一般情况下,当且仅当执行脚本的页面使用相同的协议(通常都是 http )、相同的端口( http 默认使用80端口)和相同的 host(两个页面的 document.domain 的值相同)时,才允许不同页面上的脚本互相访问。 window.postMessage 提供了一个可控的机制来安全地绕过这一限制,当其在正确使用的情况下。

window.postMessage 解决的不是浏览器与服务器之间的交互,解决的是浏览器不同的窗口之间的通信问题,可以做的就是同步两个网页,当然这两个网页应该是属于同一个基础域名。

实现方式

//a.html
<input type="text">
<iframe src="http://b.jrg.com:8080/b.html" frameborder="0"></iframe>
<script>
    var $ = function (str) {
        return document.querySelector(str);
    };
    $('input').addEventListener('input', function () {
        window.frames[0].postMessage(this.value, 'http://b.jrg.com:8080');
    });
</script>
//b.html
<input type="text">
<script>
    var $ = function (str) {
        return document.querySelector(str);
    };
    window.addEventListener('message',function (e) {
        $('input').value = e.data;
    });
</script>

推荐阅读

关于跨域,你想知道的全在这里
阮一峰 - CORS通信
跨域解决方案大全
Web开发中跨域的几种解决方案

CSS 常见样式

块级元素和行内元素分别有哪些?动手测试并列出4条以上的特性区别

  • 块级(block-level)

div h1 h2 h3 h4 h5 h6 p hr
form ul dl ol pre table
li dd dt tr td th
  • 行内(内联、inline-level)

em strong span a br img 
button input label select textarea
code script 
  • 区别:

  1. 行内元素和 inline-block 元素水平方向上默认情况下是按基线对齐。

  2. 行内元素和 inline-block 元素默认是不占据一行,块级元素默认占据一行。

  3. 行内元素的高度是由 line-height 来决定,宽度由具体的内容来决定,设置 heightwidth 无效。

  4. 行内元素设置上下 margin , padding , border 不占据空间。

  5. 行内元素的上下 padding , border 存在颜色,则颜色会显示。

  6. 行内元素可以"感受"到浮动元素的存在。

  7. 内外边距
    image

  • padding

padding代表内边距,有四个方向的值,可以合写,值可以是数值也可以是百分比(相对于父容器、不是自身)

  • padding-top
  • padding-right
  • padding-bottom
  • padding-left
padding: 20px; /* padding: 20px 20px 20px 20px; */
padding: 10px 20px; /* padding: 10px 20px 10px 20px; */
padding: 10px 20px 30px; /* padding: 10px 20px 30px 20px; */
  • margin

margin 代表外边距,有四个方向的值,可以合写,值可以是数值也可以是百分比(相对于父容器、不是自身)。还可以是负值

  • 外边距合并问题
  • margin-top
  • margin-right
  • margin-bottom
  • margin-left
margin: 20px; /* margin: 20px 20px 20px 20px; */
margin: 10px 20px; /* margin: 10px 20px 10px 20px; */
margin: 10px 20px 30px; /* margin: 10px 20px 30px 20px; */
  • margin: 0 auto

对于块级元素,设置 margin: 0 auto 可达到居中目的

.box {
  /* margin: 0 auto; 实际上是下面两个起作用 */
  margin-left: auto;
  margin-right: auto;
}
  • *
    去除元素默认样式 margin padding
*{
margin: 0;
padding: 0;
}

什么是 CSS 继承? 哪些属性能继承,哪些不能?

  • css继承:继承就是子标签继承了上级标签的CSS样式的属性。
  • 不可继承的:display、margin、border、padding、background、height、min-height、max-height、width、min-width、max-width、overflow、position、left、right、top、bottom、z-index、float、clear、table-layout、vertical-align、page-break-after、page-bread-before和unicode-bidi
  • 所有元素可继承:visibilitycursor
  • 内联元素可继承:letter-spacing、word-spacing、white-space、line-height、color、font、font-family、font-size、font-style、font-variant、font-weight、text-decoration、text-transform、direction
  • 终端块状元素可继承:text-indenttext-align
  • 列表元素可继承:list-style、list-style-type、list-style-position、list-style-image
  • 表格元素可继承:border-collapse

如何让块级元素水平居中?如何让行内元素水平居中?

  • margin:0 atuto; 块级元素
  • text-align:center; 行内元素 (text-align:center; 仅作用在块级元素上,所以 text-align:center; 这个属性应该设置在行内元素的block级父元素上)

用 CSS 实现一个三角形

.tri{
  width: 0px;
  height: 0px;
  border-top: 20px solid transparent;
  border-right: 20px solid transparent;
  border-bottom:20px solid transparent;
  border-left: 20px solid red;
}

or

width: 0;
height: 0;
border: 50px solid transparent;
border-bottom: 100px solid #000000;

triangle

单行文本溢出加 ...如何实现?

E{
  white-space: nowrap;/*不折行*/
  overflow: hidden;/*超出部分隐藏*/
  text-overflow: ellipsis;/*显示省略符号(ellipsis)代表隐藏部分的文本*/
}
  • white-space: nowrap; overflow: hidden; text-overflow: ellipsis;三者缺一不可

pxemrem 有什么区别?

  • px 在缩放页面时无法调整那些使用它作为单位的字体、按钮等的大小。
  • em 的值并不是固定的,会继承父级元素的字体大小,代表倍数。
  • rem 的值并不是固定的,始终是基于根元素 (HTML) 的,也代表倍数。

解释下面代码的作用?为什么要加引号?字体里\5b8b\4f53代表什么?

  font: 12px/1.5 tahoma,arial,'Hiragino Sans GB','\5b8b\4f53',sans-serif;
  • 设置字体大小12px,字体行高1.5,字体先看浏览器或者服务器上有没有tohoma,有则设置为tohoma;如果没有,再看浏览器或者服务器上有没有arial,以此类推。
  • 加引号的原因是:有空格,不加引号会被识别成两个元素。
  • \5b8b\4f53 是使用 Unicode 编码的字体名,\5b8b 为Unicode的“宋”,\4f53 为Unicode的“体”,所以这个编码就是指“宋体”。
  • 在 CSS 中设置字体时,直接写字体中文或英文名称浏览器都能识别,直接写中文的情况下编码(GB2312、UTF-8 等)不匹配时会产生乱码。保险的方式是将字体名称用Unicode来表示。
  • 对应字体的 Unicode 不记得时,打开控制台 escape('微软雅黑'),把 %u替换成 \就是对应字体的Unicode

推荐阅读

chrome 默认字体大小16px, 兼容小于最小字体 12px 的解决方案
字体的原理

jQuery

题目1: jQuery 能做什么?

  • 选择网页元素
  • 改变结果集
  • 元素的操作:取值和赋值
  • 元素的操作:移动
  • 元素的操作:复制、删除和创建
  • 工具方法
  • 事件操作
  • 特殊效果
  • AJAX

题目2: jQuery 对象和 DOM 原生对象有什么区别?如何转化?

区别:

jQuery 对象和 DOM 原生对象是两种不同的对象类型,两者不等价。

jQuery 无法使用 DOM 对象的任何方法,同理 DOM 对象也不能使用jQuery 里的方法。

转化:

DOM 原生对象转化为 jQuery 对象:

$(document.querySelector('.div1'))

jQuery对象转化为DOM原生对象:

$('.div1>li')[index]

题目3:jQuery 中如何绑定事件?bind、unbind、delegate、live、on、off 都有什么作用?推荐使用哪种?使用 on 绑定事件使用事件代理的写法?

jQuery 中如何绑定事件?

在1.7之前的版本中 jQuery 处理事件有多个方法,( google 搜索: jQuery live bind degelate)作用各不相同,后来统一的使用 on/off 方法。

bind、unbind、delegate、live、on、off 都有什么作用?推荐使用哪种?

bind(type,[data],fn)

为每个匹配元素的特定事件绑定事件处理函数。jQuery 3.0 已弃用。

unbind(type,[data|fn]])

bind()的反向操作,从每一个匹配的元素中删除绑定的事件。jQuery 3.0 已弃用。

delegate(selector,[type],[data],fn)

指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数。jQuery 3.0已弃用。

live(type, [data], fn)

jQuery 给所有匹配的元素附加一个事件处理函数,即使这个元素是以后再添加进来的也有效。这个方法是基本是的 .bind() 方法的一个变体。

on(events,[selector],[data],fn)

在选择元素上绑定一个或多个事件的事件处理函数。

off(events,[selector],[fn])

在选择元素上移除一个或多个事件的事件处理函数。

  • 推荐使用 on 和 off 来进行事件的处理。

使用 on 绑定事件使用事件代理的写法?

绑定事件使用事件代理的写法举例:

<div class="box">
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
</div>
<input id="ipt" type="text"> <button id="btn">添加</button>
<div id="wrap">
</div>

<script>
$('.box li').on('click', function(){
    console.log(1)
  var str = $(this).text()
  $('#wrap').text(str)
})

//等同于
$('.box>ul>li').click(function(){
    console.log(2)
  var str = $(this).text()
  $('#wrap').text(str)
})

//也可以这样写
$('.box li').on('click.hello', function(){
    console.log(3)
  var str = $(this).text()
  $('#wrap').text(str)
})
//命名空间没什么特别的作用,只不过在解绑事件时便于区分绑定的事件
$('.box li').off('click.hello')

//可是用如下方法新增的元素是没绑定事件的
$('#btn').on('click', function(){
  var value = $('#ipt').val()
  $('.box>ul').append('<li>'+value+'</li>')
})

//我们可以用事件代理
$('.box ul').on('click', 'li', function(){
  var str = $(this).text()
  $('#wrap').text(str)
})

//上面代码相当于原生 js 的
document.querySelector('.box ul').addEventListener('click', function(e){
    if(e.target.tagName.toLowerCase() === 'li'){
        //do something
    }
})

//绑定事件的时候我们也可以给事件附带些数据,只不过这种用法很少见
$('.box').on('click', {name: 'hunger'}, function(e){
    console.log(e.data)
})

题目4:jQuery 如何 展示/隐藏 元素?

  • .hide 用于隐藏元素,没有参数的时候等同于直接设置 display 属性。
  • .show 用于显示元素,用法和 hide 类似。
  • .toggle 用来切换元素的隐藏、显示,类似于 toggleClass ,用法和 show、hide 类似。

举例:

//HTML
<div id="box"></div>
<button id="button 1">hide</button>
<button id="button 2">show</button>
<button id="button 3">toggle</button>

//jQuery 
$("#button 1").on("click",function(){
  $(".box").hide()
})

$("#button 2").on("click",function(){
  $(".box").show()
})

$("#button 3").on("click",function(){
  $(".box").toggle()
})

题目5: jQuery 动画如何使用?

http://js.jirengu.com/ranun#

题目6:如何设置和获取元素内部 HTML 内容?如何设置和获取元素内部文本?

$('div').html();//不传参则获取 HTML 内容

$('div').html('<p>hello</p>');//传参则改变元素内部 HTML 内容为所传参数

$('div').text();//不传参则获取元素内部的文字信息

$('div').text('hello');//元素内部文字信息设置为 'hello'

题目7:如何设置和获取表单用户输入或者选择的内容?如何设置和获取元素属性?

$('input').val(); // 获取
$('input').val('想要设置的内容')
$(selector).attr('id'); // 获取元素属性
$(selector).attr('id', '设置的元素属性值');

题目8:使用 jQuery实现如下效果

http://js.jirengu.com/xumek

题目9:使用 jQuery 实现如下效果

http://js.jirengu.com/bamap

题目10:实现如下效果

http://js.jirengu.com/xuwaw

题目11:左右切换的 Tab 效果

http://js.jirengu.com/bibas

编码规范

命名技巧

语义化

  • 语义化标签优先
  • 基于功能命名、基于内容命名、基于表现命名
  • 简略、明了、无后患

HTML规范:

  • 用两个空格来代替制表符(tab)
  • 嵌套元素应当缩进一次(即两个空格)
  • 对于属性的定义,确保全部使用双引号,绝不要使用单引号
  • 不要在自闭合(self-closing)元素的尾部添加斜线 -- HTML5-规范中明确说明这是可选的。
  • 不要省略可选的结束标签(closing tag)
  • 遵循 HTML 标准和语义,减少标签的数量,尽量避免多余的父元素。

CSS规范:

  • 用两个空格来代替制表符(tab)--这是唯一能保证在所有环境下获得一致展现的方法。
  • 为了代码的易读性,在每个声明块的左花括号前添加一个空格。
  • 换行,声明块的右花括号应当单独成行。
  • 每条声明语句的 : 后应该插入一个空格。
  • 所有声明语句都应当以分号结尾。
  • 对于属性值或颜色参数,省略小于 1 的小数前面的 0(例如,.5 代替 0.5-.5px 代替 -0.5px)。
  • 十六进制值应该全部小写,并采用简写形式,例如#fff
  • 为选择器中的属性添加双引号,例如input[type="text"]
  • 避免为 0 值指定单位,例如,用 margin: 0;代替margin: 0px;
  • 使用简写形式的属性声明,例如margin:15px 16px;代替margin: 15px 16px 15px 16px;

常见命名

.wrap.wrapper -- 用于外侧包裹
.container.ct -- 包裹容器
.header -- 用于头部
.body -- 页面 body
.footer -- 页面尾部
asidesidebar -- 用于侧边栏
.content -- 和header footer 对应,用于主要内容
.navigation -- 导航元素
.pagination -- 分页
.tabs > .tab -- tab 切换
.breadcrumbs -- 导航列表、面包屑
.dropdown -- 下拉菜单
.article -- 文章
.main -- 用于主体
.thumbnail -- 头像,小图像
.media -- 媒体资源
.panel -- 面板
.tooltip -- 鼠标放置上去的提示
.popup -- 鼠标点击弹出的提示
.button.btn -- 按钮
.ad -- 广告
.subnav -- 二级导航
.menu -- 菜单
.tag -- 标签
.message或者.notice -- 提示消息
.summary -- 摘要
.logo -- logo
.search -- 搜索框
.login -- 登录
.register -- 注册
.username -- 用户名
.password -- 密码
.banner -- 广告条
.copyright -- 版权
.modal或者 .dialog -- 弹窗

var 名字 = {
  状态: [
    'inverse',
    'toggled',
    'switched',
    'original',
    'initial',
    'identified',
    'disabled',
    'loading',
    'pending',
    'syncing',
    'default'
  ],
  修饰: [
    'dark',
    'light',
    'shaded',
    'flat',
    'ghost',
    'maroon',
    'pale',
    'intense',
    'twisted',
    'narrow',
    'wide',
    'smooth',
    'separate',
    'clean',
    'sharp',
    'aligned'
  ],
  元素: [
    'pagination',
    'modal',
    'popup',
    'article',
    'story',
    'flash',
    'status',
    'state',
    'media',
    'block',
    'card',
    'teaser',
    'badge',
    'label',
    'sheet',
    'poster',
    'notice',
    'record',
    'entry',
    'item',
    'figure',
    'square',
    'module',
    'bar',
    'button',
    'action',
    'knob'
  ],
  布局: [
    'navigation',
    'wrapper',
    'inner',
    'header',
    'footer',
    'aside',
    'section',
    'divider',
    'content',
    'container',
    'panel',
    'pane',
    'construct',
    'composition',
    'spacing',
    'frame'
  ]
}

推荐阅读

google html css编码规范
bootstrap 编码规范
命名这货真难

CSS 选择器

classid 的使用场景?

  1. class 重在样式的复用,重普遍性。
  2. id 重在划分样式区域,可以作为样式表中的命名空间来管理样式。
  3. id 也可以指定某一个特殊元素的样式,重特殊性。

注意:在 HTML 中声明多个一样的 ID 的元素,在 CSS 中该 ID 的样式,这些元素则都会生效。而在 JavaScript 中用 DOM 选择器只会选到第一个元素。

CSS 选择器常见的有几种?

  • 基础选择器

选择器 含义
* 通用元素选择器,匹配页面任何元素(这也就决定了我们很少使用)
#id id选择器,匹配特定id的元素
.class 类选择器,匹配class包含(不是等于)特定类的元素
element 标签选择器
  • 组合选择器

选择器 含义
E,F 多元素选择器,用,分隔,同时匹配元素E或元素F
E F 后代选择器,用空格分隔,匹配E元素所有的后代(不只是子元素、子元素向下递归)元素F
E>F 子元素选择器,用>分隔,匹配E元素的所有直接子元素
E+F 直接相邻选择器,匹配E元素之后的相邻的同级元素F
E~F 普通相邻选择器(弟弟选择器),匹配E元素之后的同级元素F(无论直接相邻与否)
.class1.class2 id和class选择器和选择器连写的时候中间没有分隔符,. 和 # 本身充当分隔符的元素
element#id id和class选择器和选择器连写的时候中间没有分隔符,. 和 # 本身充当分隔符的元素
  • 属性选择器

选择器 含义
E[attr] 匹配所有具有属性attr的元素,div[id]就能取到所有有id属性的div
E[attr = value] 匹配属性attr值为value的元素,div[id=test],匹配id=test的div
E[attr ~= value] 匹配所有属性attr具有多个空格分隔、其中一个值等于value的元素
E[attr ^= value] 匹配属性attr的值以value开头的元素
E[attr $= value] 匹配属性attr的值以value结尾的元素
E[attr *= value] 匹配属性attr的值包含value的元素
  • 伪类选择器

选择器 含义
E:first-child 匹配作为长子(第一个子女)的元素E
E:link 匹配所有未被点击的链接
E:visited 匹配所有已被点击的链接
E:active 匹配鼠标已经其上按下、还没有释放的E元素
E:hover 匹配鼠标悬停其上的E元素
E:focus 匹配获得当前焦点的E元素
E:lang(c) 匹配lang属性等于c的E元素
E:enabled 匹配表单中可用的元素
E:disabled 匹配表单中禁用的元素
E:checked 匹配表单中被选中的radio或checkbox元素
E::selection 匹配用户当前选中的元素
E:root 匹配文档的根元素,对于HTML文档,就是HTML元素
E:nth-child(n) 匹配其父元素的第n个子元素,第一个编号为1
E:nth-last-child(n) 匹配其父元素的倒数第n个子元素,第一个编号为1
E:nth-of-type(n) 与:nth-child()作用类似,但是仅匹配使用同种标签的元素
E:nth-last-of-type(n) 与:nth-last-child() 作用类似,但是仅匹配使用同种标签的元素
E:last-child 匹配父元素的最后一个子元素,等同于:nth-last-child(1)
E:first-of-type 匹配父元素下使用同种标签的第一个子元素,等同于:nth-of-type(1)
E:last-of-type 匹配父元素下使用同种标签的最后一个子元素,等同于:nth-last-of-type(1)
E:only-child 匹配父元素下仅有的一个子元素,等同于:first-child:last-child或 :nth-child(1):nth-last-child(1)
E:only-of-type 匹配父元素下使用同种标签的唯一一个子元素,等同于:first-of-type:last-of-type或 :nth-of-type(1):nth-last-of-type(1)
E:empty 匹配一个不包含任何子元素的元素,文本节点也被看作子元素
E:not(selector) 匹配不符合当前选择器的任何元素
  • N的取值

  • 1,2,3,4,5

  • 2n+1, 2n, 4n-1

  • odd, even

  • 伪元素选择器

选择器 含义
E::first-line 匹配E元素内容的第一行
E::first-letter 匹配E元素内容的第一个字母
E::before 在E元素之前插入生成的内容
E::after 在E元素之后插入生成的内容

选择器的优先级是怎样的?对于复杂场景如何计算优先级?

  1. 在属性后面使用 !important 会覆盖页面内任何位置定义的元素样式
  2. 作为style属性写在元素标签上的内联样式
  3. id选择器
  4. 类选择器
  5. 伪类选择器
  6. 属性选择器
  7. 标签选择器
  8. 通配符选择器
  9. 浏览器自定义
  • 复杂场景如何计算优先级?

  • 复杂场景

  #test p.class1 {...}
  #test .class1.class2 {...}
  • 行内样式 <div style="xxx"></div> ==> a

  • ID 选择器 ==> b

  • 类,属性选择器和伪类选择器 ==> c

  • 标签选择器、伪元素 ==> d

  • 小测试

*             {}  /* a=0 b=0 c=0 d=0 -> 0,0,0,0 */
p             {}  /* a=0 b=0 c=0 d=1 -> 0,0,0,1 */
a:hover       {}  /* a=0 b=0 c=0 d=2 -> 0,0,0,2 */
ul li         {}  /* a=0 b=0 c=0 d=2 -> 0,0,0,2 */
ul ol+li      {}  /* a=0 b=0 c=0 d=3 -> 0,0,0,3 */
h1+input[type=hidden]{}  /* a=0 b=0 c=1 d=2 -> 0,0,1,1 */
ul ol li.active   {}  /* a=0 b=0 c=1 d=3 -> 0,0,1,3 */
#ct .box p        {}  /* a=0 b=1 c=1 d=1 -> 0,1,1,1 */
div#header:after  {}  /* a=0 b=1 c=0 d=2 -> 0,1,0,2 */
style=""          /* a=1 b=0 c=0 d=0 -> 1,0,0,0 */
  • 先比较a值的大小,a值大的则优先级高;如果a值相等,则再比较b值的大小,b值大的优先级高;如果b值相等,则比较c值的大小,c值大的优先级高;如果c值相等,则比较d值的大小,d值大的优先级高。

样式覆盖

div {color: #333;}
  ....
  div {color: #666;}
  • 这样div文案的颜色明显会是#666

选择器使用经验

  • 遵守 CSS 书写规范
  • 使用合适的命名空间
  • 合理的复用class

a:link, a:hover, a:active, a:visited 的顺序是怎样的? 为什么?

a:link
a:visited
a:hover
a:active
  • :link 代表为访问链接的样式,所以只要你是超链接,且未被访问过,则链接都会按照你设定的样式显示,所以它的位置顺序无所谓。
  • :visited 代表链接访问后的样式,则链接一旦被访问,则之后它的样式就会是你所设置的 visited 样式
  • :active 选择器用于选择活动链接。当您在一个链接上点击时,它就会成为活动的(激活的)。
  • :hover 代表的是你光标经过某一元素时的样式,如果将此样式放在 :active 之后,则当链接激活时,显示 :active 样式,当光标经过此链接时,会显示 hover 的样式,因为 hover 排在后,会覆盖 active 样式。如果 :hover 排在前,:active 排在后,则当光标激活时显示 :active 的样式,但当光标经过链接时,样式并未显示:hover的样式,而是:active 的样式,因为应用的active样式在hover之后,覆盖了前面的样式。
  • 简而言之,当选择器优先级相同时,后定义的会覆盖先定义的。
    因为a:visited在链接访问过一次之后永久生效,如果放在最后会覆盖掉其他的样式,a:hovera:active 就会被覆盖,不会再产生它们的预期效果。

以下选择器分别是什么意思?

   #header{
   } /* id为header的css样式 */
   .header{
   }/* class为header的css样式 */
   .header .logo{
   }/* class为header的元素后代中所有class为logo的元素的css样式 */
   .header.mobile{
   }/* class包含header和mobile的元素的css样式 */
   .header p, .header h3{
   }/* class为header的元素后代中p元素和h3元素的css样式 */
   #header .nav>li{
   }/* id为header元素后代中有class为nav的元素的直接子元素li的css样式 */
   #header a:hover{
   }/* id为header元素的后代中a元素的状态为鼠标悬停其上的css样式 */
   #header .logo~p{
   }/* id为header元素的所有后代元素中,class为logo的元素之后的所有同级元素p的css样式 */
   #header input[type="text"]{
   }/* id为header元素的所有后代元素中,所有type="text"的input标签的css样式 */

div:first-childdiv:first-of-typediv :first-childdiv :first-of-type的作用和区别 (注意空格的作用)

  • div:first-child 匹配父元素下,作为第一个子元素的div元素
  • div:first-of-type 匹配父元素的子元素中,第一个div元素
  • div :first-child 匹配所有div元素内所有元素中属于其父元素的首个子元素
  • div :first-of-type 匹配所有div元素内所有元素中属于其父元素的首个类型的子元素

运行如下代码,解析下输出样式的原因。

<style>
.item1:first-child{
  color: red;
}
.item1:first-of-type{
  background: blue;
}
</style>
 <div class="ct">
   <p class="item1">aa</p>
   <h3 class="item1">bb</h3>
   <h3 class="item1">ccc</h3>
 </div>
  • aa字体为红色: .item1:first-child 匹配元素class包含item1的第一个子元素 aa,所以为颜色变为红色
  • aa bb的背景色为蓝色: .item1:first-of-type 匹配的是class包含item1其父元素下相同类型子元素中的第一个,所以第一个p 第一个h3变蓝

引用类型 对象拷贝

引用类型有哪些?非引用类型有哪些?

  • 基本类型值(非引用类型)(数值、布尔值、null和undefined):指的是保存在栈内存中的简单数据段;
  • 引用类型值(对象、数组、函数、正则):指的是那些保存在堆内存中的对象,变量中保存的实际上只是一个指针,这个指针执行内存中的另一个位置,由该位置保存对象

如下代码输出什么?为什么?

var obj1 = {a:1, b:2};
var obj2 = {a:1, b:2};
console.log(obj1 == obj2); //false 因为 obj1 和 obj2 所指向的地址不相等
console.log(obj1 = obj2); //Object {a: 1, b: 2} 因为 obj2  把地址赋值给了 obj1
console.log(obj1 == obj2); //true 因为现在 obj1 和 obj2 指向的是同一个地址

如下代码输出什么? 为什么?

var a = 1
var b = 2
var c = { name: '饥人谷', age: 2 }
var d = [a, b, c]

var aa = a
var bb = b
var cc = c
var dd = d

a = 11
b = 22
c.name = 'hello'
d[2]['age'] = 3

console.log(aa) //1 因为 a 和 aa 为基本类型值-数值,赋值给 a 并不会影响 aa
console.log(bb) //2 因为 b 和 bb 为基本类型值-数值,赋值给 b 并不会影响 bb
console.log(cc) // Object {name: "hello", age: 3} 首先 name:"hello" 是因为 c 的地址赋值给了 cc ,c 和 cc 的地址为同一个地址; age:3 是因为 d[2]['age'] = 3 中,3 赋值给了 c 中的 age 。
console.log(dd) // [1,2,{name: "hello", age: 3}] 原因结合上面几点可以得出

如下代码输出什么? 为什么?

var a = 1
var c = { name: 'jirengu', age: 2 }

function f1(n){
  ++n
}
function f2(obj){
  ++obj.age
}

f1(a) // a 和 n 都为基本类型值。把 a 赋值给 n 进行运算,不会影响 a 的值。
f2(c) // c 为引用类型值。把 c 的地址赋值给了 obj ,c 和 obj 都指向同一个地址。所以运算后 c = { name: 'jirengu', age: 3 } 。
f1(c.age) // c.age 是基本类型值。把 c.age 赋值给 n 进行运算,不会影响 c.age 的值。
console.log(a) // 1
console.log(c) // Object {name: "jirengu", age: 3}

过滤如下数组,只保留正数,直接在原数组上操作

var arr = [3,1,0,-1,-3,2,-5]
function filter(arr){
    for (var i = 0; i < arr.length; i++){
        if (arr[i] <= 0) {
            arr.splice(i,1);
            i--;
        }
    }
}
filter(arr)
console.log(arr) // [3,1,2]

过滤如下数组,只保留正数,原数组不变,生成新数组

var arr = [3,1,0,-1,-3,2,-5]
function filter(arr){
    var arr2 = [];
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] > 0) {
            arr2.push(arr[i]);
        }
    }
    return arr2;
}
var arr2 = filter(arr)
console.log(arr2) // [3,1,2]
console.log(arr)  // [3,1,0,-1,-2,2,-5]

写一个深拷贝函数,用两种方式实现

function deepcopy(obj){
    var newObj={};
    for (var key in obj){
        if(obj.hasOwnProperty(key)){
            if(typeof obj[key] === 'number' || typeof obj[key] === 'string' ||  
                typeof obj[key] === 'boolean' ||typeof obj[key] === 'string' || obj[key] === udefinded || 
                obj[key] === null ){
                newObj[key]=obj[key]; 
            }else{
                newobj[key]=copy(obj[key]);
            }
        }
    }
    return newObj;
}
function deepCopy(obj) {
    var newObj = JSON.parse(JSON.stringify(obj));
    return newObj;
}

HTML

什么是 HTML?

  • 超文本标记语言(HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言。
  • HTML是一种基础技术,常与 CSS、JavaScript 一起被众多网站用于设计令人赏心悦目的网页、网页应用程序以及移动应用程序的用户界面。
  • 网页浏览器可以读取 HTML 文件,并将其渲染成可视化网页。
  • HTML 的发展
年份 版本
1997.1 HTML 3.2
1997.12 HTML 4.0
1999.12 HTML 4.01
2014.10 HTML 5

HTML、XML、XHTML 有什么区别?

  • HTML是超文本标记语言(Hyper Text Markup Language),是语法较为松散的、不严格的Web语言。比如大小写混写,编码不规范。
  • XML是可扩展标记语言(The Extensible Markup Language),主要用于存储数据和结构,重点是什么是数据,如何存放数据。XML 没有预定义的标签,是一种允许用户对自己的标记语言进行定义的源语言。
  • XHTML是可扩展超文本标记语言(Extensible Hyper Text Markup Language),基于XML,作用与HTML类似,但语法更严格。

HTML 语义化的理解

  • 语义化HTML是一种编写HTML的方式
  • 选择合适的标签、使用合理的代码结构,便于开发者阅读,同时让浏览器的爬虫和机器很好地解析。

表现(内容)、样式、行为分离原则的理解

HTML 指的是内容结构;CSS 指的是样式;JavaScript 指的是行为。

  • 写 HTML 的时候先不管样式,,重点放在 HTML 的结构和语义化上,让 HTML 能体现页面结构或者说内容,之后再去写样式。
  • HTML 内不允许出现属性样式,尽量不要出现行内样式。
  • 写 JS 的时候,尽量不要用 JS 去直接操作样式,而是通过给元素添加删除 class 来控制样式变化。

网页乱码的问题是如何产生的?怎样解决?

首先认识几种编码方式

  • ASCII
    American Standard Code for Information Interchange(美国信息交换代码),是基于拉丁字母的一套电脑编码系统,为美国英语通信所设计。它由128个字符组成,包括大小写字母、数字0-9、标点符号、非打印字符(换行符、制表符等4个)以及控制字符(退格、响铃等)组成,每个字符占7位(1字节是8位)。它主要用于显示现代英语,而其扩展版本EASCII则可以部分支持其他西欧语言,并等同于国际标准ISO/IEC 646。
  • ISO Latin-1
    ISO/IEC 8859-1,正式编号为ISO/IEC 8859-1:1998,又称Latin-1或“西欧语言”,是国际标准化组织内ISO/IEC 8859的第一个8位字符集。它以ASCII为基础,加入96个字母及符号,藉以供使用附加符号的拉丁字母语言使用。可以认为ASCII是美国发明针对英语设计的,但欧洲人在用的时候出现了问题。对于一些特殊的拉丁字符,比如法文德文里某些字符,ASCII字符集就不包括。于是欧洲人发明了一种8位字符集是ISO 8859-1 Latin 1,也简称为ISO Latin-1。它对ASCII做了个扩充,对于0-127之间的字符还使用ASCII里的字符不变, 把位于128-255之间的字符(也就是空置的0xA0-0xFF的范围内的字符)表示拉丁字母表中特殊语言字符。
  • Unicode
    Unicode(中文:万国码、国际码、统一码、单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)。
  • UTF-8
    UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,也是一种前缀码。它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部分修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或发送文字的应用中,优先采用的编码。
  • GBK
    汉字内码扩展规范,称GBK,全名为《汉字内码扩展规范(GBK)》1.0版。用2个字节来表示一个汉字,总共可以覆盖2万多个文字。英文保留和UTF-8同样的方式使用一个字节来表示。
  • UNICODE只是给字符一个代号,而GBK和UTF-8使用不同的规则来表示同一个代号。

网页乱码的问题是如何产生的?

我们使用编辑器进行编辑后保存的的编码格式和浏览器的解码格式不匹配,从而产生乱码。(即使编码方式和解码方式不一致,纯粹的英文也不会出现乱码问题。因为utf-8、gbk对英文都是采用1个字节的编码方式,并且使用了相同的码字。)

网页乱码的问题怎样解决?

直接告知浏览器通过指定的方式解码。如果文件保存为utf-8格式,那么一定要在html的<head>里添加<meta charset="utf-8">。同理,如果文件保存为gbk格式,一定要在文件里添加<meta charset="gbk">

颜色有几种写法,红色、绿色、蓝色、白色、黑色如何表示?透明黑色如何表示?#ccc的颜色,#eee的颜色?#333的颜色?

  • 颜色有几种写法?

    • 色彩关键字
      使用名称来表述颜色,例如 red, blue, brown, lightseagreen等
    • rgb()
      • 十六进制符号 #RRGGBB 和 #RGB
        三位数的RGB符号(#RGB)和六位数的形式(#RRGGBB)是相等的。例如,#f03 和 #ff0033 代表同样的颜色。
      • 函数符 rgb(R,G,B)
        rgb后跟3个<integer>(整数)或3个<percentage>(百分比)值。
        整数255相当于100%,和十六进制符号里的 F 或 FF 。
    • hsl()
      Hue-saturation-lightness(色相-饱和度-明度)模式。
      • 色相(H)表示色环(即代表彩虹的一个圆环)的一个角度。这个角度作为一个无单位的 <number>(整数)给出。定义 red=0=360,其它颜色分散于圆环,所以 green=120, blue=240,以此类推。作为一个角度,它隐含像 -120=240 和 480=120 这样的回环。
      • 饱和度(s)和明度(l)由百分数来表示。
        100% 是满饱和度,而 0% 是一种灰度。
        100% 明度是白色, 0% 明度是黑色,而 50% 明度是“一般的”。
    • rgba() & hsla()
      rgba & hsla 扩展了 rgb & hsl 的颜色模式。在 rgb & hsl 基础上增加了阿尔法通道来设定颜色的透明度。
      a 表示透明度(a取值0~1):0=透明;1=不透明
  • 红色、绿色、蓝色、白色、黑色如何表示?

颜色 色彩关键字 rgb hsl
红色 red rgb(255,0,0)        #FF0000 hsl(0,100%,50%)
绿色 green rgb(0,255,0)        #00FF00 hsl(120,100%,25%)
蓝色 blue rgb(0,0,255)        #0000FF hsl(240,100%,50%)
白色 white rgb(255,255,255)    #FFFFFF hsl(0,0%,100%)
黑色 black rgb(0,0,0)          #000000 hsl(0,0%,0%)
  • 透明黑色如何表示?
颜色 rgba hsla
透明黑色 rgb(0%,0%,0%,0.6) hsl(0,0%,0%,0.6)

此透明黑色的alpha值(透明度)为0.6,也就是为40%的透明。

  • #ccc#eee#333的颜色?
    • #ccc表示浅灰色
    • #eee表示灰色
    • #333表示深灰色

<!doctype html>的作用是什么?

文档声明,让浏览器按w3c所规定的html5标准渲染这个页面。

严格模式和混杂模式指什么?

  • 严格模式是指在编辑时有声明<!doctype>,浏览器进行解码时,按照此声明的规范来呈现页面。
  • 混杂模式是指在编辑时没有声明<!doctype>,浏览器按照自己的默认方式解码来呈现页面。

meta有什么作用,常见的值有哪些?

  • meta的定义和用法

<meta>元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词。
<meta>标签位于文档的头部,不包含任何内容。<meta>标签的属性定义了与文档相关联的名称/值对。

  • <meta>是用来在HTML文档中模拟HTTP协议的响应头报文,它提供用户不可见的信息。<meta>标签用于网页的<head></head>中。
  • <meta>标签的用处很多
    • 通常用来为搜索引擎robots定义页面主题,或者是定义用户浏览器上的cookie;
    • 它可以用于鉴别作者,设定页面格式,标注内容提要和关键字;
    • 还可以设置页面使其可以根据你定义的时间间隔刷新自己,以及设置RASC内容等级,等等。
  • <meta>常见的属性和值
    必需的属性和值
属性 描述
content some_text 定义与http-equivname属性相关的元信息

    可选的属性和值

属性 描述
http-equiv content-type
expires
refresh
set-cookie
content属性关联到 HTTP 头部
name author
description
keywords
generator
revised
others
content属性关联到一个名称
scheme some_text 定义用于翻译content属性值的格式

<meta http-equiv="X-UA-compatible"content="IE=edge,chrome=1"有什么作用?

强制浏览器按照最新的标准去渲染,而chrome=1将允许站点在使用了谷歌浏览器内嵌框架(Chrome Frame)的客户端渲染,对于没有使用的,则没有任何影响。

X-UA-Compatible是针对 IE8 版本的一个特殊文件头标记,用于为 IE8 指定不同的页面渲染模式,对于ie8之外的浏览器是不识别的。

常见的浏览器有哪些,什么内核?

浏览器 内核
Chrome WebKit(Chromium)>Blink
Safari WebKit
IE Trident
Firefox Gecko
Opera Presto>WebKit(Chromium)>Blink
360、QQ Webkit+Trident

常见的标签

  • h1~h6

标题

h1代表页面最大的标题
h2二级标题
h3... 更弱的标题

  • p

段落,表示大段文字

  • a

链接,链到一个地址

<a href="http://github.com" target="_blank" title="Github">github.com</a>
<a href="#">github.com</a>
<a href="#about">github.com</a>
<a href="/getCourse">github.com</a>
  • img

展示一张图片

<img src="a.png" alt="头像">
只闭合标签,最后不需要加 /
  • div

语义为“一大块”,用于给页面划分区块,让结构更清晰

<div id="header">...</div>
<div id="content">...</div>
<div id="footer">...</div>
  • ul li

ul: unsort list 无序列表
用于表示并列的内容
ul的直接子元素是li
可以嵌套

<ul class="nav">
  <li><a href="#">首页</a></li>
  <li><a href="#">关于</a></li>
  <li>
    <a href="#">更多</a>
    <ul>
      <li>联系</li>
      <li>地址</li>
    </ul>
  </li>
</ul>
  • ol li

ol: order list 有序序列表 用于表示带步骤或者编号的并列内容 ol的直接子元素只能是li 可以嵌套

<h2>把大象关到冰箱的步骤</h2>
<ol>
  <li>把大象变小</li>
  <li>打开冰箱</li>
  <li>把大象塞进去</li>
</ol>
  • dl dt dd

用于展示一系列 “标题:内容... ”的场景

<dl>
  <dt>商品名称:</dt>
  <dd>青花瓷</dd>
  <dt>特征:</dt>
  <dd>白色</dd>
  <dd>圆口</dd>
  <dt>商品介绍</dt>
  <dd>这是一个年代久远的瓷器,很贵,易碎</dd>
</dl>
  • button

按钮

<button>点我</button>

  • strong em

em 需要强调一下
strong 很重要、强调性更强

<p>优惠 <strong>100</strong> 元</p>
<p>WHV <em>成功</em> 了</p>
  • iframe

用于嵌入一个页面 注意跨域操作问题

<iframe src="http://jirengu.com" name="myPage"></iframe>
<p><a href="http://www.w3cschool.cc" target="myPage">W3Cschool.cc</a></p>
  • table

用于展示表格,不要用来做布局 thead tbody tfoot可省略,浏览器会自动添加 border-collapse: collapse;用于合并边框

<table>
  <thead>
    <tr>
      <th>姓名</th>
      <th>年纪</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>姓名</th>
      <th>年纪</th>
    </tr>
    <tr>
      <td>小明</td>
      <td>18</td>
    </tr>
    <tr>
      <td>小花</td>
      <td>20</td>
    </tr>  
  </tbody>
  <tfoot></tfoot>
</table>

<table>
  <tr>
    <th>姓名</th>
    <th>年纪</th>
  </tr>
  <tr>
    <td>小明</td>
    <td>18</td>
  </tr>
  <tr>
    <td>小花</td>
    <td>20</td>
  </tr>
</table>

注意

  • 标签属性全小写
  • 标签要闭合、自闭合标签可以省略 /
  • 标题里不能有段落,段落里不能有标题

轮播

轮播的实现原理,抽象的函数(or 接口)。

原理(简述)

  1. 多个图片横向排列,两边末端各加一张障眼法图,该图和原图列首端相同。
  2. 视窗宽高只够容纳一张图片,设置overflow: hidden隐藏其他不可见图。
  3. 滑动到图片前端或末端障眼法图时自动跳到首端或者末端,达到欺骗效果。

原理(详述)

  • CSS
  1. 首先父容器相对定位,设置宽高(确定轮播框大小),设置overflow: hidden隐藏其他图片。
  2. img 容器绝对定位,方便确定位置(不要限制死容器宽高,否则增加图片数量还需要修改 CSS ),设置overflow: hidden形成 BFC,防止因浮动产生高度坍塌。
  3. img 容器内部为多个包含 a 链接(方便跳转链接)和 img 的 li 元素,给 img 设置好宽高,li 元素左浮,横向排成一排,左右轮播键和底部按键都可使用绝对定位。
  • JS
  1. 通过移动 img 容器的位置来展现不同的图片,达到切换效果。

具体实现:

在 img 容器中,clone 最后一个元素至第一张图片的前面,clone 第一个元素至最后一张图片的后面,通过计算
(imgCount+2) * imgWidth 得到 img 容器的宽度,imgCount为初始 li 元素的个数。

先确定好第一张展示图片的位置为$imgWrapper.css({left: -imgWidth}),当图片左右切换,img 容器位置左右加减。当移动到 clone 的首图片时,立即跳转到原来的尾图片,设置 CSS 属性$imgWrapper.css({left: -imgWidth})。当运动到 clone 尾图片时,立即跳转到原来的首图片 $imgCt.css({left: -imgCount*imgWidth}),从而达到无限左右滚动效果,CSS 属性切换在人眼看来是连贯的,达到欺骗效果。

  1. 另外需要在展示不同图片的时候,知道这是第几张,设置标记位,第一张标记位为 0,后面累加。最后一张为imgCount-1,通过不同的标记位 img 容器移动对应的位置,实现跳转图片。
  • 抽象出的函数或接口
  1. 自动播放: autoPlay()
  2. 向左切换: playPre();
  3. 向右切换: playNext();
  4. 索引播放(底部导航按钮切换效果): playIndex();

实现左右滚动无限循环轮播效果

预览链接

实现渐变轮播效果, 效果范例

预览链接

CSS 常见样式2

text-align: center的作用是什么,作用在什么元素上?能让什么元素水平居中?

text-align CSS 属性定义行内内容(例如文字)如何相对它的块父元素对齐,text-align并不控制块元素自己的对齐,只控制它的行内内容的对齐。

  1. text-align:center的意思是块级元素中的行内内容居中。
  2. 作用在block-level元素上(包括了blockinline-block)
  3. 能让block-level的元素中的行内元素,替换元素和inline-block元素居中。

IE 盒模型和W3C盒模型有什么区别?

  • W3C 标准中paddingborder所占的空间不在widthheight范围内,大家俗称的 IE 的盒模型width包括content尺寸+paddingborder

img

*{ box-sizing: border-box;}的作用是什么?

把所有元素的盒模型设置为width,height包括content尺寸 + padding + border

  • box-sizing: content-box:w3c标准盒模型(默认)
  • box-sizing: border-box:“IE盒模型”的效果
  • 很多时候,我们使用 w3c 标准盒模型时,需要仔细计算borderpaddingcontent。我们可以使用box-sizing:border-box;达到 IE 盒模型的效果,可以省略很多计算。

line-height: 2line-height: 200%有什么区别?

  • 计算标准:line-height: 2根据自身元素的字体大小来计算,会较为美观。line-height: 200%根据父元素的字体大小来计算。
  • 继承:line-height: 2继承给子元素的是2这个缩放因子。line-height: 200%继承给子元素的是200%计算后的值,比如父元素的行高为1px,那么所有子元素都继承为2px,子元素的字体大小不一样时行高也都为2px,这样会导致或宽或窄,不好看甚至影响阅读。

inline-block有什么特性?如何去除缝隙?高度不一样的inline-block元素如何顶端对齐?

特性:

  1. 默认不占据一行。
  2. 设置的上下padding、margin、border占据文档空间。
  3. 水平排列按照base-line对齐,且元素之间会存在一个'空'元素的缝隙。
  4. 可以用vertical-align设置垂直对齐。
  5. 可以设置text-align属性有效。
  6. 会形成一个BFC(块级格式化上下文)。

总结:一个拥有正常盒模型的行内元素

  • 既呈现 inline 特性(不占据一整行,宽度由内容宽度决定)
  • 又呈现 block 特性 (可设置宽高,内外边距)

去除缝隙:

  1. 修改 HTML 不换行 (三行代码写成一行,让 HTML 元素之间没有间隔)

eg:

<li>按钮</li>
<li>按钮</li>
<li>按钮</li>

写成

<li>按钮</li><li>按钮</li><li>按钮</li>
  1. inline-block的父元素设置font-size:0,再给设置了inline-block的元素重新设置font-size就可以了。

  2. 设置负margin

  3. 元素设置浮动

高度不一样的inline-block元素如何顶端对齐

  • inline-block元素设置为vertical-align:top;

CSS sprite 是什么?

CSS 精灵图(CSS 雪碧图)

  • 原理:把多个小icon合成一个大的图片,使用的时候,元素以这张合成后的大图为背景,通过设置background-position的属性来获取指定icon。

  • 优点:合并原来图片的请求,减少http的性能消耗。

  • 缺点:CSS sprite不能太大,不然下载图片的时间会过长。

  • 应用:

  1. 制作一张网页的图标。
  2. 制作动画。

潜伏题:

域名发散和域名收敛

让一个元素"看不见"有几种方式?有什么区别?

常规:

display:none;
visibility:hidden;
opacity:0;

其他(以下消失都是有前提条件的):

height:0;width:0;padding:0;margin:0;border:0; ... etc
position:absolute; left:1000000px; top:100000px; ...etc;
z-index:-1000;...etc
background-color:rgba(0,0,0,0);

总结: 元素"看不见"的方式主要方式让元素用户在当前页面展示的视口里看不见。

区别:

  1. display:none;从文档流消失,不占据文档空间,但是还存在DOM树中。
  2. visibility:hidden;和opacity:0;还是会占据文档空间。
  3. display:none;和visibility:hidden;绑定的事件不会触发。
  4. opacity:0;的元素绑定的事件还是会触发事件。

潜伏题: jQuery 是如何实现获取一个元素的正常宽高的。

懒加载

如何判断一个元素是否出现在窗口可视范围(浏览器的上边缘和下边缘之间,肉眼可视)。写一个函数 isVisible 实现

function isVisible($node) {
  var scrollTop = $(window).scrollTop()//滚动高度
  var windowHeight = $(window).height()//窗口高度
  var offsetTop = $node.offset().top

  if(offset < scrollTop + windowHeight && offsetTop > scrollTop) {
  	return true
  }
  return false
}

当窗口滚动时,判断一个元素是不是出现在窗口可视范围。每次出现都在控制台打印 true 。用代码实现

lazyLoad()

$(window).on('scroll',function(){
  console.log('true')
  lazyLoad()
})

function lazyLoad(){
  $('.ct img').each(function(){
  	if(isVisible($(this)) && !isLoaded($(this)) ){
  	  loadImg($(this))
  	}
  })
}

当窗口滚动时,判断一个元素是不是出现在窗口可视范围。在元素第一次出现时在控制台打印 true,以后再次出现不做任何处理。用代码实现

lazyLoad()

var clock

$(window).on('scroll',function(){
  if(clock){
  	clearTimeout(clock)
  }
  clock = setTimeout(function(){
  	console.log('true')
  	lazyLoad()
  }, 300)
})

function lazyLoad(){
  $('.ct img').each(function(){
  	if(isVisible($(this)) && !isLoaded($(this)) ){
  	  loadImg($(this))
  	}
  })
}

图片懒加载的原理是什么?

如果一个页面中有大量的图片(比如电商网站),打开页面后一次性全部加载完的话,流量消耗巨大,而且打开速度很慢,甚至卡死。

图片懒加载就是用来解决这些问题,提升用户体验。

实现原理

  • 对于所有的img标签,把真实的地址放入自定义属性data-src
<img src="/static/loading.gif" data-src="http://真正的图片地址/xxx.jpg">

<img src="xxx">可以为空,但在一些浏览器中会显示x的符号,影响体验。所以可以用空白图片或者加载动画代替。

  • 当滚动页面时,检查页面所有的img标签,看看这个标签是否出现到我们的视野中或者说出现在屏幕中,之后再去判断它是否已经加载过,如果没有加载过,就利用 jQuery 把<img>src属性替换为data-src的内容,浏览器就会实时加载。

实现视频中的图片懒加载效果

预览地址

AJAX

AJAX 是什么?有什么作用?

  • AJAX(Asynchronous JavaScript and XML) 通过原生的 XMLHttpRequest 对象发出 HTTP 请求,得到服务器返回的数据后,再进行处理。
  • 简单来说,AJAX 就是用 JS 向服务端发起一个请求,并获取服务器返回的内容。
  • 想要用 JS 发起一个请求很简单,一共 4 步。
  1. 创建一个对象
var request = new XMLHttpRequest()
  1. 监听请求成功后的状态变化
request.onreadystatechange = function() {
  if (this.readyState == 4 && this.status == 200) {
    console.log(request.responseText)
  }
};

第三行的 request.responseText 就是服务器返回的内容了(默认是字符串)

  1. 设置请求参数
request.open("GET", "filename", true);
  1. 发送请求
request.send();

这 4 步看起来是有些复杂的,不要紧,jQuery.ajax 对这 4 步进行了封装,只需要一步就可以了:

$.get('filename').then(function(response){
  // 这里的 response 就是返回的内容
})

AJAX 的作用

更好的用户体验(不用刷新页面,或者说只需要刷新部分页面)

前后端开发联调需要注意哪些事情?后端接口完成前如何 mock 数据?

  • 前后端开发时需要注意:
  1. 约定接口类型(GET 还是 POST)、名字(传递到那个路由)
  2. 前端传递给后端的参数(参数的类型、格式)
  3. 后端返回数据的格式(是数组还是字符串还是 JSON 格式)
  • 后端接口完成之前,前端可以根据接口文档,模拟后端数据验证所写页面的响应和接口是否正常。
  • 搭建 node.js 环境,使用 server-mock 模拟前后端数据传输
  • 也可以使用 XAMPP 等集成软件使用 PHP 写一些后端程序来 mock 数据。

点击按钮,使用 ajax 获取数据,如何在数据到来之前防止重复点击?

  • 如果用户网速慢,数据响应缓慢,用户希望得到数据,很可能会重复点击,重复点击会请求多次 AJAX,而且一直请求一块区域的内容。这就导致加载过来的数据很多,而且重复。
  • 解决思路:阻止用户的重复点击。第一次点击时请求的数据还没到之前,其他的点击操作无效,被忽略。
  • 设计一个状态锁,实时监看响应数据的情况,默认为已经有响应。
  • 当点击按钮时,判断请求是不是响应了。如果没有响应,不会做任何操作。
//状态锁伪代码
var lock = false;
btn.addEventListener("click",function(){
  if(lock){
    return; //如果没有收到数据 就不往下执行
  }else{
    lock = true;
    ajax({
      ....
      lock = false; //收到响应之后才把 false 赋值给 lock
    })
   }
});

实现加载更多的功能,效果范例377,后端在本地使用server-mock来模拟数据

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>加载更多</title>
  <style>
    .ct{
      list-style: none;
      padding: 0;
    }
    .ct li{
      margin-bottom: 10px;
      border: 1px solid;
      cursor: pointer;
      height: 38px;
      padding-top: 10px;
    }
    .ct li:hover{
      background: green;
      color:white;
    }
    .button {
      display: block;
      width: 100px;
      height: 40px;
      line-height: 40px;
      margin: 0 auto;
      border: 1px solid red;
      text-align: center;
      text-decoration: none;
      color: red;

    }
  </style>
</head>
<body>
  <ul class="ct">
    <li>内容1</li>
    <li>内容2</li>
  </ul>
  <a href="#" class="button">加载更多</a>
  <script>
    var button = document.querySelector('.button')
    var content = document.querySelector('.ct')
    var xhr = new XMLHttpRequest()
    var index = 2
    var sendEnd = false
    button.addEventListener('click', function (e) {
      e.preventDefault()
      if (sendEnd){
        return
      }
      xhr.onreadystatechange = function () {
        if(xhr.readyState === 4 && (xhr.status == 200||xhr.status == 304)){
          //获取数据
          var data = JSON.parse(xhr.responseText)
          var fragment = document.createDocumentFragment()
          for (var i in data){
            //创建元素
            var li = document.createElement('li')
            //将内容放入元素
            li.innerText = data[i]
            fragment.appendChild(li)
          }
          content.appendChild(fragment)
          sendEnd = false
        }
      }

      xhr.open('get', '/loadMore?index=' + index + '&length=5', true)
      xhr.send()
      sendEnd = true
      index += 5

    })
  </script>
</body>
</html>

//  router.js
app.get('/loadMore', function(req, res) {
  var curIdx = req.query.index;
  var len = req.query.length;
  var data = [];

  for(var i = 0; i < len; i++) {
    data.push('新闻' + (parseInt(curIdx) + i))
  }
  res.send(data);
});

推荐阅读

AJAX 是什么?
AJAX-阮一峰
你真的会使用XMLHttpRequest吗?
怎样防止重复发送 Ajax 请求?

Hexo + GitHub (Coding) Pages 搭建博客

前言

喜欢写 Blog 的人,会经历三个阶段。

第一阶段,刚接触 Blog,觉得很新鲜,试着选择一个免费空间来写。
第二阶段,发现免费空间限制太多,就自己购买域名和空间,搭建独立博客。
第三阶段,觉得独立博客的管理太麻烦,最好在保留控制权的前提下,让别人来管,自己只负责写文章。

这是阮一峰在博客中写到的关于 Blog 的想法,而这里的第三阶段的实现就是利用 GitHub Pages 搭建博客。

使用 GitHub Pages 功能搭建博客的好处有:

  • 免费,GitHub 提供无限流量。
  • 都是静态文件,世界各地都有理想的访问速度。(访问速度可以进一步优化)
  • 拥有绝对的管理权,又享受 Git 的版本管理功能,不用担心文章遗失。

Hexo 是基于 Node.js 的一款静态博客框架,如果想要搭建博客,不想自己写页面的话可以考虑用 Hexo,其中有很多的简洁主题可供选择,同时 Hexo 支持 Markdown 语法,编辑文章更加方便,快捷。

注:此篇分享以 Mac 为例

环境配置

Hexo 文档有对 Hexo 安装及使用的详细介绍,推荐阅读。这里我主要写自己安装的步骤、踩过的坑以及一些优化的方法。

在正式安装 Hexo 之前,我们需要确认电脑中是否已安装下列应用程序:

当然,我们还需要 GitHub 账号,如果没有请注册
注册之后记得一定要前往邮箱确认注册,否则无法使用 GitHub Pages。

安装 Hexo

所有必备的应用程序安装完成后,即可使用 npm 安装 Hexo。终端输入如下命令:

sudo npm install -g hexo-cli

输入管理员密码( Mac 登录密码)即开始安装。

这里有个小坑:Hexo 官网上的安装命令是npm install -g hexo-cli,安装时不要忘记前面加上sudo,否则会因为权限问题报错。

初始化

使用终端cd到一个您指定的目录,执行以下命令(命令中的blog是您将要建立的文件夹的名称):

hexo init blog

使用终端cdblog文件夹下,执行以下命令,安装npm:

npm install

好了,现在可以试试看是否已经初始化成功,执行如下命令,开启本地 Hexo 服务器:

hexo s

此时,浏览器中打开网址(默认是4000端口) http://localhost:4000 ,能看到如下页面:

Hexo 本地

这里我踩了个不算坑的坑,终端输入hexo s后没有成功,我也在网上搜到了很多解决办法,但是都没有奏效,后来我尝试改了下端口就成功了,也就是说默认的4000端口无法连接。如果您的情况跟我一样,尝试了网上的很多解决办法之后依然无效,那您也许可以尝试输入命令hexo s -p 5000改一下端口试试看。

关联 GitHub

创建仓库

  1. 登录您的 GitHub 账号,新建名称为您的用户名.github.io的仓库。假设我的 GitHub 账号的用户名是 luxun,那么我就应该新建名称为luxun.github.io的仓库。
  2. Description可写可不写,随意。
  3. 勾上Initialize this repository with a README
  4. 点击Create Repository完成创建。

开启 GitHub Pages

点击Settings,你将会打开这个库的 Settings 页面,向下拖动,直到看见 GitHub Pages,如图:

gh-p

修改全局配置文件

Hexo 官方文档中有对全局配置的详细说明,推荐阅读。

小坑提醒,修改本地所有的配置文件时,注意所有的冒号:后边都要加一个空格,否则执行 Hexo 命令时会报错,一定注意。

找到本地blog文件夹下_config.yml,打开后滑到最后,修改成下边的样子:

deploy:
  type: git
  repository: https://github.com/xxx/xxx.github.io.git
  branch: master

您需要将repository后的所有xxx换成你自己的用户名,或者也可以在下图位置获取:

https 地址

然后,您需要为自己配置身份信息,终端输入yournameyouremail换成您自己的 GitHub 用户名和邮箱):

git config --global user.name "yourname"
git config --global user.email "youremail"

终端cdblog文件夹下执行生成静态页面命令:

hexo g

此时若出现如下报错:

ERROR Local hexo not found in ~/blog
ERROR Try runing: 'npm install hexo --save'

尝试执行命令:

npm install hexo --save

若无报错,自行忽略此步骤。

然后在当前目录下,终端输入:

hexo d

这里踩了个坑,如果您执行命令hexo d仍然报错:无法连接 git 或找不到 git,则执行如下命令来安装hexo-deployer-git

npm install hexo-deployer-git --save

完成安装之后,再次执行hexo ghexo d命令。

随后按照提示,分别输入自己的 GitHub 用户名和密码,开始上传。

完成上传之后,通过http://xxx.github.io/ (xxx换成您自己的仓库名,也就是用户名)来访问自己刚刚上传的网站。

  • 为避免每次输入 GitHub 用户名和密码的麻烦,可参照后文 优化(个性化设置) 添加ssh key 到 GitHub进行优化

常用指令和发布文章

  • 常用指令
hexo new "postName"        //新建文章
hexo new page "pageName"        //新建页面
hexo g          //生成静态页面至public目录
hexo server         //开启预览访问端口(默认端口4000,'ctrl + c'关闭server)
hexo deploy         //将.deploy目录部署到GitHub
  • 常用组合
hexo clean
hexo g
hexo d
hexo d -g #生成部署
hexo s -g #生成预览
  • 发布文章

终端cdblog文件夹下,执行如下命令新建文章:

hexo new "xxx"

名为xxx.md的文件会建在目录.../blog/source/_posts下。

所有的文章都会以md形式保存在_post文件夹中,只要在_post文件夹中新建md类型的文档,就能在执行hexo g的时候被渲染。新建的文章头需要添加一些信息,如下所示:

---
title: xxx    //在此处添加你的标题。
date: 2016-10-07 13:38:49   //在此处输入编辑这篇文章的时间。
tags: xxx    //在此处输入这篇文章的标签。
categories: xxx    //在此处输入这篇文章的分类。
---

文章编辑完成后,终端cdblog文件夹下,依次执行如下命令来发布:

hexo g
hexo d

至此,Mac 上搭建基于 GitHub Pages + Hexo 的博客就完成了。

下面的内容是介绍安装 Themes 、个性化设置以及优化。

设置 Themes

如果您喜欢 Hexo 默认的主题的话,可以跳过这部分。如果您想换一个主题的话,可以到Hexo 主题挑选自己中意的主题。

这里以nexT 主题为例。

终端cdblog目录下执行如下命令(这是目前的稳定版本,不是最新版。最新版有一些新特性,但是可能会不稳定,所以这里推荐选择安装稳定版):

git clone --branch v5.1.2 https://github.com/iissnan/hexo-theme-next themes/next

如果想尝试最新版,请执行如下命令:

git clone https://github.com/iissnan/hexo-theme-next themes/next

打开blog目录下的_config.yml,找到theme: landscape修改为theme: next

终端cdblog目录下,依次执行如下命令(每次部署文章的步骤):

hexo clean

hexo g

hexo d

至于更改博客的名称、描述、头像等,只需要修改blog/_config.yml文件和blog/themes/next/_config.yml文件中对应的属性名称即可(不要忘记冒号:后加空格)。

个性化设置

为博客加上 GitHub 丝带

这里以 Next 主题为例(其他主题也差不多),添加 GitHub 丝带:在blog\themes\next\layout\_layout.swig中加入相关代码,记得修改自己的链接。

添加 README.md

每个项目仓库下一般都有一个 README.md 文件,但是使用 hexo 部署到仓库后,项目仓库中是没有 README.md 文件的。

blog 目录下的 source 目录下添加一个 README.md 文件,修改站点配置文件 _config.yml,将 skip_render 参数的值设置为 README.md

skip_render: README.md

保存退出即可。

为博客添加 LICENSE

在主题配置文件中添加下面这段代码(添加之前先看看您的主题配置文件是否已经包含这段代码,已经包含就不用添加了,因为重复会报错),LICENSE 会显示在侧边栏。

# Creative Commons 4.0 International License.
# http://creativecommons.org/
# Available: by | by-nc | by-nc-nd | by-nc-sa | by-nd | by-sa | zero
creative_commons: by-nc-sa
#creative_commons:

修改文章底部的带 # 号的标签

如果您觉得#不好看,想改成图标,那么请按照下面修改。
打开/themes/next/layout/_macro/post.swig,搜索(组合键command+f)rel="tag">#,将#换成<i class="fa fa-tag"></i>

将阅读量改为热度

很多人将文章标题下的 阅读次数 改为了 热度,如果您喜欢的话可以这样修改。

打开blog/themes/next/languages/zh-Hans文件,查找阅读次数这几个字,可以看到,在post中的visitors被定义为阅读次数,把这里的阅读次数改为热度

visitors: 热度

那么怎么在页面中显示呢?打开Next主题文件夹中blog/themes/next/layout/_macro/post.swig,在这个文件里加上摄氏度的标志,在<span class="leancloud-visitors-count"></span>下面增加一行<span>℃</span>即可:

<span class="leancloud-visitors-count"></span>
<span>℃</span>

博文置顶

  • 修改 hexo-generator-index 插件

替换文件blog/node_modules/hexo-generator-index/lib/generator.js 内的代码为:

'use strict';
var pagination = require('hexo-pagination');
module.exports = function(locals){
  var config = this.config;
  var posts = locals.posts;
    posts.data = posts.data.sort(function(a, b) {
        if(a.top && b.top) { // 两篇文章top都有定义
            if(a.top == b.top) return b.date - a.date; // 若top值一样则按照文章日期降序排
            else return b.top - a.top; // 否则按照top值降序排
        }
        else if(a.top && !b.top) { // 以下是只有一篇文章top有定义,那么将有top的排在前面(这里用异或操作居然不行233)
            return -1;
        }
        else if(!a.top && b.top) {
            return 1;
        }
        else return b.date - a.date; // 都没定义按照文章日期降序排
    });
  var paginationDir = config.pagination_dir || 'page';
  return pagination('', posts, {
    perPage: config.index_generator.per_page,
    layout: ['index', 'archive'],
    format: paginationDir + '/%d/',
    data: {
      __index: true
    }
  });
};
  • 设置文章置顶

在文章 Front-matter 中添加 top 值,数值越大文章越靠前,如:

---
title: xxx
date: 2015-04-02 14:36:04
categories: xxx
tags: xxx
top: 10
---

NexT 首页文章 加载更多 设置

这里只说一个方法:编辑文章时,在您希望显示 加载更多 按钮的地方,加上<!--more-->

more

首页分割线

  在 \themes\next\source\css\_custom\custom.styl 文件中添加以下代码,可以修改博客首页中每篇文章的分割线样式,width是长度,height是宽度。

//index页面中每篇文章相隔的那条线
.posts-expand {
  .post-eof {
    display: block;
    margin: $post-eof-margin-top auto $post-eof-margin-bottom;
    width: 100%;
    height: 3px;
    background: $grey-light;
    text-align: center;
  }
}

小图标设置

博客中一切小图标都可以在fontawesome 图标库自行搜索(qq、微博、微信等图标是有的,但知乎、豆瓣等图标目前还没有)。

  • 修改网页底部的桃心图标
    打开blog/themes/next/layout/_partials/footer.swig,找到这段代码进行修改(还是在fontawesome 图标库找自己喜欢的图标):
<span class="with-love">
  <i class="fa fa-share-alt"></i>
</span>

设置网站的图标Favicon

准备一张 icon 图标文件,放在 source 目录下就可以了,在主题配置文件中找到 favicon 的设置:

# Put your favicon.ico into `hexo-site/source/` directory.
favicon: /favicon.ico

主页文章添加阴影效果

具体实现方法

打开blog\themes\next\source\css\_custom\custom.styl文件,添加以下代码:

//主页文章添加阴影效果
 .post {
   margin-top: 60px;
   margin-bottom: 60px;
   padding: 25px;
   -webkit-box-shadow: 0 0 5px rgba(202, 203, 203, .5);
   -moz-box-shadow: 0 0 5px rgba(202, 203, 204, .5);
  }

隐藏网页底部 powered By Hexo / 强力驱动

打开blog/themes/next/layout/_partials/footer.swig,使用<!-- -->隐藏符号之间的代码即可,或者直接将这段代码删除。位置如图:

隐藏底部 Hexo

添加 SSH key 到 GitHub

  • 检查 SSH keys 是否已经存在

终端执行如下命令,检查SSH keys是否存在。

ls ~/.ssh

如果显示如下信息(下面是我个人的显示,也许您跟我显示的不一样,但重点是只要有id_rsaid_rsa.pub),就说明 SSH keys 已经存在了:

id_rsa	   id_rsa.pub	  known_hosts

如果存在,则直接跳过下一个步骤进入将 SSH key 添加到 GitHub 中,否则请继续下一步骤 生成新的 SSH key

  • 生成新的 SSH key

终端执行如下命令生成新的 SSH key,注意将[email protected]换成你自己注册 GitHub 的邮箱地址。

ssh-keygen -t rsa -C "[email protected]"

默认会在相应路径~/.ssh下生成id_rsaid_rsa.pub两个文件。

1.3.将 SSH key 添加到 GitHub 中

终端依次输入:

cd ~/.ssh
cat id_rsa.pub

复制所有显示的内容

进入GitHub –> Settings –> SSH and GPG keys –> NEW SSH key,如下图所示:

settings

ssh_key

Title 里任意添一个标题,将复制的内容粘贴到 Key 里,点击下方 Add SSH key 绿色按钮即可,如下图所示:

add_ssh_key

绑定独立域名

  • 首先,需要注册一个域名。可以选择GoDaddy万网中的任意一家。

  • 然后,我们需要配置一下域名解析。推荐使用DNSPod的服务,免费稳定,解析速度也比较快。在域名注册商处(Godaddy 或万网)修改 NS 服务器地址为:

f1g1ns1.dnspod.net
f1g1ns2.dnspod.net

域名解析详细的步骤这里我就不写了,给个图:

dnspod

图中设置国内国外的原因是想让博客加载速度更快,方法请阅读后文 将个人博客同时部署到 GitHub 和 Coding

  • 如果将域名指向另一个域名,实现与被指向域名相同的访问效果,需要增加 CNAME 记录。

进入 blog/source 目录下,添加并打开 CNAME 文件,输入您的域名,重新上传您的博客。

在 GitHub 中打开您自己的博客仓库,进入库的 Settings 界面,如果看到了如下提示,说明配置成功了。

CNAME

在这一系列的操作中,修改 NS 服务器、设置解析等等,都需要一定的时间。短则10分钟,长则24小时,最长不会超过72小时。如果超过72小时,请检查自己的配置过程,或者修改自己本地的 DNS 服务器。

优化

将个人博客同时部署到 GitHub 和 Coding

Coding 可以理解为国内的 GitHub。通过将博客同时部署到 GitHub 和 Coding,可以提升博客的加载速度。

这里有个提醒,Coding 会强制用户在网站上挂推广图标,通过 Coding 加载博客还会有5s广告,如果觉得这样不好,可以选择放弃部署在 Coding 上。还有一个选择,就是花钱成为 Coding 的会员,这样上述的问题就都没有了。

  • 首先到Coding注册。创建仓库跟 GitHub 上创建仓库的要求一样。

  • 打开本地 blog 目录下的 _config.yml 文件,滑到最下面,修改如下(xxx换成自己的用户名):

deploy:
  type: git
  repository:
    github: https://github.com/xxx/xxx.github.io.git
    coding: https://git.coding.net/xxx/xxx.git
  branch: master
  • 然后执行命令hexo clean hexo g hexo d

  • 个人域名添加两条 CNAME 解析。将 GitHub 的地址 解析为 国外 ,将 Coding 的地址 解析为 国内

dnspod

  • 如果您有个人域名的话,到 Coding 博客仓库的 Pages 服务 界面,添加域名绑定,输入个人域名就 OK 了,可能需要耐心等待几分钟。

这样就可以实现从国内访问就通过 Coding 加载博客项目,从国外访问就通过 GitHub 加载博客项目,从而提升加载博客的速度。

压缩代码

压缩代码也是一个优化加载速度的方法。

目前知道的有两个插件可以压缩博文,hexo-all-minifier 插件和 gulp 插件。hexo-all-minifier 使用比较简单,也可以压缩图片,不过对文章缩进不支持。如果您对文章缩进有要求,可以暂时使用 gulp 压缩手段。

  • hexo-all-minifier 使用方法

安装 hexo-all-minifier,在站点的根目录下执行以下命令:

npm install hexo-all-minifier --save

hexo g编译的时候就会自动压缩 HTML、JS、图片。详情参考插件介绍 hexo-all-minifier

  • glup 使用方法

Hexo 依赖 gulp 插件安装,在站点的根目录下执行以下命令:

npm install gulp -g
npm install gulp-minify-css gulp-uglify gulp-htmlmin gulp-htmlclean gulp --save

blog目录下,新建 gulpfile.js 并填入以下内容:

var gulp = require('gulp');
var minifycss = require('gulp-minify-css');
var uglify = require('gulp-uglify');
var htmlmin = require('gulp-htmlmin');
var htmlclean = require('gulp-htmlclean');
// 压缩 public 目录 css
gulp.task('minify-css', function() {
    return gulp.src('./public/**/*.css')
        .pipe(minifycss())
        .pipe(gulp.dest('./public'));
});
// 压缩 public 目录 html
gulp.task('minify-html', function() {
  return gulp.src('./public/**/*.html')
    .pipe(htmlclean())
    .pipe(htmlmin({
         removeComments: true,
         minifyJS: true,
         minifyCSS: true,
         minifyURLs: true,
    }))
    .pipe(gulp.dest('./public'))
});
// 压缩 public/js 目录 js
gulp.task('minify-js', function() {
    return gulp.src('./public/**/*.js')
        .pipe(uglify())
        .pipe(gulp.dest('./public'));
});
// 执行 gulp 命令时执行的任务
gulp.task('default', [
    'minify-html','minify-css','minify-js'
]);

生成博文时执行 hexo g && gulp 就会根据 gulpfile.js 中的配置,对 public 目录中的静态资源文件进行压缩。

SEO(搜索引擎优化)

网站验证

验证方式有几种,推荐最简单的两种:文件验证和 CNAME 验证。

  • 文件验证
  1. 登录百度站长选择添加网站,使用方式为文件验证
  2. 将下载的文件放到source文件下
  3. 由于 hexo 自动会对 html 文件进行渲染,所以在站点配置文件中找到skip_render:
  4. 在后面添加文件名字,若有多个用这样的形式[xxx.html, xxx.html],比如: skip_render: [googleff0226f76d5f451b.html, baidu_verify_vHC5EAW09E.html]
  5. 重新渲染文件: hexo clean hexo d -g
  6. 点击站长的验证按钮,完成验证。
  • CNAME 验证
  1. 去站长添加网站选择 CNAME 验证
  2. 把地址解析到zz.baidu.com
  3. 完成验证

添加并提交sitemap

安装 Hexo 的 sitemap 网站地图生成插件,终端cdblog

npm install hexo-generator-sitemap --save
npm install hexo-generator-baidu-sitemap --save

站点配置文件中任意位置添加如下代码,但要看清您的 Hexo 版本。

如果您的 Hexo 版本是 2.x.x

sitemap:
    path: sitemap.xml
baidusitemap:
    path: baidusitemap.xml

如果您的 Hexo 版本是 3.x.x

sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml

配置成功后,会生成sitemap.xmlbaidusitemap.xml,前者适合提交给谷歌搜素引擎,后者适合提交百度搜索引擎。

百度 sitemap 提交如图,Google 也是一样的:

sitemap_yz

验证成功之后就可以开始推送了。Google 的收录比较快,通常第二天就能搜得到,百度就比较慢了。

主动推送

安装主动推送插件,终端cdblog

npm install hexo-baidu-url-submit --save

在根目录下,把以下内容配置到站点配置文件中:

baidu_url_submit:
  count: 3     ## 比如3,代表提交最新的三个链接
  host: xxx     ## 在百度站长平台中注册的域名
  token: xxx       ## 请注意这是您的秘钥,请不要发布在公众仓库里!
  path: baidu_urls.txt       ## 文本文档的地址,新链接会保存在此文本文档里

至于上面提到的token可在百度站长如下位置找到:

token

其次,记得查看站点配置文件中的url,必须包含站长平台注册的域名,比如:

url: http://harleywang93.com
root: /
permalink: :year/:month/:day/:title/

接下来添加一个新的 deploy 类型:

deploy:
- type: baidu_url_submitter
- type: git
  repository:
    github: https://github.com/xxx/xxx.github.io.git
    coding: https://git.coding.net/xxx/xxx.git
  branch: master

执行hexo d的时候,新的链接就会被推送了。原理:

  • 新链接的产生,hexo g会产生一个文本文件,里面包含最新的链接。
  • 新链接的提交,hexo d会从上述文件中读取链接,提交至百度搜索引擎。

自动推送

把 NexT 主题配置文件中的baidu_push:设置为true,就可以了。

添加蜘蛛协议

blog/source/目录下新建一个robots.txt文件,添加下面的一段代码(可根据自己的需要修改):

#hexo robots.txt
User-agent: *

Allow: /
Allow: /archives/

Disallow: /vendors/
Disallow: /js/
Disallow: /css/
Disallow: /fonts/
Disallow: /vendors/
Disallow: /fancybox/

Sitemap: http://xxx/sitemap.xml
Sitemap: http://xxx/baidusitemap.xml

然后到站长(这里以百度为例,Google 一样)更新一下,就像这样:

robots

感谢

自己搭建博客时,很是折腾了一番,也学习到了很多知识,阅读了很多相关的博文,在此向相关博文的作者表示感谢,谢谢你们的文章让我进步。同时,我看到有很多人想拥有自己的博客或者优化自己的博客,期间可能会遇到很多问题,我也是这么一个坑一个坑踩过来的,所以我就写了这么一篇自己折腾博客的分享,希望可以在帮助自己的同时帮助到别人。(如果踩了新坑的话,一定会更新的。)

推荐阅读

搭建一个免费的,无限流量的Blog-阮一峰
Hexo搭建博客教程
基于Hexo+Node.js+github+coding搭建个人博客——进阶篇(从入门到入土)

JS 相关概念

CSS 和 JS 在网页中的放置顺序是怎样的?

  • CSS 放在 <head> 标签之内
  • Javascript 有两种形式:
  1. <script>...</script>
  2. <script src=”index.js”></script> 外部引用
  • JavaScript 理论上可以放在网页的任何位置,但是由于 JavaScript 在加载的时候会禁止其他项加载,会阻塞内容的呈现和组件的下载,所以 JavaScript 应该放置在 body 标签的最后面,即闭合标签</body>之前。

解释白屏和FOUC

白屏

白屏的根本原因是浏览器在渲染的时候请求时间过长造成的。

  • 如果把样式放在底部,对于 IE 或者 chrome 浏览器,,在某些场景下(新窗口打开,刷新等)页面会出现白屏,而不是内容逐步展现
  • 如果使用 @import 标签,即使 CSS 放入 link, 并且放在头部,也可能出现白屏。
  • 如果把 JavaScrip 放在头部,因为脚本会阻塞后面内容的呈现和其后组件的下载。对于图片和 CSS,在加载时会并发加载(如一个域名下同时加载两个文件),但在加载 JavaScript 时,会禁用并发,并且阻止其他内容的下载。所以把 JavaScript 放入页面顶部也会导致白屏现象。

FOUC -- Flash of Unstyled Content 无样式内容闪烁

如果把样式放在底部:

  • 对于 IE 浏览器,在某些场景下(点击链接,输入 URL ,使用书签进入等),会出现 FOUC 现象(逐步加载无样式的内容,等 CSS 加载后页面突然展现样式)。
  • 对于 Firefox 会一直表现出 FOUC 。

async和defer的作用是什么?有什么区别

  • <script src="script.js"></script>
    没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。

  • <script async src="script.js"></script>
    有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。

  • <script defer src="script.js"></script>
    有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。

  • defer 和 async 的区别
    defer: 脚本延迟到文档解析和显示后执行,有顺序
    async: 不保证顺序

简述网页的渲染机制

  1. 解析 HTML 标签, 构建 DOM 树
  2. 解析 CSS 标签, 构建 CSSOM 树
  3. 把 DOM 和 CSSOM 组合成 渲染树 (render tree)
  4. 在渲染树的基础上进行布局, 计算每个节点的几何结构
  5. 把每个节点绘制到屏幕上 (painting)

从 URL 输入到页面展现

流程

  1. 在浏览器输入URL
  2. 域名解析
  3. 服务器处理
  4. 网站处理流程
  5. 浏览器处理
  6. 绘制网页

流程简述

1. 在浏览器输入 URL

什么是 URL?

  • 统一资源定位符(Uniform / Universal Resource Locator,常缩写为 URL),俗称网页地址(网址)。
  • 用于定位互联网上的资源。
  • URL 包含协议部分。协议是浏览器和 www万维网之间的沟通方式,它会告诉浏览器在网络上正确找到资源位置。常见的协议有 http、https、ftp、file 等。其中 http 是最常见的网络传输协议,而 https 则是进行加密的网络传输。

2. 域名解析

  • 域名解析是把域名指向网站空间IP,让人们通过注册的域名可以方便地访问到网站的一种服务。
  • 对于 https://github.com/HarleyWang93/blog, github.com 就是域名。
  • 对于 http://github.com 的 URL,浏览器实际上不知道 github.com 到底是什么东西,需要查找 github.com 网站所在服务器的IP地址,才能找到目标。
  • IP 地址很难记,所以发明了域名。语义化的域名更利于人们记忆,可是电脑收到用户输入的网址后,要想让电脑理解这一串字符串,就有些困难了,因为计算机更擅长处理一长串数字,那么 IP 地址和 DNS服务就显得非常重要了。

IP 地址是什么?

  • IP 地址是指互联网协议地址,每个处于互联网中的设备都有 IP 地址,形如192.168.0.1
  • 局域网 IP 和公网 IP 是有差别的
  • 127.0.0.1代表本机的 IP

域名解析的流程

  1. 浏览器缓存 – 浏览器会缓存 DNS 记录一段时间
  2. 系统缓存 - 从 Hosts 文件查找是否有该域名和对应 IP
  3. 路由器缓存 – 一般路由器也会缓存域名信息
  4. ISP DNS 缓存 – 比如到电信的 DNS 上查找缓存
  5. 如果都没有找到,则向根域名服务器查找域名对应 IP,根域名服务器把请求转发到下一级,直到找到 IP
  • 8.8.8.8 —— Google 提供的免费 DNS 服务器的 IP 地址
    114.114.114.114 —— 是国内第一个、全球第三个开放的 DNS 服务地址,又称114DNS

  • DNS劫持:DNS劫持又称域名劫持,是指在劫持的网络范围内拦截域名解析的请求,分析请求的域名,把审查范围以外的请求放行,否则返回假的IP地址或者什么都不做使请求失去响应,其效果就是对特定的网络不能反应或访问的是假网址。

3. 服务器处理

什么是服务器?

  • 服务器是一台机器安装系统的机器,每个服务器里都安装有处理请求的应用——web server。
  • 常见的web server产品有 apache、nginx、IIS 或 Lighttpd 等。
  • web服务器接收用户的 Request 交给网站代码,或者接受请求反向代理到其他 web服务器。

4. 网站处理流程

  • 网站处理,就是实际后台处理的工作。后台开发现在有很多框架,但大部分都还是按照MVC设计模式进行搭建的。
  • MVC是一个设计模式,将应用程序分成三个核心部件:模型(model)-- 视图(view)--控制器(controller),它们各自处理自己的任务,实现输入、处理和输出的分离。
  1. 视图(view)
    视图是用户看到并与之交互的界面。这是前端工作的主力部分。

  2. 模型(model)
    模型是将实际开发中的业务规则和所涉及的数据格式模型化,应用于模型的代码只需写一次就可以被多个视图重用。在MVC的三个部件中,模型拥有最多的处理任务。一个模型能为多个视图提供数据。

  3. 控制器(controller)
    控制器接受用户的输入并调用模型和视图去完成用户的需求。Controller处于管理角色,从视图接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示模型处理返回的数据。

  • 总结,首先控制器接收用户的请求,并决定应该调用哪个模型来进行处理,然后模型用业务逻辑来处理用户的请求并返回数据,最后控制器用相应的视图格式化模型返回html字符串给浏览器,浏览器呈现网页给用户。因此,下一步就来到浏览器处理阶段。

5. 浏览器处理

  • HTML 字符串被浏览器接受后被一句句读取解析
  • 解析到 link 标签后重新发送请求获取 css
  • 解析到 script 标签后发送请求获取 js,并执行代码
  • 解析到 img 标签后发送请求获取图片资源

6. 绘制网页

  • 浏览器根据 HTML 和 CSS 计算得到渲染树(DOM 树的可视化表示),绘制到屏幕上,js 也会被执行,最终完成了整个页面的展示。

推荐阅读

说说从URL输入到页面展现的过程
从URL输入到页面展现的全过程

闭包&定时器&BOM

题目1: 下面的代码输出多少?修改代码让 fnArr[i]() 输出 i 。使用 两种以上的方法

var fnArr = [];
for (var i = 0; i < 10; i ++) {
  fnArr[i] =  function(){
    return i;
  };
}
console.log( fnArr[3]() );  //10
var fnArr = [];
for (var i = 0; i < 10; i ++) {
  fnArr[i] =  (function(i){
  	return function() {
  	  return i;
  	}
  })(i);
}
console.log( fnArr[3]() );//3
var fnArr = [];
for (var i = 0; i < 10; i ++) {
  !function(i) {
  	fnArr[i] =  function(){
    return i;
  };
}(i)
}
console.log( fnArr[3]() ); //3
var fnArr = [];
for (let i = 0; i < 10; i ++) {
  fnArr[i] =  function(){
    return i;
  };
}
console.log( fnArr[3]() );//3

题目2: 封装一个汽车对象,可以通过如下方式获取汽车状态

var Car = (function(){
   var speed = 0;
   function setSpeed(s){
       speed = s
   }
   ...
   return {
      setSpeed: setSpeed,
      ...
   }
})()
Car.setSpeed(30);
Car.getSpeed(); //30
Car.accelerate();
Car.getSpeed(); //40;
Car.decelerate();
Car.decelerate();
Car.getSpeed(); //20
Car.getStatus(); // 'running';
Car.decelerate(); 
Car.decelerate();
Car.getStatus();  //'stop';
//Car.speed;  //error
var Car = (function(){
  var speed = 0;
  function setSpeed(s){
    speed = s
  }
  function getSpeed() {
  	return speed
  }
  function accelerate() {
  	speed += 10
  }
  function decelerate() {
  	if(speed > 10){
  	  speed -= 10
  	}
  }
  function getStatus() {
  	if(speed > 0){
  	  return 'running'
  	}else{
  	  return 'stop'
  	}
  }
  return {
    setSpeed: setSpeed,
    getSpeed: getSpeed,
    accelerate: accelerate,
    decelerate: decelerate,
    getStatus: getStatus
   }
})()
Car.setSpeed(30);
Car.getSpeed(); //30
Car.accelerate();
Car.getSpeed(); //40;
Car.decelerate();
Car.decelerate();
Car.getSpeed(); //20
Car.getStatus(); // 'running';
Car.decelerate(); 
Car.decelerate();
Car.getStatus();  //'stop';
//Car.speed;  //error

题目3:下面这段代码输出结果是? 为什么?

var a = 1;
setTimeout(function(){
    a = 2;
    console.log(a);
}, 0);
var a ;
console.log(a);
a = 3;
console.log(a);
//输出结果:
//1
//3
//2

//因为 setTimeout() 函数会在本次所有代码全部执行完毕以后才会去执行。
//所以会先执行 setTimeout() 函数外部的 2 个 console.log(a),最后再执行 setTimeout() 函数。

题目4:下面这段代码输出结果是? 为什么?

var flag = true;
setTimeout(function(){
    flag = false;
},0)
while(flag){}
console.log(flag);
// 声明 flag 并赋值为 true 之后,进行 while 循环,因为条件一直为 true,所以无限循环,不会退出。
// 因为无限循环,所以不会执行之后的 console.log(flag) 和 setTimeout()函数。
//所以没有输出,无结果。

题目5: 下面这段代码输出?如何输出delayer: 0, delayer:1...(使用闭包来实现)

for(var i=0;i<5;i++){
	setTimeout(function(){
         console.log('delayer:' + i );
	}, 0);
	console.log(i);
}
//输出: 0 1 2 3 4 5次delayer:5
for(var i=0;i<5;i++){
  !function(i) {
  	setTimeout(function(){
      console.log('delayer:' + i );
    }, 0);
  console.log(i);
  }(i)
}
for(var i=0;i<5;i++){
  setTimeout((function(i) {
  	return function() {
  	  console.log('delayer:' + i );
  	}
  })(i), 0);
  console.log(i);
}

题目6: 如何获取元素的真实宽高

function getStyle(element) {
return element.getComputedStyle() ? window.getComputedStyle(element) : element.currentStyle }
let trueWidth = getStyle(element).width;
let trueHeight = getStyle(element).height;
//低版本IE
function getStyle(element,pseduoElement){
    return element.currentStyle ? element.currentStyle : window.getComputedStyle(element,pseduoElement);
}
let trueWidth = getStyle(element).width;
let trueHeight = getStyle(element).height;

题目7: URL 如何编码解码?为什么要编码?

// 编码
encodeURI()
encodeURIComponent()

// 解码
decodeURI()
decodeURIComponent()

区别

encodeURI方法不会对下列字符编码

ASCII字母
数字
~!@#$&*()=:/,;?+'

encodeURIComponent方法不会对下列字符编码

ASCII字母
数字
~!*()'

所以encodeURIComponent比encodeURI编码的范围更大。

实际例子来说,encodeURIComponent 会把 http:// 编码成 http%3A%2F%2F 而 encodeURI 却不会。

如果你需要编码整个URL,然后需要使用这个URL,那么用encodeURI。

encodeURI("http://www.cnblogs.com/season-huang/some other thing"); //"http://www.cnblogs.com/season-huang/some%20other%20thing";

其中,空格被编码成了%20。但是如果你用了encodeURIComponent,那么结果变为

"http%3A%2F%2Fwww.cnblogs.com%2Fseason-huang%2Fsome%20other%20thing"

当你需要编码URL中的参数的时候,那么encodeURIComponent是最好方法。

var param = "http://www.cnblogs.com/season-huang/"; //param为参数
param = encodeURIComponent(param);
var url = "http://www.cnblogs.com?next=" + param;
console.log(url) //"http://www.cnblogs.com?next=http%3A%2F%2Fwww.cnblogs.com%2Fseason-huang%2F"

参数中的 "/" 可以编码,如果用encodeURI肯定要出问题,因为后面的/是需要编码的

  • URI的编码格式采用的是ASCII码,而不是Unicode,这也就是说URI中不能包含任何非ASCII字符,例如中文。否则如果客户端浏览器和服务端浏览器支持的字符集不同的情况下,中文可能会造成问题。这意味着,如果URL中有汉字或其它非规定字符,就必须编码后使用。

题目8: 补全如下函数,判断用户的浏览器类型

function isAndroid(){
  return /android/i.test(navigator.userAgent);
}
function isIphone(){
  return /iphone/i.test(navigator.userAgent);
}
function isIpad(){
  return /ipad/i.test(navigator.userAgent);
}
function isIOS(){
  return /iphone|ipad/i.test(navigator.userAgent);
}

HTML form 表单

form表单有什么作用?有哪些常用的input 标签,分别有什么作用?

  • 表单用于向服务器传输数据
  • 根据不同的 type 属性值,输入字段拥有很多种形式。输入字段可以是文本字段、复选框、掩码后的文本控件、单选按钮、按钮等等。
标签 功能
<input type="text"> 定义单行输入文本框
<input type="password"> 定义密码字段
<input type="radio"> 定义单选按钮,用name分组
<input type="checkbox"> 定义多选按钮
<input type="submit"> 定义提交表单数据至表单处理程序的按钮
<input type="button"> 定义按钮
<input type="reset"> 定义重置按钮
<input type="number"> 用于应该包含数字值的输入字段
<input type="date"> 用于应该包含日期的输入字段
<input type="color"> 用于应该包含颜色的输入字段

postget 方式的区别?

  • 方式

get 把参数包含在 URL 中,post 通过 request body 传递参数。

  • 安全

getpost 更不安全,因为参数直接暴露在 URL 上,所以不能用来传递敏感信息。

  • 数据量的问题

传输给后台数据量很大,post 可以防止数据传输不完整
数据量小 get

  • 使用场景

需要向后台查询数据 get
传输数据给后台 post

input里,name 有什么作用?

name属性规定input元素的名称,达到区分多个表单的目的,从而防止了表单提交到后台程序之后出现混乱,也只有设置了name属性的表单元素才能在提交表单时传递它们的值。

radio 如何 分组?

通过 name 属性分组,eg(name="sex1"的为一组,name="sex2"的为一组):

<input type="radio" name="sex1" value="male">男
<input type="radio" name="sex1" value="female" >女
<input type="radio" name="sex2" value="male">男
<input type="radio" name="sex2" value="female" >女

placeholder 属性有什么作用?

placeholder 属性能够在文本框里显示提示信息,提示信息会在输入字段时消失,在没有字段输入时显示。

type=hidden 隐藏域有什么作用? 举例说明

  • 隐藏域在页面中对于用户是不可见的,在表单中插入隐藏域的目的在于收集或发送信息,以利于被处理表单的程序所使用。浏览者单击发送按钮发送表单的时候,隐藏域的信息也被一起发送到服务器。
  • 当表单被提交时,隐藏域就会将信息用你设置时定义的名称和值发送到服务器上,可以让服务器知道数据采集的是否正确,从而避免服务器数据被假页面提交的数据攻击篡改。或者有些时候我们要给用户一信息,让用户在提交表单时提交上来以确定用户身份。

HTML 表单的用法

  • 表单用于向服务器传输数据
  • form
<form action="提交到服务器地址" method="get">
...
...
</form>

action:提交表单的地址
method:提交表单使用的方法,get或者post

  • input
    通过 type 属性来设置不同的 input 类型。
  1. text
    文本域
 <div class="username">
    <label for="username">姓名</label>
    <input id="username" type="text" name="username" placeholder="用户名">
</div>
  1. password
    密码域,显示为小黑圆点
<div class="password">
    <label for="password">密码</label>
    <input id="password" type="password" name="password" placeholder="请输入密码">
</div>
  1. button
    提交按钮,不会提交
    <input type="buttom" value="按钮">

  2. submit
    提交按钮,会提交
    <input type="submit" value="提交">

  3. reset
    重置输入按钮
    <input type="reset" value="重置">

  4. radio
    单选,通过 name 属性分组

<div class="sex">
    <label>性别</label>
    <input type="radio" name="sex" value="male">男
    <input type="radio" name="sex" value="female">女
</div>
  1. checkbox
    复选框
<div class="hobby">
    <label for="hobby">爱好</label>
    <input type="checkbox" name="hobby" value="dota">dota
    <input type="checkbox" name="hobby" value="travel">旅游
    <input type="checkbox" name="hobby" value="pet">宠物
</div>
  1. file
    上传文件
   <div class="file">
      <input type="file" name="myfile" accept="image/png">
    </div>

此例中image/png意思是只能选择此格式的图片上传

  1. hidden
    隐藏域
    <input type="hidden" name="..." value="...">
  • label

在介绍 input 元素时,label 元素已出现多次,eg:

<div class="username">
    <label for="username">姓名</label>
    <input id="username" type="text" name="username" placeholder="用户名">
</div>

label 元素为 input 元素定义标注,当鼠标选择该标签时,关联的元素控件会获得焦点,for 属性与关联元素的 id 属性要相同。

  • select元素和嵌套的option元素
    下拉菜单栏
<div class="section">
    <label for="car">My Car</label>
    <select id="car" name="car">
        <option value="TT">TT</option>
        <option value="SAAB" selected>萨博</option>
        <option value="GTR">GTR</option>
    </select>
</div>
  • textarea
    多行文本框
    <textarea name="comment"></textarea>

推荐阅读

w3school
99% 的人都理解错了 HTTP 中 GET 与 POST 的区别

CSS 垂直居中

Line-Height Method

适用范围:单行文本垂直居中

垂直居中单行文本

  • HTML
<div id="parent">
  <div id="child">text</div>
</div>
  • CSS
#child {
  line-height: 200px;
}

垂直居中一张图片

  • HTML
<div id="parent">
  <img src="img.png" alt="">
</div>
  • CSS
#parent {
  line-height: 200px;
}
#parent img {
  vertical-align: middle;
}
#parent:before {
  content: '';
  display: inline-block;
  height: 100%;
  vertical-align: middle;
}

注:该方法的重点在于 line-height 的高度等于块级元素的内容框高度(一般都是指: height 值)

line-height 的垂直居中不是纯粹的垂直居中,会有点差异,需要调节 vertical-align .

块级元素设置padding

适用范围:多行文本垂直居中

  • HTML
<div class="layout">
  <span>Imagine there's no heaven.It's easy if you try.No hell below us.Above us only sky.</span>
</div>
  • css
.layout>span {
  display: inline-block;
  padding: 100px;
}

绝对定位实现居中

适用范围:块级元素 但在 IE 版本低于 7 时不能正常工作

  • HTML
<div id="parent">
  <div id="child">content</div>
</div>
  • CSS
#parent {
  position: relative;
}
#child {
  position: absolute;
  /*top: 50%;
  transform: translateY(-50%);*/
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  width: 50%;
  height: 30%;
  margin: auto;
}

vertical-align实现居中

适用范围:一般情况下只对行内元素生效

  • HTML
<div class="layout">
  <span class="layout1">content</span>
  <span class="layout2">content</span>
</div>
  • CSS
.layout1 {
  font-size: 100px;
  vertical-align: middle;
}

.layout2 {
  font-size: 20px;
  vertical-align: middle;
}

table-cell实现居中

适用范围:只对块级元素生效

  • HTML
<div class="layout">Content</div>
  • CSS
.layout {
  display: table-cell;
  vertical-align: middle;
  width: 150px;
  height: 150px;
  color: #fff;
  background-color: red;
}

DOM 操作

DOM是什么?

  • DOM是JavaScript操作网页的接口,全称为“文档对象模型”(Document Object Model)。它的作用是将网页转为一个JavaScript对象,从而可以用脚本进行各种操作(比如增删内容)。
  • 浏览器会根据DOM模型,将结构化文档(比如HTML和XML)解析成一系列的节点,再由这些节点组成一个树状结构(DOM Tree)。所有的节点和最终的树状结构,都有规范的对外接口。所以,DOM可以理解成网页的编程接口。
  • 严格地说,DOM不属于JavaScript,但是操作DOM是JavaScript最常见的任务,而JavaScript也是最常用于DOM操作的语言。本章介绍的就是JavaScript对DOM标准的实现和用法。

题目1: dom对象的 innerText 和 innerHTML 有什么区别?

  • innerText
    innerText是一个可写属性,返回元素内包含的文本内容,忽略掉了 HTML 标签,在多层次的时候会按照元素由浅到深的顺序拼接其内容
<div>
    <p>
        123
        <span>456</span>
    </p>
</div>

外层divinnerText返回内容是 "123456"

  • innerHTML
    innerHTML属性作用和innerText类似,但是不是返回元素的文本内容,而是返回元素的 HTML 结构,包括 HTML 标签和文本内容,在写入的时候也会自动构建 DOM
<div>
    <p>
        123
        <span>456</span>
    </p>
</div>

外层divinnerHTML返回内容是 "<p>123<span>456</span></p>"

题目2: Element.children 和 Node.childNodes 的区别?

  • Element.children
    Element.children 属性返回一个 HTMLCollection 对象,包括当前元素节点的所有子元素。它是一个类似数组的动态对象(实时反映网页元素的变化)。如果当前元素没有子元素,则返回的对象包含零个成员。

  • Node.childNodes
    childNodes属性返回一个NodeList集合,成员包括当前节点的所有子节点。注意,除了HTML元素节点,该属性返回的还包括Text节点和Comment节点。如果当前节点不包括任何子节点,则返回一个空的NodeList集合。由于NodeList对象是一个动态集合,一旦子节点发生变化,立刻会反映在返回结果之中。

var ulElementChildNodes = document.querySelector('ul').childNodes;

  • Element.children与Node.childNodes属性的区别是,Element.children 只包括 HTML 元素类型的子节点,不包括其他类型的子节点。

题目3:查询元素有几种常见的方法?ES5的元素选择方法是什么?

getElementById()

getElementById 方法返回匹配指定 ID 属性的元素节点。如果没有发现匹配的节点,则返回 null。这也是获取一个元素最快的方法。

var elem = document.getElementById("test");

getElementsByClassName()

getElementsByClassName方法返回一个类似数组的对象(HTMLCollection类型的对象),包括了所有class名字符合指定条件的元素(搜索范围包括本身),元素的变化实时反映在返回结果中。这个方法不仅可以在document对象上调用,也可以在任何元素节点上调用。

var elements = document.getElementsByClassName(names);

getElementsByClassName方法的参数,可以是多个空格分隔的class名字,返回同时具有这些节点的元素。

document.getElementsByClassName('red test');

getElementsByTagName()

getElementsByTagName方法返回所有指定标签的元素(搜索范围包括本身)。返回值是一个HTMLCollection对象,也就是说,搜索结果是一个动态集合,任何元素的变化都会实时反映在返回的集合中。这个方法不仅可以在document对象上调用,也可以在任何元素节点上调用。

var paras = document.getElementsByTagName("p");

  • 上面代码返回当前文档的所有p元素节点。注意,getElementsByTagName方法会将参数转为小写后,再进行搜索。

getElementsByName()

getElementsByName方法用于选择拥有name属性的HTML元素,比如form、img、frame、embed和object,返回一个NodeList格式的对象,不会实时反映元素的变化。

// 假定有一个表单是<form name="x"></form>
var forms = document.getElementsByName("x");
forms[0].tagName // "FORM"
  • 注意,在IE浏览器使用这个方法,会将没有name属性、但有同名id属性的元素也返回,所以name和id属性最好设为不一样的值。

ES5的元素选择方法

querySelector()

querySelector方法返回匹配指定的CSS选择器的元素节点。如果有多个节点满足匹配条件,则返回第一个匹配的节点。如果没有发现匹配的节点,则返回null。

var el1 = document.querySelector(".myclass");
var el2 = document.querySelector('#myParent > [ng-click]');
  • querySelector方法无法选中CSS伪元素。

querySelectorAll()

querySelectorAll方法返回匹配指定的CSS选择器的所有节点,返回的是NodeList类型的对象。NodeList对象不是动态集合,所以元素节点的变化无法实时反映在返回结果中。

elementList = document.querySelectorAll(selectors);

querySelectorAll方法的参数,可以是逗号分隔的多个CSS选择器,返回所有匹配其中一个选择器的元素。

var matches = document.querySelectorAll("div.note, div.alert");

上面代码返回class属性是note或alert的div元素。

elementFromPoint()

elementFromPoint方法返回位于页面指定位置的元素。

var element = document.elementFromPoint(x, y);

上面代码中,elementFromPoint方法的参数x和y,分别是相对于当前窗口左上角的横坐标和纵坐标,单位是CSS像素。

elementFromPoint方法返回位于这个位置的DOM元素,如果该元素不可返回(比如文本框的滚动条),则返回它的父元素(比如文本框)。如果坐标值无意义(比如负值),则返回null。

题目4:如何创建一个元素?如何给元素设置属性?如何删除属性?

创建元素

  • createElement()
    createElement方法用来生成HTML元素节点。

var newDiv = document.createElement("div");

createElement方法的参数为元素的标签名,即元素节点的tagName属性。如果传入大写的标签名,会被转为小写。如果参数带有尖括号(即<和>)或者是null,会报错。

  • createTextNode()
    createTextNode方法用来生成文本节点,参数为所要生成的文本节点的内容。
var newDiv = document.createElement("div");
var newContent = document.createTextNode("Hello");

上面代码新建一个div节点和一个文本节点

  • createDocumentFragment()
    createDocumentFragment方法生成一个DocumentFragment对象。

var docFragment = document.createDocumentFragment();

DocumentFragment对象是一个存在于内存的DOM片段,但是不属于当前文档,常常用来生成较复杂的DOM结构,然后插入当前文档。这样做的好处在于,因为DocumentFragment不属于当前文档,对它的任何改动,都不会引发网页的重新渲染,比直接修改当前文档的DOM有更好的性能表现。

给元素设置属性

  • setAttribute()
    setAttribute()方法用于设置元素属性
var node = document.getElementById("div1");
node.setAttribute("my_attrib", "newVal");

删除属性

  • romoveAttribute()
    removeAttribute()用于删除元素属性

node.removeAttribute('id');

题目5:如何给页面元素添加子元素?如何删除页面元素下的子元素?

给页面元素添加子元素

  • appendChild()
    在元素末尾添加元素
var newDiv = document.createElement("div");
var newContent = document.createTextNode("Hello");
newDiv.appendChild(newContent);
  • insertBefore()
    在某个元素之前插入元素
var newDiv = document.createElement("div");
var newContent = document.createTextNode("Hello");
newDiv.insertBefore(newContent, newDiv.firstChild);
  • replaceChild()
    replaceChild()接受两个参数:要插入的元素和要替换的元素

newDiv.replaceChild(newElement, oldElement);

删除页面元素下的子元素

  • removeChild()

parentNode.removeChild(childNode);

题目6: element.classList有哪些方法?如何判断一个元素的 class 列表中是包含某个 class?如何添加一个class?如何删除一个class?

  • add( String [, String] )
    添加指定的类值。如果这些类已经存在于元素的属性中,那么它们将被忽略。

  • remove( String [,String] )
    删除指定的类值。

  • item ( Number )
    按集合中的索引返回类值。

  • toggle ( String [, force] )
    当只有一个参数时:切换 class value; 即如果类存在,则删除它并返回false,如果不存在,则添加它并返回true。
    当存在第二个参数时:如果第二个参数的计算结果为true,则添加指定的类值,如果计算结果为false,则删除它

  • contains( String )
    检查元素的类属性中是否存在指定的类值。

// div是具有class =“foo bar”的<div>元素的对象引用
div.classList.remove("foo");
div.classList.add("anotherclass");

// 如果visible被设置则删除它,否则添加它
div.classList.toggle("visible");

// 添加/删除 visible,取决于测试条件,i小于10
div.classList.toggle("visible", i < 10);

alert(div.classList.contains("foo"));

//添加或删除多个类
div.classList.add("foo","bar");
div.classList.remove("foo", "bar");

题目7: 如何选中如下代码所有的li元素? 如何选中btn元素?

<div class="mod-tabs">
   <ul>
       <li>list1</li>
       <li>list2</li>
       <li>list3</li>
   </ul>
   <button class="btn">点我</button>
</div>
//选中所有的 li 元素
document.querySelectorAll('li')
document.getElementsByTagName('li')

//选中 btn 元素
document.querySelector('.btn')
document.getElementsByClassName('btn')

Vim 基础使用

Vim 是什么?

  • Vim 是从 vi 发展出来的一个高效率的文本编辑器,在程序员中被广泛使用,有很多支持程序员们更快更好写代码的强大功能。

为什么要学习使用 Vim?

  • 作为一个程序员,不管是前端还是后端,工作中基本上都要跟服务器打交道,而现在服务器里面运行的操作系统基本上都是 Linux。
  • 当你远程跟服务器通信的时候,基本上都要通过终端来跟服务器建立连接。
  • 当你要修改服务器的某个配置文件的时候,在一个黑漆漆的终端里,你能用的几乎只有 Vim。不会使用 Vim,就没办法工作。

如何学习使用 Vim?

  • 学习任何东西都要循序渐进,不要想一口吃成个胖子。现在很多教程上来就列一堆快捷键,基本上看几眼就放弃了。
  • 刚开始只需要学习一些最基本的操作,后面随着代码写的越来越多,进阶的操作每次练一两个,慢慢也就会了,很简单。
  • 工具是拿来用的,不要让它成为一个负担!

新手最大的问题

  • 大小写看错
  • 空格写漏
  • 把多个命令当成一个命令

基础使用

Vim 的两种模式:编辑模式&命令模式

  • 输入vim a.md 初始进入编辑器命令模式
    注意 vima.md 之间有一个空格
  • i 进入编辑模式
  • 键盘左上角 esc 进入命令模式
  • :wq 保存退出
  • :q! 不保存强制退出

常见的文本操作

按键 功能
h或← 光标左移
l或→ 光标右移
k或↑ 光标上移
j或↓ 光标下移
gg 快速定位到文本开头
G(shift+g) 快速定位到文本最后一段
0或home 快速定位到当前段首
$或end 快速定位到当前段首
Ctrl+f 向下翻一页
Ctrl+b 向上翻一页
Ctrl+d 向下翻半页
Ctrl+u 向上翻一页
/string 查找文本中光标位置下方的string字符串,如要查找kabc则直接输入/kabc即可
?string 查找文本中光标位置上方的string字符串,如要查找kabc则直接输入?kabc即可
yy 复制光标所在的段落
y0 复制光标位置到段首的所有字符
y$ 复制光标位置到段尾的所有字符
nyy 从光标位置向下复制n段,包含光标所在的段落
ygg 复制光标位置所在段落到文本开头的所有内容
yG 复制光标位置所在段落到文本结尾的所有内容
p 将复制的内容粘贴为光标所在段落的下一段
P 将复制的内容粘贴为光标所在段落的上一段
dd 删除光标所在的段落
d0 删除光标位置到段首的所有字符
d$ 删除光标位置到段尾的所有字符
dgg 删除光标位置所在段落到文本开头的所有内容
dG 删除光标位置所在段落到文本结尾的所有内容
ndd 从光标位置向下删除n段,包含光标所在的段落
u 撤销上一个操作
Ctrl+r 重复上一个操作
:w 保存数据
:w! 保存时强制写入数据,不管文件是否为只读文件
) 移至下一个句子(sentence)首 (sentence 是以 . ! ? 为区格)
( 移至上一个句子(sentence)首
} 移至下一个段落(paragraph)首 (paragraph 是以空白行为区格)
{ 移至上一个段落(paragraph)首

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.