webpack中加入less支持

webpack文档中说明
lessc的选项在webpack中都可以使用,可用的选项可以参考less文档:

1
2
3
4
5
6
7
8
9
10
11
12
13
rules: [{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "less-loader" // compiles Less to CSS
options: {
modifyVars:{"primary-color":"#00CEC1"}
},
}]
}]

lessc支持的选项与webpack配置中的名字并不是完全一致的,大部分只需要简单的转换为驼峰式即可,小部分略有不同,例如例子中写的 global-val 在loader的选项中是 globalVars 多了一个 ‘s’,所有选项对应的名称,可以在参考lessc源码。
参考:https://zhuanlan.zhihu.com/p/27439821

在archlinux下,所有的程序安装都会生成一个像windows快捷方式的文件,这个目录在我的archlinux下
/usr/share/applications目录下,可以看到很多以扩展名为desktop的文件。而文件的默认打开程序就是关联在这些程序图标下。

当前每个文件格式默认关联的程序内容是放在:~/.local/share/applications/defaults.list。

linux下可以使用xdg-open file的方式来打开文件,不使用任何DE(desktop enviorment),比如gnome、kde,xfce4等。使用下面的命令查询并修改一个文件的默认打开程序:

# 查询文件类型
$ xdg-mime query filetype some.xls
application/msword; charset=binary
# 查询该文件类型的默认打开方式
$ xdg-mime query default application/msword
# 修改文件的默认打开方式
$ xdg-mime default libreoffice-writer.desktop application/msword

设置文件夹的默认打开程序也可以用这种方法:

$xdg-mime query filetype /home/
inode/directory
$xdg-mime query default inode/directory
$xdg-mime default Thunar-folder-handler.desktop inode/directory

原文链接:http://willam2004.iteye.com/blog/1299151

神秘博士Doctor Who S09 E05: the Doctor’s face

  • I’m so sick of losing.

  • You didn’t lose.You saved the town.

  • I don’t mean the war. I’ll lose any war you like. I’m sick of losing people.

  • My face.

  • Who frowned me this face?

  • Why this one?

  • Why did I choose this face?

  • Doctor, what’s wrong with your face?

  • I think I know why I chose it.

  • It’s like I’m trying to tell myself something.

  • I think I know what I’m trying to say.

  • Just someone.

  • Not the whole town.

  • Just save someone.

  • Come with me.

  • I know where I got this face,

  • and I know what it’s for.

  • OK, what’s it for?

  • To remind me.

  • To hold me to the mark.

火线The Wire: Old Cases S01 E04

Det. James ‘Jimmy’ McNulty: How long you been in the pawn shop unit?

Det. Lester Freamon: Thirteen years and four months.

Det. James ‘Jimmy’ McNulty: Thirteen years?

Det. Lester Freamon: And four months.

Det. James ‘Jimmy’ McNulty: I gotta ask you, what exactly does a police officer assigned to the pawn shop unit do?

Det. Lester Freamon: You intake reports from registered pawn shops on all items valued over $50. Then you make an index card for that item. Then you file that index card. If someone wants to find out if something stolen has been pawned, we look to see if we have an index card. If we do, we do. If we don’t, we don’t.

Det. James ‘Jimmy’ McNulty: You did that for thirteen years?

Det. Lester Freamon: And four months.

Det. James ‘Jimmy’ McNulty: Why’d you ask out of homicide?

Det. Lester Freamon: Wasn’t no “ask” about it.

Det. James ‘Jimmy’ McNulty: You got the boot?

Det. Lester Freamon: Uh-huh.

Det. James ‘Jimmy’ McNulty: What’d you do to piss ‘em off?

Det. Lester Freamon: Police work.

Det. James ‘Jimmy’ McNulty: I think I need to buy you a drink.

Det. Lester Freamon: Just one?

JavaScript的对象复制存在一些容易犯错的位置,从下面代码可以看出来:
直接赋值:

1
2
3
4
5
6
7
let obj = {
cat: 1,
a: { b: {c: 1} }
}
const sameObj = obj;
obj.a.b.c =2;
console.log(obj === sameObj); // ture

明明更改了初始的对象obj,但是这两个对象还是完全相等。所以这赋值操作与一般的变量赋值是有区别的。js中这种直接赋值来复制对象是将原对象在内存中的引用(c语言中的指针)复制了过去,并没有给新的对象加入新的内存空间。当这两个对象中的一个对象改变时,于是这块内存也改变了,但是这两个对象都是指向这块内存空间,于是就发生了这种情况:当一个对象改变时,这两个对象都会改变。

浅拷贝:所以要使用新的方法来复制对象:例如 Object.keys(),Object.assign(),for(let … in Obj)等方法来复制对象const a = {};``a = { ...ArrObj }Object.assign({}, Obj)

1
2
3
4
5
const obj2 = Object.assign({}, obj);    
obj.cat = 2;
obj.a.b.c =2;
console.log(obj2.cat, obj.cat === obj2.cat); // 1, false
console.log(obj2.a.b.c, obj2.a.b.c === obj.a.b.c) // 2, true

第一条打印的结果是我们想要的,新对象与原始对象不再有联系。但是第二条打印结果却又出现来跟直接赋值来复制对象相识的情况:改变一个对象的属性值,另一个对象也相应的改变了。这是因为上述的复制方法也都是只把第一层属性值重新用赋值的方式复制了一下,如果第一层的属性值仍然是指向对象的引用,这些方法复制的依然是指针,所以改变其中一个对象第二层以上的属性值,还是会导致两个对象同时改变。

理解之后可以思考一下下面的打印结果

1
2
obj.a = 1;
console.log(obj2.a.b.c); // 2

深拷贝:使用const newObj = JSON.parse(JSON.stringify(obj))可以实现复制对象是不再复制指针,进而两个对象不再有关联。可以这样理解:对象先转换成字符串,对象的指针信息自然就不再保存下来了,从这个字符串生成的对象也就没有了指针的关联,两个对象不再有任何关联。这种方法只有在原对象是json格式时有效,因为这种复制方法也会将原对象的方法(属性为函数)丢失。

ps:这样设计的目的是为了节省内存,所以为了这几kb的内存我就还是忍了吧!

递归函数深层复制

React组件更新的四个途径

  1. 首次渲染Initial Render
  2. 调用this.setState (并不是一次setState会触发一次render,React可能会合并操作,再一次性进行render)
  3. 父组件发生更新(一般就是props发生改变,但是就算props没有改变或者父子组件之间没有数据交换也会触发render)
  4. 调用this.forceUpdate
    如图所示
    React

原作者:linjinhe

链接:http://www.jianshu.com/p/4784216b8194

  • 图片按钮<input name="submit" type="image" value="ee" src="12.jpg" />
  • img下面有4px留白
  • 使用title属性显示提示信息
  • 空格:&nbsp;
  • <hr />color属性设置颜色
  • ie兼容性<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
  • 只要是有src或href的HTML标签都有跨域的能力。
  • 网页中的空格转义字符&nbsp;在命令行中不能识别为正常的空格,会导致命令执行出错
  • 将dom元素关联自定义变量:加入属性data-*
1
2
3
4
5
6
<img
data-value="31940"
onclick={(e) => {
console.log(e.target.dataset.value);
}}
/>
  • dom元素绑定事件,传入当前元素
1
2
3
4
5
6
<p onclick="handleClick(this)">如果你点我,我就会消失。</p>
<script>
function handleClick(domObj) {
console.log(domObj);
}
</script>

  • mongo:打开命令行

  • 进入数据库:use DBname。展示:show dbsshow collections

  • mongoimport mongoexport备份与恢复集合(collection)

    共同的相关配置:-d DBname -c COLname -h IPaddress:PORTname

    从filename导入:mongoimport [config] filename

    filename:mongoexport [config] -o filename

    导入数据要避免与原来的数据重复,先删除集合db.COLname.drop() 再mongoimport

  • MongoDB 数据库备份(mongodump)与恢复(mongorestore)

  • 命令行中打印变量print VARIABLE

  • 使用javascipt的数组迭代方法forEach map
    这样可以方便的操作字段名(field),如字段重命名、字段合并

1
2
3
4
5
6
7
8
9
10
11
12
db.getCollection('spaces').find({}).forEach(function(x) {
if(x.in_company) {
x.in_company = x.in_company.map(function(ele, i) {
return {
name: ele,
website: x.in_company_url ? x.in_company_url[i] : null,
}
});
delete x.in_company_url;
db.spaces.save(x);
}
})
  • 加入表的关联:mongoose字段加入ref属性,查询时加入populate方法。

数据库操作

  • db.COLname.save()包含_id则为修改文档,不包含则与db.COLname.insert()功能相同

  • 查询时注意String(‘1’)与Number(1)的区别,在mongoose的保存save与更新update操作中,定义好Schema的字段类型后,则数字与字符串没有区别。

  • 查询不存在字段名或者字段的值为nulldb.COLname.find({"FIELD": null})

    相应的查询字段存在并且值为nulldb.COLname.find({"FIELD": {"$in":[null],"$exists":true}})
    查询存在该字段的文档{$exists: true}

  • 文档中的字段存储数组/对象时的查询:在文档{"fruits" : [ "apple", "pear", "orange" ] }

    字段的值为数组:
    找到数组中包含值:find({"fruits":"apple"})

    数组中包含多个值:find({"fruits":{"$all":["apple","banana"]}})

    数组中某个索引为某个值:find({"fruits.1":"orange"})

    精确查询,要求值相同并且顺序一致:
    find({"fruits":["apple","orange","pear"]})

    字段的值为对象数组时:使用精确匹配时,只会找出字段的值相等并且顺序一致的文档。
    要求包含某些键值对,注意与字段的值为对象时查询的区别:
    find({ "name.first":"joe", "name.middle":"bush" })

安全策略

设置用户权限

  • mongod --auth开启权限认证,再加入用户分配权限
  • TLS/SSL传输加密
  • 数据库定时备份
  • 不使用mongodb默认端口,防止端口扫描
  • 不需要公网连接时,bind_ip只允许本地访问

mongoose

mongoose的model名称为首字母大写时,存到mongodb时会自动首字母小写

mongodb版本6安装

安装MongoDB Community Server
安装MongoDB Shell

  • React.Children.map(this.props.children, () => { …… })
  • 改变state不使用push方法而是setState
  • ES6语法const props = { ...this.props };
  • 组件自定义背景,在父组件位置设置style属性,然后在子组件里面继承style属性;
  • setState是异步的,不会马上更新state。setState有callback函数
  • react-router的onEnter设置路由权限
  • 使用div模拟textarea:属性contentEditable="plaintext-only"onInput={this.emitChange}this.inputRef.innerHTML获取输入内容。
1
2
3
4
5
6
7
<div
className="input_content"
onInput={this.inputChange}
contentEditable="plaintext-only"
ref={(inp) => { this.inputRef = inp }}
onKeyDown={this.onKeyDown}
/>

新版ref写法ref={this.inputRef}

  • 键盘事件

    onKeyDown = (e) => {
    console.log(e.key);
    }

状态提升

你一定听说过变量提升,函数提升,那么状态提升是什么呢?

首先你得了解双向绑定和单向数据流,双向绑定中,数据可以在不同的组件之间实现共享,这样做的确有很大的好处,但是在react中,不推荐使用双向绑定,而是使用状态提升的方式。

状态提升:state推崇单向数据流,数据从父组件通过props流向子组件,如果你在子组件中,需要修改state来和其他子组件共享数据更新,你需要使用回调函数给使数据更新给父组件,然后从父组件流向其他的子组件,这样做是保证数据有单一的来源。

如果子组件和子组件之间任意共享数据,那么,后期维护会比较痛苦,特别是找bug的时候。

看一个状态提升的例子吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Child extends React.Component {
constructor(props) {
super(props);
}
handleChange = (e) => {
this.props.upDateValue(e.target.value);
}
render() {
const {name, value} = this.props;
return (
<div>
<p>{name}:</p>
<input
value={value}
onChange={this.handleChange}
/>
</div>
);
}
}

class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {value: '', name: ''};
}
upDateValue = (value) => {
this.setState({value: value})
}
render() {
const {value} = this.state;
return (
<div>
<Child name="组件1" value={value} upDateValue={this.upDateValue} />
<Child name="组件2" value={value} upDateValue={this.upDateValue} />
</div>
);
}
}
ReactDOM.render(
<Demo />,
document.getElementById('root')
);
- 传递属性给子组件

const childrenWithProps = React.Children.map(this.props.children,
child => React.cloneElement(child, {
equityRate: this.publishTasks,
}),
);

this.context

  • this.context用法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//在父组件中包含方法
getChildContext() {
return {
USER: this.state.USER,
};
}
Parent.childContextTypes = {
USER: PropTypes.object,
};
//在子组件中
Child.contextTypes = {
USER: PropTypes.object,
};
constructor(props, context)

Atom快捷键

  • Ctrl+shift+m预览markdown

  • string操作不改变原string,只会返回新string。Buffer只改变原Buffer。
  • bin => dup
1
2
var dup = new Buffer(bin.length);
bin.copy(dup);
  • 附件上传
1
2
3
4
5
6
7
8
9
10
11
12
const uploadFile = (req, res, next) => {
//生成multiparty对象,并配置上传目标路径
var form = new multiparty.Form({uploadDir: './public/files/'});
//上传完成后处理
form.parse(req, function(err, fields, files) {
var inputFile = files.file[0].path;
console.log('inputFile', inputFile);
res.writeHead(200, {'content-type': 'text/plain;charset=utf-8'});
res.end(inputFile);
//res.end(util.inspect({files: inputFile}));
});
};
  • 实现文件下载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
router.get('/file/:fileName', function(req, res, next) {
var fileName = req.params.fileName;
var filePath = path.join(__dirname, fileName);
var stats = fs.statSync(filePath);
if(stats.isFile()){
res.set({
'Content-Type': 'application/octet-stream',
'Content-Disposition': 'attachment; filename='+fileName,
'Content-Length': stats.size
});
fs.createReadStream(filePath).pipe(res);
} else {
res.end(404);
}
});

前端<a>标签加上download属性后就可以下载了

服务器操作

  • pm2 list
  • pm2 restart 1
  • pm2 start <path/to/app.js>

Yarn

  • yarn add [package]
  • yarn add [package]@[version]
  • yarn add [package]@[tag]
  • yarn upgrade [package]
  • yarn remove [package]
  • yarn install
0%