yuuhei's Home


  • 首页

  • 归档

  • 标签

CSS工作经验总结

发表于 2019-05-17

使用line-height垂直居中时,要注意border的设置

将border设置为一个很粗的值时再进行垂直居中设置,line-height和height和border都在同一个元素设置时,会有偏差,这时候解决的方法就是将border的设置放置在此对象的外层

使用line-height,越大的时候,安卓和ios差距越大,尽量在移动端不要使用line-height进行垂直居中,多使用flex

flex左边固定宽度,右边动态高度实现

1
2
3
4
5
6
7
8
9
10
11
12
.line {
display: flex;
width: 200px;
}

.left {
width: 30px
}

.right {
flex: 1;
}
1
2
3
4
5
6
<div class="test">
<div class="line">
<div class="left">固定宽度</div>
<div class="right">动态高度,文字多的时候会换行撑开</div>
</div>
</div>
阅读全文 »

常用HTTP状态码

发表于 2019-03-27
状态码 英文 描述
200 OK 请求成功。一般用于GET与POST请求
301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302 Found 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
304 Not Modified 协商缓存。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置”您所请求的资源无法找到”的个性页面
500 Internal Server Error 服务器内部错误,无法完成请求
501 Not Implemented 服务器不支持请求的功能,无法完成请求
502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求

call/apply/bind/new/create/instanceof原理

发表于 2019-03-26

call

1
2
3
4
5
6
7
8
9
10
11
12
Function.prototype.myCall = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error');
}
context = context || window;
const args = [...arguments].slice(1);
// 将函数绑定到上下文
context.fn = this;
const result = context.fn(...args);
delete context.fn;
return result;
}

apply

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Function.prototype.myApply = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error');
}
context = context || window;
context.fn = this;
let result;
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
delete context.fn;
return result;
}
阅读全文 »

Vue工作经验总结(2)

发表于 2019-03-14

props可以控制传入的限制,使用validator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const oneOf = (value, validList) => {
for (let i = 0; i < validList.length; i++) {
if (value === validList[i]) {
return true;
}
}
return false;
}

props: {
size: {
validator(value) {
return oneOf(value, ['large', 'small', 'default'])
},
default: 'default'
}
}

provide/inject允许支持上下文特性,共享数据(类似react的context)

1
2
3
4
5
6
7
8
9
// 祖先组件
provide() {
return {
form: this
}
}

// 子组件,这样子组件就可以使用this.form访问到祖先组件的实例了
inject: ['form']

使用mixins高度抽象各类方法,方便复用

使用mixins时,如果有定义created等函数的,会先执行mixins里的created,然后再执行组件里的created。如果mixins里有定义方法,然后组件里也定义了一个同样名称的方法,组件里的方法会覆盖mixins里的方法。

组件内使用$emit出来的事件,同样可以在本组件使用$on监听到

1
2
3
// 同一个组件
this.$emit('on-select', selectValue);
this.$on('on-select', (selectValue) => {});

Vue2.x废除了Vue1.x的$dispatch和$broadcast的方法,可以使用现有的$on和$emit实现

阅读全文 »

Promise、Promise.all、Promise.race实现原理

发表于 2019-03-08

Promise

原理

  • 简易版Promise
  • 实现原理,执行从闭包带出来的resolve和reject函数
  • 然后再执行then,将函数压到执行栈中
  • 然后第一步的异步函数执行好了,就会利用resolve或reject传入参数并执行栈中的函数

实现

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
const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';

const MyPromise = function(fn) {
const that = this;
this.state = PENDING;
this.value = null;
this.resolvedCallbacks = [];
this.rejectedCallbacks = [];

function resolve(value) {
// 执行环境不同,需要使用闭包变量
if (that.state === PENDING) {
that.state = RESOLVED;
that.value = value;
that.resolvedCallbacks.forEach(cb => cb(that.value));
}
}

function reject(value) {
if (that.state === PENDING) {
that.state = REJECTED;
that.value = value;
that.rejectedCallbacks.forEach(cb => cb(that.value));
}
}

try {
fn(resolve, reject);
} catch (e) {
reject(e);
}
}

MyPromise.prototype.then = function(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : r => {
throw r
};
if (this.state === PENDING) {
this.resolvedCallbacks.push(onFulfilled);
this.rejectedCallbacks.push(onRejected);
}
// 如果在new Promise的时候就已经处理的resolve,直接执行函数
if (this.state === RESOLVED) {
onFulfilled(this.value);
}
if (this.state === REJECTED) {
onRejected(this.value);
}
}

Promise.all

原理

  • 返回新的promise,遍历循环传入的数组,处理每一个promise的then和catch
  • then里处理将返回的内容写入对应的位置,如果判断所有结果已经处理,就将数组集合resolve
  • catch里处理错误,只要有一个错误,就直接将错误reject

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const promiseAll = (arr) => {
let result = new Array(arr.length).fill(undefined),
count = arr.length;

return new Promise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
arr[i].then((res) => {
// 按顺序写入结果
result[i] = res;
if (--count === 0) {
resolve(result);
}
}).catch((err) => {
reject(err);
})
}
});
}

Promise.race

原理

  • 返回新的promise,遍历循环传入的数组,处理每一个promise的then和catch
  • then里处理返回的内容,只要有返回,立即将结果resolve
  • catch里处理错误,只要捕获到错误,立即将错误reject

实现

1
2
3
4
5
6
7
8
9
10
11
12
const promiseRace = (arr) => {
return new Promise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
// 一个成功直接返回
arr[i].then((res) => {
resolve(res);
}).catch((err) => {
reject(err);
});
}
});
}

ubuntu和nginx常用命令

发表于 2019-03-04

Ubuntu

配置host:

1
sudo vim /etc/hosts

安装nginx:

1
sudo apt-get install nginx

查看有没有nginx占用:

1
ps -ef | grep nginx

强制删除所有nginx进程:

1
sudo pkill -9 nginx

获取root权限

1
sudo su

退出root权限模式

1
ctrl+d
阅读全文 »

项目上线流程总结

发表于 2019-03-01

发布必备条件

  • 一台Linux服务器(CentOS/Ubuntu)服务器

  • 一款Web服务器(Nginx/Apache/Tomcat)

  • 一个属于自己的独立域名(cn/com/org/…)

本次流程以CentOS和Nginx配置为例

webpack设置静态地址打包

  • output的publicPath从开发地址/dist/设置为线上地址://www.yuuhei.site/dist/

服务器购买

  • 选择阿里云产品的【云服务器ECS】
  • 安全组有http(默认端口80)、https(默认端口443),linux SSH登录(默认端口22),windows远程桌面登录(默认端口3389)

链接远程服务器

  • windows下最好使用git bash,ubuntu下默认是bash控制台
  • 使用ssh user@remote_ip 连接

Web服务器的选择

  • Nginx:高性能,高并发
  • Apache:多平台,安全,流行
  • Tomcat:多用于Java做jsp解析

配置Web服务器

  • 命令行执行安装Nginx,各个linux系统的下载命令不一样,ubuntu执行sudo apt-get install nginx
  • centOS和Ubuntu的nginx的配置文件一般都在/etc/nginx下,可以使用nginx -t查看配置文件位置
  • nginx.conf文件内容的user xxx需要改为user root
  • 着重配置的是http块区域里的内容(http > server > location)

node使用官网解压包安装

  • 解压安装包
1
tar -xzvf node-v10.15.2-linux-x64.tar.xz
  • 移动文件夹到/usr/local/node
1
mv node-v10.15.2-linux-x64 /usr/local/node
  • 建立全局命令node和npm软链(全局命令一般都在/usr/local/bin/)
1
2
ls -n /usr/local/node/bin/node /usr/local/bin/
ls -n /usr/local/node/bin/npm /usr/local/bin/
  • 这时候就可以直接全局执行node和npm了

nginx.conf

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
# 改成user root
user root
# ...
http {
listen 80;
server_name yuuhei.site;
root /root/www/admin-fe/dist/;
index index.html;
# 日志文件
access_log /etc/nginx/logs/access.log combined;

# 完全满足
location = / {
# 网站路径,存放网站的地方
root /root/www/admin-fe/dist/;
# 输入ip后,默认会显示哪个网址,不设置就需要手动在浏览器上访问
index index.html index.htm;
try_files $uri $uri/ /index.html;
}

location ~ .*\.html$ {
root /root/www/admin-fe/dist/;
index index.html index.htm;
}

# 满足条件,访问.do,正则匹配服务器地址
location ~ .*\.do$ {
proxy_pass http://www.server.com;
}

# 代理后端API的配置
# 用于转发的路径标记
location /api/ {
proxy_pass http://192.168.0.1:8080/;###被代理的API地址
}

# 拒绝访问设定
location ~ /source/.* {
deny all;
}

# 指定访问静态资源,假如加载js的路径是 http://yuuhei.cn/dist/xxx.js
location ~ .*(js|css|png|jpg|gif)$ {
root /root/www/admin-fe/;
}

# 都不满足则尝试,与 = / 有区别
location / {
try_files $uri $uri/ /index.html;
}
}

部署了前端静态资源html的服务器配置nginx,达到代理请求转发的效果,例如果配置了/api/,在项目里请求的地址就是/api/xxx/xxx,且需在本地配置代理方便开发,代理配置在vue.config.js

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
{
devServer: {
port: 8802,
// 设置通过localhost和127.0.0.1都可以访问
host: '0.0.0.0',
// webpack-dev-server出于安全考虑,默认检查hostname, 经过内网穿透之后,访问会出现Invalid Host header
disableHostCheck: true,
// 代理设置
proxy: {
// 这个仅为本地调试用
[process.env.VUE_APP_DEV_API_URL]: {
target: 'http://10.20.2.182:8580',
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_DEV_API_URL]: ''
}
},
[process.env.VUE_APP_OA_DINGDING_CRM_API_URL]: {
target: 'http://10.10.14.98:8580',
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_OA_DINGDING_CRM_API_URL]: process.env.VUE_APP_OA_DINGDING_CRM_API_URL
}
}
}
}
}

域名解析

  • www:平时输入网址的www,例如www.baidu.com
  • @:平时输入网址不输入www,例如baidu.com
  • 记录值:公网服务器的IPv4地址
  • 记录类型
    • A:将域名指向一个IPv4地址
    • CNAME:将域名指向另外一个域名(redirect)
  • 备案,服务器和域名的信息必须一致才能访问

网站工作原理

  • 输入网址
  • DNS解析,寻找对应服务器地址
  • 进行握手(HTTP会话)
  • 建立文档树,加载资源

项目index.html被缓存的解决方法

单页面的项目,就算js,css等文件做了hash的处理,在发完版后进入去的第一次,会有白屏的问题。原因就是index.html被缓存,之前的js的hash都变了,然后旧的html加载了不存在的js,导致报错白屏

重点是location / 的add_header Cache-Control "no-cache, no-store";,不设置缓存,其余的是代理的设置

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
 server {
listen 8161;
server_name xxx;
#启用https配置
#listen 443;
#server_name xxx;
#ssl on;
#ssl_certificate cret/server.pem;
#ssl_certificate_key cret/server.key;
#ssl_session_timeout 5m;
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#启用TLS1.1、TLS1.2要求OpenSSL1.0.1及以上版本,若您的OpenSSL版本低于要求,请使用 ssl_protocols TLSv1;
#ssl_ciphers HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM;
#ssl_prefer_server_ciphers on;
autoindex on;
index index.html;
access_log /data/logs/xxx

location /test/ {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_pass xxx;
}

location / {
try_files $uri $uri/ /index.html;
root /data/code/prod_oa_front/oa_fe_ding_m/lsmy-oa-dingding-mobile/dist;
add_header Cache-Control "no-cache, no-store";
autoindex on;
}
}

前后端跨域解决方案总结

发表于 2019-02-27

产生跨域的原因

  • 浏览器限制
  • 请求链接跨域
  • 请求类型是XMLHttpRequest

跨域解决方法之一:JSONP

​ 实现jsonp,需要前后端都需要改造,后端需要增加支持返回js函数,主要约定是url的key字段,由于jquery默认的jsonp请求的关键字key默认是callback,后端一般都会使用callback关键字,当然也可以定义另一个名称,而这个key对应的value使用什么都可以,jquery是使用随机数,后台会获取这个随机数,作为返回js函数的函数名。这是大多数情况,原理是如此,但可能有所不同。

​ 除此之外,还需要注意要使用随机数,不然jsonp由于是js脚本,如果请求参数相同,就会使用缓存的结果,而不会使用最新的结果,jquery的jsonp默认有随机数参数

​ jsonp有以下弊端:服务端也需要改造,请求只能是get。由于请求是get,一般只能用来请求一些获取数据的接口,而不能用于修改用户信息等类型的接口(需要用到post)。由于这个缺点,一般很少接口会用到jsonp,解决跨域问题还需要找其他解决办法

网络请求的路径和解决思路

​ 一般请求路径是:Client(调用方) - Apache/Nginx(http服务器) - Tomcat(被调用方后台应用服务器)。其中Apache/Nginx会处理来自client的请求,判断该请求为什么类型的请求,如果是静态请求,则直接处理返回给client,如果是动态请求,则转发给后台的应用服务器,处理完毕后则原路返回。

​ 动态请求指,跟用户数据有关的请求,xhr等

​ 静态请求指,跟用户数据无关的请求,例如img,js,css

​ 解决跨域的思路有两种,一种是在被调用方后台应用服务器上做处理,在响应头上增加字段,告诉浏览器允许对方调用,浏览器就不会报跨域问题;第二种是隐藏跨域的思路,在http服务器上做处理,做一个http请求转发,浏览器发现所有的请求都是同一个域,就不会报跨域问题。

阅读全文 »

JS上传文件到后台并返回

发表于 2019-02-25

一般表单上传文件到后台的格式

1
2
3
4
<form name="form2" action="/manage/product/upload.do" method="post" encType="multipart/form-data">
<input type="file" name="upload_file" />
<input type="submit" value="upload" />
</form>

字段说明:

  • name:input标签的name属性值要对应后台的字段
  • enctype:属性规定在发送到服务器之前应该如何对表单数据进行编码,有以下三个值:
    • application/x-www-form-urlencoded:表单数据编码为键值对,&分隔
    • multipart/form-data:不对字符编码。在使用包含文件上传控件的表单时,必须使用该值
    • text/plain:空格转换为 “+” 加号,但不对特殊字符编码

如何实现上传不跳转

​ 默认的使用上述提交表单,选择完图片提交后会进行页面跳转,这不是所期望的。由于兼容性问题,会分为IE10+和非IE10的情况。

​ IE9和IE9以下只能用iframe表单上传拿回调,target=”rfFrame”调取的是下面这个iframe的id值。作用是为了提交表单时防止页面跳转,不兼容Formdata。

​ IE10+和其他浏览器可以使用ajax的post去send一个Formdata的js对象,可以实现提交表单不跳转。

​ FormData类型其实是在XMLHttpRequest 2级定义的,它是为序列化表以及创建与表单格式相同的数据(当然是用于XHR传输)提供便利,使用FormData的最大优点就是我们可以异步上传一个二进制文件,兼容性需要IE10+。

Formdata实现上传文件

1
2
3
4
5
6
7
8
9
// ...
// 取file文件的方法
let fileObject = document.getElementById('upload_file').files[0];
// FormData表单对象,ie10+和其他浏览器才能使用,ie9和以下只能够使用原始form+iframe取回调
let form = new FormData();
// 将文件对象打入form实例,upload_file为后台指定的名称,取的是原有的input的name属性的值
form.append('upload_file', fileObject);
// ...
xhr.send(form);

注意事项:

  • 传输文件时,send的时候不需要对参数进行序列化,直接将整个form对象发送过去,jquery设置processData为false
  • 传输文件时,不能设置请求头,jquery设置contentType为fasle
  • 可以在input框onChange时进行上传文件,点击确认和取消都会触发input的onChange
  • 点击input上传file时,如果点击取消,e.target会被更改,e.target.files[0]这个对象属性会消失

form+iframe实现上传文件不跳转

​ form原始处理form的回调这样做的:监听form指向的隐藏iframe的onLoad事件,取iframe里的innerHTML,因为它的innerHTML会直接返回一个对象,可以直接使用;有可能会返回其他东西,具体看后台怎样返回,前端再具体处理

​ jquery可以使用ajaxForm插件实现form的提交回调

具体实现原理代码

仅供参考,内嵌xhr请求实现,react版。

阅读全文 »

ElementUI中的input组件简单实现

发表于 2019-01-16

注意事项:

  • 此为ElementUI的input组件的简单实现
  • 里面的input不要使用v-model绑定数据,应该直接使用el本身的value来作为值,之前的做法一直是input又再使用了v-model
  • input的change事件是在input在失焦的时候才会触发的
  • compositionstart和compositionend是为了避免某些时候中文的预选字也会触发双向绑定,目的是为了避免输入中文输入法的时候也触发了change事件

源码:

阅读全文 »
<i class="fa fa-angle-left"></i>1234…6<i class="fa fa-angle-right"></i>

56 日志
14 标签
GitHub
© 2023 Sellenite
由 Hexo 强力驱动
主题 - NexT.Mist