jQuery()函数的4中调用方式
选择元素
$(selector)
$(selector,context)
封装成jQuery对象
$(Element|Document|Window)
创建jQuery对象
$('<img/>')
$('<img/>',{
src: url
})
传入函数,在文档加载完毕运行
DOMContentLoaded
jQuery(function(){});
$(document).ready(function(){});
$(selector)
$(selector,context)
$(Element|Document|Window)
$('<img/>')
$('<img/>',{
src: url
})
DOMContentLoaded
jQuery(function(){});
$(document).ready(function(){});
ES6的Proxy对象可以用来拦截一个Object对象的属性的修改,这次我们利用它来实现一个简单的双向绑定。
废话不多说,请看代码。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>View to model</title>
</head>
<body>
<div>
<!-- 使用'bind-to'的属性来标记这个输入框里的值会对Model里的属性进行修改 -->
<input bind-to="name" />
<input bind-to="name" />
</div>
<!-- 使用#属性名#来把Model里的值映射到DOM中 -->
<span>#name#</span>
<span>#name#</span>
<button onclick="reset()">reset</button>
<script type="text/javascript">
var handler = {
// 拦截属性的设置,触发试图的更新
set: function(target, key, value, receiver) {
target[key] = value;
updateView(propertyName);
return Reflect.set(target, key, value);
},
};
// 双向绑定的对象
var model = new Proxy({}, handler);
// 双向绑定列表
var inputs = {},views = {};
var all = document.all;
// 遍历所有DOM元素
for(var i=0,l=all.length;i<l;i++){
// 找到所有有bind-to的输入框
if(all[i].getAttribute('bind-to')){
var dom = all[i];
var propertyName = dom.getAttribute('bind-to');
inputs[propertyName] = inputs[propertyName] ? inputs[propertyName] : [];
views[propertyName] = views[propertyName] ? views[propertyName] : [];
inputs[propertyName].push(dom);
dom.addEventListener('change',function function_name(e) {
var propertyName = e.target.getAttribute('bind-to');
model[propertyName] = e.target.value;
})
}
// 找到所有model驱动的页面元素
if(all[i].innerHTML && all[i].innerHTML.length>2 &&
all[i].innerHTML[0] == '#' &&
all[i].innerHTML[all[i].innerHTML.length-1] == '#'){
var propertyName = all[i].innerHTML.slice(1,all[i].innerHTML.length-1);
inputs[propertyName] = inputs[propertyName] ? inputs[propertyName] : [];
views[propertyName] = views[propertyName] ? views[propertyName] : [];
views[propertyName].push(all[i]);
}
}
// 更新View
function updateView(propertyName) {console.log('update ' + propertyName);
if(views[propertyName]){
for(var i = 0,l = views[propertyName].length;i < l;i++){
views[propertyName][i].innerText = model[propertyName];
}
}
if(inputs[propertyName]){
for(var i = 0,l = inputs[propertyName].length;i < l;i++){
inputs[propertyName][i].value = model[propertyName];
}
}
}
function reset() {
for(var name in model){
model[name] = '';
}
}
</script>
</body>
</html>
n to manage your Node.js versionsnpm:(Recommended)npm install -g n
Since n‘s default path is /usr/local/n, it will need super user’s permission to modify file systems in the default path, we need to config n‘s path to user’s path.
N_PREFIXvim ~/.bashrc
export N_PREFIX=~/.n
source ~/.bashrc
vim ~/.bashrc
export PATH=$HOME/.n/bin:$PATH
source ~/.bashrc
# Use or install a version of node
n 9.0.0
# Use or install the latest official release
n latest
# Use or install the stable official release
n stable
# Use or install the latest LTS official release
n lts
Type n to show list of versions.
And select a version by up down button.
$ n
node/8.9.3
node/9.0.0
node/9.2.1
ο node/9.3.0
React的思想里,UI=render(data)
所以,React的组件一般是完成两种功能:
如果我们把两个功能都放在同一个组件内,那么这个组件做的事情就太多了,考虑到组件复用和业务变更,让一个组件只专注做一件事,我们可以把这个组件拆分成多个组件,让每个组件只专注做一件事,所以就衍生了一种React常用的模式:容器组件和展示组件。
容器组件在外层,有以下特点:
展示组件在容器组件内部,有以下特点:
展示组件一般可以使用纯函数的声明方式:
export default (props)=>(
<div>Hello {props.name}</div>
);
style-loader adds CSS to the DOM by injecting a style tag.
The css-loader interprets @import and url() like import/require() and will resolve them.
Use it after css-loader and style-loader, but before other preprocessor loaders like e.g sass|less|stylus-loader, if you use any.
Autoprefixer is a service for managing vendor prefixes. It adds missing prefixes and deletes obsolete ones.
Extract text from a bundle, or bundles, into a separate file.
Needed in production mode.
import from './file.css'
import from './file.less'
import from './file.sass'
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
autoprefixer({
browsers: ['> 5%']
})
]
}
}
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
autoprefixer({
browsers: ['> 5%']
})
]
}
},
'less-loader'
]
}
]
}
}
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
importLoaders: 1,
minimize: true,
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: {
plugins: [
autoprefixer({
browsers: ['> 5%']
})
]
}
},
]
})
},
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
importLoaders: 1,
minimize: true,
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: {
plugins: [
autoprefixer({
browsers: ['> 5%']
})
]
}
},
'less-loader']
})
},
]
},
plugins: [
// Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
new ExtractTextPlugin({filename: '[name].[hash:8].css'})
],
}
Promise是我们处理异步操作的时候经常用到的。
有的时候我们会需要顺序执行很多异步操作,如果操作比较少的时候还可以写成a.then(b).then(c)...,可是如果异步操作很多的时候就不能这样写了。
可以利用数组的reduce函数达到同样的效果,这个时候不管有多少异步操作都可以连在一起了。
代码如下:
function waitPromise(time) {
console.log(time);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('resolved');
}, time);
});
}
function log(data) {
return new Promise((resolve, reject) => {
console.log(data + '@' + (new Date().getSeconds()));
resolve();
});
}
var ps = [];
for (var i = 0; i < 3; i++) {
let time = (i + 1) * 1000;
ps.push(() => waitPromise(time));
ps.push(log);
}
console.log('started' + '@' + (new Date().getSeconds()));
var p = Promise.resolve();
ps.reduce((p, c) => {
return p.then(c)
}, p).then(() => {
console.log('all finished');
}).catch(reject => {
console.log('reject', reject)
});
输出结果:
started@59 1000 resolved@0 2000 resolved@2 3000 resolved@5 all finished
在android平台的uc浏览器和微信浏览器中使用display: flex;会出问题。
使用display: flex;的时候需要加上display: -webkit-box;
使用flex: 1;的时候要加上:
-webkit-box-flex: 1;
-moz-box-flex: 1;
-ms-flex: 1;
使用align-items: center;的时候需要加上:-webkit-box-align: center;
使用flex-direction: column;的时候需要加上:
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
box-orient: vertical;
这里有个demo大家可以看一下
请点击:测试页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Demo for flex on uc</title>
<style type="text/css">
html,body{
padding: 0;
margin: 0;
}
.demo1{
background-color: yellow;
text-align: center;
height: 80px;
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
/* for uc */
display: -webkit-box;
-webkit-box-align: center;
}
.demo1>div{
background-color: green;
margin: 2px;
-webkit-flex: 1;
flex: 1;
/* for uc */
-webkit-box-flex: 1;
-moz-box-flex: 1;
-ms-flex: 1;
}
.demo2{
background-color: yellow;
width: 80px;
height: 200px;
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-align-items: center;
align-items: center;
/* for uc */
display: -webkit-box;
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
box-orient: vertical;
-webkit-box-align: center;
}
.demo2>div{
background-color: green;
width: 40px;
margin: 2px;
-webkit-flex: 1;
flex: 1;
/* for uc */
-webkit-box-flex: 1;
-moz-box-flex: 1;
-ms-flex: 1;
}
</style>
</head>
<body>
<h2>左右排列,上下居中</h2>
<div class="demo1">
<div>flex</div>
<div>flex</div>
<div>flex</div>
<div>flex</div>
<div>flex</div>
</div>
<h2>上下排列,左右居中</h2>
<div class="demo2">
<div>flex</div>
<div>flex</div>
<div>flex</div>
<div>flex</div>
<div>flex</div>
</div>
</body>
</html>
Transform意思是变形,指的是变成什么样子,虽然经常在动画里用到这个属性,但是Transform本事是静态的,跟动画没什么关系。
Transition意思是过渡,指的是怎么变,这个是可以做到动画的。
div
{
width:100px;
height:100px;
background:blue;
transition:width 2s;
-moz-transition:width 2s; /* Firefox 4 */
-webkit-transition:width 2s; /* Safari and Chrome */
-o-transition:width 2s; /* Opera */
}
div:hover
{
width:300px;
}
提示:你可以先修改部分代码再运行。
通过网络获取内容既缓慢,成本又高:大的响应需要在客户端和服务器之间进行多次往返通信,这拖延了浏览器可以使用和处理内容的时间,同时也增加了访问者的数据成本。因此,缓存和重用以前获取的资源的能力成为优化性能很关键的一个方面。
好消息是每个浏览器都实现了 HTTP 缓存! 我们所要做的就是,确保每个服务器响应都提供正确的 HTTP 头指令,以指导浏览器何时可以缓存响应以及可以缓存多久。
如果在应用中使用 Webview 来获取和显示网页内容,可能需要提供额外的配置标志,以确保启用了 HTTP 缓存,并根据用途设置了合理的缓存大小,同时,确保缓存持久化。查看平台文档并确认您的设置!

服务器在返回响应时,还会发出一组 HTTP 头,用来描述内容类型、长度、缓存指令、验证令牌等。例如,在上图的交互中,服务器返回了一个 1024 字节的响应,指导客户端缓存响应长达 120 秒,并提供验证令牌(x234dff),在响应过期之后,可以用来验证资源是否被修改。
这些标头用于指定相应时间段,浏览器可在指定的这段时间内使用已缓存的资源,而无需查看网络服务器是否提供了新版资源。这些缓存标头功能强大,没有任何应用条件限制。在设置这些标头并下载资源后,浏览器不会为资源发出任何GET请求,除非过期日期到期或达到时间最大值,亦或是用户清除了缓存。
这些标头可用于指定浏览器应如何确定用于缓存的文件是否相同。在Last-Modified标头中指定的是日期,而在ETag标头中指定的则可以是唯一标识资源的任意值(通常为文件版本或内容哈希值)。Last-Modified是功能“较弱”的缓存标头,因为浏览器会使用试探法来确定是否需要从缓存中抓取内容。
借助这些标头,浏览器可以通过在用户明确重新加载页面时发出条件式GET请求,有效地更新其已缓存资源。除非您在服务器端更改资源,否则条件式GET请求不会返回完整的响应,因此相较于完整GET请求,此类请求的延迟较小。
对于所有可缓存资源,指定一个Expires或Cache-Control max-age以及一个Last-Modified或ETag至关重要。您没必要同时指定Expires和Cache-Control: max-age;或同时指定Last-Modified和ETag。
- 服务器通过 ETag HTTP 头传递验证令牌
- 通过验证令牌可以进行高效的资源更新检查:如果资源未更改,则不会传输任何数据。
让我们假设在首次获取资源 120 秒之后,浏览器又对该资源发起了新请求。首先,浏览器会检查本地缓存并找到之前的响应,不幸的是,这个响应现在已经’过期’,无法在使用。此时,浏览器也可以直接发出新请求,获取新的完整响应,但是这样做效率较低,因为如果资源未被更改过,我们就没有理由再去下载与缓存中已有的完全相同的字节。
这就是 ETag 头中指定的验证令牌所要解决的问题:服务器会生成并返回一个随机令牌,通常是文件内容的哈希值或者某个其他指纹码。客户端不必了解指纹码是如何生成的,只需要在下一个请求中将其发送给服务器:如果指纹码仍然一致,说明资源未被修改,我们就可以跳过下载。

在上面的例子中,客户端自动在If-None-MatchHTTP 请求头中提供 ETag 令牌,服务器针对当前的资源检查令牌,如果未被修改过,则返回304 Not Modified响应,告诉浏览器缓存中的响应未被修改过,可以再延用 120 秒。注意,我们不必再次下载响应 – 这节约了时间和带宽。
作为网络开发人员,您如何利用高效的重新验证? 浏览器代替我们完成了所有的工作:自动检测是否已指定了验证令牌,并会将验证令牌附加到发出的请求上,根据从服务器收到的响应,在必要时更新缓存时间戳。实际上,我们唯一要做的就是确保服务器提供必要的 ETag 令牌:查看服务器文档中是否有必要的配置标志。
提示:HTML5 Boilerplate 项目包含了所有最流行的服务器的配置文件样例,并且为每个配置标志和设置都提供了详细的注释:在列表中找到您喜欢的服务器,查找适合的设置,然后复制/确认您的服务器配置了推荐的设置。
- 每个资源都可以通过 Cache-Control HTTP 头来定义自己的缓存策略
- Cache-Control 指令控制谁在什么条件下可以缓存响应以及可以缓存多久
最好的请求是不必与服务器进行通信的请求:通过响应的本地副本,我们可以避免所有的网络延迟以及数据传输的数据成本。为此,HTTP 规范允许服务器返回 一系列不同的 Cache-Control 指令,控制浏览器或者其他中继缓存如何缓存某个响应以及缓存多长时间。
Cache-Control 头在 HTTP/1.1 规范中定义,取代了之前用来定义响应缓存策略的头(例如 Expires)。当前的所有浏览器都支持 Cache-Control,因此,使用它就够了。

no-cache表示必须先与服务器确认返回的响应是否被更改,然后才能使用该响应来满足后续对同一个网址的请求。因此,如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应,如果资源未被更改,可以避免下载。
相比之下,no-store更加简单,直接禁止浏览器和所有中继缓存存储返回的任何版本的响应 – 例如:一个包含个人隐私数据或银行数据的响应。每次用户请求该资源时,都会向服务器发送一个请求,每次都会下载完整的响应。
如果响应被标记为public,即使有关联的 HTTP 认证,甚至响应状态码无法正常缓存,响应也可以被缓存。大多数情况下,public不是必须的,因为明确的缓存信息(例如max-age)已表示 响应可以被缓存。
相比之下,浏览器可以缓存private响应,但是通常只为单个用户缓存,因此,不允许任何中继缓存对其进行缓存 – 例如,用户浏览器可以缓存包含用户私人信息的 HTML 网页,但是 CDN 不能缓存。
该指令指定从当前请求开始,允许获取的响应被重用的最长时间(单位为秒) – 例如:max-age=60表示响应可以再缓存和重用 60 秒。

按照上面的决策树来确定您的应用使用的特定资源或一组资源的最优缓存策略。理想情况下,目标应该是在客户端上缓存尽可能多的响应、缓存尽可能长的时间,并且为每个响应提供验证令牌,以便进行高效的重新验证。
| Cache-Control 指令 | 说明 |
|---|---|
| max-age=86400 | 浏览器和任何中继缓存均可以将响应(如果是`public`的)缓存长达一天(60 秒 x 60 分 x 24 小时) |
| private, max-age=600 | 客户端浏览器只能将响应缓存最长 10 分钟(60 秒 x 10 分) |
| no-store | 不允许缓存响应,每个请求必须获取完整的响应。 |
根据 HTTP Archive,在排名最高的 300,000 个网站中(Alexa 排名),所有下载的响应中,几乎有半数可以由浏览器进行缓存,对于重复性网页浏览和访问来说,这是一个巨大的节省! 当然,这并不意味着特定的应用会有 50% 的资源可以被缓存:有些网站可以缓存 90% 以上的资源, 而有些网站有许多私密的或者时间要求苛刻的数据,根本无法被缓存。
审查您的网页,确定哪些资源可以被缓存,并确保可以返回正确的 Cache-Control 和 ETag 头。
- 在资源”过期”之前,将一直使用本地缓存的响应
- 通过将文件内容指纹码嵌入网址,我们可以强制客户端更新到新版的响应
- 为了获得最佳性能,每个应用需要定义自己的缓存层级
浏览器发出的所有 HTTP 请求会首先被路由到浏览器的缓存,以查看是否缓存了可以用于实现请求的有效响应。如果有匹配的响应,会直接从缓存中读取响应,这样就避免了网络延迟以及传输产生的数据成本。然而,如果我们希望更新或废弃已缓存的响应,该怎么办?
例如,假设我们已经告诉访问者某个 CSS 样式表缓存长达 24 小时 (max-age=86400),但是设计人员刚刚提交了一个更新,我们希望所有用户都能使用。我们该如何通知所有访问者缓存的 CSS 副本已过时,需要更新缓存? 这是一个欺骗性的问题 – 实际上,至少在不更改资源网址的情况下,我们做不到。
一旦浏览器缓存了响应,在过期以前,将一直使用缓存的版本,这是由 max-age 或者 expires 指定的,或者直到因为某些原因从缓存中删除,例如用户清除了浏览器缓存。因此,在构建网页时,不同的用户可能使用的是文件的不同版本;刚获取该资源的用户将使用新版本,而缓存过之前副本(但是依然有效)的用户将继续使用旧版本的响应。
所以,我们如何才能鱼和熊掌兼得:客户端缓存和快速更新? 很简单,在资源内容更改时,我们可以更改资源的网址,强制用户下载新响应。通常情况下,可以通过在文件名中嵌入文件的指纹码(或版本号)来实现 – 例如 style.x234dff.css。

因为能够定义每个资源的缓存策略,所以,我们可以定义’缓存层级’,这样,不但可以控制每个响应的缓存时间,还可以控制访问者看到新版本的速度。例如,我们一起分析一下上面的例子:
组合使用 ETag、Cache-Control 和唯一网址,我们可以提供最佳的方案:较长的过期时间,控制可以缓存响应的位置,以及按需更新。
不存在最佳的缓存策略。根据您的通信模式、提供的数据类型以及应用特定的数据更新要求,必须定义和配置每个资源最适合的设置以及整体的’缓存层级’。
在定义缓存策略时,要记住下列技巧和方法:
jQuery.extend可以扩展jQuery对象本身。
用来在jQuery命名空间上增加新函数,或者合并对象。
1. 增加方法:
$.extend({
hello: function () {
console.log(this)//function jQuery(selector, context)
}
});
$.hello();
var obj1 = {'name' : 'sheng00'};
var obj2 = {'sex' : 'Male'};
$.extend(obj1, obj2);
console.log(obj1)//Object {name: "sheng00", sex: "Male"}
用来扩展 jQuery 元素集来提供新的方法(通常用来制作插件)
$.fn.extend({
turn_red: function () {
return this.each(function () {
this.style.color = 'red'
});
}
});
$('.elements').turn_red(); // sets color to red
效果和jQuery.fn.turn_red=function(){}是一样的