使用 workspace 和 source map 功能在 chrome 中修改并保存文件

  1. 创建测试文件

    创建 test/test.html,引入 test/test.css

  2. 打开本地服务器

    这时候审查 test.html 的页面元素修改其 css 属性并不会生效。

  3. 建立本地和服务器的文件映射

    1. 打开 chrome dev tools
    2. 设置 Workspace,添加文件夹 test/
    3. 双击这个新增的文件夹,增加映射

      URL prefix 填写浏览器地址栏对应的服务器根目录

      Folder path 填写本地文件夹的路径

  4. 审查元素,修改 test.html 中的元素的 css 属性

    用编辑器打开 test.css 就会发现修改保存到了文件中了。

  1. 使用 Sass 更进一步

    上述方法能直接将我们在浏览器中对 css 的修改保存到本地文件中,

    但我们可能不是直接编写 css 文件,而是使用了 Sass/Less 等预编译工具,这时候 source map 功能就派上用场了。

  2. 配置 source map 让 chrome 支持 Sass

    小赖使用的是 Webstorm 的 Sass 插件,其能监听 scss 文件的改变,自动生成新的 css 文件。

    但默认一个 scss 文件只会生成对应的 css 文件,我们按以上的方法在浏览器中只能修改 css 文件,而不能修改源 scss 文件。

    解决方法是:

     1. 修改 webstorm 的 sass 插件配置
    
             --no-cache --update $FileName$:$FileNameWithoutExtension$.css
    
         修改为:
    
             --sourcemap --no-cache --update $FileName$:$FileNameWithoutExtension$.css
    
         这时候 test.scss 在自动编译时不仅会生成 test.css 文件,还会生成 test.css.map 文件
    
     2. 开启 chrome 的 source map 功能
    
             打开 dev tools 后,勾选 General->Enable CSS source maps 
    

    这时候,我们审查 test.html 中的元素,则会看到对应的 test.scss 文件

    但在浏览器中修改 css 属性时,实际上修改的是 test.scss 编译生成的 test.css 文件。

    我们希望直接修改的是 test.scss 文件,这时候点击 dev tools 中的 Source,找到对应的 test.scss 文件修改后 cmd + s 保存即可。

  3. 第6点其实有点鸡肋

    目前 source map 能让我们在浏览器中修改 css 属性后保存到对应的 css 文件中。

    而要修改 Sass 文件只能借 Workspace 功能在 Source 面板中修改后保存,但这时候修改的 Sass 文件并不会自动编译为对应的 css 文件。

    在浏览器中修改 Sass 文件保存到本地后,浏览器中的 css 并没有即时改变。

Nodejs 的 stream 使用指南

使用 Stream

当我们读取一个文件内容时,可能会这么写:

var http = require('http');
var fs = require('fs');
var server = http.createServer(function (req, res) {
    fs.readFile(__dirname + '/data.txt', function (err, data) {
        res.end(data);
    });
});
server.listen(8000);

当这个文件 data.txt 非常大时,不仅会占满内存,而且对于网络不好的用户而言体验将非常差。

好在 req 和 res 都是 Stream 对象,我们可以使用 Stream 的方式来写代码:

var http = require('http');
var fs = require('fs');
var server = http.createServer(function (req, res) {
    var stream = fs.createReadStream(__dirname + '/data.txt');
    stream.pipe(res);
});
server.listen(8000);

我们使用 fs.createReadStream 创建了一个 Stream 对象,.pipe() 方法会监听对应的 dataend 事件。

使用 Stream 的好处在于,我们将 data.txt 分段(chunk)传输到客户端,减轻了网络带宽的压力。

阅读全文

bytewiser 练习

bytewiser 是 nodeschool.io 出品的nodejs入门练习项目

bytewiser-exercise-1

Write a node program that prints a buffer object containing the string “bytewiser” using console.log.

1
2
3
var str = 'bytewiser';
var buffer = new Buffer(str);
console.log(buffer);

bytewiser-exercise-2

Given an unknown number of bytes passed via process.argv, create a buffer from them and output a hexadecimal encoded representation of the buffer.

1
2
3
4
5
6
7
var array = process.argv.slice(2);
var buffer = new Buffer(array);
console.log(buffer.toString('hex'));
// 官方答案
// var bytes = process.argv.slice(2).map(function(arg) { return parseInt(arg) })
// console.log(new Buffer(bytes).toString('hex'))

阅读全文

Sass 学习笔记

  1. 1. 安装 Sass
  2. 2. 快速入门 sass 语法
    1. 2.1. Variables | 变量
    2. 2.2. Nesting | 嵌套
    3. 2.3. Partials | 模板
    4. 2.4. Mixins | 混入
    5. 2.5. Inheritance | 继承
    6. 2.6. Operators | 运算符
  3. 3. 编译 .scss 为 .css
  4. 4. 监听文件变化
    1. 4.0.1. 参考链接

安装 Sass

1
2
3
4
5
6
$ gem install sass
// 或
$ sudo gem install sass
// 查看 sass 版本
$ sass -v

快速入门 sass 语法

Variables | 变量

1
2
3
4
5
6
7
8
// test.scss
$lai-font: Roboto, sans-serif;
$lai-color: #eee;
body {
color: $lai-color;
font-family: $lai-font;
}

Nesting | 嵌套

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
nav {
ul {
margin: 0 auto;
padding: 0;
list-style: 0;
}
li {
display: inline-block;
}
a {
display: block;
padding: 5px 10px;
text-decoration: none;
}
}

Partials | 模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// _reset.scss
html,
body,
ul,
ol {
margin: 0;
padding: 0;
}
// 使用 partial
// base.scss
@import 'reset'
body {
backgrount: #333;
}

Mixins | 混入

1
2
3
4
5
6
7
8
9
10
@mixin border-radius($radius) {
-webkit-border-radius: $radius;
-moz-border-radius: $radius;
-ms-border-radius: $radius;
border-radius: $radius;
}
// 使用 mixin
.box {
@include border-radius(10px);
}

Inheritance | 继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.message {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
@extend .message;
border-color: green;
}
.error {
@extend .message;
border-color: red;
}
.warning {
@extend .message;
border-color: yellow;
}

Operators | 运算符

.container {
width: 100%;
}
article[role=”main”] {
float: left;
width: 600px / 960px 100%;
}
article[role=”sub”] {
float: right;
width: 300px / 960px
100%;
}

编译 .scss 为 .css

nested:嵌套缩进的css代码,它是默认值。
   
expanded:没有缩进的、扩展的css代码。
   
compact:简洁格式的css代码。
  
compressed:压缩后的css代码。

1
2
3
4
5
6
7
// 编译风格默认为 --style nested
$ sass test.scss test.css
// 编译风格设置为 --style compressed
$ sass --style compassed test.scss test.css
// 查看编译后的 test.css
$ cat test.css

监听文件变化

一旦某个文件/目录发生变化,Sass 就自动编译出新的版本

1
2
3
4
// 监听文件
$ sass --watch test.scss:test.css
// 监听目录,一旦 src/scss 下有文件发生变化,就编译到 dist/css 目录
$ sass --watch src/scss:dist/css

参考链接

CSS属性扫盲笔记

  1. 1. 参考资料
  • :before 和 ::before 的区别

单冒号表示 CSS3 伪类,双冒号表示 CSS3 伪元素
双冒号是 CSS3 新引入的属性, 而要兼容 IE8- 则需要使用单冒号
不需要兼容 IE8- 则可以放心的使用双冒号

  • -webkit-appearance 设置如何显示元素的外观

http://ued.ctrip.com/webkitcss/demo/appearance.html

  • -webkit-touch-callout 设置如何显示一个可触摸目标的样式

http://css-infos.net/property/-webkit-touch-callout

  • -webkit-user-select 设置是否可以选择元素内容

http://ued.ctrip.com/blog/wp-content/webkitcss/prop/user-select.html

  • -webkit-user-drag 设置是否可以拖动元素内容

http://ued.ctrip.com/blog/wp-content/webkitcss/prop/user-drag.html

  • -webkit-flex 设置伸缩布局

http://ued.ctrip.com/blog/wp-content/webkitcss/prop/flex.html

安卓 4.4+ 才支持, 伤不起啊…

  • -webkit-tap-highlight-color 设置元素的点击高亮颜色

http://ued.ctrip.com/webkitcss/prop/tap-highlight-color.html

/* 设置为透明, 则禁用该属性 */
-webkit-tap-highlight-color: transparent;

/* 场景: callout 和 hightlite 配合使用*/
.nohighlight {
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
  • 以下属性与 display: -webkit-box; 配合使用

-webkit-box-sizing 设置对象的盒模型组成模式

    .selector {
        width: 100px;
        margin: 10px;
        padding: 10px;
        border: 1px solid #eee;
        // 设置为 border-box, 则 width 包含了 padding 和 border 
        -webkit-box-sizing: border-box;
    }

-webkit-box-flex 设置弹性盒模型对象的子元素如何分配剩余空间

.selector-parent {
    width: 150px;
    display: -webkit-box;
}
.selector-child-fixed {
    width: 50px;
}
.selector-child-flex-1 {
    /* 占 40px */
    -webkit-box-flex: 2;
}
.selector-child-flex-2 {
    /*占 60px */
    -webkit-box-flex: 3;
}
  • -webkit-box-orient 设置弹性盒模型对象的子元素的排列方式

http://ued.ctrip.com/blog/wp-content/webkitcss/prop/box-orient.html

  • -webkit-box-pack 设置弹性盒模型对象的子元素的对齐方式

http://ued.ctrip.com/blog/wp-content/webkitcss/prop/box-pack.html

  • -webkit-box-align 设置弹性盒模型对象的子元素的对齐方式

http://ued.ctrip.com/blog/wp-content/webkitcss/prop/box-align.html

  • -webkit-line-clamp 设置块元素显示文本的行数

http://www.css88.com/webkit/-webkit-line-clamp/

.text-overflow-ellipsis {
    // 显示一行
    -webkit-line-clamp: 1;
    // 溢出隐藏
    text-overflow: ellipsis;
    overflow: hidden;
    // 和模型的子元素垂直排列
    display: -webkit-box;
    -webkit-box-orient: vertical;

}

参考资料

阻止元素被选中及清除选中的方法

  1. 1. 阻止选中
    1. 1.1. 使用 JS 阻止整个网页的内容被选中
    2. 1.2. 阻止特定区域的内容被选中
    3. 1.3. 使用 CSS 控制样式阻止内容被选中
  2. 2. 清除选中
    1. 2.1. 使用 JS 清除选中
    2. 2.2. 使用 CSS 清除选中
      1. 2.2.1. 参考链接

有时候,我们希望阻止用户选中我们指定区域的文字或内容。

举个栗子,有时候用户在一个区域执行频繁的点击操作,一不小心傲娇地点多了,就会选中当前区域的内容。

再举个栗子,制作轮播组件的时候,点击下一页,若点击的快的话,浏览器会识别为双击。

双击的默认效果是选中整片区域,这时候轮播图组件就会被表示忧郁的蓝色幕布盖住,多忧桑啊~

你看,这妹子多赞啊,可是你一紧张就乱点下一张的话,就变成酱紫了:

不过别怕,给这个现代化浏览器说好了咱不要这种忧桑色调就可以了:

1
2
3
.pretty-girl {
-webkit-user-select: none;
}

可是!可是!不是每个浏览器都可以不忧桑!!!那就只能请脚本大王出山了。

阻止选中

有时候,我们需要禁止用户选中一些文本区域,这时候可以直接通过让 onselectstart 事件 return false 来实现。

使用 JS 阻止整个网页的内容被选中

1
2
3
4
5
6
7
8
document.body.onselectstart = function () {
return false;
};
// 或
document.body.onmousedown = function () {
return false;
}

阻止特定区域的内容被选中

1
2
3
4
var elem = document.getElementById('elemId');
elem.onselectstart = function () {
return false;
};

使用 CSS 控制样式阻止内容被选中

仅支持非 IE10 以下的浏览器。IE9 以下请使用 onselectstart=”return false;” 的方式来实现。

1
2
3
4
5
6
7
8
9
10
.unselect {
-webkit-user-select: none;
-moz-user-select: none;
-khtml-user-select: none;
-ms-user-select: none;
/* 以下两个属性目前并未支持,写在这里为了减少风险 */
-o-user-select: none;
user-select: none;
}

user-select: auto; => 用户可以选中元素中的内容

user-select: none; => 用户不可选中元素中的内容

user-select: text; => 用户可以选中元素中的文字

目前这个 user-select 兼容 Chrome 6+、Firefox、IE 10+、Opera 15+、Safari 3.1+。

需要注意的是,这个 user-select 还带浏览器厂商前缀,意味着她们还是非标准的,将来可能会改变。在生产环境中要慎用。

清除选中

有时候用户选中文字进行复制后,我们使用手动的方式进行选中的清除。

使用 JS 清除选中

1
2
3
4
5
6
7
8
9
10
11
12
13
function clearSelections () {
if (window.getSelector) {
// 获取选中
var selection = window.getSelection();
// 清除选中
selection.removeAllRanges();
} else if (document.selection && document.selection.empty) {
// 兼容 IE8 以下,但 IE9+ 以上同样可用
document.selection.empty();
// 或使用 clear() 方法
// document.selection.clear();
}
}

使用 CSS 清除选中

不考虑低版本 IE 的情况下,我们简单给选中元素添加以上 .unselect 的样式即可。

参考链接

MDN user-select

【译】HTML5 prefetch

  1. 1. 有了浏览器缓存,为何还需要预加载?
  2. 2. Chrome 的预加载技术
  3. 3. DNS prefetch
  4. 4. Resource prefetch
  5. 5. Pre render
  6. 6. 不是所有的资源都可以预加载
  7. 7. 手动触发预渲染操作
  8. 8. 兼容性
  9. 9. 警告
    1. 9.0.1. 参考链接

声明:此文带着自己的理解,不完全按原文翻译,原文地址

prefetch 即预加载,在用户需要前我们就将所需的资源加载完毕。

有了浏览器缓存,为何还需要预加载?

  • 用户可能是第一次访问网站,此时还无缓存
  • 用户可能清空了缓存
  • 缓存可能已经过期,资源将重新加载
  • 用户访问的缓存文件可能不是最新的,需要重新加载

Chrome 的预加载技术

现在的 chrome 聪明到根据你的浏览记录,预测到你可能访问或搜索哪些网站,在你打开网站之前就加载好了一些资源了。
举个栗子,当你在搜索框输入 “amaz” 时,它猜测到你可能要访问 amazon.com,可能就帮你加载了这个网站的一些资源。
如果这个预测算法精准的话,就能大大地提高用户的浏览体验了。

DNS prefetch

我们知道,当我们访问一个网站如 www.amazon.com 时,需要将这个域名先转化为对应的 IP 地址,这是一个非常耗时的过程。

DNS prefetch 分析这个页面需要的资源所在的域名,浏览器空闲时提前将这些域名转化为 IP 地址,真正请求资源时就避免了上述这个过程的时间。

1
2
3
4
5
6
<meta http-equiv='x-dns-prefetch-control' content='on'>
<link rel='dns-prefetch' href='http://g-ecx.images-amazon.com'>
<link rel='dns-prefetch' href='http://z-ecx.images-amazon.com'>
<link rel='dns-prefetch' href='http://ecx.images-amazon.com'>
<link rel='dns-prefetch' href='http://completion.amazon.com'>
<link rel='dns-prefetch' href='http://fls-na.amazon.com'>

应用场景1:我们的资源存在在不同的 CDN 中,那提前声明好这些资源的域名,就可以节省请求发生时产生的域名解析的时间。
应用场景2:如果我们知道用户接下来的操作一定会发起一起资源的请求,那就可以将这个资源进行 DNS-Prefetch,加强用户体验。

Resource prefetch

在 Chrome 下,我们可以用 link标签声明特定文件的预加载:

1
2
3
4
<link rel='subresource' href='critical.js'>
<link rel='subresource' href='main.css'>
<link rel='prefetch' href='secondary.js'>

在 Firefox 中或用 meta 标签声明:

1
<meta http-equiv="Link" content="<critical.js>; rel=prefetch">

rel=’subresource’ 表示当前页面必须加载的资源,应该放到页面最顶端先加载,有最高的优先级。

rel=’prefetch’ 表示当 subresource 所有资源都加载完后,开始预加载这里指定的资源,有最低的优先级。

注意:只有可缓存的资源才进行预加载,否则浪费资源!

Pre render

前面说到的预解析DNS、预加载资源已经够强悍了有木有,可还有更厉害的预渲染(Pre-rendering)!

预渲染意味着我们提前加载好用户即将访问的下一个页面,否则进行预渲染这个页面将浪费资源,慎用!

1
<link rel='prerender' href='http://www.pagetoprerender.com'>

rel=’prerender’ 表示浏览器会帮我们渲染但隐藏指定的页面,一旦我们访问这个页面,则秒开了!

在 Firefox 中或用 rel=’next’ 来声明

1
<link rel="next" href="http://www.pagetoprerender.com">

不是所有的资源都可以预加载

当资源为以下列表中的资源时,将阻止预渲染操作:

  • URL 中包含下载资源
  • 页面中包含音频、视频
  • POST、PUT 和 DELETE 操作的 ajax 请求
  • HTTP 认证(Authentication)
  • HTTPS 页面
  • 含恶意软件的页面
  • 弹窗页面
  • 占用资源很多的页面
  • 打开了 chrome developer tools 开发工具

手动触发预渲染操作

在 head 中强势插入 link[rel=’prerender’] 即可:

1
2
3
4
var hint =document.createElement("link")
hint.setAttribute(“rel”,”prerender”)
hint.setAttribute(“href”,”next-page.html”)
document.getElementsByTagName(“head”)[0].appendChild(hint)

兼容性

这么好用的特性,当然要考虑各浏览器的兼容程度了(哭:

IE9 支持 DNS pre-fetching 但管它叫 prefetch。

IE10+ 中 dns-prefetch 和 prefetch 是等价的。

其他方面的测试,目前还没有很好的方案,暂且只能通过查看浏览器是否缓存来测试。

在 Chrome 中打开了 chrome developer tools 开发工具会阻止页面的预渲染,所以我们看不到这个过程,但可以在 chrome://cache/ 或 chrome://net-internals/#prerender 中查看。

Firefox 可以在 about:cache 中查看。

警告

这些特定还是实验性质的,将来可能改变。

权利越大,责任越大,不要滥用!

参考链接

Git fork 别人的项目后更新代码的方法

  1. 举个例子,需要 fork 这个项目 https://github.com/tarobjtu/WebFundamentals.git

  2. 点击 fork, 就会复制一份代码到自己的 repo https://github.com/laispace/WebFundamentals.git

  3. 本地 clone 自己 repo 中的这个项目

    $ git clone https://github.com/laispace/WebFundamentals.git

  4. 添加自己的远程仓库

    $ cd WebFundamentals
    $ git remote add laispace https://github.com/laispace/WebFundamentals.git

  5. 修改代码后进行 push

    $ git add —all
    $ git commit -m ‘edit some files’
    $ git push

这时候,如果源仓库 tarobjtu 的项目代码进行了更新,而我们自己 fork 下来的代码想要合并这些更新怎么做呢?

  1. 添加源项目的远程仓库

    $ git remote add tarobjtu https://github.com/tarobjtu/WebFundamentals.git
    // 这时候可以看到有两个源了
    $ git remote
    // laispace
    // tarobjtu

  2. 拉取源仓库的代码到本地

    $ git fetch tarobjtu

  3. 合并源仓库的 master 分支代码到本地

    $ git merge tarobjtu/master

  4. 提交代码到我们自己的仓库

    $ git add —all
    $ git commit -m ‘合并源仓库代码’
    $ git push

Base 64 编码

在浏览器中,使用 window.btoa() 将字符串或二进制值转化为 Base64 编码,使用 window.atob() 还原。

1
2
window.btoa('laispace'); //=> "bGFpc3BhY2U="
window.atob("bGFpc3BhY2U="); //=>"laispace"

注意,要将非 ASCII 编码字符转化为 Base64 编码的话,需要先进行转码,否则会报错

1
2
3
window.btoa(encodeURI('赖小赖')); //=> "JUU4JUI1JTk2JUU1JUIwJThGJUU4JUI1JTk2"
window.atob('JUU4JUI1JTk2JUU1JUIwJThGJUU4JUI1JTk2'); //=> "%E8%B5%96%E5%B0%8F%E8%B5%96"
decodeURI("%E8%B5%96%E5%B0%8F%E8%B5%96"); //=> "赖小赖"