来试试wordpress自己的客户端

很偶然的发现wordpress出了这么一个客户端程序,这两天没事时间体验了一下。

首先介绍一下如何安装吧:

第一步:wordpress这个客户端依赖官网的一个管理插件jeypack,安装方法很简单,直接在wordpress插件管理器里搜索安装就好了,然后可以根据自身需要设置一下,具体我就不废话了,傻瓜式的,很简单;

第二步:自己网站装好jeypack之后,打开客户端主程序,用wordpress官网的帐号登录(是你在wordpress官网上注册的帐号哦,不是你自己网站的管理帐号),然后根据提示绑定好自己的网站就ok了。

然后,这个客户端功能还是很全的:标签管理、页面管理、用户管理、分类管理、菜单管理等等,应有尽有,在线上能改的,这里都可以改。速度那还用说,比线上好太多了~

之前用过一段事件的window live writter,那时候感觉用wlw写文章就已经很享受了,虽然wlw已经六年没更新了,但用端写总比用页面写舒服很多。如今wp的官方端忽然出现,真是惊喜啊,而且这么丰富的功能,完全可以不用线上改任何东西了,超赞~!

另外jeypack还支持邮件写文章哦,在jeypack设置里生成一个邮件地址就可以了,然后随时随地,发个邮件,就变成一篇漂亮的文章啦,小伙伴们快来用用吧~~~

来试试wordpress自己的客户端

IOS下body绑定click事件的bug

今天在做项目的时候,遇到了一个特别莫名奇妙的问题:
我在写动态创建出来的模块点击事件的时候,经常会用到事件代理,把click事件绑定到body上,然后今天忽然发现,这么绑定事件在ios却没有效果,各种浏览器都不行。

为了消除其他代码的影响,我写了一个超级简单的页面,然而结果还是不行

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style media="screen">
            html,body{height: 100%;width: 100%;position: relative;background-color: green}
        </style>
    </head>
    <body>
        <div style="position:absolute;height:300px;width:300px;background:red;top:100px;left:100px;">

        </div>
        <script type="text/javascript">
            document.body.addEventListener('click',function(e){
                alert(e.target.tagName);
            })
        </script>
    </body>
</html>

经过测试
1.IOS各版本都存在这个bug,包括ihone、ipad、touch
2.IOS下的各种浏览器无一幸免
3.window,document,body 绑定click事件,都不会被触发

这真是莫名其妙的设定。。。

不过还好,屏蔽掉的只是click,touchstart等其他事件还是可以用的
如果需要把事件代理给body处理的话,click是没办法用了,改用touchstart或者模拟的事件tap吧

另外这里介绍一下tap:

click事件在移动端本身是带有300毫秒的延迟的(有的浏览器貌似要有500ms,其实具体多少也不太好测,通常大家都说300,那就300吧),这个问题会导致click事件在移动端相应很慢,如果大量点击交互的话(比如拼图游戏等),用户体验会特别差,为了解决这个问题,于是诞生了这个tap。

tap其实是一个组合事件:一个touchstart+一个touchend事件,tap事件的设定是延迟很小的,完全避免了click在某些场景下存在的延迟问题。

但是,tap的出现,同时又带来了另外一个问题:击穿!就是当一个浮层上有点击关闭这个浮层的效果时,如果我们使用的tap事件,那就会在点下并抬起的瞬间,这个浮层的display直接设置成none,这时候tap事件虽然进行完了,但是300毫秒之后,还有一个click在那等着,这时候浮层关闭了,这个click事件就会被传递给这个复层下面的内容,下面如果是个链接,那页面就会跳转到这个链接所指向的页面~

为了解决tap带来的新bug,我一般会用下面这种办法(tap执行的时候给body设置pointer-events:none,取消掉所有元素的鼠标及触屏行为,500毫秒之后重新设置pointer-events:all):

//阻止击穿
function preThrough(){
	document.body.throughTimer && clearTimeout(document.body.throughTimer);
	document.body.style.pointerEvents = 'none';
	document.body.throughTimer = setTimeout(function(){
		document.body.style.pointerEvents = 'all';
	},500);
}
IOS下body绑定click事件的bug

canvas文字换行–小插件

插件说明:
canvas 描述:canvas对象(目前只支持dom)
message 描述:需要输出得文字
maxWidth 描述:文字最大得宽度(超过此宽度将换行)
top 描述:开始输出文字的纵轴坐标(基于canvas原点)
left 描述:开始输出文字的横轴坐标(基于canvas原点)
lineHeight 描述:文字行高
fontSize 描述:字体大小
maxLine 描述:显示的最大行数(超过则输出’…’)
color 描述:文字颜色
fontFamily 描述:字体

插件太简单了,不写例子了…

下面是源码(或转至https://github.com/mulianju/2016/blob/master/src/Components/DrawText.js):

function DrawText(options) {
    var _this = this;
    _this.opts = {}

    for (var ele in _this.defaults) {
        if (typeof options[ele] !== 'undefined') {
            _this.opts[ele] = options[ele];
        } else {
            _this.opts[ele] = _this.defaults[ele];
        }
    }
    var allWords = _this.opts.message.split('');

    _this.nowLine = 0;

    _this.cutWords(allWords, _this.opts.maxWidth);
}
DrawText.prototype = {
    cutWords: function(allWords, maxWidth) {
        var _this = this,
            tempText = '',
            shiftWord = '',
            ctx = _this.opts.canvas.getContext('2d');
        ctx.font = _this.opts.fontSize + 'px ' + _this.opts.fontFamily;
        ctx.fillStyle = _this.opts.color;
        // p = document.getElementById('q'); if (!p) {     p = document.createElement('p');     p.id = 'canvasTextTemp';     p.style.cssText = 'opacity:0;position:absolute;top:0;visibility:hidden;left:0;pointer-event:none;z-index:-1;font-size:' +
        // this.opts.fontSize + 'px;white-space:nowrap'     document.body.appendChild(p); } p.innerText = '';

        for (var i = 0; i < allWords.length; i--) {
            if (!allWords.length)
                return;

            if (ctx.measureText(tempText).width < maxWidth) {
                shiftWord = allWords.shift()
                // p.innerHTML += shiftWord;
                tempText += shiftWord;
                if (!allWords.length) {
                    // tempText = p.innerHTML;
                    _this.drawWords(tempText);
                    // p.remove();
                }
            } else {
                allWords.unshift(shiftWord);
                // p.innerHTML = p.innerHTML.substr(0, p.innerHTML.length - 1); tempText = p.innerHTML;
                if (_this.nowLine + 1 == _this.opts.maxLine && allWords.length) {
                    tempText = tempText.substr(0, tempText.length - 1) + '...';
                }
                _this.drawWords(tempText);
                _this.nowLine += 1;

                if (_this.nowLine < _this.opts.maxLine) {
                    _this.cutWords(allWords, _this.opts.maxWidth)
                }
                // p.remove();
                return;
            }
        }
    },
    drawWords: function(tempText) {
        var _this = this,
            ctx = _this.opts.canvas.getContext('2d');

        ctx.fillText(tempText, _this.opts.left, _this.opts.top + _this.nowLine * _this.opts.lineHeight * _this.opts.fontSize, _this.opts.maxWidth);
        ctx.closePath();
    }
}
Object.defineProperty(DrawText.prototype, 'defaults', {
    value: {
        canvas: document.getElementById('canvas'),
        message: 'Please enter your text~',
        maxWidth: 520,
        top: 0,
        left: 20,
        lineHeight: 1.5,
        fontSize: 32,
        maxLine: 4,
        color: '#000',
        fontFamily: window.getComputedStyle(document.documentElement)['font-family']
    }
})
canvas文字换行–小插件

给dom节点扩展closest方法

想必大家都用过jq的closest方法(用来查找上级中最近的指定元素),这里我写的是一个简单的原生方法的实现

实际原生dom也是有这个方法的,只是兼容的浏览器少之又少

这里是一个最最简单的实现,工作中经常用到,所以记录一下

HTMLElement.prototype.closest = function(str){
	
	if(!str){
		return this.parentNode;
	}else{
		var temp = this.parentNode;
		while(temp){
			if(checkNode(temp)){
    			return temp;
    		}else{
    			temp = temp.parentNode;
    		}
		}
	}
	function checkNode(obj){
		var _this = obj;
		switch(str.substr(0,1)){
			case '.':
				if(_this.classList.contains(str.split('.')[1])){
					return true;
				}else{
					return false;
				}
				break;
			case '#':
				if(_this.id == str.split('#')[1]){
					return true;
				}else{
					return false;
				}
				break;
			default:
				if(_this.tagName == str){
					return true;
				}else{
					return false;
				}
				break;
		}
	}
}
给dom节点扩展closest方法

rem解决方案

基于一位前辈写的框架,修复了一些小问题

! function(W) {
	/* 
	    dpr         设备像素比
	    scale       缩放倍数
	    timer       延迟对象 
	    rootElement 根元素
	    viewport    meta > viewport
	*/
	var dpr,
		scale,
		timer,
		rootElement = document.documentElement,
		viewport = document.querySelector('meta[name="viewport"]'),
		initFontSize = parseInt(window.getComputedStyle(rootElement)["font-size"]),
		zolDesignParams = document.querySelector('meta[name="zol-rem-params"]'),
		defaultDesignWidth = 640,
		fontStyle = document.getElementById('zol-rem-font-style'),
		rootStyle = document.getElementById('zol-rem-root-style'),
		ua = navigator.userAgent;

	function setZolParams(params){
		if(!params)return;
		if(params = params.content){
			var width = /width=(\d+)/.exec(params);
			width && width[1] && (defaultDesignWidth = width[1]);
			
			var fonts = /fonts=([^;]+)/.exec(params);
			fonts && fonts[1] && (fonts = fonts[1].split(','));
			
			var str = 'body:{font-size:' + initFontSize * dpr + 'px}';

			fonts && fonts.forEach(function(size){
				str += '[data-dpr="1"] .f' + size + '{font-size:' + size / 2 + 'px!important}'
				str += '[data-dpr="2"] .f' + size + '{font-size:' + size + 'px!important}'
				str += '[data-dpr="3"] .f' + size + '{font-size:' + size / 2 * 3 + 'px!important}'
			});
			
			if(fonts && !fontStyle){
				fontStyle = document.createElement('style');
				fontStyle.id = 'zol-rem-font-style';
				fontStyle.innerHTML = str;
				document.getElementsByTagName('head')[0].appendChild(fontStyle);
				document.documentElement.setAttribute('data-dpr',dpr);
			}
		};
	};
	
	// 初始化REM,现阶段设计稿依然以640为主,按照取整数的原则,以64来划分刚好得到10,便于换算
	function initialRem() {
		var width = rootElement.getBoundingClientRect().width; // 文档宽度
		width / dpr > defaultDesignWidth && (width = defaultDesignWidth * dpr);
		initialRem.rem = width * 100 / defaultDesignWidth ; // 将页面划分64份,1rem为页面的1/64;
		//rootElement.style.fontSize = initialRem.rem + 'px' // 为根元素设置font-size;
		
		if(!rootStyle){
			rootStyle = document.createElement('style');
			rootStyle.id = 'zol-rem-root-style';
			document.getElementsByTagName('head')[0].appendChild(rootStyle);
		}
		rootStyle.innerHTML = 'html{font-size:' + initialRem.rem + 'px;-webkit-text-size-adjust: 100%;}';
	};

	// 平台暂只支持iPhone和Android,Windows Phone由于用户基数少暂不考虑
	// 规则只取整数,:3倍,2倍,1倍
	if (!dpr && !scale) {
		var platform = (W.navigator.appVersion.match(/android/gi) || W.navigator.appVersion.match(/iphone/gi));
		dpr = W.devicePixelRatio;
		dpr = platform ? dpr >= 3 ? 3 : dpr >= 2 ? 2 : 1 : 1;
		/android/ig.test(ua) && /ucbrowser/ig.test(ua) && (dpr = 1);
		scale = 1 / dpr;
	}

	// 经测试,发现ZOL安卓客户端的UIWebview处理起来会有问题,需添加target-densitydpi进行处理
	if (!viewport) {
		viewport = document.createElement('meta');
		viewport.setAttribute('name', 'viewport');
		viewport.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no' + (/android/i.test(ua) && /zol/i.test(ua) ? ', target-densitydpi=device-dpi' : ''));
		rootElement.firstElementChild.appendChild(viewport);
	} else {
		// 如果已有viewport 将根据初始化缩放比例来;没有按照计算的来
		var initScale = viewport.getAttribute('content').match(/initial\-scale=([^\,$]+)/);
		initScale && (scale = parseFloat(initScale[1]), dpr = parseInt(1 / scale))
	}

	// 将window.dpr设为只读
	Object.defineProperty(window, 'dpr', {
		value: dpr,
		writable: !1
	});

	// 处理resize的情况
	W.addEventListener('resize', function() {
		clearTimeout(timer), timer = setTimeout(initialRem, 300)
	}, false);

	// 处理bfcache的情况,UC等浏览器下存在
	W.addEventListener('pageshow', function(e) {
		e.persisted && (clearTimeout(timer), timer = setTimeout(initialRem, 300))
	}, false);


	// 重置字体方法,主要用于初始化处理和通过ajax动态写入部分的字体处理,只接受一个参数,即需要处理模块,缺省默认为body;
	// 这个方法只是一个临时性的,以后将全部采用react的方式,不在使用此方式进行处理
	W.setupFontSize = function(a) {
		2 !== W.dpr && (a || (a = document.body), a = a.querySelectorAll("[data-changed]"), [].forEach.call(a, function(a) {
			if (!a.style.fontSize) {
				var b = +getComputedStyle(a)["font-size"].replace(/px/, "");
				a.style.fontSize = b / 2 * window.dpr + "px"
			}
		}))
	};
	initialRem();
	setZolParams(zolDesignParams);
	
	var ondocumentReady = function() {
		setupFontSize();
	}
	// 设置字体大小
	document.readyState === 'complete' ? ondocumentReady() : document.addEventListener('DOMContentLoaded',ondocumentReady , false);
	
	
}(window);
rem解决方案

使用bind代理并扩展console.log

使用bind代理并扩展console.log

var log = (function(a) {
	return console.log.bind(console, arguments[0]);
})('app')
log([123123131], 1);

在EcmaScript5中扩展了叫bind的方法(IE6,7,8不支持),使用方法如下:

function T(id) {
	this.id = "Object";
	this.dom = document.getElementById(id);
	this.init && this.init();
}
T.prototype = {
	init: function() {    
		this.dom.onmouseover = function() {
			//this指向dom
			console.log("Over-->" + this.id);
		}
		this.dom.onmouseout = function() {
			//this指向此对象的实例化t
			console.log("Out -->" + this.id);
		}.bind(this)
	}
};
var t = new T('mulianju') //页面中存在的Id;

bind call 和apply 的区别:

http://www.cnblogs.com/jingwhale/p/4604917.html?utm_source=tuicool&utm_medium=referral

使用bind代理并扩展console.log

javascript获取地址栏参数的3种方法

本文列举了用javascript获取地址栏参数的三种方法:

方法一:

String.prototype.getQuery = function(name) {  
	var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
	var r = this.substr(this.indexOf("?")+1).match(reg);
	if (r!=null) return unescape(r[2]); return null;
}  
var strHref = "www.eyezip.com/index.htm?a=aaa&b=bbb&c=ccc";
alert(strHref.getQuery("a"));
alert(strHref.getQuery("b"));
alert(strHref.getQuery("c"));

方法二:

function getUrlPara(paraName){  
	var sUrl  =  location.href; 
	var sReg  =  "(?:\?|&){1}"+paraName+"=([^&]*)" 
	var re=new RegExp(sReg,"gi"); 
	re.exec(sUrl); 
	return RegExp.$1; 
} 
//应用实例:test_para.html?a=11&b=22&c=33 
alert(getUrlPara("a")); 
alert(getUrlPara("b")); 

方法三:

function Request(strName){  
	var strHref = "www.eyezip.com/index.htm?a=aaa&b=bbb&c=ccc";
	var intPos = strHref.indexOf("?");
	var strRight = strHref.substr(intPos + 1);
	var arrTmp = strRight.split("&");
	for(var i = 0; i < arrTmp.length; i++) {
		var arrTemp = arrTmp[i].split("=");
		if(arrTemp[0].toUpperCase() == strName.toUpperCase()) return arrTemp[1];
	}  
	return "";
}  
alert(Request("a"));
alert(Request("b"));
alert(Request("c"));
javascript获取地址栏参数的3种方法

上半个月做的一个移动端整站项目–zol攒机

项目地址:m.zol.com.cn/cuanji/

项目难点:这个项目用到很大量的ajax、移动端很恶心的标签滑动切换(因为影响到容器的高度)、多标签的滚动加载(同一个页面 多个标签,每个标签单独加载)…

解决方案:其实最麻烦的就是多标签的滚动加载,我这里用到也不是什么特别高深的技术,只不过涉及到一点思想上的问题。

我的处理方式很傻瓜,声明一个全局变量(或者window对象的一个公开属性),用来存放当前显示的标签节点,这个节点就是对应标签内容的容器,我会把所有的相关参数,方法什么的一股脑都添加到这个节点的属性里,这样在切换标签的时候,只要获取到当前显示的标签,就能拿到所有的东西了,就像是把节点当成一种接口的思想~

上半个月做的一个移动端整站项目–zol攒机

分享一个viewport自动设置的方式

if (/Android (d+.d+)/.test(navigator.userAgent)) {
	var version = parseFloat(RegExp.$1);
	if (version > 2.3) {
		var phoneScale = parseInt(window.screen.width) / 640;
		document.write('<meta name="viewport" content="width=640, minimum-scale = ' + phoneScale + ', maximum-scale = ' + phoneScale + ', target-densitydpi=device-dpi">');
	} else {
		document.write('<meta name="viewport" content="width=640, target-densitydpi=device-dpi">');
	}
} else {
	document.write('<meta name="viewport" content="width=640, user-scalable=no, target-densitydpi=device-dpi">');
}
分享一个viewport自动设置的方式