在 Vue element-ui 中 from 表单常用的正则可以对此封装一次,方便表单验证使用,搜集了一批常用的正则,出处:
https://www.cnblogs.com/zqifa/p/regex-1.html

1.校验数字的表达式

  1. 数字:^[0-9]*$
  2. n位的数字:^\d{n}$
  3. 至少n位的数字:^\d{n,}$
  4. m-n位的数字:^\d{m,n}$
  5. 零和非零开头的数字:^(0|[1-9][0-9]*)$
  6. 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
  7. 带1-2位小数的正数或负数:^(-)?\d+(.\d{1,2})?$
  8. 正数、负数、和小数:^(-|+)?\d+(.\d+)?$
  9. 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
  10. 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
  11. 非零的正整数:^[1-9]\d$ 或 ^([1-9][0-9]){1,3}$ 或 ^+?[1-9][0-9]*$
  12. 非零的负整数:^-[1-9][]0-9″$ 或 ^-[1-9]\d$
  13. 非负整数:^\d+$ 或 ^[1-9]\d*|0$
  14. 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
  15. 非负浮点数:^\d+(.\d+)?$ 或 ^[1-9]\d.\d|0.\d[1-9]\d|0?.0+|0$
  16. 非正浮点数:^((-\d+(.\d+)?)|(0+(.0+)?))$ 或 ^(-([1-9]\d.\d|0.\d[1-9]\d))|0?.0+|0$
  17. 正浮点数:^[1-9]\d.\d|0.\d[1-9]\d$ 或 ^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$
  18. 负浮点数:^-([1-9]\d.\d|0.\d[1-9]\d)$ 或 ^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$
  19. 浮点数:^(-?\d+)(.\d+)?$ 或 ^-?([1-9]\d.\d|0.\d[1-9]\d|0?.0+|0)$

2.校验字符的表达式

  1. 汉字:^[\u4e00-\u9fa5]{0,}$
  2. 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
  3. 长度为3-20的所有字符:^.{3,20}$
  4. 由26个英文字母组成的字符串:^[A-Za-z]+$
  5. 由26个大写英文字母组成的字符串:^[A-Z]+$
  6. 由26个小写英文字母组成的字符串:^[a-z]+$
  7. 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
  8. 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
  9. 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
  10. 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
  11. 可以输入含有^%&』,;=?$\」等字符:[^%&』,;=?$\x22]+
  12. 禁止输入含有~的字符:[^~\x22]+

3.特殊需求表达式

  1. Email地址:^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$
  2. 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
  3. InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+.)+[\w-]+(/[\w-./?%&=]*)?$
  4. 手机号码(可根据目前国内收集号扩展前两位开头号码):^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
  5. 电话号码(「XXX-XXXXXXX」、」XXXX-XXXXXXXX」、」XXX-XXXXXXX」、」XXX-XXXXXXXX」、」XXXXXXX」和」XXXXXXXX):^((\d{3,4}-)|\d{3.4}-)?\d{7,8}$
  6. 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
    7.15位身份证号:^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$
    8.18位身份证号:^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$
  7. 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
  8. 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
  9. 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.\d)(?=.[a-z])(?=.*[A-Z]).{8,10}$
  10. 日期格式:^\d{4}-\d{1,2}-\d{1,2}
  11. 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
  12. 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
  13. 钱的输入格式:
    (1)有四种钱的表示形式我们可以接受:」10000.00″ 和 「10,000.00」, 和没有 「分」 的 「10000」 和 「10,000」:^[1-9][0-9]$ (2)这表示任意一个不以0开头的数字,但是,这也意味着一个字符」0″不通过,所以我们采用下面的形式:^(0|[1-9][0-9])$
    (3)一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9])$ (4)这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$ (5)必须说明的是,小数点后面至少应该有1位数,所以」10.」是不通过的,但是 「10」 和 「10.2」 是通过的:^[0-9]+(.[0-9]{2})?$ (6)这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$ (7)这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})(.[0-9]{1,2})?$
    (8)1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$

备注:这就是最终结果了,别忘了」+」可以用」*」替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里

  1. xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\.[x|X][m|M][l|L]$
  2. 中文字符的正则表达式:[\u4e00-\u9fa5]
  3. 双字节字符:^\x00-\xff
  4. 空白行的正则表达式:\n\s*\r (可以用来删除空白行)
  5. HTML标记的正则表达式:<(\S?)[^>]>.?|<.? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
  6. 首尾空白字符的正则表达式:^\s|\s$或(^\s)|(\s$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
  7. 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
  8. 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
  9. IP地址:\d+.\d+.\d+.\d+ (提取IP地址时有用)
  10. IP地址:((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))

React小书:http://huziketang.mangojuice.top/books/react/lesson1
React 开发者学习线路图(2018):https://www.css88.com/archives/10111
React中文文档:https://react.css88.com/
WebPack 4 教程,从零配置到生产发布:https://www.css88.com/archives/9436
React入门教程:https://react.docschina.org/tutorial/tutorial.html#%E8%AF%BE%E5%89%8D%E5%87%86%E5%A4%87
React Router 教程:https://react-guide.github.io/react-router-cn/docs/guides/basics/IndexRoutes.html

Electron的开发相对还是蛮简单的,看了一写简单的资料就能快速上手开发了。留下三篇相对全的资料,以备查询:
开发:https://juejin.im/post/5a6a91276fb9a01cbd58ce32
打包:https://juejin.im/entry/5805e39ad20309006854e58f
https://www.jianshu.com/p/1c2ad78df208
更新:https://segmentfault.com/a/1190000012904543

先不多说,上图:

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);
                  }
              }
          });
      }
  }
}

场景是这样的,用户编辑完文本之后,上传了一张图片。而这个时候并没有让编辑器重新获得焦点。就会导致提交的图片为:themes/default/images/spacer.gif 。原因是上传完成图片之后,数据正确返回但是并没有动态绑定到图片的 src 属性中。这个时候需要手动设置一次富文本编辑框的值,触发 change 事件。修改代码如下:

ueditor.all.js  24518行

function callback(){
try{
	var link, json, loader,
	body = (iframe.contentDocument || iframe.contentWindow.document).body,
	result = body.innerText || body.textContent || '';
	json = (new Function("return " + result))();
	link = me.options.imageUrlPrefix + json.url;
	if(json.state == 'SUCCESS' && json.url) {
		loader = me.document.getElementById(loadingId);
		loader.setAttribute('src', link);
		loader.setAttribute('_src', link);
		loader.setAttribute('title', json.title || '');
		loader.setAttribute('alt', json.original || '');
		loader.removeAttribute('id');
		domUtils.removeClasses(loader, 'loadingclass');
		me.execCommand('inserthtml', '');   // 就是这一行,记住了!!!
	} else {
		showErrorLoader && showErrorLoader(json.state);
	}
}catch(er){
	showErrorLoader && showErrorLoader(me.getLang('simpleupload.loadError'));
}
form.reset();
domUtils.un(iframe, 'load', callback);
}

修改源码后就可以解决这个问题啦。

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

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

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

/*
 * author:      liucan
 * email:       [email protected]
 * 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

 

前端日常工作是什么?拿到PSD图,然后开切!首先我们建立一个app的文件夹,然后在app下,我们建立img文件夹,接下来是 css …… 项目终于搞定之后,我们要使用在线压缩工具把样式表进行合并压缩,把所有的大尺寸图片重新导入Ps,保存为 web 格式,然后调整质量 。。。。。。

你就没想过偷懒的办法么?你就是这么把时间耗在没有意义的简单机械的活儿中么?

或者,很多前端都已经开始使用Grunt这样的工具了,自动压缩、自动打包、文件合并、Less,Sass 编译、文件监控、本地文件服务器调试环境。不错,基于Grunt另外推出了非常多的 generate ,类似 angularJS , Ember , Backbone, webapp, bootstrap 等等等等,但是 Grunt 的学习曲线也是非常陡的。虽然能够通过一些通用脚手架来搭建前端工程作为基础架构。一旦需要修改配置,则是异常痛苦。

gulp 的功效和 Grunt 也是异曲同工、插件也是异常丰富。

通过 Grunt 与 gulp 的对比。我个人还是比较喜欢 gulp 的一些操作模式。不管是从词法、编程语义的理解程度来说。gulp 都是优于 Grunt 。官网的介绍谈到了文件流、以及处理速度。因为没有现成的案例,所以不能妄自评论。下面就浅谈一下两者之间的使用细节。

这里引用?http://markgoodyear.com/2014/01/getting-started-with-gulp/ 中的例子:

Grunt

sass: {
  dist: {
    options: {
      style: 'expanded'
    },
    files: {
      'dist/assets/css/main.css': 'src/styles/main.scss',
    }
  }
},

autoprefixer: {
  dist: {
    options: {
      browsers: [
        'last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'
      ]
    },
    src: 'dist/assets/css/main.css',
    dest: 'dist/assets/css/main.css'
  }
},

grunt.registerTask('styles', ['sass', 'autoprefixer']);

Gulp

gulp.task('sass', function() {
  return gulp.src('src/styles/main.scss')
    .pipe(sass({ style: 'compressed' }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(gulp.dest('dist/assets/css'))
});

不管从代码还是从阅读性上来说,Gulp 不是更加优越一些嘛?从代码的输入和输出,以及事件的操作顺序一幕了然,完全不用在复杂的GruntFile中间去找各种各样的变量表达式。妈妈再也不用担心我的学习!

那么我们来一个简单的Case吧。

首先确保你安装了NodeJS。

然后运行Continue reading