Hank's House


  • Home

  • About

  • Tags

  • Categories

  • Archives

node基础学习——网络操作

Posted on 2018-03-20

编写高性能web服务器

http部分

req和res的梳理
均可直接访问头数据如req.method res.headers等;均可req.on(‘data’/‘end’,function(){})
一个实际的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//客户端 发送请求
http.get('http://127.0.0.1:8080',function(res){
//http.request({hostname:'',port:8080},function) post请求时可如此。Q:此例如此写无法执行,因为本地主机的原因?
var body = [];
res.on('data',(chunk)=>{
body.push(chunk);
}); //服务器返回的数据
res.on('end',()=>{
console.log(body.toString());//body本身输出是二进制buffer数组
})
})
//服务器端
http.createServer((req,res)=>{
res.writeHead(200,{'Content-Type':'text/plain'});
res.write('hello');
res.end();
}).listen(8080)

HTTPS

和http类似,只是多了额外的SSL证书配置。
//服务器端
var options = {
key:fs.readFileSync(‘./ssl/default.key’), //服务器使用的私钥
cert:fs.readFileSync(‘./ssl/default.cer’) //服务器使用的公钥
} //相比于http多了该参数
var server = https.creatServer(options,(req,res)=>{

})
//SNI技术,即此服务器为多个域名提供服务
//添加不同域名证书
server.addContext(‘foo.com’,{
key:…,
cert:…
})
//客户端模式发起请求
https.request(options,(res)=>{ //别和服务器的options混了,这里是请求头、主机端口等信息

})

url

""
url字符串:比如http://user:pass@host.com:8080/p/a/t/h?query=string#hash
url对象:每一部分拆解开
转换方式:url.parse(‘url字符串’) 转换成对象
parse的另外两个参数:参数二为true,query字段返回的不是字符串而是queryString处理后的参数对象;参数三为true,可正确解析不含协议头的url如’//www.baidu.com'
url.format(‘url对象’) 转换成url字符串
url.resolve(‘www.baidu.com','/hank') 拼接url(引申:path.join是拼接文件路径哦)

queryString

url参数字符串和对象互相转换。解析url查询参数。
querystring.parse(‘foo=bar&b=w’) 得{foo:bar,b:w}
querystring.stringify({})

zlib模块

开启gzip压缩功能

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
//服务器端。压缩HTTP响应体数据发给客户端。判断客户端是否开启,再决定是否启用
http.createServer((req,res)=>{
//测试数据
var i = 1024,data='';
while(i--) {
data += '.';
}
if((req.headers['accept-encoding']).indexOf('gzip')!==-1){ //此处可以用正则表达式来写!
zlib.gzip(data,(err,data){
res.writeHead(200,{
'Content-Type':'text/plain',
'Content-Encoding':'gzip' //accept-encoding和content-encoding
});
res.end(data);
});
} else {
//不设置gzip即可
}
}).listen(8080)
//客户端。收到响应体数据进行解压缩。判断服务器端是否使用gzip,是的话进行解压
var options = {
...
headers:{
'Accept-Encoding':'gzip,deflate' //两种压缩方式,服务器会根据这决定返回哪种压缩文件
}
}
http.request(options,(res)=>{
var body = [];
res.on('data',(chunk)=>{
body.push(chunk)
});
res.on('end',()=>{
body = Buffer.concat(body);
if(res.headers['Content-Encoding']==='gzip'){ //或者switch(res.headers['content-encoding'])判断是gzip or deflate等
zlib.gunzip(body,(err,data){
console.log(data.toString())
})
} else {
console.log(body)
}
})
})

net模块

创建socket服务器或客户端。
socket协议是传输控制层的,websocket是应用层

node基础学习——文件操作

Posted on 2018-03-19

js是脚本语言,对于html中的js,浏览器作为解析器(运行环境);对于单独的js,node作为解析环境。
浏览器中操作DOM,提供document等内置对象;NODEJS操作磁盘文件or搭建HTTP服务器,提供fs、http等内置对象。
所有模块执行过程中只初始化一次。

模块路径:

1.内置模块直接调用如require(‘fs’)
2.node_modules目录下如某个绝对路径为’/home/user/h.js’的文件中require(‘foo/bar’),则使用的路径依次为/home/user/node_modules/foo/bar或者/home/node_modules…或者/node_modules/…
3.NODE_PATH环境变量(尝试额外的搜索路径)

下载第三方数据包,可以先写入package.json,再npm insatall.

文件读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//异步拷贝
fs.readFile('./t.txt', function(err, data) {
if (err) {
console.log('read fail!');
} else {
console.log('reading data...');
fs.writeFile('./tee.txt', data, function(err) {
if (err) {
console.log('write fail!');
} else {
console.log('writing data...');
}
});
}
});
//同步复制
/*function copy(src,dst) { //源路径 目标路径
fs.writeFileSync(dst,fs.readFileSync(src)); //读取原路径写进来
}
copy('./t.txt','./tee.txt');*/
//或者fs.writeFileSync('./tee.txt',fs.readFileSync('./t.txt'));
//流stream
//fs.createReadStream('./te.txt').pipe(fs.createWriteStream('./t.txt'));
//读取后流入到新文件中,适合大文件

windows命令行复制文件:如将d:\1.jpg复制到f盘根目录——copy d:\1.jpg f:\1.jpg
所以可以在node中调用命令行实现文件复制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var child_process = require('child_process');
var util = require('util');

function copy(source, target, callback) {
child_process.exec(
util.format('copy %s %s', source, target), callback);// %s依次使用后面的字符串替换,所谓的格式化就是变量替换嘛
}

copy('C:\\Users\\hank.li\\Desktop\\hank\\s.png', 'C:\\Users\\hank.li\\Desktop', function (err) {
console.log(err);
});
//坑:双斜线防止转义啊!斜线方向要注意啊!
//exec命令行开启执行子进程
//spawn cluster

其他API:

buffer:处理二进制数据

stream:内存一次装不下以及需要边读取边处理
var a = fs.createReadStream(pathname); //只读流
b = fs.createWriteStream(dst);
a.on(‘data’,function(chunk){b.write(chunk)})
a.on(‘end’,function(){b.end()})
基于事件机制的,stream实例继承自node中的eventEmitter
灵活使用回调,比如防止读取data太快导致后续函数处理不过来,可使用回调,即在处理函数前暂停读取,然后dosomething(chunk,function(){}).
最好加一步判断是否会爆仓(写入太慢读取太多),写入时a.on(‘data’,…)中判断b.write(chunk)===false,成立的话说明传入的数据放到缓存了还没写入目标,先暂停读取。另添加一个监听 b.on(‘drain’,function(){启动read}),drain事件用于判断缓存数据已写入目标。其实这与pipe实现很类似。(注意读写之间来不及处理的数据放在缓存中!)

文件系统:关于fs模块。(此处展示node异步)
属性读写:stat(判断文件还是目录) chmod(异步方式改变文件读写权限) chown(更改文件所有权)
内容读写: readFile(异步读取) readdir(读取目录directory,返回包含所有文件和子目录的数组) writeFile mkdir(新建目录,fs.mkdir(‘./xxx’,function(err){}))
底层文件操作:open read write close
上述均为异步且都有同步方法。回调参数基本都有两个,错误+返回执行结果。

Path:处理文件路径
normalize 标准化路径。实例:path.normalize(‘foo//baz//../bar’)得出foo/bar(多余斜杠会取消,..会回退上一级)
join 拼接路径。实例:path.join(‘foo/‘,’baz/‘,’../bar’)得出foo/bar
extname 返回扩展名,从最后一个.开始计算。如返回’.js’之类。

遍历目录
递归算法:简洁但是耗内存
遍历算法:树状结构目录,深度优先+先序遍历,即优先子集而非同级元素+首次到达某节点即遍历完成。
一个文件重命名demo:

1
2
3
4
5
6
7
8
//demo入口文件index.js放在test文件夹同级
var counter = 9;
fs.readdir('./test',function(err,files) { //读取test文件夹中的所有txt文件
files.forEach(function(fn){
fs.renameSync('./test/'+fn,'./test/'+counter+'.txt');//fn只是test中的文件,重命名需加上目录。将前者重命名为后者(升序排列)。此处路径也是相对index文件所在目录
counter++;

})

同步遍历:
1
2
3
4
5
6
7
8
9
10
//遍历index的同级文件夹
function travel(dir,aa) {
fs.readdirSync(dir).forEach(function(file){
var pathname = path.join(dir,file);//这里插入一个判断是目录还是文件(fs.statSync(pathname).isDirectory()),是目录的话就回调遍历函数。stat返回值是一个标志对象。
aa(pathname);
})
}
travel('./',function aa(pathname){
console.log(pathname)
});

异步遍历:略。
文本编码
常用文本编码主要是GBK(国家编码,包含全部中文字符)和UTF-8(国际编码)。二者之间通过unicode编码进行转换。
BOM 隐藏字符(UTF-8允许含BOM)
读取文本文件需去BOM,即:
1
2
3
4
5
6
7
function read(pathname) {
var bin = fs.readFileSync(pathname);//返回一个字符串(buffer二进制数据),如果声明encoding则返回普通字符串(添加第2个参数{encoding:'utf-8')
if(bin[0]===0xEF && bin[1]===0xBB && bin[2]===0xBF) {
bin = bin.slice(3);//BOM被去除
}
return bin.toString('utf8');//转换成utf8编码(测试过转为汉字)
}

字符编码参考网站:https://www.cnblogs.com/xiaomia/archive/2010/11/28/1890072.html

未分类知识点散记

Posted on 2018-03-18

export、exports、export default

require node和es6均支持
export/import es6支持
module.exports/exports node支持 (均指向某内存块{},就用exports.xx = xx就好)

关于export和export default:
后者每个模块只有一个;前者可直接导出变量表达式。
前者(导出变量or方法):
export const a = 100 或者 export const b = function(){}
或者
function xxx(){}
export { xxx };
后者:
const c = 100;
export default c;
前者导出的在导入时要加{},import { b } from ‘./…’
而export default则不用,import c from ‘./…’

import as ObjectX from ‘./…’ 将零散的export导出为对象,而export default 是导出为default属性。
(吐槽:default只有一个肯定无所谓对象什么啦!soObjectX.c 不存在的。由于每个模块就一个default,所以ObjectX.default即可。)
ObjectX.b();执行函数b
(Q:引入多个模块均由export default怎么办?)
参考地址:https://segmentfault.com/a/1190000010426778*

WebP格式

有损 无损 有损带透明
相比于jpg、png等格式,压缩效果更好,体积减小。
对比图:
""
参考地址:https://www.zhihu.com/question/27201061

网络相关

SNI 服务器名称指示。同IP下多域名虚拟主机的SSL/TLS认证。
正常客户端发起SSL握手请求时不包含host主机头信息,也就不知道该引向哪个域名((http协议就有hostname)。而SSI会提交Host信息,使得服务器可以切换到正确的域并返回相应的证书。

node安装

环境变量配置:计算机属性=>高级系统设置=>环境变量=>PATH
修改node文件夹下的.npmrc文件,以设置npm全局安装位置(默认是在appdata里的)

vue-留言板+localStorage+node后台留言板

Posted on 2018-03-15

提交留言后显示在当前界面,存储在本地localStorage,保证下次加载不丢失。
重要知识点:localStorage的使用。

前端留言板

1
2
3
4
5
6
7
8
9
//html部分,注意显示留言循环调用数组即可
<p>内容:
<input type="text" name="msg" v-model="newMsg">
</p>
<input type="button" value="提交" @click="addMsg">
<button @click="removeMsg">清除</button>
<ul>
<li v-for="msg in msgs"></li>
</ul>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//localStorage部分,封装起来统一使用
var STORAGE = 'liuyanban';//设定一个存储空间,只是为了方便。不然就得localStorage.setItem('liuyanban','xxx'),其中xxx为数组或对象,但需要做字符串转化处理。
var msgStorage = {
save(msgs) { //有msgs变化即调用存储
localStorage.setItem(STORAGE,JSON.stringify(msgs));//必须转化为字符串!
},
fetch() {
var msgs = JSON.parse(localStorage.getItem(STORAGE));//msgs直接存入localStorage,显示的话调用localStorage中的msgs
return msgs;
},
clear() { //清除localStorage
localStorage.removeItem(STORAGE)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//调用存储部分
data:{msgs:msgStorage.fetch()}
watch:{
msgs:{
handle(msgs){
msgStorage.save(msgs)
}
}
}
methods:{
addMsg(){
if(this.newMsg === "") return;
this.msgs.push({title:this.newMsg}) //msgs有变化,故调用save存储
},
removeMsg(){ //清理显示和localStorage两部分
this.msgs = [];
msgStorage.clear(); //如果调用localStorage就全部清除了= =
}
}

关于localStorage

存储路径在C:/用户/AppData下面。
chrome分配存储空间5M,整个子域共享,即www.baidu.com/下的任何域名都共享该空间。
常用的基本就是上述使用的API:
setItem getItem removeItem :key value
length
key(i) 获取第i个数据的key
clear(清除全部存储数据,剩余的只有这几个API)
清除后看了下自己电脑控制台:
""

1
2
3
for(var i in localStorage) {
console.log(i);
}

另,统计界面刷新次数也可以使用这,每次重载innerHTML写入时getItem后数字加1即可。
1
2
3
if(!localStorage.getItem('number')) {localStorage.setItem()}
localStorage.number = parseInt(localStorage.getItem('number')) + 1;
console.log(localStorage.number);

node服务器端留言板

require模块:http url querystring
俩路径通过pathname判断。
/message
写入form表单,即res.write(form)
/messageok
写入form中输入的文本,即
req.on(‘data’,(chunk)=>{
body += chunk;
})
req.on(‘end’,()=>{
console.log(qs.parse(body));
res.end(‘over’); //网页显示over,命令行显示提交的内容
})

node-上传图片练习

Posted on 2018-03-12

keywords:formidable模块 multipart/form-data格式(content-type类型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
//index.js
//根文件,服务器启动,准备解析相应url
var server = require("./server");
var router = require('./router');
var requestHandlers = require('./requestHandlers')

var handle = {};
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
handle["/show"] = requestHandlers.show;

server.start(router.route, handle);

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
 
//server.js
//监听8888端口,路由跳转
var http = require('http');
var url = require('url');

function start(route, handle) {
function onRequest(req, res) {
if (req.url === "/favicon.ico") return;
//屏蔽浏览器favicon,这玩意就是标签页顶显示的那个小图标,否则刷新页面会出现两次路径
<!--关于favicon图标,要么直接扔到根目录,要么head里设置如下
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> //这里保证IE兼容性
//<link rel="icon" href="/favicon.ico" sizes="32x32" />
//网站图标缓存,尽量不要超过16kb吧。32*32一般也就4kb-->
console.log('received');
var pathname = url.parse(req.url).pathname; //解析req.url
route(handle,pathname,req,res);
}
http.createServer(onRequest).listen(8888);
console.log('start');
}
exports.start = start;
/*var postData = ""; 这部分是读取文件测试
req.setEncoding("utf8");
req.addListener("data", function(chunk) {
postData += chunk;
console.log(chunk);
});
req.addListener("end", function() {
route(pathname, handle, res, postData);
})*/
1
2
3
4
5
6
7
8
9
10
11
12
13
 
//router.js
//路径无效404处理,有效开始分配事件处理程序
function route(handle,pathname,req,res) {
if (typeof handle[pathname] === 'function') {
handle[pathname](res.req);//注意req在前?总是提示“res.writeHead not a function”的坑,只能各个文件轮流更改参数顺序了
} else {
res.writeHead(404, { "Content-Type": "text/html" });
res.write("404");
res.end();
}
}
exports.route = route;
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
 
//requestHandlers.js
//事件处理程序,针对不同路由
var exec = require('child_process').exec; //注意没()
var querystring = require('querystring'),fs = require("fs"),
formidable = require('formidable');

function start(res) {
/*function sleep(sec) {
let now = new Date().getTime();
while (new Date().getTime() < now + sec);
/*let now = new Date(),exitTime = startTime.getTime()+sec;
while (true) {
now = new Date();
if (now.getTime() > exitTime)
return;
}
}
sleep(10000);*/
/*var content = "empty";
exec("ca.txt", function(error, stdout, stderr) {*/
var body = '<html>' +
'<head>' +
'<meta http-equiv="Content-Type" content="text/html; ' +
'charset=UTF-8" />' +
'</head>' +
'<body>' +
'<form action="/upload" enctype="multipart/form-data" method="post">' +
'<input type="file" name="upload">' +
'<input type="submit" value="Upload file""/>' + //判断是否提交, onchange="alert(this.value)或者判断value是否为空?实际就是表单验证
'</form>' +
'</body>' +
'</html>';
res.writeHead(200, { "Content-Type": "text/html;charset=utf-8" });
res.write(body); //写入相应路径的返回值
res.end(); //直接打开相应文件了

}
function upload(res, req) {
var form = new formidable.IncomingForm();
form.parse(req,function(err,fields,files){
fs.renameSync(files.upload.path,"./tmp/2.jpg");//重命名为右侧
res.writeHead(200, { "Content-Type": "text/html;charset=utf-8" });
res.write("<img src='/show'>");
res.end();
})

}

function show(res){
fs.readFile("./tmp/2.jpg","binary",function(err,file){
if(err){
res.writeHead(500, { "Content-Type": "text/plain;charset=utf-8" });
res.write(err+"\n");
res.end();
}else{
res.writeHead(200, { "Content-Type": "image/jpg" });
res.write(file,"binary");
res.end();
}
})
}
exports.start = start;
exports.upload = upload;
exports.show = show;

各种名词随手记

Posted on 2018-03-11

####git & github
merge 合并(git合并分支)

####设计模式
MVC:model view controller。单向流,view中触发DOM事件,controller触发数据更新,model将数据显示到view中。(也可直接向controller发送指令,如改变url触发hashChange事件)
MVP:presenter。双向通信。隔绝V和M之间的通信,减少维护对象数量。
MVVM:ViewModel。类似于MVP。但是M和VM之间数据绑定进行双向交互。观察者/数据劫持。
""
""
""

C/S模式:客户机/服务器
B/S模式:浏览器/服务器

前后端分离:
团队分工更细,后端只提供接口,前端可自己mock数据,负责页面展现接口设计和功能页面开发。
开发流程图:
""
过程性文档:
接口契约文档:前端提出的定义前后端的接口定义。责任方:前端;评审方:后端、测试QA、产品
集成测试用例文档
功能测试用例完档:定义验收页面功能的用例。责任方:测试QA;评审方:前端、产品
单元测试用例:定义后端各个功能模块的单元用例。
技术框架选型
项目管理:
前端团队进度:基于mock接口三个阶段——一是跑通所有界面的mock接口(发现接口调用、css等各种问题);二是基于所有页面进行迭代,问题统一解决,抽离公共组建进行优化界面;三是分批接入后端模块并提交QA进行功能测试。
参考网站:http://www.infoq.com/cn/articles/practice-frontend-backend-separation

计算机基础

四个时代:电子管 晶体管 集成电路 大规模集成电路
进制转换:
十进制小数到二进制小数——乘2取整法,从上到下读。如0.68752 = 1.375 取1,继续0.3752类推。
信息编码:
BCD码(8421编码)——4 === 0100
ASCII码 ——通用7位版本
汉字编码
(国标码GB2312-80 区位码(9494,一行为区,一列为位。所以共94个区,每个区内94个位的汉字字符集,有唯一的位置编码即区位码))
(机内码)
(汉字字形码)
计算机组成:*
运算器 控制器 存储器 输入输出设备
存储器:内存、外存(硬盘光盘等)
""
多核CPU:一个CPU上有多个计算引擎(核心处理器)【单线程用不了】
多个CPU:一个主板上搞了几个CPU,通过总线进行通信

进程:操作系统进行资源分配的最小单元;线程:进程内部的一个执行单元
进程创建后,即启动主线程比如main函数之类。主线程中止,进程即中止。
多线程要注意的是资源共享,即两个线程同时访问一个资源,只能在使用时共享资源处于锁定状态。一个线程一个线程的来执行。

node执行某js文件,创建的是进程,但可能包含多个线程,但一次只执行一个线程(所谓的node单线程)。好处就是不用像java等多线程语言一样注意死锁、状态同步、上下文切换开销等。

CPU主频(MHz)高,微机运算速度快
RAM(随机/运行内存,断电就没) ROM(只读内存相当于手机的硬盘存放安卓系统、软件、文件等) 快存(高速缓存存储器)
操作系统(OS):单用户操作系统(多任务,windows)、分时操作系统(unix)等
语言编译程序:机器语言 汇编语言 高级语言

localStorage适合存储不需要和后台交互的,比如有些草稿功能,关闭界面再进入仍然有效。
cookie中可放语言设置等。浏览器进行实现和管理。
域domain 路径(同一目录和子目录下才OK)
类型:浏览网站本身设置、网页嵌入广告用于跟踪使用信息

git学习笔记&实践问题

Posted on 2018-03-09

###git学习笔记
""
""
""
分支管理:要提交没写完的代码使自己下次继续,需要创建一个自己的分支,别人看不到,在自己的分支上工作,开发完毕后再合并到原来的分支上。
""
""
""
另:git分布式版本控制系统,Linux内核开发者所写。

###Q&A
Q:基础上传项目顺序
A:项目文档右键git bash后 ==> git init(设为仓库) ==> git add .(添加到暂存区,.可以替换为具体文件) ==> git commit -m “something”(统一提交更改) ==> git remote add origin git@github.com:losthank(连接远程库) ==> git push -u origin master(推送到远程库)

Q:push到远程库时出现”failed to push refs to ‘git@github…’”字样
A:可强制推送,使用git push -u origin master -f即可。但是协同合作时不建议使用。

Q:git push -u origin master
A:upstream上传流(-u),只有第一次推送代码时创建,之后无需-u

Q:修改后再次上传
A:重复add commit pull push的过程

Q:.gitignore文件
A:vue项目传输到github时,node-modules库会被忽略。

Q:git status和git log
A:前者查看是否有文件没有被commit,后者查看commit的历史记录。

css权威指南查漏补缺散记

Posted on 2018-03-02

学习中

后代元素和子元素的区别:前者包含后者。表示形式——空格和>

XML中不支持.class写法,故有h1[class=””]{color:red;}类似写法。

伪类选择器:a:visited(静态伪类,改变一次即保持);a:hover(动态伪类);input:focus{}用于设置选中输入框准备输入时的样式,比如设置背景为银色等。
:first-child :nth-child(n)
:lang(de)语言
伪元素选择器: :first-letter/line :before/after

color:red !important;重要标记的规则不会被覆盖

web安全颜色:按照不同表示法,分别有能被20%整除的数(如rgb(40%,0,80%))、0或被51整除的数(如rgb(0,204,153))、三元组(00 33 66 99 CC FF)。这些在256色计算机系统上可以避免颜色抖动。

段落首行缩进:text-indent:3em

上下标:vertical-align:sub/super。当然之前常用的是middle实现垂直居中。

white-space的属性值影响空白符、换行符、自动换行等。

auto:width margin的left right可以设置。根据父元素宽度自动计算,即比如margin padding等宽度已知,设置width为auto,auto值即为计算得出。如果手动设置的margin left+right+width不为父元素宽度,则right自动调整为计算值。
设置left right均为auto,会设置相等的宽度,即居中。

(非)替换元素:浏览器是否根据属性替换内容,如img input等。

行间距 line-height font-size三个区别:行高-font-size等于行间距
行框 行内框:行框高度取同一行最高行内框的高度;行内框高度即为line-height

BFC 还有IFC(行内级的)
块级元素排布的规则,规定子元素如何定位以及同级元素如何排布。
在生成BFC后(float absolute inline-block flex overflow不为visible等) 垂直排布,两个BFC块之间的margin不会发生重叠。其实许多都是常用的。IE的haslayout属性,是IE内置的布局属性,对于不支持BFC的可以调用。

数据属性
HTML中


这些属性没有可视化展现意义,js读取时,可以使用document.getElementById(‘#test’).dataset.columns = “4”

百度地图API调用学习

Posted on 2018-03-01

百度地图实践中…

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
var map = new BMap.Map("container");
var point = new BMap.Point(116.404,39.915);
var opts = {offset:new BMap.Size(150,18)};
var mapStyle = {style:"hardedge"};//设置界面风格。自定义风格可设置颜色等生成JSON。
var marker = new BMap.Marker(point);//添加标注点
map.addOverlay(marker);
marker.enableDragging();
marker.addEventListener('dragend',function(e){
alert('当前位置'+e.point.lng+','+e.point.lat);//拖拽时显示相应坐标
})
map.setMapStyle(mapStyle);
map.centerAndZoom(point,13);//地图级别,数字越小尺度越大。point为中心点
map.enableScrollWheelZoom(true);
map.addControl(new BMap.NavigationControl());//添加平移缩放控件
//若改变缩放控件的外观,定义一个opts对象{type:BMAP_NAVIGATION_CONTROL_SMALL}即可
map.addControl(new BMap.ScaleControl(opts));//添加比例尺控件,opts设置偏移像素位置
/*window.setTimeout(function(){
map.panTo(new BMap.Point(116.109,39.918))
},2000);*/
//自定义控件
class ZoomControl extends BMap.Control{
constructor() {
super();//继承父
this.defaultAnchor = BMAP_ANCHOR_TOP_LEFT;
this.defaultOffset = new BMap.Size(100,10);
}
initialize(map){
var div = document.createElement("div");
div.appendChild(document.createTextNode("放大2级"));
gotCss(div);
// 绑定事件,点击一次放大两级
div.onclick = function(e){
map.zoomTo(map.getZoom() + 2);
}
// 添加DOM元素到地图中
map.getContainer().appendChild(div);
return div;
}
}
function gotCss(div){
div.style.cursor = "pointer";
div.style.border = "1px solid gray";
div.style.backgroundColor = "white";
return div;
}
var myZoomCtrl1 = new ZoomControl();
var myZoomCtrl2 = new ZoomControl();
myZoomCtrl2.defaultOffset = new BMap.Size(200,60);
map.addControl(myZoomCtrl1);
map.addControl(myZoomCtrl2);

vue公共组件

Posted on 2018-02-27

####实例1:按钮封装
正常思路是使用slot实现可复用组件(比如确定等字样的更改)
什么情况使用render?
示例:
export default {
name:’base-button’,//this will be shown in components tree
render(h) {
return h(‘a’,
{
class:[‘button’]
},
this.$slots.default)
}
}
子组件样式的slot配合props:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
<template>
<div :class="classes">
<slot>default</slot>
</div>
<template>
<script>
props:['type']
computed:{
classes(){
return {
'success':this.type==='success'
}
}
}
</script>
<style>
.success{

}
</style>

至于slot是按钮还是文本,就是在父组件中操作啦。
动态更新的话,要么在父组件中使用 :slot动态改变选择的slot的name,要么直接在公共组件中动态绑定name。
真*实例:
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
 
<template>
<div>
<div id="modal" v-show='show'>
<p class="modal-topic"></p>
<span type="button" :class="btnStyle" @click="sure"></span>
<span type="button" @click="cancel"></span>
</div>
<div id="shadow" v-show="show"></div>
</div>
</template>
<script>
export default {
data(){
return {
btnStyle:'grey',//可props传递为动态
show:true
}
},
props:{//或者写成对象形式,使用computed得出该对象
topic:String,
btnText1:String,
btnText2:String
},
methods:{
sure(){
this.$emit('sure');
},
cancel(){
this.$emit('cancel');
}
}
}
</script>
<style>
.grey{
color:red;
}
#modal{
background-color:aquamarine;
width: 250px;
position: absolute;
top: 50%;
left:50%;
transform:translate(-50%,-50%);
box-shadow: 10px 10px 5px #888888;
padding:10px 0 20px 0;
z-index: 99;
border-radius: 10px;
}
#shadow{
position: fixed;
top: 0;
width: 100%;
height: 100%;
background-color: grey;
z-index:55;
opacity: 0.5;
filter: blur(25px);
}
span{
display: inline-block;
margin-top: 10px;
margin-bottom:0;
padding:5px 6px;
cursor: pointer;
box-sizing: border-box;
border: 1px solid transparent;
border-radius: 4px;
color: #333;
background-color: #fff;
border-color: #ccc;
}
</style>

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
 
<template>
<div id="app">
<test :topic="topic" :btnText1="text1" :btnText2="text2" @sure="sure" @cancel="cancel" ref="test"></test>
</div>
</template>
<script>
export default{
name: 'app',
data () {
return {
topic:'您拨打的用户已关机,请稍后再拨您拨打的用户已关机,请稍后再拨您拨打的用户已关机,请稍后再拨',
text1:'sure',
text2:'cancel'
}
},
components:{
test
},
methods:{
sure(){
},
cancel(){
this.$refs.test.show = false;
}
}
}
</script>

注意遮罩层。
我们可能需要在一个嵌套了很多层的子组件里面触发modal。这种情况下,你应该把modal放在根组件里面,然后从子组件触发一个事件上去。
效果图:
""

####实例2:tab标签

123

Hank

29 posts
11 tags
© 2019 Hank
Powered by Hexo
|
Theme — NexT.Mist v5.1.4