DingMing

丁大铭的个人空间,用来分享一些前端小技巧,默默成长吧,哈哈

JWT学习

JSON Web Token

缩写JWT 一种目前比较流行的跨域认证解决方案

JWT的原来

原理就是:服务器认证以后,生成一个JSON对象,发回给用户,如下

1
2
3
4
5
{
"姓名": "张三",
"角色": "管理员",
"到期时间": "2018年7月1日0点0分"
}

以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名。

服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

Read More

electron基础

进程和线程

  • electron 和 chrome 是采用多进程的模式

好处是这样各个模块之间没有联系,一处崩溃不会影响其他地方

坏处就是会导致内存消耗比较大

主进程 - Main Process

  • 可以使用和系统对接的Electron API -创建菜单,上传文件 等等
  • 创建渲染进程 -Renderer Process
  • 全面支持 Node
  • 只有一个,作为整个程序的入口点

渲染进程 - Renderer Process

  • 可以有多个,每个对应一个窗口
  • 每个都是一个单独的进程
  • 全面支持 node 和 DOM API
  • 可以使用部分Electron提供的API

进程之间的通讯方式

  • Electron使用IPC在进程之间进行通讯
  • remote 渲染进程直接可以使用主进程API

JS与native交互方式

原生和H5 的交互方式

在 原生开发 Hybrid App 的时候,前端和原生通信,需要jsBridge进行交互,在此总结下和原生一些交互的方式

需要说明App内嵌的H5都是基于原生WebView来实现的,为h5展示提供了容器

JS && OC

ios的WebView有两种,分别 是UIWebView 、WKWebView

Read More

ios-input键盘弹起收回BUG解决方式

方案1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<input class="ipt" @focus="focus" @blur='done' type="text" placeholder="请输入名字" v-model="addressDetail.userName">

methods: {
focus() {
document.body.scrollTop = 0;

},
done() {
document.body.scrollTop = document.body.scrollHeight;

},
}

// 获得焦点时让页面滚动0
// 失去焦点时让页面滚动当前页面高度

方案2

1
2
3
4
5
6
setInterval(() => {
window.scrollTo(0, document.body.scrollTop + 1);
document.body.scrollTop >= 1
&& window.scrollTo(0, document.body.scrollTop - 1);
}, 300);
// 效果很好,但不推荐使用

方案3

1
2
3
4
5
6
document.body.addEventListener('focusin', () => { // 软键盘弹起事件
console.log('键盘弹起');
});
document.body.addEventListener('focusout', () => { // 软键盘关闭事件
console.log('键盘收起');
});

html

<input type=”text” placeholder=”联系人的手机号/QQ/微信” v-model=”contact” class=”ipt” **@blur=’done’**/>

js

done() {
   document.body.scrollTop = document.body.scrollHeight;
}

*这样在 失去焦点 的时候触发 done方法 页面滚动下 就好了

ios-音乐自动播放问题

ios

方法一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//第一步:首先加载一个微信JS-SDK
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
//第2步:写一些配置
<script>
function autoPlayAudio() {
wx.config({
// 配置信息, 即使不正确也能使用 wx.ready
debug: false,
appId: '',
timestamp: 1,
nonceStr: '',
signature: '',
jsApiList: []
});
wx.ready(function() {
var globalAudio=document.getElementById("audio标签id");
globalAudio.play();
});
};
// 解决ios音乐不自动播放的问题
autoPlayAudio();
</script>

Read More

event-loop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
console.log('script start');

setTimeout(function() {
console.log('setTimeout');
}, 0);

new Promise((resolve) => {
console.log('Promise')
resolve()
}).then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});

console.log('script end');
// script start => Promise => script end => promise1 => promise2 => setTimeout

  • 以上代码虽然 setTimeout 写在 Promise 之前,但是因为 Promise 属于微任务而 setTimeout属于宏任务,所以会有以上的打印。
  • 微任务包括 process.nextTick ,promise ,Object.observe,MutationObserver
  • 宏任务包括 script , setTimeout ,setInterval,setImmediate ,I/O ,UI renderin

很多人有个误区,认为微任务快于宏任务,其实是错误的。因为宏任务中包括了 script ,浏览器会先执行一个宏任务,接下来有异步代码的话就先执行微任务

所以正确的一次 Event loop 顺序是这样的

  • 执行同步代码,这属于宏任务
  • 执行栈为空,查询是否有微任务需要执行
  • 执行所有微任务
  • 必要的话渲染 UI
  • 然后开始下一轮 Event loop,执行宏任务中的异步代码

通过上述的 Event loop 顺序可知,如果宏任务中的异步代码有大量的计算并且需要操作 DOM 的话,为了更快的 界面响应,我们可以把操作 DOM 放入微任务中

文本框根据输入内容自适应高度

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<!DOCTYPE html>
<html>
<head>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
<title>文本框根据输入内容自适应高度</title>
<style type="text/css">
h2 {
text-align: center;
margin: 50px auto;
}

#textarea {
display: block;
margin: 0 auto;
overflow: hidden;
width: 60%;
font-size: 14px;
height: 18px;
line-height: 24px;
padding: 2px;
}

textarea {
outline: 0 none;
border-color: rgba(82, 168, 236, 0.8);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
}
</style>


</head>

<body>
<h2>文本框根据输入内容多少自适应高度</h2>
<textarea id="textarea" placeholder="回复内容"></textarea>
<script>
/**
* 文本框根据输入内容自适应高度
* @param {HTMLElement} 输入框元素
* @param {Number} 设置光标与输入框保持的距离(默认0)
* @param {Number} 设置最大高度(可选)
*/
var autoTextarea = function(elem, extra, maxHeight) {
extra = extra || 0;
var isFirefox = !!document.getBoxObjectFor || 'mozInnerScreenX' in window,
isOpera = !!window.opera && !!window.opera.toString().indexOf('Opera'),
addEvent = function(type, callback) {
elem.addEventListener ?
elem.addEventListener(type, callback, false) :
elem.attachEvent('on' + type, callback);
},
getStyle = elem.currentStyle ? function(name) {
var val = elem.currentStyle[name];
if (name === 'height' && val.search(/px/i) !== 1) {
var rect = elem.getBoundingClientRect();
return rect.bottom - rect.top -
parseFloat(getStyle('paddingTop')) -
parseFloat(getStyle('paddingBottom')) + 'px';
};
return val;
} : function(name) {
return getComputedStyle(elem, null)[name];
},
minHeight = parseFloat(getStyle('height'));
elem.style.resize = 'none';
var change = function() {
var scrollTop, height,
padding = 0,
style = elem.style;
if (elem._length === elem.value.length) return;
elem._length = elem.value.length;
if (!isFirefox && !isOpera) {
padding = parseInt(getStyle('paddingTop')) + parseInt(getStyle('paddingBottom'));
};
scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
elem.style.height = minHeight + 'px';
if (elem.scrollHeight > minHeight) {
if (maxHeight && elem.scrollHeight > maxHeight) {
height = maxHeight - padding;
style.overflowY = 'auto';
} else {
height = elem.scrollHeight - padding;
style.overflowY = 'hidden';
};
style.height = height + extra + 'px';
scrollTop += parseInt(style.height) - elem.currHeight;
document.body.scrollTop = scrollTop;
document.documentElement.scrollTop = scrollTop;
elem.currHeight = parseInt(style.height);
};
};
addEvent('propertychange', change);
addEvent('input', change);
addEvent('focus', change);
change();
};

var text = document.getElementById("textarea");
autoTextarea(text); // 调用
</script>
</body>

</html>

AntV-F2-折线图研究

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta name="chart-name" content="雷达面积图">
<title>F2 图表组件库 - AntV</title>
<link rel="stylesheet" href="https://gw.alipayobjects.com/os/rmsportal/YmDAMEQVbLJpVbKiRQVX.css" />
<style>
.mountNode {
width: 400px;
height: 300px;
}

.aws-tooltip {
position: absolute;
background: #ccc;
font-size: 28px;
width: 50px;
height: 50px;
line-height: 50px;
text-align: center;
border-radius: 50%;
}

.aws-tooltip::after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 20px;
background: #000;
}
</style>
<script>/*Fixing iframe window.innerHeight 0 issue in Safari*/document.body.clientHeight;</script>

<script src="https://gw.alipayobjects.com/os/antv/assets/f2/3.3.0/f2.min.js"></script>

<script src="https://gw.alipayobjects.com/os/antv/assets/lib/lodash-4.17.4.min.js"></script>
<script src="https://gw.alipayobjects.com/os/antv/assets/lib/jquery-3.2.1.min.js"></script>
<!-- 在 PC 上模拟 touch 事件 -->
<script src="https://gw.alipayobjects.com/os/rmsportal/NjNldKHIVQRozfbAOJUW.js"></script>
</head>

<body>


<div class="content">
<canvas id="mountNode" class="mountNode"></canvas>
<div class="aws-tooltip">
<span></span>
</div>
</div>
<script>
var canvasOffsetTop = $('#mountNode').position().top;
var canvasOffsetLeft = $('#mountNode').position().left;
console.log(canvasOffsetTop, canvasOffsetLeft);
const _this = this;
let list = [{
text: '拔尖',
num: 0,
}, {
text: '优秀',
num: 22,
}, {
text: '高潜力',
num: 16,
}, {
text: '中等',
num: 26,
}, {
text: '不足',
num: 12,
}, {
text: '待提高',
num: 26,
}]
var chart = new F2.Chart({
id: 'mountNode',
pixelRatio: window.devicePixelRatio,
});
chart.source(list, { // 数据传出入
num: {
// ticks: [],
tickCount: 5,
min: 0,
},
text: {
tickCount: 7,
range: [0, 1],
},

});

chart.axis('text', { // 底部样式
line: // null,
{
strokeStyle: {
color: '#000'
},
lineWidth: '3',
strokeOpacity: '0.8',
shadowColor: '#04ca73',
shadowBlur: '3',
},
tickLine: {
lineWidth: 1,
stroke: '#ccc',
length: 5, // 刻度线长度
},
label: function label(text, index, total) {
var cfg = {
textAlign: 'center',
fill: '#04ca73',
fontSize: 12,
fontWeight: 700,
};
return cfg;
},
});

chart.axis('num', {
label: {
fill: '#000',
},
line: {
stroke: '#9ec3b8',
},
// grid: {
// lineDash: null,
// stroke: '#54b858',
// },
});
chart.tooltip({ // 提示消息
showCrosshairs: false,
custom: true, // 是否自定义 tooltip 提示框
showTooltipMarker: true, // 是否显示 tooltipMarker
tooltipMarkerStyle: { // 点的样式
fill: {
color: '#000'
}, // 设置 tooltipMarker 的样式
stroke: '#1890ff',
fillOpacity: 0.8,
lineWidth: '3',
shadowColor: '#04ca73',
shadowBlur: '10',
},
onHide(obj) { // tooltip 隐藏时的回调函数
// console.log('onHide', obj);
// obj: { x, y, title, items }
},
onChange(obj) { // tooltip 内容发生改变时的回调函数
// console.log('onChange', obj);
// obj: { x, y, title, items }
const tooltipEl = $('.aws-tooltip');
const currentData = obj.items[0];
const text = currentData.value;
// console.log('onChange', currentData, text);
tooltipEl.html([`<span>${text}</span>`].join(''));
tooltipEl.css({
opacity: 1,
left: `${canvasOffsetLeft + currentData.x - parseInt(tooltipEl.css('width').replace('px', ''), 0) / 2.0}px`,
top: `${canvasOffsetTop + currentData.y - tooltipEl.height() - 15}px`,
});
},
});

// 线条的样式
chart.line().position('text*num').color('l(0) 0:#1890FF 1:#f7f7f7').shape('smooth')
.size(5)
.style({
shadowColor: '#04ca73',
shadowBlur: '100',
});
// 下方渐变的样式
chart.area().position('text*num').color('l(90) 0:#000 1:#f7f7f7').shape('smooth');
// 点的样式
// chart.point().position('text*num').color('#EED5FF').size(5);
chart.render();
</script>


</body>

</html>

在vs-code中开启本地服务器

方案1

1、vs code 有一个Go Live插件,可以直接起服务,比较推荐这个

方案2

1、点击“终端”,在里面直接输入

1
npm install -g live-server

2、在终端输入:live-server会出现下面的信息

直接就可以调试了

==-和-===的区别

常人理解是:

1
2
3
4
5
6
7
8
 == 是相等 值相等,返回true
=== 是全等 值相等 , 类型也相等,返回就是 true
这个理解是错的 []== false => true
[1]===[1] => false 推翻上面的理念
初级解释
真确的理解
== 是 相等 先转换再比较, 返回true
=== 是 全等 不转化就比较 , 返回true

初级进阶

1
2
3
4
5
6
7
1.如果有一个操作数是布尔值,则在比较前先将其转换为数值,true转换为1,false转换为0,例如false == 0,true == 1
2.如果一个操作数是字符串,另一个操作数是数值,先将字符串转换成数值,例如"1"==1,'' ==0
3.如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的基本类型按照前面的规则进行比较。(解释不清楚)
4.null和undefined是相等的。
5.如果有一个数是NaN,则相等操作符返回false,而不想等操作符返回true。NaN == NaN返回为false,因为规则如此。
6.如果两个操作数是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回true,否则返回false。
例如:var obj = {a:1};foo = obj;bar = obj;foo==bar;foo==bar返回为true,因为他们指向同一个对象,obj

高级解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[] == fasle => true
== 有 强制转换的 作用
1. [] ==false => [] == 0
经过ToNumber(false),false会被转换为0.
2. [] == 0 => ''==0
[].valueOf().toString() => []=> ''
3. '' == 0 => 0 == 0


[1] === [1] =>false
再来看下===操作符,其中有句话可以完美解释[1]===[1]返回false,但是var obj = {a:1};foo = obj;bar = obj;foo===bar中foo===bar返回为true的原因。

由于[1]===[1]三等号左右的[1],不是same Object,因此返回为false.

而foo===bar,三等号左右其实本质上都是指向obj这个对象,值相等更是必然,所以返回为true。我们由此可以举一反三,[1]==true返回true,而[1,2,3]==true返回false的原因也不足为奇了。