先不多说,上图:

JSDuck文档说明

初步使用,感觉还不错,因为其使用的运行环境是 Gem,所以需要安装 Ruby 相关的环境。安装可以参考链接:https://my.oschina.net/lsjcoder/blog/1583072

常用的命令表如下:

参数 含义
— 或 空 需要生成文档的文件或者目录,也可以是一个集合
–output 文档存放的目录
–config 配置文件路径
–encoding 文档编码方式
–exclude 不生成文档的目录或文件,可以是一个集合
–title 文档标题
–footer 文档标尾
–head-html 文档页面的head中需要添加的内容
–body-html 文档页面的body中需要添加的内容
–css 额外添加的样式​
–welcome 欢迎页面
–guides 向导配置
–examples 示例配置
–categories 分类配置
–images 图片路径配置
–tags 自定义标签
–examples-base-url 示例文件的基础路径
–help 查看命令帮助
–version 查看当前版本

随着 JavaScript 在越来越多的工程中扮演越来越重要的角色,文档的完善越来越重要,同时也开始约束 JSer 慢慢开始学习工程化,系统化的编写代码。开始自我改造吧。

测试效果如图:


当鼠标划过的时候,需要显示更多的信息,因为GridPanel表格显示区域不够,所以把部分信息移动到 Tip 中显示。代码如下:

store: {
  type: 'EduCartoonStore',
  autoLoad: false,
  listeners: {
      'load': function() {
          // 得到当前的Gird
          var grid = Ext.getCmp('eduCartoonListGrid');
          var view = grid.getView();
          // 创建一个 Tip
          var tip = Ext.create('Ext.tip.ToolTip', {
              target: view.el,
              delegate: view.itemSelector,
              trackMouse: true,
              renderTo: Ext.getBody(),
              listeners: {
                  // 显示Tip
                  beforeshow: function updateTipBody(tip) {
                      var record = view.getRecord(tip.triggerElement);
                      var state = '';
                      var createTime = '';
                      var packageTime = '-';
                      var showHtml = '';
                      // 状态
                      if (record.data.status === 0) {
                        state = "<span style='color:red'>待审核</span>";
                      } else if (record.data.status === 1) {
                        state = "<span style='color:green'>已审核</span>";
                      } else if (record.data.status === -1) {
                        state = "<span style='color:grey'>已关闭</span>";
                      }
                      // 创建时间
                      createTime = formatDate(record.data.ctime);
                      // 打包时间
                      if (record.data.zipGenerateTime !== undefined) {
                        packageTime = formatDate(record.data.zipGenerateTime)
                      }
                      showHtml += '<p><b>ID编号</b>:' + record.data.id + '</p>';
                      showHtml += '<p><b>状态</b>:' + state + '</p>';
                      showHtml += '<p><b>创建时间</b>:' + createTime + '</p>';
                      showHtml += '<p><b>打包时间</b>:' + packageTime + '</p>';
                      tip.update(showHtml);
                  }
              }
          });
      }
  }
}

因业务需要,只能动手来研究一个拖拽模块。研究之前觉得很简单,在我印象里好想类似的 Vue,jQuery 的插件非常多。应该是分分钟就可以搞定。结果花了很长的时间来研究这个玩意。现在把思路记下来方便下次查阅。

  • 创建拖拽对象
  • 确定“接受拖拽对象的”区域
  • 新建一个类,用于实现 ExtJS 中关于 “拖拽” 方法的实现
  • 使用新编写带有实现的类应用到拖拽对象中
  • 编写CSS来提升用户体验
  • 拖拽结束之后的节点复制和移动

基本上就是上述的几个步骤,为了方便查阅我把所有的脚本都构建在一个 JS 文件中,若真用到项目中,请严格按照 Sencha ExtJS 的 MVC 标准做代码的分离。代码如下:

/*
 * author:      liucan
 * email:       33370733@qq.com
 * description: 系统顶部模块
 */

// 在这里需要重写拖拽的方法,基础的 API 并没有基于业务的实现。
// 拖拽完成,必须要判定是否拖放在指定的区域中,并且长宽要一致
// 对其当前的容器元素,TOP,LEFT 必须为 0
var overrides = {
    startDrag: function () {
        this.originalXY = this.el.getXY();
    },
    onDrag: function () {
        this.el.addCls('item-draging');
    },
    onDragEnter: function (e, id) {
        // console.log('onDragEnter');
        if(id != this.el.dom.parentNode.id){
            this.el.addCls('item-drag-ok');
        }else{
            this.onDragOut();
        }
    },
    onDragOver: function (e, id) {
    },
    onDragOut: function (e, id) {
        this.el.removeCls('item-drag-ok');
    },
    onDragDrop: function (e, id) {
    },
    onInvalidDrop: function () {
        // 无效拖动,需要使用动画还原。
        this.invalidDrop = true;
        this.el.removeCls('item-draging');    
    },
    endDrag: function (e, id) {
        this.el.removeCls('item-draging');
        if(this.invalidDrop === true){
            // 无效的移动
            var animCfgObj = {
                easing: 'elasticOut',
                duration: 1,
                scope: this,
                callback: function(){
                    this.el.dom.style.postion = '';
                }
            }
            this.el.setXY(this.originalXY);
            delete this.invalidDrop;
        }else{
            // 判定 TARGET 的值,并且做好磁力贴效果
            // 复制节点到指定元素,删除原有节点
            var newNode = this.el;
            if(e.item){
                e.item.firstChild.append(newNode.dom)
                newNode.dom.style = "";
            }
        }
    }
};

var pinyinTpl = new Ext.XTemplate(
    '<div id="pinyin_panel" class="pinyin-panel">',
        '<tpl for=".">',
            '<div class="pinyin-item">{.}<div class="reset-this">x</div></div>',
        '</tpl>',
    '</div>'
);
var fontTpl = new Ext.XTemplate(
    '<div class="font-panel">',
        '<tpl for=".">',
            '<div class="thumb-wrap">',
                '<div class="thumb-pinyin"></div>',
                '<div class="thumb-font">{.}</div>',
            '</div>',
        '</tpl>',
        '<div style="clear: both"></div>',
    '</div>'
);

Ext.define('xjcms.view.util.Pinyin', {
    extend: 'Ext.window.Window',
    alias: 'widget.Pinyin',
    title: '生成拼音',
    requires: [
        'xjcms.view.util.pinyin.PinyinController',
        'xjcms.view.util.pinyin.PinyinModel'
    ],
    controller: {
        type: 'pinyin'
    },
    viewModel: 'pinyin',
    width: 600,
    minHeight: 320,
    layout: 'fit',
    scrollable: false,
    // 遮罩层
    modal: true,
    constrain: true,
    closable: true,
    autoDestroy: true,
    draggable: true,
    resizable: false,
    items: [{
        xtype: 'form',
        bodyPadding: '10 10 10 10',
        items: [{
            xtype: 'container',
            layout: 'hbox',
            items: [{
                xtype: 'textfield',
                fieldLabel: '文字',
                labelWidth: 60,
                width: 500,
                emptyText: '请输入文字',
                regex: /^([\u4e00-\u9fa5]+)/,
                regexText: '该输入框仅仅只支持输入汉字',
                value: ''
            }, {
                xtype: 'button',
                text: '生成拼音',
                handler: function () {
                    // word-lib/convert2Pinyin
                    var text = this.prev().getValue();
                    var vm = this.up('window').getViewModel();
                    var vmStores = vm.storeInfo;
                    var fontData = [];
                    text = Ext.util.Format.trim(text);
                    // 请求数据
                    Ext.Ajax.request({
                        url: 'https://easy-mock.com/mock/5ae02d829c4a407f53115d81/rms/py',
                        method: 'GET',
                        params: {
                            font: text
                        },
                        success: function (response, opts) {
                            var obj = Ext.decode(response.responseText);
                            // 中文字和拼音字母
                            var font = obj.data.font;
                            var py = obj.data.py;
                            vmStores['fontStore'] = Ext.create('Ext.data.Store', {
                                data: font
                            });
                            vmStores['pinyinStore'] = Ext.create('Ext.data.Store', {
                                data: py
                            });
                            vm.setStores(vmStores);
                        },
                        failure: function (response, opts) {
                            console.log('server-side failure with status code ' + response.status);
                        }
                    });
                }
            }]
        }, {
            xtype: 'dataview',
            tpl: pinyinTpl,
            itemSelector: 'div.pinyin-item',
            bind: {store: '{pinyinStore}'},
            listeners: {
                'refresh': function () {
                    var pinyins = Ext.select('.pinyin-item');
                    Ext.each(pinyins.elements, function (el) {
                        // 第一步,创建可拖动的元素
                        var dd = Ext.create('Ext.dd.DD', el, 'pyDDGroup', {
                            isTarget: false
                        });
                        Ext.apply(dd, overrides);
                    })
                }
            }
        }, {
            // 拼音的拖拽区域
            xtype: 'dataview',
            tpl: fontTpl,
            bind: {store: '{fontStore}'},
            itemSelector: 'div.thumb-wrap',
            emptyText: '<div class="font-none-data">暂时还没有任何文字哦</div>',
            listeners: {
                'refresh': function () {
                    var thumbWrap = Ext.select('.thumb-wrap');
                    // 第二步,创建可以用于接收的元素
                    Ext.each(thumbWrap.elements, function (el) {
                        var thumbWrapDDTarget = Ext.create('Ext.dd.DDTarget', el, 'pyDDGroup', {
                            ignoreSelf: false
                        });
                    })
                },
                'itemclick': function(thisViewObj, record, item, index, e, eOpts){
                    var clsName = e.target.className;
                    if(clsName === 'reset-this'){
                        // 移除这个元素
                        var pNode = e.target.parentNode;
                        // console.dir(pNode);
                        Ext.get('pinyin_panel').appendChild(pNode);
                    }
                }
            }
        }],
        buttons: [{
            xtype: 'button',
            text: '确定'
        }, {
            xtype: 'button',
            text: '取消',
            handler: function () {
                this.up('window').destroy();
            }
        }]
    }]
});

知乎上的WebPack三连击,非常实用的东西。分享一下。

  • Webpack傻瓜式指南(一)http://zhuanlan.zhihu.com/FrontendMagazine/20367175
  • Webpack傻瓜式指南(二)http://zhuanlan.zhihu.com/FrontendMagazine/20397902
  • Webpack傻瓜式指南(三)http://zhuanlan.zhihu.com/FrontendMagazine/20522487

 

偶尔翻出来以前写的一些小东西。做应用开发久了,久而久之一开始就很注意框架的选择。但是最初写Javascript那种alert逐步调试。写一些通用的工具类的时间仿佛离我很远了。翻了下以前的一些代码,把他贴出来。就权当是复习下吧。

/**
 * author:      可乐加糖
 * description: 呵呵,不知道写什么好,随便吧。
 */

(function (window) {
    //基础类库
    var cola = {
        get_node: function (elem_id) {
            if (elem_id.constructor != String) {
                throw new Error("参数传递错误");
                return false;
            }
            return document.getElementById(elem_id) || null;
        },
        prev: function (elem) {
            do {
                elem = elem.previousElementSibling
            } while (elem && elem.nodeType != 1);
            return elem
        },
        next: function (elem) {
            do {
                elem = elem.nextSibling;
            } while (elem && elem.nodeType != 1);
            return elem
        },
        first_node: function (elem) {
            elem = elem.firstChild;
            return elem && elem.nodeType != 1 ? this.next(elem) : elem;
        },
        last: function (elem) {
            elem = elem.lastChild;
            return elem && elem.nodeType != 1 ? prev(elem) : elem;
        },
        parent: function (elem, num) {
            num = num || 1;
            for (var i = 0; i < num; i++) {
                if (elem != null)
                    elem = elem.parentNode;
                return elem;
            }
        },
        remove: function (elem) {
          if(elem)
            elem.parentNode.removeChild(elem);
        },
        empty: function (elem) {
            while(elem.firstChild)
                elem.removeChild(elem.firstChild)
        }
    }
    window.cola = cola;
})(window)

这是最开始写的一个二级下拉导航条的代码

document.getElementsByClassName = function(clsName){
    if(typeof(clsName)!="string" || clsName.constructor != String){
        throw new Error("className必须是字符串");
        return false;
    }
    var nodes = document.getElementsByTagName("*");
    var nodeArr = new Array();
    for(var i= 0,icount = nodes.length;i<icount;i++){
        if(nodes[i].className == clsName)
            nodeArr.push(nodes[i]);
    }
    return nodeArr;
}
window.onload = function(){
    var nodes = document.getElementsByClassName("has-child");
    for(var i= 0,icount = nodes.length;i<icount;i++){
        nodes[i].onmouseover = function(){
            var child_menu = this.getElementsByTagName("ul");
            child_menu[0].style.display = "block";
        }
        nodes[i].onmouseout = function () {
            var child_menu = this.getElementsByTagName("ul");
            child_menu[0].style.display = "none";
        }
    }
}

还有获取元素的样式表,当初也是在IE下调试了很久才搞定。

function getStyle(elem,name){
    if(elem.style[name])
        return elem.style[name];
    else if(elem.currentStyle)
        return elem.currentStyle[name];
    else if(document.defaultView && document.defaultView.getComputedStyle){
        name = name.replace(/([A-Z])/g,"-$1");
        name = name.toLowerCase();
        var s = document.defaultView.getComputedStyle(elem,"");
        return s && s.getPropertyValue(name);
    }
    else
        return null;
}

最近一直在阅读 JQuery 的源码,涉及到核心组件,需要复习一下 JavaScript 的底层属性,把这篇文章转载过来,作为资料。
原帖地址:http://blog.csdn.net/hikvision_java_gyh/article/details/8937157

在Javascript语言中,constructor属性是专门为function而设计的,它存在于每一个function的prototype属性中。这个constructor保存了指向function的一个引用。在定义一个函数(代码如下所示)时,


function F() {   
    // some code  
 }

JavaScript内部会执行如下几个动作:

为该函数添加一个原形属性(即prototype对象).

为prototype对象额外添加一个constructor属性,并且该属性保存指向函数F的一个引用。

这样当我们把函数F作为自定义构造函数来创建对象的时候,对象实例内部会自动保存一个指向其构造函数(这里就是我们的自定义构造函数F)的prototype对象的一个属性__proto__,所以我们在每一个对象实例中就可以访问构造函数的prototype所有拥有的全部属性和方法,就好像它们是实例自己的一样。

当然该实例也有一个constructor属性了(从prototype那里获得的),这时候constructor的作用就很明显了,因为在这时,每一个对象实例都可以通过constrcutor对象访问它的构造函数,请看下面代码:

 

[javascript]?view plaincopy


var?f?=?new?F();
alert(f.constructor?===?F);//?output?true
alert(f.constructor?===?F.prototype.constructor);//?output?true

我们可以利用这个特性来完成下面的事情: 对象类型判断,如

[javascript]?view plaincopy


if(f.constructor?===?F)?{
    //?do?sth?with?F
}

其实constructor的出现原本就是用来进行对象类型判断的,但是constructor属性易变,不可信赖。
我们有一种更加安全可靠的判定方法:instanceof 操作符。
下面代码仍然返回true


if(f instanceof F)?{
    // do sth with F
}.

原型链继承,由于constructor存在于prototype对象上,因此我们可以结合constructor沿着原型链找到最原始的构造函数,如下面代码:


function Base() {
}
// Sub1 inherited from Base through prototype chain
function Sub1() {
}
Sub1.prototype = new Base();
Sub1.prototype.constructor = Sub1;
Sub1.superclass = Base.prototype;
// Sub2 inherited from Sub1 through prototype chain
function Sub2() {
}
Sub2.prototype = new Sub1();
Sub2.prototype.constructor = Sub2;
Sub2.superclass = Sub1.prototype;
// Test prototype chain
alert(Sub2.prototype.constructor);
// function Sub2(){}
alert(Sub2.superclass.constructor);
// function Sub1(){}
alert(Sub2.superclass.constructor.superclass.constructor);
// function Base(){}

上面的例子只是为了说明constructor在原型链中的作用,更实际一点的意义在于:一个子类对象可以获得其父类的所有属性和方法,称之为继承,关于继承我们有好多可以分析和讨论,本篇限于篇幅不在此讨论。
一个容易掉入的陷阱(gotchas) 之前提到constructor易变,那是因为函数的prototype属性容易被更改,我们用时下很流行的编码方式来说明问题,请看下面的示例代码:


function F() {

}
F.prototype = {
    _name:Eric,
    getName: function () {
        return this._name;
    }
}

初看这种方式并无问题,但是你会发现下面的代码失效了:

var f = new F();
alert(f.constructor === F); // output false

怎么回事?F不是实例对象f的构造函数了吗?
当然是!只不过构造函数F的原型被开发者重写了,这种方式将原有的prototype对象用一个对象的字面量{}来代替。
而新建的对象{}只是Object的一个实例,系统(或者说浏览器)在解析的时候并不会在{}上自动添加一个constructor属性,因为这是function创建时的专属操作,仅当你声明函数的时候解析器才会做此动作。
然而你会发现constructor并不是不存在的,下面代码可以测试它的存在性:

alert(typeof f.constructor == ‘undefined’);// output false

既然存在,那这个constructor是从哪儿冒出来的呢?

我们要回头分析这个对象字面量{}。

因为{}是创建对象的一种简写,所以{}相当于是new Object()。

那既然{}是Object的实例,自然而然他获得一个指向构造函数Object()的prototype属性的一个引用__proto__,又因为Object.prototype上有一个指向Object本身的constructor属性。所以可以看出这个constructor其实就是Object.prototype的constructor,下面代码可以验证其结论:

alert(f.constructor === Object.prototype.constructor);//output true
alert(f.constructor === Object);// also output true

一个解决办法就是手动恢复他的constructor,下面代码非常好地解决了这个问题:


function F() {
}
F.prototype = {
    constructor: F, /* reset constructor */
    _name: Eric,
    getName: function () {
        return this._name;
    }
};

之后一切恢复正常,constructor重新获得的构造函数的引用,我们可以再一次测试上面的代码,这次返回true
var f = new F();
alert(f.constructor === F); // output true this time ^^
解惑:构造函数上怎么还有一个constructor?它又是哪儿来的?
细心的朋友会发现,像JavaScript内建的构造函数,如Array, RegExp, String, Number, Object, Function等等居然自己也有一个constructor:
alert(typeof Array.constructor != ‘undefined’);// output true
经过测试发现,此物非彼物它和prototype上constructor不是同一个对象,他们是共存的:
alert(typeof Array.constructor != ‘undefined’);// output true
alert(typeof Array.prototype.constructor === Array); // output true
不过这件事情也是好理解的,因为构造函数也是函数。
是函数说明它就是Function构造函数的实例对象,自然他内部也有一个指向Function.prototype的内部引用__proto__啦。
因此我们很容易得出结论,这个constructor(构造函数上的constructor不是prototype上的)其实就是Function构造函数的引用:
alert(Array.constructor === Function);// output true
alert(Function.constructor === Function); // output true
OK, constructor从此真相大白,你不在对它陌生了~

话不多说,直接上图:

1

搜了一把皮肤制作,大多数都是英文文档,看了几遍差不多熟练了之后就把皮肤问题得以搞定,记录下来方便下次使用。

步骤:

1.?安装环境,JDK、ruby、compass、sass (JDK 通过下载安装,RUBY 通过下载安装- http://rubyinstaller.og ,sass 通过Ruby 中的 gem 能够自动安装)

2.?下载 SenchaCmd-3.1.2.342-windows.exe 、SenchaSDKTools-2.0.0-beta3-windows.exe (Linux 环境请自行下载安装包,配置PATH)

3. 环境搭建完毕之后,开始构建工程,使用命令
sencha –sdk /extjs的路径/ generate app 工程名 工程存放的路径
2

3

继续阅读

网址:http://caniuse.com/#index

Html5属性支持

Html5属性支持

该网站提供了非常丰富的H5以及各种新型浏览器API,并且能够在网站上快速搜索某一属性在各个浏览器以及设备上的支持情况。
例如:搜索GEOLOCATION属性的支持。

Html5属性支持

Html5属性支持

这样极大的方便了日常H5开发的浏览器支持一览,如果需要支持低端浏览器,可以在重构HTML之前就查询相应的支持,从而判断如何使用降级版本处理方案。

优化了一下代码,结果如下。

调用:

<script type="text/javascript">
function aaa(){
	var student_panel = new WX.student.AddStudent({
		callback_fun:function(){
			alert("我是页面的方法");
		}
	}).show();
}
</script>

组件定义

Ext.define('WX.student.AddStudent', {
	
    extend: 'Ext.window.Window',

    modal:true,
    height: 585,
    width: 590,
    layout: {
        type: 'fit'
    },
    title: '新增学生',
    //用于组件函数回调
    callback_fun:function(){},
    initComponent: function() {
    	
        var me = this;
        
        Ext.applyIf(me, {
            items: [
                {
                    waitTitle: '加载中...',
                    items: [
                        ......
                    ],
                    buttons:[{
                    	text:'保存',
                    	scope:this,                  // <============== 关键参数 
                    	handler:function(){
                    		//DO SOMETHING...
                    		alert("组件的事件");
                    		this.callback_fun();
                    	}
                    }]
                }
            ]
        });
        me.callParent(arguments);
    }

});