杂食性程序猿:专注于 Android,web frontend,flutter,node.js 等大前端领域,也会玩玩 python 和 java 等后端技术 ...

2013年10月 的文章归档

共找到 3 篇文章

Chrome自定义Userscript脚本

随着现代浏览器的不断升级,浏览器给我们带来的已经不仅是浏览网页的体验。而是提供了各种的接口,来满足用户多样化的需求。从这种角度看,浏览器已经渐渐的在脱离它本来的初衷,而是渐渐的朝着Web平台的方向在发展。

本文我们来介绍的是Chrome自己提供的Userscript脚本的机制,用户可以在浏览器中加入自己写的脚本达到各种的需求。删除页面上牛皮癣似的广告啦,添加一些自定义的数据啦,当然还有个貌似最重要的在某神奇的车票网站上刷票啦!
这一切都可以通过添加Userscript脚本的方式来实现!!
还在等什么!?是不是突然发现无比的神奇呢?是不是觉得自己已经摆脱了屌丝的命运,俨然化身成互联网的神了呢?
哈哈,自己DIY,一切就是那么简单!

首先要创建一个以.user.js为后缀名的js脚本文件,例如创建了一个名为home.user.js的文件。
安装脚本的方式也是非常的简单,在浏览器的地址栏中输入“chrome://extensions/”,你就可以看到当前你的Chrome中所包含的扩展包。将我们的home.user.js文件拖拽入其中。

会出现

的提示,说明插件已经安装完成。
这是最新的Chrome为开发者内建了这种简单的扩展机制,非常的方便。

这只是添加了这么一个Userscript空格的脚本,基本上没什么作用。我们也无法看到任何的效果。
下边我们来往home.user.js中添加代码。

从用途上来讲,Userscript代码的结构可以分为两大部分,第一部分是Userscript的注释。用来告诉浏览器,你的这段脚本的作者,名称,日期,作用范围,版本等等一些基本的信息。第二部分则是开发者自己编写的功能代码。
让我们用一个最简单的删除Gmail顶部的牛皮癣小广告的作为例子。

头部的注释的一个简单范例如下所示:

// ==UserScript==
// @name           Just for testing Chrome APP
// @description    Yes
// @version        1.0
// @author         Kai.XU
// @namespace      http://botobe.net/
// @include        https://mail.google.com/*
// ==/UserScript==

让我们一条条的做个解释。

首先外层的

// ==UserScript==
//
// ==/UserScript==

固定格式,浏览器会读取这段注释中的基本信息。
@name@description@version@author用来记录名称,描述和当前软件的版本号以及开发者的名称。
@namespace是浏览器在识别查件的时候,当插件名一样时用以区分不同插件的命名空间。
在头部注释中,比较重要的,是@include@exclude,前者用来表示当前的脚本所能作用的域,后者表示在前者包括的内容中再剔除后者表示的域。
例如:

// @include    *
// @exclude    http://127.0.0.1:3000/*

则表示,该脚本能作用的地址为除了127.0.0.1:3000域名下的所有地址。

脚本内容中能够使用包括当前页面提供的,以及Chrome原生支持的所有API,文档可以参考这里
好了,现在我们可以编写删除Gmail中广告部分的代码了,如下所示

var removeAdd = function() {
  var mqEl = document.getElementsByClassName('mq');
  if (mqEl && mqEl.length != 0) {
    mqEl = mqEl[0];
    mqEl.remove();
  } 
  setTimeout(removeAdd, 500);
};

removeAdd();

OK,到此为止,插件差不多完成了。用上述的步骤,重新安装Userscript,是不是发现打开Gmail的时候,广告不见了呢?
如果需要调试我们的插件,可以打开控制台 ——> source ——> content script来进行调试。

当然,这里还需要注意一个问题,就是这段代码究竟是在页面加载到何时的情况下运行的呢?
可以写个简单的测试脚本:

document.addEventListener('DOMContentLoaded', function() {
  console.log('Document load event fired!');
}, false);

window.addEventListener('load', function() {
  console.log('Window onload event fired!');
}, false);

再将home.user.js脚本中打印一串“User script loaded!”。在不断地刷新页面,可以得出结论,userscript应该是放在window.onload中执行的,位于domready时间之后,因此可以放心的编写安全的代码了。

Enjoy yourself !
转载请注明出处
botobe.net
本文Github链接

2013.06.28
一切安好。
Merci !

node.js对session的简单封装

Session是神马?
百度百科(百度最有价值的产品)上的解释是
“在计算机专业术语中,session是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经过的时间以及如果需要的话,可能还有一定的操作空间。”
通俗的讲,就是服务器端一段记录当前访问用户的空间。客户端的则是cookie,因为http协议无状态的特性,所以session的存在则必须依托于cookie。
前段时间打算搞个NodeJS的简单框架来支持WALNUT的后台的。突然发现NodeJS神马的,连个session也没有,提供给一次请求的参数就是http. ServerResponse和http.ClientRequest实例化出来的对象。充满幻想的我顿时内牛满面 … …
只好自己动手丰衣足食了。
服务器端必须在客户端使用cookie,可以在返回的头文件中设置,使用http.ServerResponse类中的:

response.setHeader('Set-Cookie', ['SID=' + sID]);

再通过每次获得客户端传来的cookie的,取出存放在服务器端对应session的方式,则可以很简单的模拟出session的效果。
如果不存在则新建一个session,代码如下所示:

var parse = require('querystring').parse;

/**
 * @description 设置session过期时间
 */
var EXPIRE_TIME = 3 * 60 * 1000;

/**
 * @description 存放服务器端所有session
 */
var _sessions = {};

function genSID(pre) {
  pre = (pre)?pre : 'SESSION';
  var time = new Date().getTime() + '';
  var id = pre + '_' + (time).substring(time.length - 6) + '_' + (Math.round(Math.random() * 1000));
  return id;
}

/**
 * @description 定时清理过期的session
 */
setInterval(function(){
  for (var id in _sessions) {
    if (!_sessions.hasOwnProperty(id)) 
      continue;
    if (new Date() - _sessions[id].timestamp > EXPIRE_TIME)
      delete _sessions[id];
    }
}, 1000);

var createSession = function(sID) {
  var session = {
    SID: sID,
    timestamp: new Date()
  }
  return session;
}

/**
 * @description 维护了对session的引用,可进行增删查改操作
 * @param {string} sID 当前用户的session ID
 * @param {object} _sessions
 */
var context = function(_sessions, sID) {
  this.poke = function() {
    _sessions[sID].timestamp = new Date();
  };
  this.destory = function() {
    delete _sessions[sID];
  };
  this.del = function(key) {
    this.poke();
    delete _sessions[sID][key];
  }
  this.set = function(key, value) {
    this.poke();
    _sessions[sID][key] = value;
  };
  this.get = function(key) {
    this.poke();
    return _sessions[sID][key];
  };
}

/**
 * @description 开始session
 * @param {object} request 
 * @param {object} response
 * @param {function} process 回调函数
 */
exports.startSession = function(request, response, process) {
  var cookies = parse(request.headers.cookie, '; ');
  var sID;
  for (var i in cookies) {
    if (i == 'SID') {
      sID = cookies[i];
      break;
    }
  }
  if (!sID || typeof _sessions[sID] == 'undefined') {
    var sID = genSID();
    _sessions[sID] = createSession(sID);
  }
  response.setHeader('Set-Cookie', ['SID=' + sID]);
  process.call(new context(_sessions, sID), request, response);
}

测试代码,主程序:

var http = require('http');
var sessionFactory = require('./session');

var server = http.createServer(function(request, response) {
  sessionFactory.startSession(request, response, handler);
});

var handler = function(request, response) {
  var session = this;
  session.set('banana', '你个巴啦~');
  response.end(session.get('banana'));
}

server.listen('80');

OK.
写在最后:
NodeJS,语言既是服务器,服务器既是语言的,这种方式很特别。想当初,nginx,apache的设计,就是为了把应用服务器和应用给分开来。这样的设计究竟是进步了还是倒退了,嗯~ 不好说。
总而言之,其实也无所谓啦!存在即合理,适合的就是最好的。
转载请注明出处
botobe.net
本文Github链接

2011.12.6,一切安好。
Merci !

JS框架系列笔记 —— prototype.js的面向对象

本文假定你有了一定的javascript面向对象的基础了,就不过多的关于javascript面向对象基础的介绍。
首先,让我们来举个例子,做个传统意义上的javascript的继承。

/**
 * @description 新建个“人类”的类,拥有三个初始的属性,姓名,年龄,性别。
 * 在其构造方法中,我们可以对这些属性做一个初始化的工作。
 *
 * @param {string} name 
 * @param {number} age
 * @param {string} gender
 */
function Humen(name, age, gender) {
  this.age = 0 || age;
  this.name = '' || name;
  this.gender = '' || gender;
}
Humen.prototype.eat = function() {}
Humen.prototype.sleep = function() {}

/**
 * @description 新建个“超人”的类,拥有三个初始的属性,姓名,年龄,性别。
 * 在完成了和人类相同的属性的同时,他比人类还多了一个属性“power”,能量值。
 *
 * @param {string} name 
 * @param {number} age
 * @param {string} gender
 * @param {number} power
 */
function SuperMen(name, age, gender, power) {
  this.age = 0 || age;
  this.name = '' || name;
  this.gender = '' || gender;
  this.power = '' || power;
}
SuperMen.prototype = new Humen;
SuperMen.prototype.constructor = SuperMen;
SuperMen.prototype.eat = function() {}
SuperMen.prototype.fly = function() {}

OK, 初步完成了一个“人类”和一个“超人”的基本结构了,下面让我们看下这段对“人类”的描述代码,在结构上究竟有什么不足呢?
1. SuperMen在继承的过程中出现了代码的冗余,this.xxx重复的调用了。
2. 在“超人”中,同样拥有了“人类”吃的属性,但是超人可能“吃”的具体行为和“人类”不一样。“超人”需要在拥有了“人类”吃的全部属性的同时,增加一些新的特点,比如喝喝汽油,吃吃燃料啥的。在代码中的具体表现,就是突发调动父类的方法。导致了代码会冗余。
3. 结构不够优雅(好吧,这个就见仁见智了,要是你说这样的代码很漂亮,那… … 他就很漂亮吧~)

下面让我们看下prototype.js对这段代码的重新定义

var Humen = Class.create({
  initialize: function(name, age, gender) {
    this.age = age;
    this.name = name;
    this.gender = gender;
  },
  eat: function() {
    console.log('I eat normal food !');
  },
  sleep: function() {}
});

var SuperMen = Class.create(Humen, {
  initialize: function($super, name, age, gender, power) {
    $super(name, age, gender, power);
  },
  eat: function($super) {
    $super();
    console.log('I am ' + this.name + ', I still can eat gasoil, can you ?');
  }
})

var sm = new SuperMen('supermen');
sm.eat();

结果如下:
I eat normal food ! general.js:9
I am supermen, I still can eat gasoil, can you ?

嗯,让我们现在再来做个对比,看看prototype.js中OOP的继承部分的大概结构。
prototype.js定义类的方法很简单,比起原始的js用function来定义而言,引入了Class类别。具体可以看这里。
initialize方法定义了这个类的构造函数,初始化类的基本数据。这里,值得关注的是构造方法中的第一个参数$super,如果父类中有同样的方法,$super则表示父类中同名的函数。这样一来,是不是就可以调用父类的方法了呢。而不至于造成代码的冗余。

在prototype.js的类中,有两个比较特别的参数superclasses,subclasses。分别表示了当前类的所有的子类,或者是所有的父类。这样一来,在当前的类中,我们就不不止可以操作父类中的方法,而且祖宗八倍的方法都可以调用了
是不是很棒!?

prototype.js异于jQuery的最明显的区别,就在于设计的理念不一样了,jQuery崇尚的是select and do,而在Prototype.js里,体现的更多的是一切皆是对象的思想。
prototype.js胜于jQuery的一步就在于它在定义了一些工具类方法,屏蔽了浏览器差异的同时,也为灵活的js规定了一套编程的规范,代码的规整,类的封装等等。使用这套框架的开发人员都按照这样的规则去写,代码就不至于显得太凌乱。
转载请注明出处
botobe.net
本文Github链接

2012.08.13
一切安好。
Merci !