annewanghy / annewanghy.github.io Goto Github PK
View Code? Open in Web Editor NEWHome Page: https://annewanghy.github.io
Home Page: https://annewanghy.github.io
1. 制作u盘启动盘
2. 重启,按f12进入bash, 切换到startup启动项,将制作好的u盘调到首位
3. 进入deepin安装界面, 选择安装盘
4. 拔掉u盘, 重启, 完成安装
先安装一个 nvm( https://github.com/creationix/nvm )
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.2/install.sh | bash
nvm 的全称是 Node Version Manager,之所以需要这个工具,是因为 Node.js 的各种特性都没有稳定下来,所以我们经常由于老项目或尝新的原因,需要切换各种版本。
安装完成后,重启bash, 你的 shell 里面应该就有个 nvm 命令了,调用它试试
$ nvm
当看到有输出时,则 nvm 安装成功。
安装 Node.js
使用 nvm 的命令安装 Node.js 最新稳定版,现在是 v6.8.0。
$ nvm install 6.8.0
安装完成后,查看一下
why@why-PC:~/Downloads$ node -v
v6.8.0
why@why-PC:~/Downloads$ npm -v
3.10.8
查看自己安装的所有 Node.js 版本
$ nvm ls
-> v6.8.0
node -> stable (-> v6.8.0) (default)
stable -> 6.8 (-> v6.8.0) (default)
iojs -> iojs- (-> N/A) (default) #iojs是node.js的一个预发版本, 可以自己百度查看
如果出现下面错误,node未找到命令可以使用下面方法
why@why-PC:~/Downloads$ node
bash: node: 未找到命令
why@why-PC:~/Downloads$ nvm use stable
Now using node v6.8.0 (npm v3.10.8)
npm config set registry 'https://registry.npm.taobao.org'
或直接使用cnpm, 接下来每次都使用cnpm安装
npm install -g cnpm
express
url
<scheme>://<user>:<password>@<host>:<port>/<url-path>
mkdir lesson1 & cd lesson1
npm install express --save-dev
touch app.js
// 引入express模块
var express = require('express');
// 调用express实例
var app = express();
//app本身有很多方法, 最常用的get, post, put/patch, delete
// handler函数接收req, res两个参数, 分别试request请求和response会员
app.get('/', function(req, res) {
res.send('Hello world!'); //res.send向屏幕输出一个字符
})
// 监听3000端口
app.listen(3000, function(){
console.log('app is listening at port 3000');
})
node app.js
打开浏览器,localhost:3000, 出现Hello Wolrd!字样
express-generator
快速生成express项目全局安装express-generator
npm install express-generator -g
快速生成项目
express --view=pug myapp
create : myapp
create : myapp/package.json
create : myapp/app.js
create : myapp/public
create : myapp/routes
create : myapp/routes/index.js
create : myapp/routes/users.js
create : myapp/views
create : myapp/views/index.pug
create : myapp/views/layout.pug
create : myapp/views/error.pug
create : myapp/bin
create : myapp/bin/www
create : myapp/public/javascripts
create : myapp/public/images
create : myapp/public/stylesheets
create : myapp/public/stylesheets/style.css
install dependencies:
$ cd myapp && npm install
run the app:
$ DEBUG=myapp:* npm start
> [email protected] start /home/why/Downloads/myapp
> node ./bin/www
myapp:server Listening on port 3000 +0ms
route路由, get. post, put/patch, delete
Respond with Hello World! on the homepage:
app.get('/', function (req, res) {
res.send('Hello World!')
})
Respond to POST request on the root route (/), the application’s home page:
app.post('/', function (req, res) {
res.send('Got a POST request')
})
Respond to a PUT request to the /user route:
app.put('/user', function (req, res) {
res.send('Got a PUT request at /user')
})
Respond to a DELETE request to the /user route:
app.delete('/user', function (req, res) {
res.send('Got a DELETE request at /user')
})
package.json
和ultity.md5()加密npm init来生成一个package.json文件
npm install express utility --save 本地安装,会多出来依赖
"dependencies": {
"express": "^4.15.3",
"utility": "^1.12.0"
}
http://localhost:4000/?q=st
md5加密之后
627fcdb6cc9a5e16d657ca6cdef0a6bb
var express = require('express')
var utility = require('utility')
var app = express()
app.get('/', function(req,res){
var q = req.query.q
var md5value = utility.md5(q)
res.send(md5value)
})
app.listen(4000, function(req, res){
console.log('listening at port 3000')
})
7. superagent
和cherrio
爬虫
superagent
request
.post('/api/pet')
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')
.set('Accept', 'application/json')
.end(function(err, res){
if (err || !res.ok) {
alert('Oh no! error');
} else {
alert('yay got ' + JSON.stringify(res.body));
}
});
爬取cnodejs网站的信息
var express = require('express')
var superagent = require('superagent')
var cheerio = require('cheerio')
app = express()
app.get('/', function(req, res){
// 使用superagent爬取https://cnodejs.org/的内容
superagent.get('https://cnodejs.org')
.end(function(err, content){ //命名为content是为了不与res冲突
if(err) {
return next(err)
}
// 使用cheerio解析网页的html内容,与jquery类似
var $ = cheerio.load(content.text)
var items = []
$('#topic_list .topic_title').each(function(idx, element) {
var $element = $(element)
items.push({
title: $element.attr('title'),
href: $element.attr('href')
})
})
res.send(items)
})
})
app.listen(3001, function(req,res) {
console.log('listening at port 3001')
})
netstat -nap | grep node
查看node.js打开的端口
tcp6 0 0 :::6000 :::* LISTEN 10958/node
tcp6 4 0 :::3000 :::* LISTEN 8035/node
tcp6 0 0 :::3001 :::* LISTEN 11004/node
tcp6 3 0 :::4000 :::* LISTEN 9443/node
tcp6 2 0 :::5000 :::* LISTEN 10849/node
tcp6 1 0 127.0.0.1:4000 127.0.0.1:39482 CLOSE_WAIT 9443/node
tcp6 1 0 127.0.0.1:5000 127.0.0.1:40180 CLOSE_WAIT 10849/node
tcp6 1 0 127.0.0.1:5000 127.0.0.1:40182 CLOSE_WAIT 10849/node
tcp6 491 0 127.0.0.1:5000 127.0.0.1:39340 CLOSE_WAIT 10849/node
tcp6 1 0 127.0.0.1:5000 127.0.0.1:40178 CLOSE_WAIT 10849/node
tcp6 0 0 127.0.0.1:3001 127.0.0.1:47786 ESTABLISHED 11004/node
使用kill -9 8035
杀死进程, 其中8035是pid
11.Mongodb 与 Mongoose 的使用
node --v8-options | grep harmony
Babel
是一个ES6转码器,可以将ES6代码转换为ES5代码, 从而在现有环境下支持
箭头函数=> 转换为普通函数 function(){}
配置文件.babelrc
{
"presets": [],
"plugins": []
}
presets字段设置转码规则
# 最新转码规则
$ npm install --save-dev babel-preset-latest
# react 转码规则
$ npm install --save-dev babel-preset-react
# 不同阶段语法提案的转码规则(共有4个阶段),选装一个
$ npm install --save-dev babel-preset-stage-0
$ npm install --save-dev babel-preset-stage-1
$ npm install --save-dev babel-preset-stage-2
$ npm install --save-dev babel-preset-stage-3
{
"presets": [
"latest",
"react",
"stage-2"
],
"plugins": []
}
babel-cli工具, 用于命令行转码
$ npm install --global babel-cli
emmet 是什么
首先是官网上的介绍。
Emmet is a plugin for many popular text editors which greatly improves HTML & CSS workflow.
Emmet 是一个可用在许多流行文本编辑器上的极大简化 HTML 和 CSS 工作流程的插件。
前身是 Zen coding
,他使用仿 css 选择器的语法来生成代码,极大提高了编写 HTML/CSS 的效率,之后改名为 emmet
,但是随之而来的改变不仅限于名字,还增加了许多新的特性。
新建一个html文档, 输入html:5, 按下tab键, 神奇的事情发生了
html:5
// tab
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
</body>
</html>
添加类、id、文本和属性
emmet 的一个强大特性,使用类 CSS 选择器的方式,
. 是生成类名,
# 是生成 id,
{} 中生成文本内容,
[] 中可以设置属性, 可以嵌套使用。
p
<p></p>
p.bar
<p class="bar"></p>
p.bar1.bar2
<p class="bar1 bar2"></p>
p#foo
<p id="foo"></p>
input[type=radio]
<input type="radio">
p.bar#foo{123}
<p class="bar" id="foo">123</p>
嵌套和分组
emmet 又一个强大的特性,也是让你写 html 速度起飞的关键因素。嵌套语法:
>:子元素符号,表示嵌套的元素
+:同级标签符号^:可以使该符号前的标签提升一行
其中 ^ 用的不多,容易让人逻辑混乱,这个时候就需要良好的分组来实现。
p>span
<p><span></span></p>
p+span
<p></p>
<span></span>
p>h1^span
<p>
<h1></h1>
</p>
<span></span>
(p>h1)+span
<p>
<h1></h1>
</p>
<span></span>
重复添加相同元素
ul>li*5
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
加上分组的应用,可以处理更复杂的 html 结构
(div.warp>p.bar+span#foo)*2
<div class="warp">
<p class="bar"></p>
<span id="foo"></span>
</div>
<div class="warp">
<p class="bar"></p>
<span id="foo"></span>
</div>
列表按序计数
ul>li.item$*3
<ul>
<li class="item1"></li>
<li class="item2"></li>
<li class="item3"></li>
</ul>
如果想要两位数的序号,添加两个$即可,依此类推
ul>li{item$$}*3
<ul>
<li>item01</li>
<li>item02</li>
<li>item03</li>
</ul>
参考资料
emmet 官网
Emmet:HTML/CSS 代码快速编写神器
sublime text 2 中 Emmet8 个常用的技巧
console.disableYellowBox = true;
ScreenToGif--屏幕录制软件,到官网上下载就是一个.exe文件,无需安装,操作简单。
txt2Mobi通用版--txt文件格式文件必须转换为mobi等格式才可以在kindle阅读,这个下载下来也是一个.exe
文件,打开之后将.txt
文件拖到软件,就会自动生成一个.html
文件和.mobi
文件,接下来只需要将.mobi
文件拷贝到kindle的.document
文件夹就可以直接阅读了。
sdr-Cleaner_win文件只有5.4M,也是一个.exe
文件,数据线连接kindle和电脑,双击这个.exe
文件就会自动清理kindle了。
everything电脑上的文件查找软件,非常强大,Windows64操作系统可以选择Everything-1.4.0.713b.x64.Multilingual-Setup.exe
这个下载,安装之后文件也不是很大。
微盘上面的两个网站都是微盘的网站,的确微盘是一个找资源的好网站。
谷歌浏览器的插件都需要通过谷歌应用商店添加,但是无奈的是需要翻墙,但是山人自有妙计,谷歌插件网就是一个国内的谷歌插件网站,这个网站上有很多强大的停不下来的插件,可以完美地解决添加插件的问题。下面是我正在用的插件
insight
给github换成IDE的风格
adblock pluschorme去广告插件,官网https://adblockplus.org/zh_CN/,官网的缺点是不能成功下载,所以我的链接是直接到上面提及的谷歌插件网下载。这个插件可以屏蔽大多数广告,还可以自己手动右键屏蔽广告。
花瓣网页采集工具,网页截图还可以编辑图片,快捷键ctrl+ Shift+ R
还可以截取网页制作长图,还可以收集网页上好看的图片,花瓣网本身也是设计师的天堂。
click && Clean 一键删除浏览记录,以前只能通过设置->历史记录—>清除浏览记录
才可以删除浏览记录,这样太消耗时间,现在用这个插件,实时显示浏览网页的个数,一键就可以删除,关闭浏览器自动清除浏览记录,如果遇到关闭重要的网页,还可以直接用谷歌自带快捷键ctrl+ shift + T
,恢复刚刚关闭的网页。
印象笔记·悦读,自动识别博客主文,让阅读博客免受干扰,选择本站下载,就会自动添加到chorme插件上。
Video Downloader [FVD]网页视频自动检测,并下载,网页链接的图有点。。。但是下载不成问题,重要的是工具使用,很流畅地下载微博上的短视频。
以上是我在用的,小而功能强大的软件,如果你也有好的软件,非常欢迎一起分享,文章会持续更新!
空间换时间的原理, 会占用一点点内存, 但是给你的 web 服务提升明显的性能.
使用redis缓存数据, 当数据不变时, 直接从redis缓存中读取, 只有当要与数据库进行交互时,才去访问数据库.
var redis = require('redis');
var md5 = require('md5');
var redisClient = redis.createClient();
app.get('/demo', function (req, res) {
var name = req.query.name;
var key = md5([req.method, req.url, JSON.stringify(req.query)].join(':'));
var expired = 60*5;
redisClient.get(key, function (err, result) {
if (err) {
return res.send({message: 'Failed', data: err});
}
if (result) {
// Read data from cache.
return res.send({message: 'OK', JSON.parse(result)});
} else {
// Read data from Mongo and write result into redis.
User.findOne({name: name}, function (err, user) {
if (err) {
return res.send({message: 'Failed', data: err});
}
res.send({message: 'OK', user});
redisClient.setex(key, expired, JSON.stringify(user));
});
}
});
});
[Redis + Node.js: 请求缓存](http://m.2cto.com/kf/201612/575924.html)
2.Buffers 缓存对象
3. node-cache 轻量级
var cache = require('memory-cache');
// now just use the cache
cache.put('foo', 'bar');
console.log(cache.get('foo'));
// that wasn't too interesting, here's the good part
cache.put('houdini', 'disappear', 100, function(key, value) {
console.log(key + ' did ' + value);
}); // Time in ms
console.log('Houdini will now ' + cache.get('houdini'));
setTimeout(function() {
console.log('Houdini is ' + cache.get('houdini'));
}, 200);
// create new cache instance
var newCache = new cache.Cache();
newCache.put('foo', 'newbaz');
setTimeout(function() {
console.log('foo in old cache is ' + cache.get('foo'));
console.log('foo in new cache is ' + newCache.get('foo'));
}, 200);
http://yijiebuyi.com/blog/c37a444faab98617a98098f7a29e09db.html
http://localhost:3000/repos?org=risingstack
4. node-redis--redis - a node.js redis client
the-little-redis-book
Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED 127.0.0.1:6379
redis - windows
config redis server
Redis 是一个开源,高级的键值存储和一个适用的解决方案,用于构建高性能,可扩展的 Web 应用程序。
Redis 有三个主要特点,使它优越于其它键值数据存储系统 -
Redis 将其数据库完全保存在内存中,仅使用磁盘进行持久化。
与其它键值数据存储相比,Redis 有一组相对丰富的数据类型。
Redis 可以将数据复制到任意数量的从机中
const express = require('express')
const superagent = require('superagent')
var redis_client = require('redis').createClient()
const PORT = 3000
const app = express()
function getNumberOfRepos(req, res, next) {
const org = req.query.org
superagent.get(`https://api.github.com/orgs/${org}/repos`, (err, response) => {
if (err) throw err
var num = response.body.length
redis_client.setex(org, 10, num)
res.send(`Organization "${org}" has ${num} public repositories.`)
})
}
function cache(req, res, next) {
const org = req.query.org
redis_client.get(org, (err, data) => {
if(err) throw err
if(data != null){
res.send(`Orginization "${org}" has ${data} public repositories.`)
} else {
next()
}
})
}
app.get('/repos', cache, getNumberOfRepos)
app.listen(PORT, () => console.log(`app listen on port ${PORT}`))
# 启动redis-server
redis-server redis.windows.conf
# 配置redis为windows服务
redis-server --service-install redis.windows.conf
# 开启redis-server服务
redis-server --service-start
# 关闭redis-server服务
redis-server --service-stop
λ redis-cli
127.0.0.1:6379>
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> CONFIG GET loglevel
1) "loglevel"
2) "notice"
var redis = require('redis'),
client = redis.createClient(null, null, { detect_buffers: true }),
router = express.Router();
router.route('/latestPosts').get(function(req,res){
client.get('posts', function (err, posts) {
if (posts) {
return res.render('posts', { posts: JSON.parse(posts) });
}
Post.getLatest(function(err, posts) {
if (err) {
throw err;
}
client.set('posts', JSON.stringify(posts));
res.render('posts', { posts: posts });
});
});
});
我们首先检查 Redis 缓存,看看是否有帖子。如果有,我们从缓存中拿这些帖子列表。否则我们就检索数据库内容,然后把结果缓存。此外,一定时间之后,我们可以清理 Redis 缓存,这样就可以更新内容了
hjkl
移动
i
进入 insert
模式esc
退出到 normal
模式:wq
保存并退出:q!
退出不保存i,a,A
都可以进入到insert
模式
i
在指针cursor
前插入insert
a
在指针cursor
后插入append
A
在行尾插入o
也可以直接向后插入一行,并进入insert mode
ctrl+v
进入vision
模式, 可以进行反白状态的多选y
复制p
粘贴pastex
删除一个word
dd
删除一行u
撤销undo
ctrl+r
重做redo
c
(change)直接在R
直接进入Replace mode
/
开启查找n
向后重复查找N
向前重复查找G
文件尾gg
文件首暂时记住了这么多,w
不是很会用
原文:Koa 框架教程 - 阮一峰的网络日志
学习阮一峰对于Koa框架的心得体会:
context
对象, 表示一次http对话的上下文,包含context.request
和context.response
, 缩写为ctx
,Context.response.body
是发送给用户的内容.ctx.response.type
, 默认是text/plain
, 可以指定返回类型,比如ctx.response.type = 'html';
fs
的读文件流, ctx.response.body = fs.createReadStream('./demos/template.html')
ctx.request.path
获取用户请求的路由; 使用koa-route
模块,app.use(route.get('/', main));
koa-static
模块访问静态资源,path
模块处理路径const path = require('path');
const serve = require('koa-static');
const main = serve(path.join(__dirname));
app.use(main);
ctx.response.redirect()
middleware
const logger = (ctx, next) => {
console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`);
next();
}
app.use(logger);
像上面代码中的logger函数就叫做 "中间件"(middleware),因为它处在 HTTP Request
和 HTTP Response
中间,用来实现某种中间功能。app.use()
用来加载中间件。
基本上,Koa
所有的功能都是通过中间件实现的。每个中间件默认接受两个参数,第一个参数是 Context
对象,第二个参数是next
函数。只要调用next
函数,就可以把执行权转交给下一个中间件.
8. 中间件栈middle stack
, 以 "先进后出"(first-in-last-out
)的顺序执行
最外层的中间件首先执行。
调用next函数,把执行权交给下一个中间件。
...
最内层的中间件最后执行。
执行结束后,把执行权交回上一层的中间件。
...
最外层的中间件收回执行权之后,执行next函数后面的代码。
async
和await
两个关键字fs.readFile
是一个异步操作,必须写成await fs.readFile()
,然后中间件必须写成async
函数。const fs = require('fs.promised');
const Koa = require('koa');
const app = new Koa();
const main = async function (ctx, next) {
ctx.response.type = 'html';
ctx.response.body = await fs.readFile('./demos/template.html', 'utf8');
};
app.use(main);
app.listen(3000);
koa-compose
中间件的合成const compose = require('koa-compose');
const middlewares = compose([logger, main]);
app.use(middlewares);
ctx.throw()
, 404错误可以通过设置ctx.response.status
为404.try...catch
处理错误const handler = async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.response.status = err.statusCode || err.status || 500;
ctx.response.body = {
message: err.message
};
}
};
const main = ctx => {
ctx.throw(500);
};
app.use(handler);
app.use(main);
error
事件app.on('error', (err, ctx) =>
console.error('server error', err);
);
emit
手动释放error
事件const handler = async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.response.status = err.statusCode || err.status || 500;
ctx.response.type = 'html';
ctx.response.body = '<p>Something wrong, please contact administrator.</p>';
ctx.app.emit('error', err, ctx); # 释放
}
};
const main = ctx => {
ctx.throw(500);
};
app.on('error', function(err) {
console.log('logging error ', err.message);
console.log(err);
});
Cookie
处理,使用ctx.cookie
读写Cookie
koa-body
读取页面上的信息const koaBody = require('koa-body');
const main = async function(ctx) {
const body = ctx.request.body;
if (!body.name) ctx.throw(400, '.name required');
ctx.body = { name: body.name };
};
app.use(koaBody());
koa-body
获取页面内容,os
取得文件目录,path
获取文件路径, fs.createReadStream
文件读入流, fs.createWriteStream
文件写入流,pipe()
管道处理,实现表单上传, 特别要注意multipart
值为true
const os = require('os');
const path = require('path');
const koaBody = require('koa-body');
const main = async function(ctx) {
const tmpdir = os.tmpdir();
const filePaths = [];
const files = ctx.request.body.files || {};
for (let key in files) {
const file = files[key];
const filePath = path.join(tmpdir, file.name);
const reader = fs.createReadStream(file.path);
const writer = fs.createWriteStream(filePath);
reader.pipe(writer);
filePaths.push(filePath);
}
ctx.body = filePaths;
};
app.use(koaBody({ multipart: true }));
let
和const
代替原有的var
定义变量let sum = 0;
for(const i=0;i<array.length;i++){
sum += array[i];
}
for ... of
代替原有的for
循环for(for list of lists){
console.log(list);
}
=>
代替原来的function
, 并去掉关键字return
.# 无参, 直接用()代替
() => x
# 有参, 直接使用参数返回
x => x*x;
(x, y) => (x=1, y=2)
# 单个参数
function(x=1, y=2)
# 数组赋值
function([x, y] = [1,2])
# 对象赋值
function({x, y} = {1,2})
# 嵌套赋值
function({x,[y,z]} = {1, [2, 3]})
Class
, 每个类必须定义构造方法constructor
, 类的方法不需要原型关键字prototype
属性赋值,而且方法之间不要,
分割Classs A {
constructor(){
}
getX(){
}
}
extends
概念, 子类可以继承父类的所有方法, 使用super()
函数继承Class B extends A {
constructor(){
super();
}
getX(){
}
}
that = this
方法变为局部变量that = this
<h1></h1>
来编写HTML, 使用${num}
来显示变量# 一行
`<h1>${title}</h1>`
# 多行
`
<h1>
<p>${content}</p>
</h1>
`
let a = "a";
let b = "b"
let array = [a, b];
# 原来的写法是 var array = [a:a, b:b];
The freedom to make my own mistakes 能自由地犯错 was all I ever wanted只是我一生追求 Mence Rayder, you've been called the King-beyound-the-Wall 曼斯 雷德 你被成为境外之王 Westeros only have one king维斯特洛只有一个真正的王 Bend the knee, I promise you mercy下跪 我答应宽宏处理 kneel and live 下跪即活着 This was my home for many years这里曾是我家园多年 I wish you good fortune in the wars to come在即将到来的战争中, 我祝你好运 We all must choose我们都必须进行选择Man or woman, young or old不管男或女 不管老或幼 lord or peasant, our choices are the same 不管王或民,我们选择皆同we choose light or we choose darkness选择光明或是黑暗we choose good or we choose evil选择正义或是邪恶 we choose the true god or the false选择真神或是假神
彦萍和我谈心,说我要是心情不好,或者是我不想理人的话,会表现的很明显,然后说话也会很平淡,然后没说几句她就会走掉了,然后如果我心情很好,那么和我聊天会很开心,我真的是表情这么这么明显的人吗,仿佛一切都发生在脸上
link: https://www.youtube.com/watch?v=pbCrDBQFU_A&index=5&list=PLN3n1USn4xlnfJIQBa6bBjjiECnk6zL6s
code -> preference -> User Snipper
{
// Place your snippets for typescriptreact here. Each snippet is defined under a snippet name and has a prefix, body and
// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the
// same ids are connected.
// Example:
// "Print to console": {
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// },
"Typescript React PureComponent": {
"prefix": "rpc",
"body": [
"import * as React from 'react'",
"",
"export class $1 extends React.PureComponent {",
"\trender() {",
"\t\treturn ($2);",
"}}",
],
"description": "Typescript React PureComponent"
}
}
create a new file eg.tsx
, then input rpc
and enter, you will get a code snipper
import * as React from 'react'
export class extends React.PureComponent {
render() {
return ();
}}
brew install mysql
.mysql -uroot
;create database if not exist asics3
;cd go/src/github.com/theplant/aigle/aigleapp
cd ~
cd go/src/github.com/theplant/
code
, 进入目录之后,直接输入code .
在vscode打开当前目录pwd
显示当前文件目录,编辑zsh环境变量 zshrc文件`vi ~/.zshrc`
#前端工作面试问题
What did you learn yesterday/this week?你在昨天/本周学到了什么?
这一周,主要将开发环境从windows迁移到ubuntu, 学习javascript的基础。
What excites or interests you about coding?编写代码的哪些方面能够使你兴奋或感兴趣?
将自己的预期目标实现已经给了我很大的鼓励,如果有人夸奖的话,会更加兴奋。
What is a recent technical challenge you experienced and how did you solve it?你最近遇到过什么技术挑战?你是如何解决的?
万事开头难,比如之前是如何安装ubuntu双系统,现在是如何把ubuntu改造成的开发环境,遇到困难,首先想到的就是谷歌和百度搜索,看看有没有其他人也来遇到过同样的问题,正在努力看英文文档解决问题。
What UI, Security, Performance, SEO, Maintainability or Technology considerations do you make while building a web application or site?在制作一个网页应用或网站的过程中,你是如何考虑其 UI、安全性、高性能、SEO、可维护性以及技术因素的?
UI: 现在有很多,比如一开始使用的bootstrap, 到现在的elementUI, 谷歌主推的material等等作为参考。
主要考虑,1界面美观,2配色好看,前几天看到数据,说蓝色是全世界人普遍都喜欢的颜色,即使对红绿色盲患者也是识别度最高,之前看服装搭配,也说蓝色和粉色是最搭的颜色。3对用户友好,尽量多用选择, 4提供搜索和提示功能。
安全性:1对输入进行有效性验证,以前听说过一个新闻,有人使用单引号注册,结果导致一个系统奔溃,是因为在数据库的插入语句中,单引号和双引号还是有很大的区别。利用trim()去掉多余的空格。2身份验证,现在的国外的网站大多有机器识别的一个按钮,国内现在还是主推二维码,但是都是在验证是不是机器人,或者是爬虫等程序。3.授权,权限管理,用户权限不同,可以获得的页面也是不同的。4异常错误处理。5加密,对于密码等信息,在存入数据库之前都需要进行bcrypt等等的加密处理,防止泄露用户信息。
高性能:1DNS负载均衡 2.HTTP重定向3. 分布式缓存redis 4.数据库扩展 5.反向代理均衡
SEO: seo是最近才了解到事物,优化浏览器搜索,之前了解过爬虫,这个也是类似的,主要优化关键字,描述语言,合理使用h1-h6, 对图片添加alt属性,链接添加target熟悉。
可维护:代码模块化,合理统一字段名,函数风格。
Talk about your preferred development environment.请谈谈你喜欢的开发环境。
之前一直是使用Windows的系统,其实也觉得在Windows上开发蛮方便的。但是后来慢慢接触到了ubuntu, 大多数博主,比如阮一峰等等,都推荐使用ubuntu, 实验楼的开发环境都是ubuntu, 而且之前买过服务器也是linux系统,再到招聘要求也有很多心仪的公司要求是熟悉linux系统,因此这次下定决心搬迁到ubuntu了。搬过来虽然有很多问题,资料也大多是英文的,但是每天学一点,积累下来,每天都有收获,心情也很美丽。
然后编辑器是sublime(最熟悉), vscode(最喜欢), atom(Windows上有点卡,但是很好看)
浏览器一直是chrome. 扩展程序简直太棒了,比如jsonView等等。
Which version control systems are you familiar with?你最熟悉哪一套版本控制系统?
git, 这个是我在大二开始接触的,一个人的代码,现在都托管在github上,换了电脑,配置一下开发环境就可以编码了。团队开发也利用它。减少了很多代码拷贝来拷贝去,还不知道那一份是最新的问题。常用的命令就是git add, git commit, git push origin master, 和git merge.
Can you describe your workflow when you create a web page? 你能描述当你制作一个网页的工作流程吗?
首先是设计UI,设计数据库的表和字段,然后是搭建整体的框架,最后是完善里面的每一个模块,利用CSS美化每一个细节。
If you have 5 different stylesheets, how would you best integrate them into the site?假若你有 5 个不同的样式文件 (stylesheets), 整合进网站的最好方式是?
看到人家的回答是文件拼合,减少HTTP请求,利用一个大的css文件将所有的小的css文件拼在一起,减少浏览器请求的延迟。这也要求每个CSS必须考虑冲突的问题,整理好命名和层级之间的关系。现在的webpack, gulp等前端自动化工具也是将这些静态资源整合在一起的。
Can you describe the difference between progressive enhancement and graceful degradation?你能描述渐进增强 (progressive enhancement) 和优雅降级 (graceful degradation) 之间的不同吗?
这个之前没了解过,参考这篇文章渐进增强和优雅降级吗?[css3兼容性写法]
.transition { /*渐进增强写法*/
-webkit-transition: all .5s;
-moz-transition: all .5s;
-o-transition: all .5s;
transition: all .5s;
}
.transition { /*优雅降级写法*/
transition: all .5s;
-o-transition: all .5s;
-moz-transition: all .5s;
-webkit-transition: all .5s;
}
何谓渐进增强:
渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。
何谓优雅降级:
优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。比如一开始使用 CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行 hack 使其可以在低版本浏览器上正常浏览。
How would you optimize a website's assets/resources?你如何对网站的文件和资源进行优化?
How many resources will a browser download from a given domain at a time?浏览器同一时间可以从一个域名下载多少资源?
浏览器并发请求数,
Name 3 ways to decrease page load (perceived or actual load time).请说出三种减少页面加载时间的方法。(加载时间指感知的时间或者实际加载时间)
If you jumped on a project and they used tabs and you used spaces, what would you do?如果你参与到一个项目中,发现他们使用 Tab 来缩进代码,但是你喜欢空格,你会怎么做?
Describe how you would create a simple slideshow page.请写一个简单的幻灯效果页面。
If you could master one technology this year, what would it be?如果今年你打算熟练掌握一项新技术,那会是什么?
Explain the importance of standards and standards bodies.请谈谈你对网页标准和标准制定机构重要性的理解。
What is Flash of Unstyled Content? How do you avoid FOUC?什么是 FOUC (无样式内容闪烁)?你如何来避免 FOUC?
Explain what ARIA and screenreaders are, and how to make a website accessible.请解释什么是 ARIA 和屏幕阅读器 (screenreaders),以及如何使网站实现无障碍访问 (accessible)。
Explain some of the pros and cons for CSS animations versus JavaScript animations.请解释 CSS 动画和 JavaScript 动画的优缺点。
What does CORS stand for and what issue does it address?什么是跨域资源共享 (CORS)?它用于解决什么问题?
doctype
do?doctype
(文档类型) 的作用是什么?application/xhtml+xml
?如果页面使用 'application/xhtml+xml' 会有什么问题吗?data-
attributes good for?使用 data-
属性的好处是什么?cookie
, sessionStorage
and localStorage
.请描述 cookies
、sessionStorage
和 localStorage
的区别。<script>
, <script async>
and <script defer>
.请解释 <script>
、<script async>
和 <script defer>
的区别。<link>
s between <head></head>
and JS <script>
s just before </body>
? Do you know any exceptions?为什么通常推荐将 CSS <link>
放置在 <head></head>
之间,而将 JS <script>
放置在 </body>
之前?你知道有哪些例外吗?z-index
和叠加上下文是如何形成的。* { box-sizing: border-box; }
do? What are its advantages?请解释 * { box-sizing: border-box; }
的作用, 并且说明使用它有什么好处?translate()
instead of absolute positioning, or vice-versa? And why?请问为何要使用 translate()
而非 absolute positioning,或反之的理由?为什么?this
works in JavaScript 请解释 JavaScript 中 this
是如何工作的。function foo(){ }();
.请解释为什么接下来这段代码不是 IIFE (立即调用的函数表达式):function foo(){ }();
.
null
, undefined
or undeclared?描述以下变量的区别:null
,undefined
或 undeclared
?
function Person(){}
, var person = Person()
, and var person = new Person()
?请指出以下代码的区别:function Person(){}
、var person = Person()
、var person = new Person()
?.call
and .apply
?.call
和 .apply
的区别是什么?Function.prototype.bind
.请解释 Function.prototype.bind
?document.write()
?在什么时候你会使用 document.write()
?==
and ===
?==
和 ===
有什么不同?duplicate([1,2,3,4,5]); // [1,2,3,4,5,1,2,3,4,5]
"use strict";
? what are the advantages and disadvantages to using it?什么是 "use strict";
? 使用它的好处和坏处分别是什么?100
while outputting "fizz" at multiples of 3
, "buzz" at multiples of 5
and "fizzbuzz" at multiples of 3
and 5
请实现一个遍历至 100
的 for loop 循环,在能被 3
整除时输出 "fizz",在能被 5
整除时输出 "buzz",在能同时被 3
和 5
整除时输出 "fizzbuzz"。load
event? Does this event have disadvantages? Do you know any alternatives, and why would you use those?为何你会使用 load
之类的事件 (event)?此事件有缺点吗?你是否知道其他替代品,以及为何使用它们?foo
between function foo() {}
and var foo = function() {}
解释 function foo() {}
与 var foo = function() {}
用法的区别Question: What is the value of foo
?
var foo = 10 + '20';
Question: How would you make this work?
add(2, 5); // 7
add(2)(5); // 7
Question: What value is returned from the following statement?
"i'm a lasagna hog".split("").reverse().join("");
Question: What is the value of window.foo
?
( window.foo || ( window.foo = "bar" ) );
*Question: What is the outcome of the two alerts below?*下面两个 alert 的结果是什么?
var foo = "Hello";
(function() {
var bar = " World";
alert(foo + bar);
})();
alert(foo + bar);
Question: What is the value of foo.length
?
var foo = [];
foo.push(1);
foo.push(2);
Question: What is the value of foo.x
?
var foo = {n: 1};
var bar = foo;
foo.x = foo = {n: 2};
*Question: What does the following code print?*下面代码的输出是什么?
console.log('one');
setTimeout(function() {
console.log('two');
}, 0);
console.log('three');
frontend/containers/popupShops:
PopupShops.getInitialProps = ({ context }: InitialProps): Promise<ShopProps> =>
makeService(api.PopUpShopService, context)
.all({})
.then(({ popupShops: shops }) => ({ shops }));
frontend/containers/popupShops.test.js
主要测试
Promise对象,resolve和reject。resolve表示成功,reject表示被拒绝
describe("PopupShop.getInitialProps", () => {
test("happy path", async () => {
const response: typeof api.PopUpShopService.prototype.all = () =>
Promise.resolve(new api.PopUpShopList({ popupShops: testProps }));
api.PopUpShopService.prototype.all = jest.fn(response);
const props = await PopupShops.getInitialProps(testContext());
const expected: Props = { shops: testProps };
expect(props).toMatchObject(expected);
});
test("failing API call", () => {
const error = new Error("test error");
api.PopUpShopService.prototype.all = jest.fn(() => Promise.reject(error));
expect.hasAssertions();
return expect(PopupShops.getInitialProps(testContext())).rejects.toBe(
error
);
});
});
frontend/proto.d.ts, 类型声明文件, PopupShopService里面有一个all方法,返回一个Promise对象
class PopUpShopService extends $protobuf.rpc.Service {
/**
* Constructs a new PopUpShopService service.
* @param rpcImpl RPC implementation
* @param [requestDelimited=false] Whether requests are length-delimited
* @param [responseDelimited=false] Whether responses are length-delimited
*/
constructor(rpcImpl: $protobuf.RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean);
/**
* Creates new PopUpShopService service using the specified rpc implementation.
* @param rpcImpl RPC implementation
* @param [requestDelimited=false] Whether requests are length-delimited
* @param [responseDelimited=false] Whether responses are length-delimited
* @returns RPC service. Useful where requests and/or responses are streamed.
*/
public static create(rpcImpl: $protobuf.RPCImpl, requestDelimited?: boolean, responseDelimited?: boolean): PopUpShopService;
/**
* Calls All.
* @param request Empty message or plain object
* @param callback Node-style callback called with the error, if any, and PopUpShopList
*/
public all(request: google.protobuf.IEmpty, callback: api.PopUpShopService.AllCallback): void;
/**
* Calls All.
* @param request Empty message or plain object
* @returns Promise
*/
public all(request: google.protobuf.IEmpty): Promise<api.PopUpShopList>;
}
frontend/proto.js,实现文件, 用变量PopUpShopService.prototype.all
调用all
方法
api.PopUpShopService = (function() {
PopUpShopService.prototype.all = function all(request, callback) {
return this.rpcCall(all, $root.google.protobuf.Empty, $root.api.PopUpShopList, request, callback);
};
}
api/popupshop.proto 后端文件有一个service类型的PopUpShopService,有一个rpc类型的All方法,返回一个PopupList
package api;
import "github.com/golang/protobuf/ptypes/empty/empty.proto";
import "github.com/theplant/mastani/popupshop/spec.proto";
message PopUpShopList {
repeated popupshop.PopUpShop popup_shops = 1;
}
service PopUpShopService {
rpc All(google.protobuf.Empty) returns (PopUpShopList);
}
错误处理文件在frontend/prottp/index.ts文件下
三个错误,一个networkerror表示网络错误,可以通过Promise的reject得到
而其他两个错误是得到数据之后,验证错误提示哪一个field出错和Authorication权限错误
400以上的都是http错误
type IServiceError =
| INetworkError
| IHTTPError
| IValidationError
| IAuthenticationError;
const validateStatus = (props: { statusCode: number; body: Uint8Array }) => {
if (props.statusCode === 422) {
throw new ValidationError(props.body);
} else if (props.statusCode === 403) {
throw new AuthenticationError();
} else if (props.statusCode >= 400) {
throw new HTTPError(props.statusCode);
}
return props;
};
https://github.com/zeit/next.js#setup
Install it:
npm install --save next react react-dom
Next.js 4 only supports React 16.
We had to drop React 15 support due to the way how React 16 works and how we use it.
and add a script to your package.json like this:
{
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
}
After that, the file-system is the main API. Every .js file becomes a route that gets automatically processed and rendered.
Populate ./pages/index.js
inside your project:
export default () => <div>Welcome to next.js!</div>
and then just run npm run dev
and go to http://localhost:3000
@wanghuiying commented on Mon Aug 14 2017
@wanghuiying commented on Mon Aug 14 2017
vue-cli
中使用jquery
package.json
文件的dependence
里面引入jquery
"jquery": "^1.11.1",
修改webpack.base.conf.js
增加
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
],
upload.vue
<template>
<div>
<!-- 断点续传 start-->
<!-- 隐藏域 实时保存上传进度 -->
<input id="jindutiao" type="hidden"/>
<div id="uploader" class="wu-example">
<!-- 文件列表:选择文件后在该 div 显示 -->
<div id="thelist" class="uploader-list" style="margin-left:160px;"></div>
<div class="btns">
<div id="picker">选择文件</div>
<button class="btn" id="startOrStopBtn" @click="FileUpload()" style="padding:8px 18px;margin-top:20px;"> 开始上传 </button>
</div>
</div>
</div>
<!-- 断点续传 end-->
</template>
<script>
import '../../static/webuploader.css'
import * as webuploader from '../../static/webuploader.js'
export default {
data() {
return {
}
},
mounted(){
this.$nextTick(function(){
webuploader.WebUploadRegister();
webuploader.WebUploadCreate();
webuploader.WebUploaderFileOperation();
})
},
methods: {
FileUpload : function(){
webuploader.startOrStopUpload()
}
}
}
</script>
<style>
</style>
webupload.js
import WebUploader from 'webuploader'
/******************* 初始化参数 *********************************/
var state = 'pending',// 初始按钮状态
uploader, //uploader 对象
errorUpload = false;
var fileMd5; // 文件唯一标识
/****************** 下面的参数是自定义的 *************************/
var fileName;// 文件名称
var oldJindu;// 如果该文件之前上传过 已经上传的进度是多少
var count=0;// 当前正在上传的文件在数组中的下标,一次上传多个文件时使用
var filesArr=new Array();// 文件数组:每当有文件被添加进队列的时候 就 push 到数组中
var map={};//key 存储文件 id,value 存储该文件上传过的进度
/***************************************************** 监听分块上传过程中的三个时间点 start ***********************************************************/
export const WebUploadRegister = function(){
WebUploader.Uploader.register({
"before-send-file":"beforeSendFile",// 整个文件上传前
"before-send":"beforeSend", // 每个分片上传前
"after-send-file":"afterSendFile", // 分片上传完毕
},
{
// 时间点 1:所有分块进行上传之前调用此函数
beforeSendFile:function(file){
var deferred = WebUploader.Deferred();
//1、计算文件的唯一标记 fileMd5,用于断点续传 如果. md5File(file) 方法里只写一个 file 参数则计算 MD5 值会很慢 所以加了后面的参数:10*1024*1024
(new WebUploader.Uploader()).md5File(file,0,10*1024*1024).progress(function(percentage){
})
.then(function(val){
$('#'+file.id ).find("p.state").text("成功获取文件信息...");
fileMd5=val;
// 获取文件信息后进入下一步
deferred.resolve();
});
fileName=file.name; // 为自定义参数文件名赋值
return deferred.promise();
},
// 时间点 2:如果有分块上传,则每个分块上传之前调用此函数
beforeSend:function(block){
var deferred = WebUploader.Deferred();
$.ajax({
type:"POST",
url:"../upload?param=checkChunk", //ajax 验证每一个分片
data:{
fileName : fileName,
jindutiao:$("#jindutiao").val(),
fileMd5:fileMd5, // 文件唯一标记
chunk:block.chunk, // 当前分块下标
chunkSize:block.end-block.start// 当前分块大小
},
cache: false,
async: false, // 与 js 同步
timeout: 1000, //todo 超时的话,只能认为该分片未上传过
dataType:"json",
success:function(response){
if(response.ifExist){
// 分块存在,跳过
deferred.reject();
}else{
// 分块不存在或不完整,重新发送该分块内容
deferred.resolve();
}
}
});
this.owner.options.formData.fileMd5 = fileMd5;
deferred.resolve();
return deferred.promise();
},
// 时间点 3:所有分块上传成功后调用此函数
afterSendFile:function(){
// 如果分块上传成功,则通知后台合并分块
$.ajax({
type:"POST",
url:"../upload?param=mergeChunks", //ajax 将所有片段合并成整体
data:{
fileName : fileName,
fileMd5:fileMd5,
},
success:function(data){
count++; // 每上传完成一个文件 count+1
if(count<=filesArr.length-1){
uploader.upload(filesArr[count].id);// 上传文件列表中的下一个文件
}
// 合并成功之后的操作
}
});
}
});
}
/***************************************************** 监听分块上传过程中的三个时间点 end **************************************************************/
export const WebUploadCreate = function(){
/************************************************************ 初始化 WebUploader start ******************************************************************/
uploader = WebUploader.create({
auto:true,// 选择文件后是否自动上传
chunked: true,// 开启分片上传
chunkSize:10*1024*1024,// 如果要分片,分多大一片?默认大小为 5M
chunkRetry: 3,// 如果某个分片由于网络问题出错,允许自动重传多少次
threads: 3,// 上传并发数。允许同时最大上传进程数 [默认值:3]
duplicate : false,// 是否重复上传(同时选择多个一样的文件),true 可以重复上传
prepareNextFile: true,// 上传当前分片时预处理下一分片
swf: 'http://cdn.staticfile.org/webuploader/0.1.0/Uploader.swf',// swf 文件路径
server: '../upload/',// 文件接收服务端
fileSizeLimit:6*1024*1024*1024,//6G 验证文件总大小是否超出限制, 超出则不允许加入队列
fileSingleSizeLimit:3*1024*1024*1024, //3G 验证单个文件大小是否超出限制, 超出则不允许加入队列
pick: {
id: '#picker', // 这个 id 是你要点击上传文件按钮的外层 div 的 id
multiple : true // 是否可以批量上传,true 可以同时选择多个文件
},
resize: false, // 不压缩 image, 默认如果是 jpeg,文件上传前会先压缩再上传!
accept: {
// 允许上传的文件后缀,不带点,多个用逗号分割
extensions: "txt,jpg,jpeg,bmp,png,zip,rar,war,pdf,cebx,doc,docx,ppt,pptx,xls,xlsx",
mimeTypes: '.txt,.jpg,.jpeg,.bmp,.png,.zip,.rar,.war,.pdf,.cebx,.doc,.docx,.ppt,.pptx,.xls,.xlsx',
}
});
/************************************************************ 初始化 WebUploader end ********************************************************************/
}
export const WebUploaderFileOperation = function(){
// 当有文件被添加进队列的时候(点击上传文件按钮,弹出文件选择框,选择完文件点击确定后触发的事件)
uploader.on('fileQueued', function(file) {
$('#thelist').append( '<div id="' + file.id + '"class="item">' +
'<h4 class="info">' + file.name + '</h4>' +
'<p class="state"> 等待上传...</p>' +
'<a href="javascript:void(0);"class="btn btn-primary file_btn btnRemoveFile"> 删除 </a>' +
'</div>' );
// 限制单个文件的大小 超出了提示
if(file.size>3*1024*1024*1024){
alert("单个文件大小不能超过 3G");
return false;
}
/************* 如果一次只能选择一个文件,再次选择替换前一个,就增加如下代码 *******************************/
// 清空文件队列
// $('#thelist').html("");
// 清空文件数组
filesArr=[];
/************* 如果一次只能选择一个文件,再次选择替换前一个,就增加以上代码 *******************************/
// 将选择的文件添加进文件数组
filesArr.push(file);
$.ajax({
type:"POST",
url:"../upload/", // 先检查该文件是否上传过,如果上传过,上传进度是多少
data:{
fileName : file.name // 文件名
},
cache: false,
async: false, // 同步
dataType:"json",
success:function(data){
// 上传过
if(data>0){
// 上传过的进度的百分比
oldJindu=data/100;
// 如果上传过 上传了多少
var jindutiaoStyle="width:"+data+"%";
$('#thelist').append( '<div id="' + file.id + '"class="item">' +
'<h4 class="info">' + file.name + '</h4>' +
'<p class="state"> 已上传'+data+'%</p>' +
'<a href="javascript:void(0);"class="btn btn-primary file_btn btnRemoveFile"> 删除 </a>' +
'<div class="progress progress-striped active">' +
'<div class="progress-bar"role="progressbar"style="'+jindutiaoStyle+'">' +
'</div>' +
'</div>'+
'</div>' );
// 将上传过的进度存入 map 集合
map[file.id]=oldJindu;
}else{// 没有上传过
$list.append( '<div id="' + file.id + '"class="item">' +
'<h4 class="info">' + file.name + '</h4>' +
'<p class="state"> 等待上传...</p>' +
'<a href="javascript:void(0);"class="btn btn-primary file_btn btnRemoveFile"> 删除 </a>' +
'</div>' );
}
}
});
uploader.stop(true);
// 删除队列中的文件
$(".btnRemoveFile").bind("click", function() {
var fileItem = $(this).parent();
uploader.removeFile($(fileItem).attr("id"), true);
$(fileItem).fadeOut(function() {
$(fileItem).remove();
});
// 数组中的文件也要删除
for(var i=0;i<filesArr.length;i++){
if(filesArr[i].id==$(fileItem).attr("id")){
filesArr.splice(i,1);//i 是要删除的元素在数组中的下标,1 代表从下标位置开始连续删除一个元素
}
}
});
});
// 文件上传过程中创建进度条实时显示
uploader.on('uploadProgress', function(file, percentage) {
var $li = $( '#'+file.id ),
$percent = $li.find('.progress .progress-bar');
// 避免重复创建
if (!$percent.length){
$percent = $('<div class="progress progress-striped active">' +
'<div class="progress-bar"role="progressbar"style="width: 0%">' +
'</div>' +
'</div>').appendTo($li).find('.progress-bar');
}
// 将实时进度存入隐藏域
$("#jindutiao").val(Math.round(percentage * 100));
// 根据 fielId 获得当前要上传的文件的进度
var oldJinduValue = map[file.id];
if(percentage<oldJinduValue && oldJinduValue!=1){
$li.find('p.state').text('上传中'+Math.round(oldJinduValue * 100) + '%');
$percent.css('width', oldJinduValue * 100 + '%');
}else{
$li.find('p.state').text('上传中'+Math.round(percentage * 100) + '%');
$percent.css('width', percentage * 100 + '%');
}
});
// 上传成功后执行的方法
uploader.on('uploadSuccess', function(file) {
// 上传成功去掉进度条
$('#'+file.id).find('.progress').fadeOut();
// 隐藏删除按钮
$(".btnRemoveFile").hide();
// 隐藏上传按钮
$("#startOrStopBtn").hide();
$('#'+file.id).find('p.state').text('文件已上传成功,系统后台正在处理,请稍后...');
});
// 上传出错后执行的方法
uploader.on('uploadError', function(file) {
errorUpload=true;
$('#startOrStopBtn').text('开始上传');
uploader.stop(true);
$('#'+file.id).find('p.state').text('上传出错,请检查网络连接');
});
// 文件上传成功失败都会走这个方法
uploader.on('uploadComplete', function(file) {
$( '#'+file.id ).find('.progress').fadeOut();
});
uploader.on('all', function(type){
if (type === 'startUpload'){
state = 'uploading';
}else if(type === 'stopUpload'){
state = 'paused';
}else if(type === 'uploadFinished'){
state = 'done';
}
if (state === 'uploading'){
$('#startOrStopBtn').text('暂停上传');
} else {
$('#startOrStopBtn').text('开始上传');
}
});
}
export const startOrStopUpload = function(){
if (state === 'uploading'){
uploader.stop(true);
} else {
// 当前上传文件的文件名
var currentFileName;
// 当前上传文件的文件 id
var currentFileId;
//count=0 说明没开始传 默认从文件列表的第一个开始传
if(count==0){
currentFileName=filesArr[0].name;
currentFileId=filesArr[0].id;
}else{
if(count<=filesArr.length-1){
currentFileName=filesArr[count].name;
currentFileId=filesArr[count].id;
}
}
// 先查询该文件是否上传过 如果上传过已经上传的进度是多少
$.ajax({
type:"POST",
url:"../upload/",
data:{
fileName : currentFileName// 文件名
},
cache: false,
async: false, // 同步
dataType:"json",
success:function(data){
// 如果上传过 将进度存入 map
if(data>0){
map[currentFileId]=data/100;
}
// 执行上传
uploader.upload(currentFileId);
}
});
}
}
webuploader.css
.webuploader-container {
position: relative;
}
.webuploader-element-invisible {
position: absolute !important;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px,1px,1px,1px);
}
.webuploader-pick {
position: relative;
display: inline-block;
cursor: pointer;
background: #00b7ee;
padding: 10px 15px;
color: #fff;
text-align: center;
border-radius: 3px;
overflow: hidden;
}
.webuploader-pick-hover {
background: #00a2d4;
}
.webuploader-pick-disable {
opacity: 0.6;
pointer-events:none;
}
效果
npm install -g create-react-native-app
create-react-native-app AwesomeProject
错误信息,不支持npm5, 使用npm4或yarn代替
Create React Native App doesn't work with npm 5 yet, unfortunately. We
recommend using npm 4 or yarn until some bugs are resolved.
全局安装
npm install yarn -g
create-react-native-app AwesomeProject
cd AwesomeProject
yarnpkg start
resolve - then
reject - catch
this - global object 全局变量
document.readyState
《使用 promise 替代回调函数》
知识点
理解 Promise 概念,为什么需要 promise
学习 q 的 API,利用 q 来替代回调函数 (https://github.com/kriskowal/q )
课程内容
第五课 (https://github.com/alsotang/node-lessons/tree/master/lesson5 ) 讲述了如何使用 async 来控制并发。async 的本质是一个流程控制。其实在异步编程中,还有一个更为经典的模型,叫做 Promise/Deferred 模型。
本节我们就来学习这个模型的代表实现:q
首先,我们思考一个典型的异步编程模型,考虑这样一个题目:读取一个文件,在控制台输出这个文件内容。
var fs = require('fs');
fs.readFile('sample.txt', 'utf8', function (err, data) {
console.log(data);
});
看起来很简单,再进一步: 读取两个文件,在控制台输出这两个文件内容。
var fs = require('fs');
fs.readFile('sample01.txt', 'utf8', function (err, data) {
console.log(data);
fs.readFile('sample02.txt', 'utf8', function (err,data) {
console.log(data);
});
});
要是读取更多的文件呢?
var fs = require('fs');
fs.readFile('sample01.txt', 'utf8', function (err, data) {
fs.readFile('sample02.txt', 'utf8', function (err,data) {
fs.readFile('sample03.txt', 'utf8', function (err, data) {
fs.readFile('sample04.txt', 'utf8', function (err, data) {
});
});
});
});
这段代码就是臭名昭著的邪恶金字塔 (Pyramid of Doom)。可以使用 async 来改善这段代码,但是在本课中我们要用 promise/defer 来改善它。
promise 基本概念
先学习 promise 的基本概念。
promise 只有三种状态,未完成,完成 (fulfilled) 和失败 (rejected)。
promise 的状态可以由未完成转换成完成,或者未完成转换成失败。
promise 的状态转换只发生一次
promise 有一个 then 方法,then 方法可以接受 3 个函数作为参数。前两个函数对应 promise 的两种状态 fulfilled, rejected 的回调函数。第三个函数用于处理进度信息。
promiseSomething().then(function(fulfilled){
//当promise状态变成fulfilled时,调用此函数
},function(rejected){
//当promise状态变成rejected时,调用此函数
},function(progress){
//当返回进度信息时,调用此函数
});
学习一个简单的例子:
var Q = require('q');
var defer = Q.defer();
/**
then 方法会返回一个 promise,在下面这个例子中,我们用 outputPromise 指向 then 返回的 promise。
var outputPromise = getInputPromise().then(function (fulfilled) {
}, function (rejected) {
});
现在 outputPromise 就变成了受 function(fulfilled) 或者 function(rejected)控制状态的 promise 了。怎么理解这句话呢?
当 function(fulfilled) 或者 function(rejected) 返回一个值,比如一个字符串,数组,对象等等,那么 outputPromise 的状态就会变成 fulfilled。
在下面这个例子中,我们可以看到,当我们把 inputPromise 的状态通过 defer.resovle() 变成 fulfilled 时,控制台输出 fulfilled.
当我们把 inputPromise 的状态通过 defer.reject() 变成 rejected,控制台输出 rejected
var Q = require('q');
var defer = Q.defer();
/**
/**
/**
/**
/**
/**
/**
/**
/**
/**
比如说我们想要读取一个文件的内容,然后把这些内容打印出来。可能会写出这样的代码:
//错误的写法
var outputPromise = getInputPromise().then(function(fulfilled){
fs.readFile('test.txt','utf8',function(err,data){
return data;
});
});
然而这样写是错误的,因为 function(fulfilled) 并没有返回任何值。需要下面的方式:
var Q = require('q');
var fs = require('fs');
var defer = Q.defer();
/**
/**
/**
*/
outputPromise.then(function(fulfilled){
console.log(fulfilled);
},function(rejected){
console.log(rejected);
});
/**
/**
方法传递有些类似于 Java 中的 try 和 catch。当一个异常没有响应的捕获时,这个异常会接着往下传递。
方法传递的含义是当一个状态没有响应的回调函数,就会沿着 then 往下找。
没有提供 function(rejected)
var outputPromise = getInputPromise().then(function(fulfilled){})
如果 inputPromise 的状态由未完成变成 rejected, 此时对 rejected 的处理会由 outputPromise 来完成。
var Q = require('q');
var fs = require('fs');
var defer = Q.defer();
/**
/**
/**
/**
var Q = require('q');
var fs = require('fs');
var defer = Q.defer();
/**
/**
outputPromise.then(function(fulfilled){
console.log('fulfilled: ' + fulfilled);
},function(rejected){
console.log('rejected: ' + rejected);
});
/**
/**
var Q = require('q');
var fs = require('fs');
var defer = Q.defer();
/**
/**
/**
}).progress(function(progress){
console.log(progress);
});
defer.notify(1);
defer.notify(2); //控制台打印1,2
promise 链
promise 链提供了一种让函数顺序执行的方法。
函数顺序执行是很重要的一个功能。比如知道用户名,需要根据用户名从数据库中找到相应的用户,然后将用户信息传给下一个函数进行处理。
var Q = require('q');
var defer = Q.defer();
//一个模拟数据库
var users = [{'name':'andrew','passwd':'password'}];
function getUsername() {
return defer.promise;
}
function getUser(username){
var user;
users.forEach(function(element){
if(element.name === username) {
user = element;
}
});
return user;
}
//promise链
getUsername().then(function(username){
return getUser(username);
}).then(function(user){
console.log(user);
});
defer.resolve('andrew');
我们通过两个 then 达到让函数顺序执行的目的。
then 的数量其实是没有限制的。当然,then 的数量过多,要手动把他们链接起来是很麻烦的。比如
foo(initialVal).then(bar).then(baz).then(qux)
这时我们需要用代码来动态制造 promise 链
var funcs = [foo,bar,baz,qux]
var result = Q(initialVal)
funcs.forEach(function(func){
result = result.then(func)
})
return result
当然,我们可以再简洁一点
var funcs = [foo,bar,baz,qux]
funcs.reduce(function(pre,current),Q(initialVal){
return pre.then(current)
})
看一个具体的例子
function foo(result) {
console.log(result);
return result+result;
}
//手动链接
Q('hello').then(foo).then(foo).then(foo); //控制台输出: hello
// hellohello
// hellohellohello
//动态链接
var funcs = [foo,foo,foo];
var result = Q('hello');
funcs.forEach(function(func){
result = result.then(func);
});
//精简后的动态链接
funcs.reduce(function(prev,current){
return prev.then(current);
},Q('hello'));
对于 promise 链,最重要的是需要理解为什么这个链能够顺序执行。如果能够理解这点,那么以后自己写 promise 链可以说是轻车熟路啊。
promise 组合
回到我们一开始读取文件内容的例子。如果现在让我们把它改写成 promise 链,是不是很简单呢?
var Q = require('q'),
fs = require('fs');
function printFileContent(fileName) {
return function(){
var defer = Q.defer();
fs.readFile(fileName,'utf8',function(err,data){
if(!err && data) {
console.log(data);
defer.resolve();
}
})
return defer.promise;
}
}
//手动链接
printFileContent('sample01.txt')()
.then(printFileContent('sample02.txt'))
.then(printFileContent('sample03.txt'))
.then(printFileContent('sample04.txt')); //控制台顺序打印sample01到sample04的内容
很有成就感是不是。然而如果仔细分析,我们会发现为什么要他们顺序执行呢,如果他们能够并行执行不是更好吗? 我们只需要在他们都执行完成之后,得到他们的执行结果就可以了。
我们可以通过 Q.all([promise1,promise2...]) 将多个 promise 组合成一个 promise 返回。 注意:
当 all 里面所有的 promise 都 fulfil 时,Q.all 返回的 promise 状态变成 fulfil
当任意一个 promise 被 reject 时,Q.all 返回的 promise 状态立即变成 reject
我们来把上面读取文件内容的例子改成并行执行吧
var Q = require('q');
var fs = require('fs');
/**
*读取文件内容
*@Private
*/
function printFileContent(fileName) {
//Todo: 这段代码不够简洁。可以使用Q.denodeify来简化
var defer = Q.defer();
fs.readFile(fileName,'utf8',function(err,data){
if(!err && data) {
console.log(data);
defer.resolve(fileName + ' success ');
}else {
defer.reject(fileName + ' fail ');
}
})
return defer.promise;
}
Q.all([printFileContent('sample01.txt'),printFileContent('sample02.txt'),printFileContent('sample03.txt'),printFileContent('sample04.txt')])
.then(function(success){
console.log(success);
}); //控制台打印各个文件内容 顺序不一定
现在知道 Q.all 会在任意一个 promise 进入 reject 状态后立即进入 reject 状态。如果我们需要等到所有的 promise 都发生状态后 (有的 fulfil, 有的 reject),再转换 Q.all 的状态, 这时我们可以使用 Q.allSettled
var Q = require('q'),
fs = require('fs');
/**
*读取文件内容
*@Private
*/
function printFileContent(fileName) {
//Todo: 这段代码不够简洁。可以使用Q.denodeify来简化
var defer = Q.defer();
fs.readFile(fileName,'utf8',function(err,data){
if(!err && data) {
console.log(data);
defer.resolve(fileName + ' success ');
}else {
defer.reject(fileName + ' fail ');
}
})
return defer.promise;
}
Q.allSettled([printFileContent('nosuchfile.txt'),printFileContent('sample02.txt'),printFileContent('sample03.txt'),printFileContent('sample04.txt')])
.then(function(results){
results.forEach(
function(result) {
console.log(result.state);
}
);
});
结束 promise 链
通常,对于一个 promise 链,有两种结束的方式。第一种方式是返回最后一个 promise
如 return foo().then(bar);
第二种方式就是通过 done 来结束 promise 链
如 foo().then(bar).done()
为什么需要通过 done 来结束一个 promise 链呢? 如果在我们的链中有错误没有被处理,那么在一个正确结束的 promise 链中,这个没被处理的错误会通过异常抛出。
var Q = require('q');
/**
@Private
/
function getPromise(msg,timeout,opt) {
var defer = Q.defer();
setTimeout(function(){
console.log(msg);
if(opt)
defer.reject(msg);
else
defer.resolve(msg);
},timeout);
return defer.promise;
}
/
*没有用done()结束的promise链
*由于getPromse('2',2000,'opt')返回rejected, getPromise('3',1000)就没有执行
然后这个异常并没有任何提醒,是一个潜在的bug
/
getPromise('1',3000)
.then(function(){return getPromise('2',2000,'opt')})
.then(function(){return getPromise('3',1000)});
/
*用done()结束的promise链
*有异常抛出
*/
getPromise('1',3000)
.then(function(){return getPromise('2',2000,'opt')})
.then(function(){return getPromise('3',1000)})
.done();
结束语
当你理解完上面所有的知识点时,你就会正确高效的使用 promise 了。本节只是讲了 promise 的原理和几个基本的 API,不过你掌握了这些之后,再去看 q 的文档,应该很容易就能理解各个 api 的意图。
基本思路: 当用户登录成功之后, 给用户一个登录的accessToken值
微博开发授权机制
接口 | 说明 |
---|---|
OAuth2/authorize | 请求用户授权 Token |
OAuth2/access_token | 获取授权过的 Access Token |
OAuth2/get_token_info | 授权信息查询接口 |
OAuth2/revokeoauth2 | 授权回收接口 |
OAuth2/get_oauth2_token | OAuth1.0 的 Access Token 更换至 OAuth2.0 的 Access Token |
https://api.weibo.com/oauth2/access_token?client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=authorization_code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI&code=CODE
{
"access_token": "SlAV32hkKG",
"remind_in": 3600,
"expires_in": 3600
}
豆瓣电影API开发文档-https://developers.douban.com/wiki/?title=movie_v2
使用方法, 比如电影战狼-http://api.douban.com/v2/movie/subject/26363254
其中的数字就是
https://movie.douban.com/subject/26363254/?from=showing
{"rating":
{"max": 10, "average": 7.5, "stars": "40", "min": 0},
"reviews_count": 6185,
"wish_count": 42078,
"douban_site": "",
"year": "2017",
"images": {
"small": "http://img7.doubanio.com\/view\/movie_poster_cover\/ipst\/public\/p2485983612.webp",
"large": "http://img7.doubanio.com\/view\/movie_poster_cover\/lpst\/public\/p2485983612.webp",
"medium": "http://img7.doubanio.com\/view\/movie_poster_cover\/spst\/public\/p2485983612.webp"
},
"alt": "https:\/\/movie.douban.com\/subject\/26363254\/",
"id": "26363254",
"mobile_url": "https:\/\/movie.douban.com\/subject\/26363254\/mobile", "title": "\u6218\u72fc2", "do_count": null,
"share_url": "http:\/\/m.douban.com\/movie\/subject\/26363254", "seasons_count": null, "schedule_url": "https:\/\/movie.douban.com\/subject\/26363254\/cinema\/",
"episodes_count": null,
"countries": ["\u4e2d\u56fd\u5927\u9646"],
"genres": ["\u52a8\u4f5c"],
"collect_count": 246104,
"casts": [{
"alt": "https:\/\/movie.douban.com\/celebrity\/1000525\/",
"avatars": {
"small": "http://img7.doubanio.com\/img\/celebrity\/small\/39105.jpg",
"large": "http://img7.doubanio.com\/img\/celebrity\/large\/39105.jpg",
"medium": "http://img7.doubanio.com\/img\/celebrity\/medium\/39105.jpg"
},
"name": "\u5434\u4eac",
"id": "1000525"
},
{
"alt": "https:\/\/movie.douban.com\/celebrity\/1100321\/",
"avatars": {
"small": "http://img3.doubanio.com\/img\/celebrity\/small\/1415801312.29.jpg",
"large": "http://img3.doubanio.com\/img\/celebrity\/large\/1415801312.29.jpg",
"medium": "http://img3.doubanio.com\/img\/celebrity\/medium\/1415801312.29.jpg"
},
"name": "\u5f17\u5170\u514b\u00b7\u683c\u91cc\u7f57",
"id": "1100321"
},
{
"alt": "https:\/\/movie.douban.com\/celebrity\/1274840\/",
"avatars": {
"small": "http://img7.doubanio.com\/img\/celebrity\/small\/1401440361.14.jpg",
"large": "http://img7.doubanio.com\/img\/celebrity\/large\/1401440361.14.jpg",
"medium": "http://img7.doubanio.com\/img\/celebrity\/medium\/1401440361.14.jpg"
},
"name": "\u5434\u521a",
"id": "1274840"
},
{
"alt": "https:\/\/movie.douban.com\/celebrity\/1031500\/",
"avatars": {
"small": "http://img3.doubanio.com\/img\/celebrity\/small\/1408604480.79.jpg",
"large": "http://img3.doubanio.com\/img\/celebrity\/large\/1408604480.79.jpg",
"medium": "http://img3.doubanio.com\/img\/celebrity\/medium\/1408604480.79.jpg"
},
"name": "\u5f20\u7ff0",
"id": "1031500"
}],
"current_season": null,
"original_title": "\u6218\u72fc2",
"summary": "\u6545\u4e8b\u53d1\u751f\u5728\u975e\u6d32\u9644\u8fd1\u7684\u5927\u6d77\u4e0a\uff0c\u4e3b\u4eba\u516c\u51b7\u950b\uff08\u5434\u4eac \u9970\uff09\u906d\u9047\u4eba\u751f\u6ed1\u94c1\u5362\uff0c\u88ab\u201c\u5f00\u9664\u519b\u7c4d\u201d\uff0c\u672c\u60f3\u6f02\u6cca\u4e00\u751f\u7684\u4ed6\uff0c\u6b63\u5f53\u4ed6\u6253\u7b97\u8fd9\u4e48\u505a\u7684\u65f6\u5019\uff0c\u4e00\u573a\u7a81\u5982\u5176\u6765\u7684\u610f\u5916\u6253\u7834\u4e86\u4ed6\u7684\u8ba1\u5212\uff0c\u7a81\u7136\u88ab\u5377\u5165\u4e86\u4e00\u573a\u975e\u6d32\u56fd\u5bb6\u53db\u4e71\uff0c\u672c\u53ef\u4ee5\u5b89\u5168\u64a4\u79bb\uff0c\u5374\u56e0\u65e0\u6cd5\u5fd8\u8bb0\u66fe\u7ecf\u4e3a\u519b\u4eba\u7684\u4f7f\u547d\uff0c\u5b64\u8eab\u72af\u9669\u51b2\u56de\u6ca6\u9677\u533a\uff0c\u5e26\u9886\u8eab\u9677\u5c60\u6740\u4e2d\u7684\u540c\u80de\u548c\u96be\u6c11\uff0c\u5c55\u5f00\u751f\u6b7b\u9003\u4ea1\u3002\u968f\u7740\u6597\u4e89\u7684\u6301\u7eed\uff0c\u4f53\u5185\u7684\u72fc\u6027\u9010\u6e10\u590d\u82cf\uff0c\u6700\u7ec8\u5b64\u8eab\u95ef\u5165\u6218\u4e71\u533a\u57df\uff0c\u4e3a\u540c\u80de\u800c\u6218\u6597\u3002",
"subtype": "movie",
"directors": [{
"alt": "https:\/\/movie.douban.com\/celebrity\/1000525\/",
"avatars": {
"small": "http://img7.doubanio.com\/img\/celebrity\/small\/39105.jpg",
"large": "http://img7.doubanio.com\/img\/celebrity\/large\/39105.jpg",
"medium": "http://img7.doubanio.com\/img\/celebrity\/medium\/39105.jpg"
},
"name": "\u5434\u4eac",
"id": "1000525"}
],
"comments_count": 131887,
"ratings_count": 239666,
"aka": ["\u65b0\u6218\u72fc", "\u65b0\u6218\u6b7b\u6c99\u573a", "Wolf Warriors 2"]
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css">
<title>news app</title>
</head>
<body>
<div class="container" id="app">
<h3 class="text-center">VueNews</h3>
<p>{{ results }}</p>
</div>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="app.js"></script>
</body>
</html>
app.js
const vm = new Vue({
el: '#app',
data: {
results: {}
},
mounted(){
axios.get('http://api.douban.com/v2/movie/subject/26363254')
.then(response => {this.results = response.data})
}
})
出现跨域错误:
XMLHttpRequest cannot load http://api.douban.com/v2/movie/subject/26363254. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
解决方法1.cors解决跨域
解决方法2: qs绕过跨域请求
latency 潜伏 pipelining 流水线 Eliminate 消除 schemes 方案 格式 promotes 促进 protocol 协议 memos 备忘录 numerous 众多 variants 变种 dedicated 专用 charter 宪章 specification 规格 procedures 程序 suffix 后缀 spec 规范 spearheaded 带头 implementation 实现 significant重大的 significant证明 deployed 部署restraints限制innovate创新 maintain保持 paradigms 范式 URLs 网址 scheme 方案 proxy 代理 Subsequently 后来 features 特征 reduce 减少 mantra 口头禅 mandatory 强制的 minor 次要的 compatible 兼容 upgrade 升级 round-trip 往返 penalty 罚款 negotiation 谈判 significantly 显著的 widespread 广泛的 assumption 假设 interfere 干扰 hand-wringing 握手 agitated 激动 fierce 激烈 ciphers 密码 blacklist 黑名单 suite 套件 restrictions 限制 Application Layer Protocol Negotiation 应用层协议协商 promoted 提拔 marshaling 分送处理 instinctively 本能地arguments参数 superior 优越 handcraft 手工 intermixed 混合 compression 压缩 diminishes 减少 inspector 检察员 dissector 解剖器 Stream Identifier 流标识符 frame payload 帧有效载荷 fundamental 基本的 Multiplexed复合 directional 定向 sequence序列stream流 bi-directional sequence of frames双向帧序列 concurrently 同时 endpoint 端点 interleaving 交错 unilaterally 单方面 significant重大地 Priorities 优先级 restraints 限制 In short 简而言之 paradigm 范例 repetitive 重复 tricky 狡猾 vulnerable 弱势 encrypted 加密 crafted 将雕细作 exploit 利用 leak 泄漏receiver 接收器context上下文re-indexing 重新索引Huffman-encoded哈夫曼编码 drawbacks 缺点,outcoming弱点 Content-Length 内容长度 handshake 握手 bandwidth 带宽 tear down 拆除 Server push 服务器端推送explicitly明确地 spirit精神 peer 窥视 mandates 任务 hop-by-hop 逐条 debated 辩论 swinging 摇摆 ultimately 最终 inclusion 包容 Alternative替代 adoption 采用 suspect 疑似 potentially 可能 balancers 平衡器 maintenance 保养 asynchronously 异步 Opportunistic 机会主义somewhat 有些 debatable值得商榷 unauthenticated 未经验证 firmly 牢牢地 Blocked 阻止 forbids 禁止facilitate 促进 discarding 丢弃 parallel 平行 trim 修剪 toolbox 工具箱tricks技巧 justification理由 Spriting and inlining 精灵和内联, Sharding 拆分detrimental有害 futile 无用 doomed 注定outdated过时terms 条款 tech preview 技术预览 insecure 不安全 critiques 批评 forth 向前 implying 意味着illustrating说明
mkdir myblog
touch index.js
ls
mv filename newfilename
clean或者ctrl + l
alias node="node --harmony"
unalias node
ps aux | grep server | grep node
lsof -t -i:9009
kill -9 13761
@wanghuiying commented on Thu Aug 10 2017
@wanghuiying commented on Wed Aug 09 2017
npm install -g create-react-native-app
create-react-native-app AwesomeProject
错误信息,不支持npm5, 使用npm4或yarn代替
Create React Native App doesn't work with npm 5 yet, unfortunately. We
recommend using npm 4 or yarn until some bugs are resolved.
全局安装
npm install yarn -g
create-react-native-app AwesomeProject
cd AwesomeProject
yarnpkg start
@wanghuiying commented on Thu Aug 10 2017
初始化项目,配置舒适的环境
深入浅出/react.js/开发环境
npm install webpack webpack-dev-server --save-dev
安装 css-loader、style-loader、image-loader, 可以在 js 下加载 css 样式文件和图片
npm install css-loader style-loader image-loader --save
安装 react.js 依赖包(react react-dom)和 babel 依赖包(转换 jsx-js 等)
npm install --save react react-dom babel-preset-react babel-preset-es 2015 babel-loader babel-core
新建webpack.config.js文件
var webpack = require('webpack')
var path = require('path')
module.exports = {
entry: './app/entry.js', //项目打包入口
output: {
path: __dirname,
filename: './build/bundle.js' //项目打包出口
},
module: {
loaders: [{
test: /\.js[x]?$/,
exclude: /node_modules/,
loaders: 'babel-loader?presets[]=es2015&presets[]=react'
},{
test: /\.css$/,
loader: 'style-loader!css-loader'
},{
test: /\.(png|jpg)$/,
loader: 'url-loader?limit=8192'
}]
}
};
在package.json文件添加下面脚本
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack-dev-server --devtool eval --progress --colors --hot",
"deploy":"NODE_ENV=production & webpack -p",
"deploy-windows":"SET NODE_ENV=production & webpack -p",
"validate":"npm ls"
},
添加React Router组件
npm install -S react-router
添加 React Redux (状态管理)
npm install react-redux --save
添加 ESLint (代码质量)
npm install eslint --save
添加 antd (蚂蚁金服一款简洁的 UI)
npm install antd --save
首先需要安装 babel-plugin-import 依赖
npm install babel-plugin-import --save-dev
新建.babelrc文件
{
"plugins": [["import", {"libraryName": "antd", "style": "css"}]] //import js and css modulary
}
app/components/app.js
import React from 'react';
import ReactDOM from 'react-dom';
import {
Button
} from 'antd';
var App = React.createClass({
render: function(){
return (
<div>
<h1>Hey,this is a React and Antd IDE</h1>
<div className="Antd">
<Button type="danger" size="large">成功加载Antd组件</Button>
</div>
</div>
)
}
});
ReactDOM.render(
<App/>,
document.getElementById('app')
);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>index</title>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript" src="build/bundle.js"></script>
</body>
</html>
app/entry.js
'use strict';
//component
import './components/App'
// css
import './style/main.css'
npm start
> webpack-dev-server --devtool eval --progress --colors --hot
'webpack-dev-server' 不是内部或外部命令,也不是可运行的程序
检查package.json
文件,发现未安装好webpack
和webpack-dev-server
,重新安装
npm start
http://localhost:8081/
成功访问
这是刚刚搭建好的网站
https://annewang.netlify.com/
开源项目https://github.com/gatsbyjs/gatsby
Install
npm install -g gatsby
Usage
gatsby new my-test-gatsby-site
This creates the directory for your Gatsby project and adds the minimal files needed.cd my-test-gatsby-site
gatsby develop
— Gatsby will start a hot-reloading development server accessible at localhost:8000
发现神奇的是:
.DS_Store
node_modules/
这样的好处是,可以忽略node_modules等类型的大文件。提高远程仓库的递交速度
远程仓库的递交方法是
git clone https://github.com/WangHuiying/vCustomers
.git
文件夹全部拷贝到当前的工作目录下,注意.git文件是一个隐藏文件git add .
git commit -m "说明"
git push origin master
这样就可以完成远程的递交
可以把github当成是自己的代码的网盘哦,一般人应该不会把代码保存到百度网盘吧。而且不支持历史记录和修改
使用Hexo编写文章,把github当成一个免费的服务器, 欢迎参观我的博客
可以利用github写简历https://resume.github.io/?WangHuiying, 全英文,高大上,有木有
可以在chrome安装一个gitGist
插件, 将看到的代码文章什么的都保存在github上
最后,如果自己不知道怎么编写.gitignore文件,这边有个在线网站,支持一键生成https://www.gitignore.io/
➜ ~ createuser admin -P
Enter password for new role:
Enter it again:
➜ ~ createdb cake -O admin -E UTF8 -e
CREATE DATABASE cake OWNER admin ENCODING 'UTF8';
➜ ~ psql -U admin -d cake -h 127.0.0.1
cake-> \c cake
You are now connected to database "cake" as user "admin".
cake=> CREATE TABLE test (id int, text VARCHAR(50));
CREATE TABLE
cake=> INSERT INTO test(id, text) VALUES(1, 'test');
INSERT 0 1
cake=> select * from test where id =1;
id | text
----+------
1 | test
(1 row)
cake=> update test set text='aaaaaa' where id =1 ;
UPDATE 1
cake=> select * from test where id = 1;
id | text
----+--------
1 | aaaaaa
(1 row)
cake=> delete from test where id = 1;
DELETE 1
cake=> select * from test;
id | text
----+------
(0 rows)
cake=> pg_dump admin > /usr/local/psql/backup/pg.sql;
npm install -g pg
var { Client } = require("pg");
//创建连接
//var conString = "postgres://y-user:y-ps@localhost:5432/y-db";
var conString = "postgres://admin:1234@localhost:5432/cake";
var client = new Client(conString);
await client.connect();
var res = await client.query("select * from test"); //await 报错,使用内部
query.rows.foreach(row => {
console.log(row);
});
await client.end();
var { Client } = require("pg");
const client = new Client({
user: "admin",
password: "1234",
database: "cake",
host: "localhost",
port: 5432
});
client.connect();
client.query("select * from test", (err, res) => {
if (err) {
console.log(err);
}
console.log(res);
res.rows.forEach(row => {
console.log(row);
});
client.end();
});
var { Client } = require("pg");
var conString = "postgres://admin:1234@localhost:5432/cake";
const client = new Client(conString);
client.connect();
client
.query("select * from test")
.then(res => {
res.rows.forEach(row => {
console.log(row);
});
client.end();
})
.catch(e => console.log(e));
var { Client } = require("pg");
var conString = "postgres://admin:1234@localhost:5432/cake";
const client = new Client(conString);
client.connect();
const query = {
name: "fetch-data",
text: "select * from test where id = $1",
values: [1]
};
client
.query(query)
.then(res => {
res.rows.forEach(row => {
console.log(row);
client.end();
});
})
.catch(e => console.log(e));
插入
const query = {
name: "insert-data",
text: "insert into test (id, test) values ($1,$2)",
values: [1, "test-1"]
};
删除
const query = {
name: "delete-data",
text: "delete from test where id=$1",
values: [1]
};
Result {
command: 'SELECT',
rowCount: 1,
oid: null,
rows: [ anonymous { id: 1, test: 'test' } ],
fields:
[ Field {
name: 'id',
tableID: 16389,
columnID: 1,
dataTypeID: 23,
dataTypeSize: 4,
dataTypeModifier: -1,
format: 'text' },
Field {
name: 'test',
tableID: 16389,
columnID: 2,
dataTypeID: 1043,
dataTypeSize: -1,
dataTypeModifier: 54,
format: 'text' } ],
_parsers: [ [Function: parseInteger], [Function: noParse] ],
RowCtor: [Function: anonymous],
rowAsArray: false,
_getTypeParser: [Function: bound ] }
vue-cli
初始化项目npm install vue-cli -g # 全局安装vue-cli
vue init webpack vueTest # 初始化一个vueTest项目, webpack是打包工具
cd vueTest # 进入vueTest项目根目录
npm install # 安装依赖, 这边取消安装eslint和接下来的一些工具,可以提高开发效率
npm run dev # 运行项目
v-for
循环<ul v-for="item in items">
<li>{{ item.text }}</li>
</ul>
v-on:click
<button v-on:click="addItem">Add Item</button>
v-on:keypress.enter
# 点击enter
<input id="itemForm" v-on:keypress.enter="addItem"/>
methods : {
addItem: function(){
var input = document.getElementById('itemForm');
if(input.value !== '') {
this.items.push({
text: input.value
})
input.value = "";
}
},
deleteItem: function(){
this.items.splice(index, 1);
}
}
filter
事件<header> {{ title | capitalize}} <header>
<a href="">{{ dio.text | underscore | url }}</a>
data: {
},
filters: {
capitalize: function(value) {
if(!value) return "";
value = value.toString();
return value.CharAt(0).toString() + Value.splice(1);
},
undercase: function(value){
if(!value) return "";
value = value.toString();
return value.toLowerCase()
},
url: function(value) {
if(!value) return '';
value = value.toString();
return "https://en.wikipedia.org/wiki/" + value;
}
}
compute
方法data: {
return() {
totals: 0,
length: 0
}
}
methods: {
},
computed: {
totals: function() {
var sum = 0;
var items = this.items;
for(var i in items) {
sum += items[i].quantity
}
return sum;
},
length: function(){
return this.length
}
}
watch
方法, 监听方法, 当长度太长,就切换按钮的text
data: {
},
watch: {
input: _.debounce(function(){
this.buttonText = this.input !== "“ ? "Add" + this.input: "Add Dinsour";
}, 250);
}
9.v-bind
绑定属性, class
<button v-bind:class="[sizeToggle ? 'large' : '', {'rounded':isRounded }]"
v-bind:style="styles"
v-bind:disabled="disabled">Start Tour</button>
computed: {
styles: function(){
return {
color: this.fontColor,
background: this.backgroundColor,
'margin-left': this.range + %
}
}
}
v-if
, v-else
和v-show
v-if="array.length > 0"
v-else
v-show="dins.quanatity"
v-on:submit.prevent="
表单提交<form v-on:submit.prevent="addDins">
<button>Add {{amount}} Dinsours</button>
<input type="number" v-model="amount" />
</form>
<p>you have {[ total }} dinosaurs !</p>
v-bind:name
和props
<dino-counter v-bind:name="dino.name"
v-bind:initial-quantity="dino.quantity"></dino-counter>
componets: {
'dino-counter': {
template: '#dino-counter',
props: ['name', 'initialQuantity'],
data: function(){
return {
quantity: this.quantity
}
}
}
}
\bhi\b
完全匹配hi
\bhi\b*\blucy\b
匹配hi.........lucy
(不换行)
0\d{2}-\d{8}
匹配0后面2个数字-8个数字
[0-9]
\w
匹配字母或数字或下划线或汉字等
[a-z0-9A-Z_]
\ba\w*\b
也就是a然后是任意的数字和字母\w*
\d+
匹配 1 个或更多连续的数字
\b\w{6}\b
匹配刚好 6 个字符的单词
^\d{5,12}$
匹配qq号必须是5-12位的数字
\(?0\d{2}[) -]?\d{8}
匹配(010)88886666
,或 022-22334455
,或 02912345678
, ?
表示出现0次或1次
0\d{2}-\d{8}|0\d{3}-\d{7}
, 一种是三位区号,8 位本地号 (如 010-12345678
),一种是 4 位区号,7 位本地号 (0376-2233445
), |
表示分支条件
(\d{1,3}\.){3}\d{1,3}
匹配ip地址127.0.0.1
的格式
((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
匹配正确的ip地址255.255.255.255
\
转义字符代码 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
代码 / 语法 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复 n 次 |
{n,} | 重复 n 次或更多次 |
{n,m} | 重复 n 到 m 次 |
反义
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
---|---|
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了 x 以外的任意字符 |
[^aeiou] | 匹配除了 aeiou 这几个字母以外的任意字符 |
后向引用部分以及后面部分有点看不懂
read css
https://juejin.im/post/5a0c184c51882531926e4294#heading-45
iterm & zsh & oh-my-zsh
http://www.dreamxu.com/mac-terminal/
fix previous-image-show-momentarily
little image will flash from previous to the new
React 的 vDom diff 算法能保证最小程度的 DOM 改变
在渲染的时候,数据发生改变,因此react会立马判断大图发生改变而更新,小图是根据数组的key得到的,因此反应慢一拍
key 值必须是独一无二的,最好不要是数字,绝对不能是遍历中的 index
<WR perRow={2}>
{restImages.map(
({ id }, index) =>
id ? (
<C key={index}>
<ThumbImg id={id} />
</C>
) : null
)}
{restImages.length % 2 == 1 && <C />}
</WR>
修改
index为 一个独一无二的值,比如id
参考
React 应用性能优化之 shouldComponentUpdate 与 key
了解id是什么
//mastani-dev.s3-ap-southeast-1.amazonaws.com/product_images/322/file/xse-k-67-2.20171108075217046927828.png
//mastani-dev.s3-ap-southeast-1.amazonaws.com/product_images/323/file/xse-k-67-3.20171108070217627002371.png
XX-net/XX-Net#8797
手机上的xx-net浏览器,导入APPID之后就可以直接访问外网
配置小狼毫輸入法
Steward--在chrome里使用aflred
http://oksteward.com/%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97.html
cors
redis
和session
搭配使用,提高node.js
缓存效率node.js
日志处理log4js.json
express
中的use, get, post, put/patch, delete
的优先级比较axios
处理后台数据jade
前端语言的使用morgan
node.js的日志处理系统, .format
定义日志格式env
本地和development
开发环境的区别path
serve-favicon
的中间件,可以用于请求网页的logoimport React from "react";
export default React.createClass({
render: function() {
return <div>Hello React!</div>;
}
});
heatpack index.js
index.js
import React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";
import todoApp from "./reducers";
import App from "./components/App";
let store = createStore(todoApp);
export default React.createClass({
render: function() {
return (
<Provider store={store}>
<App />
</Provider>
);
}
});
reducer/index.js
import { combineReducers } from "redux";
import todos from "./todos";
import visibilityFilter from "./visibilityFilter";
const todoApp = combineReducers({
todos,
visibilityFilter
});
export default todoApp;
reducer/todos.js
const todos = (state = [], action) => {
switch (action.type) {
case "ADD_TODO":
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
];
case "TOGGLE_TODO":
return state.map(
todo =>
todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
);
default:
return state;
}
};
export default todos;
reducer/visibilityFilter.js
const visibilityFilter = (state = "SHOW_ALL", action) => {
switch (action.type) {
case "SET_VISIBILITY_FILTER":
return action.filter;
default:
return state;
}
};
export default visibilityFilter;
containers
containers/AddTodo.js
import React from "react";
import { connect } from "react-redux";
import { addTodo } from "../actions";
let AddTodo = ({ dispatch }) => {
let input;
return (
<div>
<form
onSubmit={e => {
e.preventDefault();
if (!input.value.trim()) {
return;
}
dispatch(addTodo(input.value));
input.value = "";
}}
>
<input
ref={node => {
input = node;
}}
/>
<button type="submit">Add Todo</button>
</form>
</div>
);
};
AddTodo = connect()(AddTodo);
export default AddTodo;
containers/FilterLink.js
import { connect } from "react-redux";
import { setVisibilityFilter } from "../actions";
import Link from "../components/Link";
const mapStateToProps = (state, ownProps) => {
return {
active: ownProps.filter === state.visibilityFilter
};
};
const mapDispatchToProps = (dispatch, ownProps) => {
return {
onClick: () => {
dispatch(setVisibilityFilter(ownProps.filter));
}
};
};
const FilterLink = connect(mapStateToProps, mapDispatchToProps)(Link);
export default FilterLink;
containers/VisibieTodoList.js
import { connect } from "react-redux";
import { toggleTodo } from "../actions";
import TodoList from "../components/TodoList";
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case "SHOW_ALL":
return todos;
case "SHOW_COMPLETED":
return todos.filter(t => t.completed);
case "SHOW_ACTIVE":
return todos.filter(t => !t.completed);
}
};
const mapStateToProps = state => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
};
};
const mapDispatchToProps = dispatch => {
return {
onTodoClick: id => {
dispatch(toggleTodo(id));
}
};
};
const VisibleTodoList = connect(mapStateToProps, mapDispatchToProps)(TodoList);
export default VisibleTodoList;
actions/index.js
let nextTodoId = 0;
export const addTodo = text => {
return {
type: "ADD_TODO",
id: nextTodoId++,
text
};
};
export const setVisibilityFilter = filter => {
return {
type: "SET_VISIBILITY_FILTER",
filter
};
};
export const toggleTodo = id => {
return {
type: "TOGGLE_TODO",
id
};
};
components
components/App.js
import React from "react";
import Footer from "./Footer";
import AddTodo from "../containers/AddTodo";
import VisibleTodoList from "../containers/VisibleTodoList";
const App = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
);
export default App;
components/Footer.js
import React from "react";
import FilterLink from "../containers/FilterLink";
export default React.createClass({
render: function() {
return (
<p>
Show: <FilterLink filter="SHOW_ALL">All</FilterLink>
{", "}
<FilterLink filter="SHOW_ACTIVE">active</FilterLink>
{", "}
<FilterLink filter="SHOW_COMPLETED">completed</FilterLink>
</p>
);
}
});
components/Link.js
import React from "react";
import PropTypes from "prop-types";
const Link = ({ active, children, onClick }) => {
if (active) {
return <span>{children}</span>;
}
return (
<a
href="#"
onClick={e => {
e.preventDefault();
onClick();
}}
>
{children}
</a>
);
};
Link.propTypes = {
active: PropTypes.bool.isRequired,
children: PropTypes.node.isRequired,
onClick: PropTypes.func.isRequired
};
export default Link;
components/Todo.js
import React from "react";
import PropTypes from "prop-types";
const Todo = ({ onClick, completed, text }) => (
<li
onClick={onClick}
style={{
textDecoration: completed ? "line-through" : "none"
}}
>
{text}
</li>
);
Todo.propTypes = {
onClick: PropTypes.func.isRequired,
completed: PropTypes.bool.isRequired,
text: PropTypes.string.isRequired
};
export default Todo;
components/TodoList.js
import React from "react";
import PropTypes from "prop-types";
import Todo from "./todo";
const TodoList = ({ todos, onTodoClick }) => (
<ul>
{todos.map(todo => (
<Todo key={todo.id} {...todo} onClick={() => onTodoClick(todo.id)} />
))}
</ul>
);
TodoList.propTypes = {
todos: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
completed: PropTypes.bool.isRequired,
text: PropTypes.string.isRequired
}).isRequired
).isRequired,
onTodoClick: PropTypes.func.isRequired
};
export default TodoList;
@requires_authorization
class SomeClass:
pass
if __name__ == '__main__':
# A comment
print 'hello world'
项目 | 价格 | 数量 |
---|---|---|
计算机 | $1600 | 5 |
手机 | $12 | 12 |
管线 | $1 | 234 |
#1. github在线简历
http://hacknical.com/github/WangHuiying?locale=zh
Vue.js 创新项目
create-a-github-file-explorer-using-vue-js
如何使用 nodejs 作为 java(后端)和前端的中间件?
在这种研发模式下,前后端的职责很清晰。对前端来说,两个 UI 层各司其职:
1、Front-end UI layer 处理浏览器层的展现逻辑。通过 CSS 渲染样式,通过 JavaScript 添加交互功能,HTML 的生成也可以放在这层,具体看应用场景。
2、Back-end UI layer 处理路由、模板、数据获取、cookie 等。通过路由,前端终于可以自主把控 URL Design,这样无论是单页面应用还是多页面应用,前端都可以自由调控。后端也终于可以摆脱对展现的强关注,转而可以专心于业务逻辑层的开发。
通过 Node,Web Server 层也是 JavaScript 代码,这意味着部分代码可前后复用,需要 SEO 的场景可以在服务端同步渲染,由于异步请求太多导致的性能问题也可以通过服务端来缓解。前一种模式的不足,通过这种模式几乎都能完美解决掉。
与 JSP 模式相比,全栈模式看起来是一种回归,也的确是一种向原始开发模式的回归,不过是一种螺旋上升式的回归。
基于 Node 的全栈模式,依旧面临很多挑战:
1、需要前端对服务端编程有更进一步的认识。比如 network/tcp、PE 等知识的掌握。
2、Node 层与 Java 层的高效通信。Node 模式下,都在服务器端,RESTful HTTP 通信未必高效,通过 SOAP 等方式通信更高效。一切需要在验证中前行。
3、对部署、运维层面的熟练了解,需要更多知识点和实操经验。
4、大量历史遗留问题如何过渡。这可能是最大最大的阻力。
Gitbook:
node 中间层搭建 · GitBook
nodejs+express+mongodb 学习笔记
koa
(RESTful的理解)[http://nodeonly.com/2015/06/09/expressjs-rest/]
七个路由,见app/routes/users.js
其中 4 个路由是 crud
GET /users[/] => user.list()
POST /users[/] => user.create()
PATCH /users/:id => user.update()
DELETE /users/:id => user.destroy()
另外 3 个是页面渲染用的
GET /users/new => user.new()
GET /users/:id => user.show()
GET /users/:id/edit => user.edit()
那么我们先来看一下 crud 对应的请求方法
get 用于请求列表
post 用于创建
patch 用于更新,局部更新资源
delete 用于删除
var UserDao = new MongooseDao(User); 数据库操作对象
所以在 controller 里我们看到了如下代码
+ User.getAll(function(err, users){
+ User.getById(id, function(err, user) {
+ User.create({name: req.body.name,password: req.body.password}, function (err, user) {
+ User.updateById(id,{name: req.body.name,password: req.body.password}, function (err, user) {
+ User.deleteById(id, function (err) {
Vue.js处理前端
node.js中间件
java-后端
axios处理网络交互
前端vue.js 后端node.js的交互程序
Java和node.js的历史发展
exports 和 module.exports 的区别了:
https://www.w3schools.com/cssref/pr_pos_vertical-align.asp
vertical-align: baseline|length|sub|super|top|text-top|middle|bottom|text-bottom|initial|inherit;
table 里面可以使用vertical-align来控制处于用一个高度
这个月的记录:
这个月超级充实,哈哈哈,等待国庆放假回来可以收到美金,哈哈哈
/* Chrome, Opera, Safari */
::webkit-input-placeholder {
color: #ff6600; /*orange*/
}
/* Firefox 19+*/
::-moz-placeholder {
color: #ff6600;
opacity: 1; /*提高透明度*/
}
/* Firefox 18 and below*/
:-moz-placeholder {
color: #ff6600;
opacity: 1;
}
/* MS IE 10+ */
:-ms-input-placeholder {
color: #ff6600;
opacity: 1;
}
@media screen and (max-width: ${BREAKPOINT - 1}px) {
padding: ${MOBILE_PADDING}px;
}
valuse = [“CL1”], return fieldName = “ネックレス”
what if values = [“CL1”, “CL2"], should return fieldName = “ネックレス, ネッス“?
// getProductField returns the raw field value inside the `product.filterProperties`.
const getProductField = (
fieldName: ProductField,
product: products.IProduct
): string | null => {
if (!product.filterProperties) {
return null;
}
const property = product.filterProperties.find(
({ field }) => field === fieldName
);
if (!property || !property.values || property.values.length === 0) {
return null;
}
return property.values[0]; // ? should return property.values
};
productResponse{
code: 'ES-00',
properties: [
{
"field": "Collection",
"inValues": ["CL1"]
}
]
}
const rdGroups = [
{
info: {
itemType: "ProductFilterProperties",
code: ProductField.Collection
},
items: [
{
itemType: ProductField.Collection,
code: "CL1",
slug: "necklace",
name: "ネックレス"
}
]
}
];
find filename
-- find file pathopen filename
-open filecode .
不能打开当前目录的问题,写的脚本不对:Pseudo-classes 伪类:DOM在不同状态、不同位置下的特殊效果;
::Pseudo-elements 伪元素:DOM按匹配规则伪造出的元素;
常用伪元素
::after 在元素的内容之后
::before 在元素的内容之前
::first-line 元素的第一行
::first-letter 元素的第一个字母
::placeholder 占位符,用于input输入框之类的提醒
::selection 被选取的元素,用于改变网页被选中部分的效果
:active 当元素被点击的时
:blank 空白的元素
:checked 被选中的元素
:default 默认被选中或默认会被提交的元素
:dir() 匹配特定文字书写方向的元素
:disabled 处于被禁止操作状态的元素
:empty 没有任何内容的元素
:enabled 处于可操作状态的元素
:first 用于打印文档的第一页
:first-child 父级元素下的第一个子元素
:first-of-type 父级元素下的第一个同类子元素
:focus 当元素成为焦点
:fullscreen 当元素被HTML5 API调用RequestFullscreen方式全屏时
:hover 当鼠标移动到链接元素上面时
:in-range 当元素属性值处于其指定的范围内时
:indeterminate 当元素属性值处于不确定状态的
:invalid 当元素属性值不是指定的type属性时
:lang() 匹配有正确lang 属性值的元素,如 lang(zh-Hans)
:last-child 元素的最后一个子元素
:last-of-type 元素的最后一个同类子元素
:left 选择打印文档的左侧页
:link 未被访问的链接元素
:not() 否定选择器(不匹配条件则生效)
:nth-child() 元素的一个或多个特定的子元素
:nth-last-child() 元素的一个或多个特定的子元素,从该元素的最后一个子元素开始算;
:nth-of-type() 选择指定的元素
:nth-last-of-type() 选择指定的元素,从元素的最后一个开始计算
:only-child 元素是它的父元素的唯一子元素
:only-of-type 元素是它的父级元素的唯一一个相同类型的子元素
:optional 未指定required属性的表单元素
:out-of-range 超出规定值范围的元素
:read-only 元素设置了 'readonly' 属性生效
:read-write 元素没有 "readonly" 属性生效
:required 设置了 "required" 属性的元素
:right 选择打印文档的左侧页
:root 文档的根元素
:scope 作用域的伪类,默认为HTML(案例 :scope #mammma {...})
:target 当前活动的元素(匹配页面URI中对应的目标元素)
:valid 表示有效的元素
:visited 已被访问过的元素
content 在元素之前或之后添加的内容。
graphql 模式(schema)、查询(query)、解析器(resolver)
超级小的svg icon, 每个都基本小于1k https://github.com/edent/SuperTinyIcons
阅读PWA中文书📖 https://github.com/SangKa/PWA-Book-CN
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.