模拟AngularJS之依赖注入 - 猴子猿 - 博客园

mikel阅读(981)

来源: 模拟AngularJS之依赖注入 – 猴子猿 – 博客园

一、概述

AngularJS有一经典之处就是依赖注入,对于什么是依赖注入,熟悉spring的同学应该都非常了解了,但,对于前端而言,还是比较新颖的。

依赖注入,简而言之,就是解除硬编码,达到解偶的目的。

下面,我们看看AngularJS中常用的实现方式。

方法一:推断式注入声明,假定参数名称就是依赖的名称。因此,它会在内部调用函数对象的toString()方法,分析并提取出函数参数列表,然后通过$injector将这些参数注入进对象实例。

如下:

复制代码
//方法一:推断式注入声明,假定参数名称就是依赖的名称。
//因此,它会在内部调用函数对象的toString()方法,分析并提取出函数参数列表,
//然后通过$injector将这些参数注入进对象实例
injector.invoke(function($http, $timeout){
    //TODO
});
复制代码

方法二:行内注入声明,允许我们在函数定义时,直接传入一个参数数组,数组包含了字符串和函数,其中,字符串代表依赖名,函数代表目标函数对象。

如下:

//方法二:行内注入声明,允许我们在函数定义时,直接传入一个参数数组,
//数组包含了字符串和函数,其中,字符串代表依赖名,函数代表目标函数对象。
module.controller('name', ['$http', '$timeout', function($http, $timeout){
    //TODO
}]);

看了上述代码,心中有一疑问,这些是怎么实现的呢?

哈哈,下面,我们就来一起模拟一下这些依赖注入方式,从而了解它们。

二、搭建基本骨架

依赖注入的获取过程就是,通过字段映射,从而获取到相应的方法。

故而,要实现一个基本的依赖注入,我们需要一个存储空间(dependencies),存储所需键值 (key/value);一个注册方法(register),用于新增键值对到存储空间中;还有一个就是核心实现方法(resolve),通过相关参数, 到存储空间中获得对应的映射结果。

So,基本骨架如下:

复制代码
var injector = {
    dependencies: {},
    register: function(key, value){
        this.dependencies[key] = value;
        return this;
    },
    resolve: function(){
                            
    }
};
复制代码
三、完善核心方法resolve

从我们搭建的基本骨架中,可以发现,重点其实resolve方法,用于实现我们具体形式的依赖注入需求。

首先,我们来实现,如下形式的依赖注入:推断式注入声明。

如下:

injector.resolve(function(Monkey, Dorie){
    Monkey();
    Dorie();
});

要实现上述效果,我们可以利用函数的toString()方法,我们可以将函数转换成字符串,从而通过正则表达式获得参数名,即key值。 然后通过key值,在存储空间dependencies找value值,没找到对应值,则报错。

实现如下:

复制代码
var injector = {
    dependencies: {},
    register: function(key, value){
        this.dependencies[key] = value;
        return this;
    },
    resolve: function(){
        var func, deps, args = [], scope = null;
        func = arguments[0];
        //获取函数的参数名
        deps = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1].replace(/ /g, '').split(',');
        scope = arguments[1] || {};
        for(var i = 0, len = deps.length; i < len, d = deps[i]; i++){
            if(this.dependencies[d]){
                args.push(this.dependencies[d]);
            }else{
                throw new Error('Can\'t find ' + d);
            }
        }
        func.apply(scope, args);                    
    }
};
复制代码

测试代码,如下:

代码稍长,请自行打开

推断式注入声明,有个缺点,就是不能利用压缩工具压缩,因为我们是通过函数的参数作为依赖的,当我们压缩时,会将参数名改掉,参数名都变了,那肯定扑街咯。

那么下面,我们就看看行内注入声明,它可以弥补这缺点。

实现行内注入声明,如下:

injector.resolve(['Monkey', 'Dorie', function(M, D){
    M();
    D();
}]);

利用typeof判断arguments[0]的类型可以辨别并获得依赖参数和函数。

实现如下:

复制代码
var injector = {
    dependencies: {},
    register: function(key, value){
        this.dependencies[key] = value;
        return this;
    },
    resolve: function(){
        var firstParams, func, deps = [], scope = null, args = [];
        firstParams = arguments[0];
        scope = arguments[1] || {};
        //获得依赖参数
        for(var i = 0, len = firstParams.length; i < len; i++){
            var val = firstParams[i],
                type = typeof val;
            if(type === 'string'){
                deps.push(val);
            }else if(type === 'function'){
                func = val;
            }
        }
        //通过依赖参数,找到关联值
        for(i = 0, len = deps.length; i < len, d = deps[i]; i++){
            if(this.dependencies[d]){
                args.push(this.dependencies[d]);
            }else{
                throw new Error('Can\'t find ' + d);
            }
        }
        func.apply(scope || {}, args);                    
    }
};
复制代码

测试代码,如下:

复制代码
<!DOCTYPE html>
    <head>
        <meta charset="utf-8"/>
    </head>
    <body>
        <script>
            var injector = {
                dependencies: {},
                register: function(key, value){
                    this.dependencies[key] = value;
                    return this;
                },
                resolve: function(){
                    var firstParams, func, deps = [], scope = null, args = [];
                    firstParams = arguments[0];
                    scope = arguments[1] || {};
                    //获得依赖参数
                    for(var i = 0, len = firstParams.length; i < len; i++){
                        var val = firstParams[i],
                            type = typeof val;
                        if(type === 'string'){
                            deps.push(val);
                        }else if(type === 'function'){
                            func = val;
                        }
                    }
                    //通过依赖参数,找到关联值
                    for(i = 0, len = deps.length; i < len, d = deps[i]; i++){
                        if(this.dependencies[d]){
                            args.push(this.dependencies[d]);
                        }else{
                            throw new Error('Can\'t find ' + d);
                        }
                    }
                    func.apply(scope || {}, args);                    
                }
            };
            //测试代码
            injector.register('Monkey', function(){
                console.log('Monkey');
            }).register('Dorie', function(){
                console.log('Dorie');
            });
            injector.resolve(['Monkey','Dorie',function(M, D){
                M();
                D();
                console.log('-.-');
            }]);    
        </script>
    </body>
</html>
复制代码

因为行内注入声明,是通过字符串的形式作为依赖参数,so,压缩也不怕咯。

最后,我们将上面实现的两种方法,整合到一起,就可以为所欲为啦。

那,就合并下吧,如下:

复制代码
var injector = {
    dependencies: {},
    register: function(key, value){
        this.dependencies[key] = value;
        return this;
    },
    resolve: function(){
        var firstParams, func, deps = [], scope = null, args = [];
        firstParams = arguments[0];
        scope = arguments[1] || {};
        //判断哪种形式的注入
        if(typeof firstParams === 'function'){
            func = firstParams;
            deps = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1].replace(/ /g, '').split(',');
        }else{
            for(var i = 0, len = firstParams.length; i < len; i++){
                var val = firstParams[i],
                    type = typeof val;
                if(type === 'string'){
                    deps.push(val);
                }else if(type === 'function'){
                    func = val;
                }
            }    
        }
        //通过依赖参数,找到关联值
        for(i = 0, len = deps.length; i < len, d = deps[i]; i++){
            if(this.dependencies[d]){
                args.push(this.dependencies[d]);
            }else{
                throw new Error('Can\'t find ' + d);
            }
        }
        func.apply(scope || {}, args);                    
    }
};
复制代码
四、花絮—RequireJS之依赖注入

依赖注入并非在AngularJS中有,倘若你使用过RequireJS,那么下面这种形式,不会陌生吧:

require(['Monkey', 'Dorie'], function(M, D){
    //TODO    
});

通过,上面我们一步步的模拟AngularJS依赖注入的实现,想必,看到这,你自己也会豁然开朗,换汤不换药嘛。

模拟实现如下:

复制代码
var injector = {
    dependencies: {},
    register: function(key, value){
        this.dependencies[key] = value;
        return this;
    },
    resolve: function(deps, func, scope){
        var args = [];
        for(var i = 0, len = deps.length; i < len, d = deps[i]; i++){
            if(this.dependencies[d]){
                args.push(this.dependencies[d]);
            }else{
                throw new Error('Can\'t resolve ' + d);
            }
        }
        func.apply(scope || {}, args);
    }
};
复制代码

测试代码如下:

复制代码
<!DOCTYPE html>
    <head>
        <meta charset="utf-8"/>
    </head>
    <body>
        <script>
            var injector = {
                dependencies: {},
                register: function(key, value){
                    this.dependencies[key] = value;
                    return this;
                },
                resolve: function(deps, func, scope){
                    var args = [];
                    for(var i = 0, len = deps.length; i < len, d = deps[i]; i++){
                        if(this.dependencies[d]){
                            args.push(this.dependencies[d]);
                        }else{
                            throw new Error('Can\'t resolve ' + d);
                        }
                    }
                    func.apply(scope || {}, args);
                }
            };
            //测试代码            
            injector.register('Monkey', function(){
                console.log('Monkey');
            }).register('Dorie', function(){
                console.log('Dorie');
            });
            injector.resolve(['Monkey', 'Dorie'], function(M, D){
                M();
                D();
                console.log('-.-');
            });        
        </script>
    </body>
</html>
复制代码
五、参考

1、AngularJS应用开发思维之3:依赖注入

2、Dependency injection in JavaScript

 

如果喜欢本文,请点击右下角的推荐,谢谢~

微信公众号开发总结(Node.js+express+winston) - 智辉 - 博客园

mikel阅读(1255)

来源: 微信公众号开发总结(Node.js+express+winston) – 智辉 – 博客园

转载请注明出处 http://www.cnblogs.com/laizhihui/p/5785125.html
依据:《中华人民共和国著作权法实施条例》《报刊转载、摘编法定许可付酬标准暂行规定》
保护原创,从你我做起。

关于订阅号、服务号、企业号

官方定位

订阅号:主要偏于为用户传达资讯(类似报纸杂志),认证后每天可以群发一条消息,可达到宣传效果,构建与读者之间更好的沟通和管理模式。
服务号:主要偏于服务交互(类似银行,114,提供服务查询),认证前后都是每个月可群发4条消息。给企业和组织提供更强大的业务服务与用户管理能力。
企业号:主要用于公司内部通讯使用,用来管理内部企业员工、团队。
订阅号、服务号、企业号的区别

接口权限区别

下图展示了接口权限的区别,虽然是官方的图,但不是时分准确了,详细请看 微信公众平台官网开发者文档

接口权限区别-不时分准确

微信认证

认证费用300元/次,需要年审,即300元/年

微信认证
详细请查看 官网资料

关于项目

环境搭建

  1. 安装 node.js,这里选择的是 v4.5.0 LTS,node.js 官网
  2. 安装 express$ npm install express -g
  3. 初始化项目,找到项目所要放置的文件夹,$ express WechatDemo$ cd WechatDemo$ npm install$ npm start,执行完以上命令,一个最基本的基于 express 的 node 项目已经搭建好了,此时访问 localhost:3000 应该能看到 express 初始化的页面。

项目调整为 MVC 结构

项目初始化时,目录是这样的:

项目初始化结构

项目最终目录结构:

项目最终目录结构

  1. 创建一个 app_server 文件夹,将根目录的 routes、views 移动到 app_server 文件夹下,再创建 controllers、dao、models 文件夹
  2. 此时如果启动项目,会报错,因为 app.js 还要相应修改如下,才能正常启动:
    var routes = require('./app_server/routes/index');
    var users = require('./app_server/routes/users');
    //...
    app.set('views', path.join(__dirname, 'app_server', 'views'));
  3. 由于 routes 中,路由与业务逻辑耦合在一起了,所以将路由文件中的内容移至 controllers 中, 在 controllers 中处理业务逻辑,详细可以查看源码
  4. 增加一个 dao 文件夹,操作数据库的逻辑写在这里。
  5. 增加一个 common 文件夹,用于存放公共的组件。

项目调试

  1. 为了不每次修改都手动重启服务器,这里采用 nodemon + WebStorm 2016.1.3 来调试项目,先安装 nodemon:$ npm install nodemon --save,save 是为了同步到 package.json。
  2. 在 WebStorm 中,点击右上角的下拉箭头,如果没有配置过,应该是灰色的,然后选择 Edit Configurations,选择弹出框左上角的 + 号,新增一个 Node.js 项,然后配置如下:
    WebStorm调试node.js
  3. 配置完成之后,点击右上角的 Debug 按钮(小虫形状的按钮)即可断点调试,修改 js 文件,也可以自动重启服务器了。

微信公众号接入

官网:微信公众平台开发者文档开始开发/接入指南 中有讲到如何接入。

用户与微信公众号交互时,主要有两种形式:

  1. 点击一个按钮,或者发送一段文字,这时,微信 app 会发送请求到微信服务器,微信服务器会转发请求到开发者的服务器。
  2. 点击一个链接,这时,微信 app 不会发送请求到微信服务器,而是直接请求链接所在的服务器。

对于第一种,为了安全起见(比如可能有心怀不轨的人故意给开发者的服务器发送请求,取消某人的关注,这时开发者的程序将该用户的openid移除, 此后该用户再也收不到公众号的消息,除非开发者主动刷新用户列表从微信服务器取回来。更甚者可能会对支付等比较敏感的操作进行模拟请求),微信服务器每次 发来的请求都带了加密的参数,通过特定的算法可以验证该请求来自微信服务器,算法在开发者文档里写得很清楚了,在接入认证的时候就需要用这种算法响应一次 微信服务端的请求。

这里采用微信官方开发的一个 npm 包 wechat 来处理请求,这意味着可以不写那套验证算法。$npm install wecaht --save,关于 wechat 的使用方法,请看官方文档,写得很详细。另外可以查看源码示例

另外,可以申请一个测试号,测试号几乎有所有的接口权限。

本地调试微信公众号

微信公众号接入的时候,是需要一台能够被微信服务器访问到的服务器,如果采用本地开发,localhost 不能被微信服务器访问到,那么就要想办法把本地服务器暴露出去,这里采用花生壳将 本地服务器映射到外网(注册时需要付费,我注册时是15元),但不是很稳定,偶尔映射会失败,需要重新启动软件或电脑。因为微信服务器需要接入到开发者服 务器的 80 端口或者 443 端口,如果这两个端口都被占用,可用花生壳将本地 3000 的端口映射为外网 80 端口,软件挺人性化的,一个按键即可映射到外网。

关于 access_token

开发者每次请求微信服务器提供的接口(除了获取access_token的接口),都需要在请求里带上 access_token 这个参数,但是这个参数的有效期只有 7200 秒,也就是两个小时,所以需要定期(setTimeout)去请求 access_token,但是如果服务器重启了,setTimeout 也就失效了,官方建议用一台独立的服务器专门获取 access_token,但如果不用独立的服务器,可以将 access_token 和 expired_in 保存到数据库。可以查看源码AccessTokenController.js 和 AccessTokenDao.js来了解详细的过程。

关于 log

  1. 在控制台、文件、MySQL 数据库记录 log
  2. 文件 log 每天记录在不同的文件
  3. 每个 request.on(“end”) 时记录 log
  4. 有需要时可以记录 log
  5. 格式为:2016-08-18 17:55:02 INFO NoticeDao.js [SQL:SELECT * FROM gdas_notice]

自定义 Logger API
logger.log 等级默认为 ‘info’,接收一个字符串或者一个对象,对象会被序列化成对应的格式
logger.info 与 logger.log 的作用是一样的
logger.warn level 为 warn
logger.error level 为 error

自定义 log 是在 winston 的基础上写出来的,winston 没有自带 MySQL log,可以自定义,详情请看 winston 官方文档
关于上面 log 的第 2 点,可以查看:winston-daily-rotate-file
自定义 log 也可以查看源代码

原生javascript实现分享到朋友圈功能 支持ios和android-JavaScript/Ajax教程-源码库|专注为中国站长提供免费商业网站源码下载!

mikel阅读(1241)

 

来源: 原生javascript实现分享到朋友圈功能 支持ios和android-JavaScript/Ajax教程-源码库|专注为中国站长提供免费商业网站源码下载!

  现在主流的分享工具也有很多,例如JiaThis、bShare分享,甚至一些大公司的如百度分享,但是他们依旧停留在只是在PC端的分享,对手机端的支持不是太好。

大家都知道现在很多手机端浏览器都内置了一些分享组件,像UC浏览器、QQ浏览器,内置的组件分享可以直接启动相应的APP分享,要是一个JS能调用浏览器的内置分享组件,那是多么酷啊。

高手在民间啊,下面ASPKU源码库的小编就带你来看看这位兄弟的编写的JS库。

一、工具介绍 nativeShare.js

一个可以通过JavaScript直接调用原生分享的工具,该工具具有以下特点:

1.支持原生微博、微信好友、微信Android/105260.html”>朋友圈、QQ好友、QQ空间分享
2.支持调用浏览器更多分享功能
3.不依赖任何JQuery以及其他插件
注意:目前仅支持手机UC浏览器和QQ浏览器

github项目地址:https://github.com/JefferyWang/nativeShare.js
Git@OSC项目地址:http://git.oschina.net/wangjunfeng/nativeShare.js

二、使用方法

1.引入CSS文件

 

复制代码代码如下:
<link rel=”stylesheet” href=”nativeShare.css”/>

 

2.在需要添加分享的地方插入以下代码:

 

复制代码代码如下:
<div id=”nativeShare”></div>

 

3.添加配置信息,并实例化

 

复制代码代码如下:
<script>
var config = {
url:’http://blog.wangjunfeng.com’,// 分享的网页链接
title:’王俊锋的个人博客’,// 标题
desc:’王俊锋的个人博客’,// 描述
img:’http://www.wangjunfeng.com/img/face.jpg’,// 图片
img_title:’王俊锋的个人博客’,// 图片标题
from:’王俊锋的博客’ // 来源
};
var share_obj = new nativeShare(‘nativeShare’,config);
</script>

 

三、演示截图

javascript,朋友圈,ios,android
图1:分享到新浪微博

javascript,朋友圈,ios,android
图2:分享到微信Android/105260.html”>朋友圈

javascript,朋友圈,ios,android
图3:微信分享给联系人

javascript,朋友圈,ios,android
图4:QQ分享给联系人

javascript,朋友圈,ios,android
图5:QQ分享到空间

javascript,朋友圈,ios,android
图6:调用浏览器的内置分享组件

注:相关教程知识阅读请移步到JavaScript/Ajax教程频道。

让一个div层浮在最上层的方法_newevan_新浪博客

mikel阅读(895)

让一个div层浮在最上层的方法_newevan_新浪博客,newevan,

来源: 让一个div层浮在最上层的方法_newevan_新浪博客

设置 style 中 z-index:auto
auto可定义为一个值(整数数字),越大代表越置前,如可定义为: z-index:9999。

若定义为-1,代表为最底层。

另:

若是会被一些FLASH文件给遮住,
可将flash对象的参数wmode设置为transparent即可。

【开源分享:入门到精通ASP.NET MVC+EF6+Bootstrap】月薪过万不是梦,从这里开始,一起搭框架(1)开篇介绍

mikel阅读(2124)

 

框架简介

 

这几年一直在做ASP.NET开发,几年前做项目都是老老实实一行行的写代码,后来发现那些高手基本都会有自己积累起来的代码库,现在称之为开发框架, 基础代码不用再去堆,主要精力可以集中在业务逻辑实现上。这样开发效率高了,他们的待遇也会比我高出很多。我也想有自己的房子、车子、妹子,我也想成为开 发高手,于是我想拥有一套自己的开发框架。

首先找的是李天平的动软代码生成器,生成实体什么的是没问题,但是UI层完全没有啊,而且里面有错误。后来有些人开始做收费版的开发框架了,做得确实专 业,但是上万的东西,我穷啊,买不起,于是我开始混际于博客园、CSDN这类论坛当起了伸手党,是经常有人放开源的出来可是真是没法用!底层先不说,先说 界面,不是EXT就是EasyUI要么就是这二者的衍生品。千篇一律,简直像学生练手用的根本没法拿去做项目啊!

看来指望别人是指望不上了,痛定思痛于是我开始自己积累,开发一套自己的开发框架,从UI到底层,一个个组件都自己来搭建。现在做项目真是快,而且质量还不错,好东西不能私藏,今天就拿出来分享给大家。

 

框架底层采用经典DDD架构,UI层采用JQuery+Bootstrap打造而成的一套符合中国式操作习惯的快速开发框架。

伸手党快滚过来!开源地址在这里:http://www.oschina.net/p/nfine

框架功能:

  1. 系统管理 机构管理、角色管理、岗位管理、用户管理、数据字典、区域管理
  2. 权限管理 系统菜单、系统按钮、角色权限分配
  3. 系统安全 数据备份、访问控制及服务器监控;
  4. 统计报表 报表插件集成、报价单
  5. 常用示例 邮件、短信、打印、电子签章等常用功能示例;

框架工程:

 

1:NFine.Code 底层核心类(开发时不涉及,可编绎成dll提供)

2:NFine.Data 数据层(开发时不涉及,可编绎成dll提供)

3:NFine.Application  主要是html。

4:源码里还有两个空的工程项目:Web.Entity和Web.Utility( 预留给不懂怎么规划存放项目类的新手)

前后端使用技术:

  • 1、前端技术
  • JS框架:JQuery-2.1.1、Bootstrap.js、JQuery UI
  • CSS框架:Bootstrap v3.3.4(稳定是后台,UI方面根据需求自己升级改造吧)。
  • 客户端验证:jQuery Validation Plugin 1.9.0。
  • 在线编辑器:ckeditor、simditor
  • 上传文件:Uploadify v3.2.1
  • 动态页签:Jerichotab(自己改造)
  • 数据表格:jqGrid、Bootstrap Talbe
  • 对话框:layer-v2.3
  • 下拉选择框:jQuery Select2
  • 树结构控件:jQuery zTree、jQuery wdtree
  • 页面布局:jquery.layout.js 1.4.4
  • 图表插件:echarts、highcharts
  • 日期控件: My97DatePicker
  • 2、后端技术
  • 核心框架:ASP.NET MVC5、WEB API
  • 持久层框架:EntityFramework 6.0
  • 定时计划任务:Quartz.Net组件
  • 安全支持:过滤器、SQL注入、请求伪造
  • 服务端验证:实体模型验证、自己封装Validator
  • 缓存框架:微软自带Cache、Redis
  • 日志管理:Log4net、登录日志、操作日志
  • 工具类:NPOI、Newtonsoft.Json、验证码、丰富公共类似

框架界面展示:

 

 

后续我会介绍一下这个框架的设计及原理,请继续关注!

在线演示地址:http://www.nfine.cn

感谢您的阅读。如果文章对您有用,那么请轻轻点个推荐,以资鼓励。
作者:NFine
技术交流群:549652099
出处:http://www.cnblogs.com/huanglin/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

国内外的安卓模拟器哪个最好用?

mikel阅读(4795)

1.Windroy:国人做的模拟器,这个模拟器实际上是一个安卓到Windows的直接移植,属于技术黑客流的作品。运行起来超级快,而且安装包很小。Windroy的问题是好久没更新了。

2.BlueStacks(蓝 叠):印度人做的模拟器,后来得到融资到了硅谷。Bluestacks做得算是不错的,用了虚机技术,所以和Windroy不同,Bluestacks必 须运行在有硬件虚拟化支持的机子上,否则就会慢死。Bluestacks的最大亮点是性能优化得不错,对于ARM模拟这块也有不错的支持,不过貌似是偷偷 用了qemu的东西,要知道qemu是需要修改者开放源码的,可是Bluestacks没有遵守该遵守的GPL协议,估计是防着竞争对手呢。玩家倒是不关 心具体怎么做的,只要东西好就行,Bluestacks用起来还是不错的。但是印度人做东西总是有点挠不到痒处,具体的以后再说,这里可以举个类比例子, 水果的iTunes就是一帮印度哥们做的,觉得iTunes好用的请举手。还有,Bluestacks好像用的是安卓 4.0.4版本,确实有点低了。

3.Genymotion: 法国人做的,基于VBOX虚机,质量不错,主要面向开发人员,还是开源的。安卓应用开发人员可以选择各种手机版本下载,配合开发使用。 Genymotion的目的实际上是替掉Google的qemu模拟器,因为后者实在是太慢了。其实开发人员需要的是像iOS那样的一个模拟器,水果的模 拟器非常快,因为它是模拟API的模拟器,而不是全系统模拟器。说到这里,插一句,其实Windroy是个API层面的模拟器,希望Windroy在这方 面有所动作,若有所成,那真是安卓开发者的福音了。

4.Windroye(文 卓爷):这个也是Windroy团队的出品,也是基于VBOX虚机,发布比Windroy快多了。这个模拟器用起来感觉很简洁,直接给用户一个原生安卓界 面,这一点是秉承了Windroy的风格。比Windroy多的特性是集成了应用中心,下载中心等,还集成了一个微信助手,估计是考虑到微信用户群实在太 广了。Windroye的好处是该支持的功能都支持了,包括平板用户的多点触摸,重力感应,GPS,声音输入输出,前后摄像头等,以及Windows输入 法的集成等等,这一点可以说是所有模拟器里做的最好的。Windroy团队似乎仍然是想在电脑上做一个完整的安卓系统。值得一提的是,Windroye还 提供了一个手机伴侣,手机(当然是安卓手机)安装上这个APK后,就可以把手机当作遥控器,来远程控制Windroye,我拿它来玩赛艇,射击等游戏,确 实有点游戏主机的感觉,这个值得表扬。

5.AndY:这个基本上是抄袭Genymotion的东西,不过网站上挺能吹的,我下载运行了下,感觉完全不是那么回事。除了在某些机器上安装会有问题,最大的问题是,运行超慢,看来抄Genymotion都没抄好。这个根本不能算是原创的作品。

JS 银行卡号验证

mikel阅读(1136)

//Description:  银行卡号Luhm校验

//Luhm校验规则:16位银行卡号(19位通用):

// 1.将未带校验位的 15(或18)位卡号从右依次编号 1 到 15(18),位于奇数位号上的数字乘以 2。
// 2.将奇位乘积的个十位全部相加,再加上所有偶数位上的数字。
// 3.将加法和加上校验位能被 10 整除。

//方法步骤很清晰,易理解,需要在页面引用JQuery.js

//bankno为银行卡号 banknoInfo为显示提示信息的DIV或其他控件
function luhmCheck(bankno){
var lastNum=bankno.substr(bankno.length-1,1);//取出最后一位(与luhm进行比较)

var first15Num=bankno.substr(0,bankno.length-1);//前15或18位
var newArr=new Array();
for(var i=first15Num.length-1;i>-1;i–){    //前15或18位倒序存进数组
newArr.push(first15Num.substr(i,1));
}
var arrJiShu=new Array();  //奇数位*2的积 <9
var arrJiShu2=new Array(); //奇数位*2的积 >9

var arrOuShu=new Array();  //偶数位数组
for(var j=0;j<newArr.length;j++){
if((j+1)%2==1){//奇数位
if(parseInt(newArr[j])*2<9)
arrJiShu.push(parseInt(newArr[j])*2);
else
arrJiShu2.push(parseInt(newArr[j])*2);
}
else //偶数位
arrOuShu.push(newArr[j]);
}

var jishu_child1=new Array();//奇数位*2 >9 的分割之后的数组个位数
var jishu_child2=new Array();//奇数位*2 >9 的分割之后的数组十位数
for(var h=0;h<arrJiShu2.length;h++){
jishu_child1.push(parseInt(arrJiShu2[h])%10);
jishu_child2.push(parseInt(arrJiShu2[h])/10);
}

var sumJiShu=0; //奇数位*2 < 9 的数组之和
var sumOuShu=0; //偶数位数组之和
var sumJiShuChild1=0; //奇数位*2 >9 的分割之后的数组个位数之和
var sumJiShuChild2=0; //奇数位*2 >9 的分割之后的数组十位数之和
var sumTotal=0;
for(var m=0;m<arrJiShu.length;m++){
sumJiShu=sumJiShu+parseInt(arrJiShu[m]);
}

for(var n=0;n<arrOuShu.length;n++){
sumOuShu=sumOuShu+parseInt(arrOuShu[n]);
}

for(var p=0;p<jishu_child1.length;p++){
sumJiShuChild1=sumJiShuChild1+parseInt(jishu_child1[p]);
sumJiShuChild2=sumJiShuChild2+parseInt(jishu_child2[p]);
}
//计算总和
sumTotal=parseInt(sumJiShu)+parseInt(sumOuShu)+parseInt(sumJiShuChild1)+parseInt(sumJiShuChild2);

//计算Luhm值
var k= parseInt(sumTotal)%10==0?10:parseInt(sumTotal)%10;
var luhm= 10-k;

if(lastNum==luhm){
$(“#banknoInfo”).html(“Luhm验证通过”);
return true;
}
else{
$(“#banknoInfo”).html(“银行卡号必须符合Luhm校验”);
return false;
}
}

[译]Angular2 和TypeScript -- 一次简要的预览 - bee0060 - 博客园

mikel阅读(950)

来源: [译]Angular2 和TypeScript — 一次简要的预览 – bee0060 – 博客园

原文链接:https://www.infoq.com/articles/Angular2-TypeScript-High-Level-Overview

作者:  Yakov Fain Posted on  Apr 26, 2016

——————————————————————————————————————————

AngularJS是目前最流行的可用于创建网页应用的JavaScript框架。而且现在Angular2和TypeScript正在让真正的面向对象开发方式的成为网页开发的主流方式,而且在语法上与Java 8惊人的相似。

根据Google工程总监Brad Green介绍, 有130万开发人员在使用AngularJS且有30万开发人员已经准备好开始使用Angular2了。 在使用了Angular2将近十个月之后,我相信其对JavaScript社区的影响将能媲美Spring框架对于Java社区的影响。

在这篇文章中,我将会展示一个关于Angular2框架的简要概述。

在2014年末,google宣布Angular2将会对AngularJS进行完全的重写, 为了写Angular2的应用程序,他们甚至创建了一个全新的语言“AtScript”。

但同时, 微软答应要对他们的TypeScript语言(一个严格类型的Javascriptz超集语言)增加对装饰(亦称注释)的支持,这就为开发Angular2框架诞生了一个新语言,并且这是一门使用AngularJS框架开发应用的推荐语言。

你当然也可以用Javascript(ECMAScript5和6都可以)和Dart开发Angular 2应用。

此外,Angular团队集成了另一个微软的项目到Angular2框架中– RxJS库,一个原生Javascript的扩展类库。

Angular2不是一个MVC框架,而是一个基于组件化的框架。在Angluar2种,应用是一个松散耦合的组件树。

举个栗子,下面这个截图展示了一个示例在线拍卖应用的登陆页面, 该页面是由导航栏、搜索框、轮转展示区、产品和底部这些组件组合而成的最初原型。

上面这张图片演示了3个产品呈现组件。自动呈现功能是通过在模板上绑定一个从服 务端获取数据的组件数组。 每个产品的title是一个关联到产品详情页的链接。既然我们想将拍卖系统设计为一个单页面应用(SPA),我们就不希望为了展示产品详情而刷新整个页 面。让我们重复利用现在被轮转区和产品列表占用的区域,它也可以用来呈现产品详情同时保持页面的其他区域不变。这个任务可以通过简单的几步完成:

1. 用Angular的路由-出口指令,这允许你将被轮转区和产品列表占用的区域定义为《路由出口》, 以便它可以通过用户的导航栏来改变内容。

2. 将轮转区和产品组件封装到主页组件里

3. 新建一个产品详情组件

4. 配置Angular的路由让其在特定的《路由出口》区域显示主页或产品详情组件。

 

我们已经说了很多关于组件的内容,但我们还没有明确定义什么是组件。在TypeScript中,一个组件就是一个简单的通过@Component关键字注释的类:

复制代码
 1 @Component({
 2   selector: 'auction-home',
 3   template: `
 4     HTML or other markup is in-lined here
 5   `
 6 })
 7 export default class HomeComponent {
 8 
 9  // Application logic goes here
10 }
复制代码

@component注释是用来定义组件和相关的元数据的。 在这个例子中,selector属性的值定义了用于展现该组件的HTML标签名。template属性是HTML(或其他)标记的占位符。

回到我们的拍卖登陆页面,最高级别的应用组件模板看起来应该像是这样的:

 

这个模板由标准和自定义的html标签混合而成,自定义HTML标签标识各个组件。在例子中我们把html纵向排列了。如果我们希望把标记存储在不 同的文件中(在这个例子中是application.html), 我们可以使用templateURL属性代替template属性, 然后ApplicationComponent的代码就会像这样:

复制代码
import {Component} from 'angular2/core';
import {Route, RouteConfig, RouterOutlet} from 'angular2/router';
import HomeComponent from '../home/home';
import NavbarComponent from '../navbar/navbar';
import FooterComponent from '../footer/footer';
import SearchComponent from '../search/search';
import ProductDetailComponent from "../product-detail/product-detail";

@Component({
  selector: 'auction-application',
  templateUrl: 'app/components/application/application.html',
  directives: [
    RouterOutlet,
    NavbarComponent,
    FooterComponent,
    SearchComponent,
    HomeComponent
  ]
})
@RouteConfig([
  {path: '/', component: HomeComponent, as: 'Home'},
  {path: '/products/:id', component: ProductDetailComponent, as: 'ProductDetail'}
])
export default class ApplicationComponent {}
复制代码

ApplicationComponent类使用了@Component和 @RouteConfig(用于标记为URL依赖内容)进行注释。selector属性的值会被用来指定用户自定义的HTML标 签<auction-application>。 templateURL属性指定了标记的位置。section指令包含了路由出口和所有子级组件。

@RouteConfig注释为客户端导航栏配置了两个路由:

· 名字为Home(主页)的路由节点的内容会被HomeComponenet组件渲染并映射到URL片段’/’ 下。

· 名字为ProductDetail(产品详情)的路由节点会被ProductDetailComponent组件映射到URL片段’/product:id’下。

当用户点击一个特定的产品标题时,默认Home路由节点的内容会被ProductDetail路由节点的内容替换,该点击事件会提供参数id的值并 将产品详情展示在路由出口区域。 例如,用于导航到ProductDetail路由节点的链接,带有一个产品ID参数,且值为1234, 看起来可以像下面这样:

<a [routerLink]=”[‘/ProductDetail’, {‘prodId’: 1234}]”>{{ product.id }}</a>

 

依赖注入

组件们使用服务来实现业务逻辑。服务就是些由Angular实例化并注入到组件中的类。

复制代码
export class ProductService {
  products: Product[] = [];
  getProducts(): Array<Product> {
    // The code to retrieve product into goes here
    return products;
  }
}
复制代码

 

现在如果你将一个类型是ProductService的变量以参数形式传入到HomeComponent的构造器中,Angular会自动实例化并注入该服务到该组件中:

复制代码
@Component{
 ...
}
export default class HomeComponent {
  products: Product[] = [];

  constructor(productService: ProductService) {
    this.products = productService.getProducts();
  }
}
复制代码

Angular的依赖注入模型是很灵活的,它很容易使用, 因为对象都只能通过构造器进行注入。注入器可以形成一个层(每个组件都有一个注入器),并且可注入对象不需要在应用级别被实现为单例模式,因为它默认就是单例的,就像在Spring中一样。

 

组件间通信

组件间通信可以并且应该以松耦合的方式来实现。 一个组件可以定义输入和输出属性。要从父组件传输数据给子组件, 父组件需要绑定子组件的输入属性的值。子组件不需要知道是谁提供了这些值,它只需要知道怎么使用这些值。

如果一个组件需要将数据传输给外界,它通过输出属性往外发送事件。 发送给谁? 这个组件就不用管了。 对该事件感兴趣的组件会对该自定义组件的事件创建侦听器。

这种机制允许我们将组件看作黑盒,我们可以把值传进去或发出来。我最近录制了一段可能对你有用的短片,该短片演示了在Angular2中实现中间人设计模式的一种方法。

 

为什么用TypeScript

TypeScript是Javascript的一个超集, 但又像Java一样允许你定义新的类型。 通过类型定义变量,而不是依然用原本的var关键字为新工具的支持开后门,你会发现这是一个巨大的生产力的提高。TypeScript带来了一个静态代码 分析器,当你输入代码到你的可识别TypeScript的编辑器(如WebStorm/IntelliJ Idea,Visual Studio Code, Sublime Text等等) 对上下文敏感的智能提示功能会引导你给函数传入有效的参数,如让参数使用有效的对象或类型。如果你偶然使用了不正确的类型,编辑器会将错误的代码高亮显 示。在这里看看WebStorm是如何支持TypeScript的.

即使你的TypeScript应用使用了第三方类库来编写Javascript,你也可以设置一个类型定义文件(使用.d.ts后缀名),包含该类库的类型定义。数百个流行的Javascript类库的类型定义文件可以免费获得,你可以很容易的通过Typings安 装他们, Typings是一个TypeScript的定义管理工具。 想象一下你想要在你的TypeScript代码中使用JQuery(用Javascript编写)。JQuery的类型定义文件会包含所有JQuery的 APIs定义(包含类型),所以你的IDE就可以提示你需要用哪些类型,或把错误的代码高亮。

 

性能和渲染

渲染性能在Angular2种得到了答复提高。最重要的是,事实上, 渲染模块已经位于一个独立的模块当中,该模块允许你在工作线程中运行运算量较大的代码。可以访问重绘速度挑战网站来比较各个框架的渲染性能。你能感受到不断更新的巨大数据网格的高速渲染。运行标题为“DBMON Angular 2.0测试版-网络工作者”的测试用例,一个包含大量数据的网格不断的刷新数据(在独立的线程中)并在浏览器中进行极快速的重绘。

如果你想问是什么功能让Angular2从其他框架中脱颖而出,出现在我的清单中的第一位将会是模板渲染的分区的独立模块:

· 具有组件界面定义的独立模板文件会通过一个独立的渲染器进行处理,这为模板的优化和预编译领域提供了新的机会,让其具有创建模板并渲染在不同的设备上的能力。

· zone.js模块会侦听应用的改变,并决定什么时候去更新每个组件的界面。 任何异步事件的触发都会重新验证每个组件的界面而且速度快的吓人。

注意:对于大多数应用,你不需要知道zone.js的内部原理,但如果你所在的项目要求优化一个复杂应用的界面渲染,你就需要准备好拨出一些时间去学习更多的zone的内部运作细节。

让渲染引擎保持在一个独立模块中并允许第三方类库替换原始DOM的渲染器,这能实现不依赖于浏览器平台的目标。例如,允许将应用代码跨设备重用, 在移动设备中,界面渲染器就将使用原生组件。 TypeScript类的代码不需要改变,但@Component注释的内容会包含XML或其他语言,这些内容将用于渲染原生组件。一个自定义的 Angular2渲染器已经在NativeScript框架中得以实现, 该渲染器提供的服务就像在Javascript、原生iOS和安卓界面组件之间架起一座桥梁一样。通过NativeScript你可以重用组件的代码,而你需要做的仅仅是将模板中的HTML替换为XML。 另一个自定义界面渲染器允许使用Angular 2 with React Native,这是一种完全不同的为iOS和安卓系统创建原生(不是hybird)界面的方法。

 

工具集

虽然Angular2的语法和架构比AngularJS 1.X更容易理解, 但Angular2的工具集却比后者更复杂一些。这并不让人惊讶;毕竟你正在用一种语言写代码并将其编译为另一种语言,因为所有东西都会被编译成Javascript。

Angular CLI现在是一个承诺了会提供命令行界面的项目,它能大幅简化各个流程,从项目最初开始到生产部署。

应用调试可以在编辑器或浏览器中完成。我们使用Chrome的开发者工具来进行调试。 Chrome生成出的源码地图允许你在浏览器运行Javascript时调试TypeScrip代码。如果你更乐于调试Javascript, 这也是可以的, 因为TypeScript转译器会生成Javascript代码,这就能让别人直接去读了。

 

测试和部署

Angular2自带了一个测试库, 该库允许你在BDD格式下编写测试用例。目前它仅支持Jasmine框架,但能支持更多的框架已经指日可待。我们使用Karma测试工具, 该工具允许针对不同的浏览器分别跑不同的测试用例。

Protractor框架允许你为你的应用编写端到端测试用例。如果你在开发模式下加载一个简单应用时监控你的网络,你会看到浏览器下载了超过5兆 (这其中有一半是模块加载器要用到的TypeScript编译器,叫做SystemJS)。但在运行了部署和优化脚本(我们用的是Webpack打包工 具)后,这个小应用的体积可以缩小到160K(包含了Angular2框架)。我们正期待着想看看Angular CLI会如何实现生产环境的打包功能。 Angular团队在实现离线模板编译功能,这能让框架的体积缩小到50Kb左右。

 

界面组件库

在我写这篇文章的时候,已经有少数几个界面组件库你可以在Angular2应用中使用:

· PrimeNG – 一个PrimeFaces(一个在Java服务端框架中使用的非常流行的库)的创造者编写的Angular2界面组件库。

· Wijmo 5 – 一个商业的Angular 2界面组件库。 你需要购买开发者证书才能使用它。

· Polymer – 一个Google开发的可扩展的非常漂亮的组件库。 在我们公司我们已经设法使用Polymer组件库创建一个Angular2的飞行员应用,但在两者的整合上还有提升的空间。

· Material Design 2 – 一个Google特别为了Angular2开发的界面组件库。 目前这个库还处于雏形阶段, 但是其发展得非常迅速, 而且我非常期待在未来的三到四个月内可以看到一大堆设计良好的界面组件。

· NG-Lightning – 一个Angular2的组件和指令库, 该库是在Lightning设计系统的CSS框架下用TypeScript写出来的。

 

在内部系统中使用Angular2稳妥吗?

从第一个公测版发布开始,我们在Farata系统使用Angular2来编写一个真实世界项目,而且并没有陷入任何大麻烦中, 至少没遇到找不到解决方法的问题。

如果你想更保险一点, 可以再等多几个月。小道消息说Angular2的RC版本(指有可能成为最终产品的候选版本)会在2016年5月的Google I/0大会上公布。

 

将来会发生什么?

2016年3月, 布拉德·格林通过O’Reilly在Fluent大会上发表了一次主题演讲。 可以看看这次演讲的视频。 你被触动到了吗? 反正我被触动到了。

 

关于作者

Yakov Fain是一位住在纽约的Java拥护者,同时是IT咨询Farata系统的合作伙伴。 他领导着 Princeton JUG组织,他也在软件开发领域写过很多文章和几本书。最近他正与人共同创作《用TypeScript开发Angular 2》这本书, 这本书会在2016年6月筹备发布。Yakov经常在技术大会上发表演讲,同时还教授Java和Angular2课程。 他的博客是yakovfain.com。

 

————–

翻译的不对欢迎指出。

谢谢观看。

 

 

2016.08.11

MySQL中tinytext、text、mediumtext和longtext详解_于士博_新浪博客

mikel阅读(1406)

MySQL中tinytext、text、mediumtext和longtext详解_于士博_新浪博客,于士博,

来源: MySQL中tinytext、text、mediumtext和longtext详解_于士博_新浪博客

一、数字类型

类型
范围
说明
Char(N) [ binary] N=1~255 个字元
binary :分辨大小写
固定长度 std_name cahr(32) not null
VarChar(N) [binary] N=1~255 个字元
binary :分辨大小写
可变长度 std_address varchar(256)
TinyBlob 最大长度255个字元(2^8-1) Blob (Binary large objects)储存二进位资料,且有分大小写 memo text not null
TinyText 最大长度255个字元(2^8-1)
Blob 最大长度65535个字元(2^16-1)
Mysql <wbr><wbr>: <wbr><wbr>tinytext, <wbr><wbr>text, <wbr><wbr>mediumtext, <wbr><wbr>longtext Text 最大长度65535个字元(2^16-1)
MediumBlob 最大长度 16777215 个字元(2^24-1)
MediumText 最大长度 16777215 个字元(2^24-1
LongBlob 最大长度4294967295个字元 (2^32-1)
LongText 最大长度4294967295个字元 (2^32-1)
Enum 集合最大数目为65535 列举(Enumeration),Enum单选、Set复选 sex enum(1,0)
habby set(‘玩电玩’,’睡觉’,’看电影’,’听音乐’)
Set 集合最大数目为64

辨別Null与Not Null :Null为允许储存空值(Null)

二、数值

类型
范围
说明
例如
TinyInt[M] [UNSIGNED] -128~127
UNSIGNED : 0~255
num tinyint unsigned
SmallInt[M] [UNSIGNED] -32768~32767
UNSIGNED :0~ 65535
MediumInt[M] [UNSIGNED] -8388608~8388607
UNSIGNED :0~16777215
Int[M] [UNSIGNED] -2^31~2^31-1
UNSIGNED : 0~2^32
BigInt[M] [UNSIGNED] -2^63~2^63-1
UNSIGNED : 0~2^64
Float [(M,D)] -3.4E+38~3.4E+38( 约 ) 注: M 为长度, D 为小数,Float 4 bytes,Double 8 bytes
Double [(M,D)] -1.79E+308~1.79E+308( 约 )
Decimal [(M,D)]

辨別ZeroFill:当宣告关键字ZeroFill为自动填满0,如 000021

三、日期时间

类型
范围
说明
Date 日期(yyyy-mm-dd)
Time 时间(hh:mm:ss)
DateTime 日期与时间組合(yyyy-mm-dd hh:mm:ss)
TimeStamp yyyymmddhhmmss
Year 年份yyyy

Mysql临时表 - 风生水起 - 博客园

mikel阅读(998)

来源: Mysql临时表 – 风生水起 – 博客园

当你创建临时表的时候,你可以使用temporary关键字。如:

create temporary table tmp_table(name varchar(10) not null,passwd char(6) not null)‘

CREATE TEMPORARY TABLE IF NOT EXISTS sp_output_tmp ENGINE = MEMORY SELECT …from … where ID=current_id;

临时表只在当前连接可见,当这个连接关闭的时候,会自动drop。这就意味着你可以在两个不同的连接里使用相同的临时表名,并且相互不会冲突,或者使用 已经存在的表,但不是临时表的表名。(当这个临时表存在的时候,存在的表被隐藏了,如果临时表被drop,存在的表就可见了)。创建临时表你必须有

create temporary table 权限。

下面几点是临时表的限制:

临时表只能用在 memory,myisam,merge,或者innodb

临时表不支持mySQL cluster(簇)

在同一个query语句中,你只能查找一次临时表。例如:下面的就不可用

mySQL> SELECT * FROM temp_table, temp_table AS t2;

ERROR 1137: Can’t reopen table: ‘temp_table’

如果在一个存储函数里,你用不同的别名查找一个临时表多次,或者在这个存储函数里用不同的语句查找,这个错误都会发生。

show tables 语句不会列举临时表

你不能用rename来重命名一个临时表。但是,你可以alter table代替:

mysql>ALTER TABLE orig_name RENAME new_name;

临时表用完后要记得drop掉:

    DROP TEMPORARY TABLE IF EXISTS sp_output_tmp;