0%

最近做个项目需要访问跳板机(堡垒机)中的 Oracle 数据库。需要 ssh 到某一个 IP,转发到本地 127.0.0.xxx IP 中的某一个端口。 Windows 下使用 SecureCRT 进行这个操作时溜溜的,到了 Mac(10.11.2) 下面就嗝屁了,具体表现为:

1. SecureCRT 中每次连接服务器都会提示输入密码,超级麻烦; 2. 全部设置好了以后依然无法连接到跳板机。

搜索之,翻了一大圈(使用中文关键词「mac securecrt 跳板机」),出来的结果都不甚理想。后来实在不甘心,在家大便的时候使用英文关键词搜索「mac securecrt port forwarding」,终于在官网找到了答案,现整理如下:

1. 打开 SecureCRT,按 ⌘ + , 进入偏好设置, General 中去除勾选「Use Keychain」,解决连接时保存密码不成功的问题; 2. 打开终端,输入下面的命令,绑定本地 IP(根据具体需求修改 xxx 部分);

sudo ifconfig lo0 alias 127.0.0.xxx

3. 选中当前连接,按 ⌘ + enter,进入 Property 设置,选中 Port Forwarding,添加相应的转发规则(方法); 4. 双击连接,成功。

PS:SecureCRT 与第三方输入法配合使用时,会出现 Console 中无法使用快捷键(比如 ⌃ + C 中断)的现象,切换为原生英文输入法就好了。

题设:生成 N 个随机正整数,使他们的和等于某个数。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
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
// 绑定表单,点击后给出计算结果
document.addEventListener('DOMContentLoaded', function(e){
var elForm = document.getElementById('form'),
elResult = document.getElementById('result');
elForm.addEventListener('submit', function(e){
e.preventDefault();
var self = this,
total = self\['Total'\].value,
num = self\['Number'\].value,
min = self\['Min'\].value,
app = new Random(num, total, min),
result = app.run();
elResult.innerHTML = 'Result:
' \+ result.join(', ');
}, false);
}, false);

// 计算类
var Random = function(num, total, min){
this.total = parseInt(total) || 100;
this.num = parseInt(num) || 1;
this.min = parseInt(min) || 0;
this.result = \[\];
};
Random.prototype = {
// 生成一个随机数
random : function(t) {
var max = t,
min = this.min;
return Math.floor(Math.random() * (max-min)) + min;
},
// 递归计算
calc : function(t){
var self = this,
num = self.num,
min = this.min;
if(num * min > self.total){
return this.result = \['The total number is not enough.'\];
}
if(num === 0){
return false;
}
if(num === 1){
self.result.push(self.total);
}
if(num > 1){
var t = self.total - (num-1)*min;
r = self.random(t),
self.result.push(r);
self.total -= r;
}
self.num--;
self.calc();
},
// 开始计算
run : function(){
this.calc();
return this.result;
}
};

点击查看 DEMO备用地址) | 源码调试

使用同步方式提交表单时最郁闷的事情就是刷新时表单重复提交了,一次重复提交以后,后续做各种操作(reset 表单、删除表单都不奏效)都很难避免,搜了一下网上的答案,无外乎以下两种:

  1. 改为 AJAX 进行表单交互;
  2. 改进服务端,使用一个中转页面进行 redirect

然而很多时候我们并不能去修改服务端(比如没有权限,或者后端功能已经趋于稳定、修改成本高),那么这样就不能避免重复提交了吗?于是我根据页面中转的思路使用 iframe 做了一次尝试,果然页面就不会重复提交了,方法如下:

  1. 为页面添加一个隐藏的 iframe(假设 css 中 .hide 的样式已经设置为了 display:none )

  2. 将 form 的 target 绑定到 iframe 上

    // 表单内容

  3. 编写 JS 绑定相关事件

    document.addEventListener(‘DOMContentLoaded’, function(){
    var form = document.querySelector(‘#form’),
    iframe = document.querySelector(‘#iframe’),
    href = window.location.href;
    iframe.setAttribute(‘src’, href); // 设置 iframe 加载当前地址栏的页面(因为有一些表单提交时会验证 url)
    // 绑定表单提交事件
    form.addEventListener(‘submit’, function(event) {

    // 当表单提交时,为 iframe 绑定 load 事件,
    // 当 iframe 中页面加载完毕(提交成功时,跳转当前页面为当前 url,替代刷新效果)
    iframe.addEventListener('load', function(event) {
      window.location = window.location.href;
    }, false);

    }, false);
    }, false);

这个逻辑的精髓在于,使用了一个 iframe 充当中间跳转页面的角色,在不需要修改后端代码的情况下既可以避开页面刷新重复提交了。当然,如果页面提交后,会有某些提示信息,也可以在 iframe 的 load 事件中进行监测,获取相应字符串以后再判断接下来做什么。获取 iframe 中的内容方法如下(以 body 为例):

var iframeDocument = iframe.contentDocument || iframe.contentWindow.document,
ibody = iframeDocument.body;
console.log(ibody.textContent); // 打印 iframe 中 body 里所有的文本内容

有几个项目使用了 es6 + babelify(babel) + gulp 的发布工具,一开始用着还挺好,后来手贱 npm outdated 并升级了几个插件以后,就嗝屁了,编译时提示错误:

‘import’ and ‘export’ may appear only with ‘sourceType: module’

如果把 babelify 降级使用倒是可以正常,但是作为一个追新党不能忍,最后通过不懈的搜索终于发现了问题的所在,原来是 babel 升级为 6.0 后,对 es6 的支持从 core 里面分离开来,需要单独安装插件 babel-preset-es2015 和 babel-preset-react,并进行相关配置。安装方法如下:

cd path/to/project
npm i –save-dev babelify babel-preset-es2015 babel-preset-react

gulpfile.js 的 transform 中需要添加如下配置(browserify 为例):

.transform(‘babelify’, {presets: [“es2015”, “react”]})

详细代码及插件结构参见:package.json, gulpfile.js

开发移动应用时会遇到一个 UI 里面既可以点击(touchend)又可以滑动(scroll window)的情况,如果同时绑定两个事件就会同时执行,这是我们所不愿意看到的情况。大致解决思路是通过一个变量标记当前的触摸状态,当手指移动时标记为正在拖拽,而没有移动的时候则标记为没有在拖拽。代码如下:

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
// jQuery 代码 
var isDragging = false, element = $('#element');
element.on('touchstart', '.target', function(event) {
isDragging = false;
});
element.on('touchmove', '.target', function(event) {
isDragging = true;
});
element.on('touchend', '.target', function(event) {
if(isDragging) return false;
var self = $(this);
// 点击时的业务代码
console.log(self);
});

// 原生 JS 代码(ES5)
var isDragging = false,
element = document.querySelector('#element');
element.addEventListener('touchstart', function(event) {
isDragging = false;
}, false);
element.addEventListener('touchmove', function(event) {
isDragging = true;
}, false);
element.addEventListener('touchend', function(event) {
if(isDragging) return false;
var self = event.target,
t = 'target';
while(self && self.classList && !self.classList.contains(t)){
self = self.parentNode;
}
// 点击时的业务代码
console.log(self);
}, false);