[ Content | Sidebar ]

Archives for web dev

ubuntu上flex开发相关

最近项目需要用到flex, 于是我要学这个本不打算学的东西…

我的环境很简单 flex sdk 4.0 + vim

sdk的安装参考 : http://blog.minidx.com/2008/05/17/853.html

flex的Makefile参考 : http://www.mindlence.com/WP/?p=301

编写好Makefile之后,就可以在vim里通过:make命令编译当前项目

vim的as和mxml语法高亮: http://www.fireyang.com/blog/?p=115

最后是我自己加的自动补全的字典(从flex4的文档里扣出来的….)

"将字典文件放到相应的目录就可以了,这里是~/.vim/as3_dict.txt
au FileType actionscript call AddAS3Dict()
function AddAS3Dict()
    set dictionary-=~/.vim/as3_dict.txt dictionary+=~/.vim/as3_dict.txt
    set complete-=k complete+=k
endfunction
Copy Code 

字典文件下载 : as3_dict
这个字典有9K多行,应该够用了…

初学的一点感觉:
虽然actionscript3已经远离了js的语法,但仍然是事件驱动的,所以对熟悉js开发的同学来说,flex很容易上手. 另一点感受是我再也不用考虑狗屁浏览器兼容性了..

最最后最近阅文档无数的终极结果,我的第一个flex半成品 : http://bluehua.org/demo/avatar-editor/

发个套页面的辅助工具

2010.4.22 使用vim的同学可以这样

command -nargs=0 HTML2Array :call HTML2Array()
function HTML2Array()
    exe("'<,'>s/\"/\\\\\"/g")
    exe("'<,'>s/^/\"/")
    exe("'<,'>s/$/\",/")
    exe("'<,'>g/^\"[\\t ]*\",$/d")
endfunction
Copy Code 

先用=排版命令对html排版,然后选中,:HTML2Array就可以了
———————————————–
jser套的页面一般是这样的

var html = [
//....
"            <div  class=\"right\">\n",
"                <div>\n",
"                    <span>\n",
"                        <input name=\"a\" type=\"text\" />\n",
"                    </span>\n",
"                    <span>\n",
"                        <input name=\"b\" type=\"text\" />\n",
"                    </span>\n",
"                </div>\n",
"                <div>\n",
"                    <input name=\"c\" type=\"text\" />\n",
"                </div>\n",
"                <div>\n",
"                    <input name=\"d\" type=\"text\" />\n",
"                </div>\n",
"            </div>\n",
//....
].join('');
Copy Code 

以前偶都是一点一点手工拼接的,今天抽时间写了段python,可以辅助一下~

#可以生成上面形式的字符串
cat tmp.html | python html2js.py
#或者生成 "abcd" + 这种字符串拼接的形式
cat tmp.html | python html2js.py --string
Copy Code 

脚本下载 : html2js.0.1

测试环境: ubuntu 9.10 python 2.6.4

wordpress api的js实现版本

2012 4.4第二版 (感谢kmvan的宝贵意见:))
主要做了以下修改:
1. 修正在回调中remove注销自己时会出问题
2. 支持add_action(‘ac1|ac2′, func);的方式一次添加多个action
3. filter也可以传递额外参数

(function(ns)
{
    var filters = {};
    var max_priority = 10;
    var default_priority = 10;
 
    var each = function(a, cb) {
        a = a.concat([]);
        for (var i = 0, j = a.length; i < j; i ++) {
            if (cb && cb(i, a[i]) === false) break;
        }
    };
 
    var array_include = function(a, v) {
        for (var i = 0, j = a.length; i < j; i ++)
            if (a[i] === v) return true;
 
        return false;
    };
 
    var to_array = function(a) {
        var rt = [];
        for (var i = 0, j = a.length; i < j; i ++) {
           rt.push(a[i]); 
        }
        return rt;
    };
 
    function _set(func, tag, priority, key, value) {
        func['__filter_' + tag + '_' + priority + '_' + key] = value; 
    }
 
    function _get(func, tag, priority, key) {
        return func['__filter_' + tag + '_' + priority + '_' + key]; 
    }
 
    ns.add_filter = ns.add_action = function(tag, func, priority, run_once) {
        run_once = typeof run_once === 'undefined' ? false : run_once;
        priority = priority || default_priority; 
        each(tag.split('|'), function(i, tag) {
            if (!filters[tag]) filters[tag] = {};   
            if (!filters[tag][priority]) filters[tag][priority] = [];
            if (!array_include(filters[tag][priority], func)) {
                filters[tag][priority].push(func);
            }
 
            _set(func, tag, priority, 'run_once', run_once); 
        });
    };
 
    ns.remove_filter = ns.remove_action = function(tag, func, priority, run_once) {
        priority = priority || default_priority;
        each(tag.split('|'), function(i, tag) {
            if (!filters[tag]) return;
            if (!filters[tag][priority]) return;
            var funcs = filters[tag][priority]; 
            each(funcs, function(i, f) {
               if (f === func)
                    funcs.splice(i, 1);
            });
        });
    };
 
    ns.add_once_filter = ns.add_once_action = function(tag, func, priority) {
        ns.add_filter(tag, func, priority, true);
    };
 
    function filter_or_action(ac, tag, value) {
        if (!filters[tag]) return value;
 
        var args = to_array(arguments);
        args.shift();args.shift();
 
        if (ac === 'filter') args.shift();
 
        var _cfs = filters[tag];
        var i = 1, func, funcs; 
        var rt = value;
        var breaked = false;
        while ( i <= max_priority ) {
            funcs = _cfs[i];
            if ( !funcs || funcs.length === 0 ) {
                i ++;
                continue;
            }
 
            each(funcs, function(i, func) {
                if (typeof func !== 'function') {
                    return;
                }
 
                if (ac == 'action') {
                    rt = func.apply(null, args);
                } else {
                    rt = func.apply(null, [rt].concat(args));
                }
 
                if (_get(func, tag, i, 'run_once')) {
                    funcs.splice(i, 1);
                } 
 
                if ( rt && rt['end'] ) {
                    rt = rt['value'] || null;
                    breaked = true;
                    return false;
                }
            });
 
            if (breaked) return rt;
            i ++;
        }
        return rt;
    };
 
    ns.apply_filters = function(tag, value) {
        var args = to_array(arguments);
        return filter_or_action.apply(null, ['filter'].concat(args));
    };
 
    ns.do_action = function(tag) {
        var args = to_array(arguments);
        filter_or_action.apply(null, ['action'].concat(args));
    };
})(window);
Copy Code 

————————————
上次提到的一个想法的实现版本,正在应用到偶开发的项目当中~
比wordpress的action和filter增加两个特性

  • 能够添加一个只运行一次的action或者filter
  • 可以通过返回{end:true}这种特殊对象来结束一个action或者filter

这两个特性在web开发里灰常有用

<html>
<script>
//2010.4.10 第一版
(function(ns)
{
    var filters = {};
    var max_priority = 10;
    var default_priority = 10;
 
    var array_include = function(a, v)
    {
        for ( var i = 0, j = a.length; i < j; i ++ )
        {
            if ( a[i] == v ) return true;
        }
        return false;
    };
 
    var to_array = function(a)
    {
        var rt = [];
        for ( var i = 0, j = a.length; i < j; i ++ )
        {
           rt.push(a[i]); 
        }
        return rt;
    };
 
    function _set(func, tag, priority, key, value)
    {
        func['__filter_' + tag + '_' + priority + '_' + key] = value; 
    }
 
    function _get(func, tag, priority, key)
    {
        return func['__filter_' + tag + '_' + priority + '_' + key]; 
    }
 
    ns.add_filter = ns.add_action = function(tag, func, priority, run_once) 
    {
        run_once = run_once === undefined ? false : run_once;
        priority = priority || default_priority; 
        if ( !filters[tag] ) filters[tag] = {};   
        if ( !filters[tag][priority] ) filters[tag][priority] = [];
        if ( !array_include(filters[tag][priority], func) )
        {
            filters[tag][priority].push(func);
        }
 
        _set(func, tag, priority, 'run_once', run_once);
    };
 
    ns.add_once_filter = ns.add_once_action = function(tag, func, priority)
    {
        ns.add_filter(tag, func, priority, true);
    };
 
    function filter_or_action(ac, tag, value)
    {
        if (!filters[tag]) return value;
        if ( ac == 'action' )
        {
            var args = to_array(arguments);
            args.shift();
            args.shift();
        }
        var _cfs = filters[tag];
        var i = 1, func; 
        var rt = value;
        while ( i <= max_priority )
        {
            if ( !_cfs[i] || _cfs[i].length === 0 ) 
            {
                i ++;
                continue;
            }
 
            for ( var j = 0, length = _cfs[i].length; j < length; j ++ )
            {
                func = _cfs[i][j];
 
                if ( ac == 'action' )
                {
                    rt = func.apply(null, args);
                }
                else
                {
                    rt = func.call(null, rt);
                }
 
                if ( _get(func, tag, i, 'run_once') ) 
                {
                    _cfs[i].splice(j, 1);
                    j --;
                    length --;
                }
                if ( rt && rt['end'] ) return rt['value'] || null;
            }
 
            i ++;
        }
        return rt;
    };
 
    ns.apply_filters = function(tag, value)
    {
        return filter_or_action('fitler', tag, value)
    };
 
    ns.do_action = function(tag)
    {
        var args = to_array(arguments);
        filter_or_action.apply(null, ['action'].concat(args));
    };
})(window)
 
function log(str)
{
    document.write('<p>' + str + '</p>');
}
 
//普通的filter
add_filter('status', function(text)
{
    return text.replace(/orz/g, '超人');
});
log(apply_filters('status', 'orzorz'));
//再添加一个filter
add_filter('status', function(text)
{
    return text.replace('超人', '动感');
});
log(apply_filters('status', 'orzorz'));
 
//添加一个优先级较高的filter,并通过返回包含end字段的对象结束过滤器
add_filter('status', function(text)
{
    return {end:true, value:text};
}, 5);
log(apply_filters('status', 'orzorz'));
 
//但是下面这个优先级较高的会执行
add_filter('status', function(text)
{
    return text + '管不着我';
}, 1);
log(apply_filters('status', 'orzorz'));
 
log('-----------------------------');
log('action测试');
log('-----------------------------');
 
//下面是action
add_action('ac_success', function(a, b, c)
{
    log('返回数据:' +  a + b + c); 
});
 
//添加一个只会执行一次的action回调
add_once_action('ac_success', function(a, b, c)
{
    log('我只会执行一次的');
});
 
add_action('ac_success', function(a, b, c)
{
    log('俺的优先级比较高');
}, 5);
 
log('----------第一次执行----------------');
do_action('ac_success', '1', '2', '3');
 
log('----------第二次执行----------------');
do_action('ac_success', '4', '5', '6');
 
add_action('ac_success', function(a, b, c)
{
    log('全部屏蔽');
    return {end:true}; 
}, 1);
 
log('----------第三次执行----------------');
do_action('ac_success', '1', '2', '3');
</script>
</html>
Copy Code | Run Code

例举js中组装类的好处

先举个简单的组装的例子

//纸
var paper = new Paper();
//处理下
enable_fire_destory(paper);
//ok,可以燃烧了..
paper.fire();
//猪
var pig = new Pig();
enable_fire_destory(pig);
//不管怎么着,也能着了
pig.fire();
Copy Code 

这种组装方式用于给毫不相关的对象快速添加一些通用的方法, 用法得当将节省大量代码~

这里举个实际开发中的例子,下面的代码肯定是我们平时经常写的,用于防止一次ajax请求没有完毕就请求第二次

obj = {
....
is_loading : false,
load_sth : function(callback)
{
    if ( this.is_loading ) return;
    this.is_loading = true;
    new Ajax({
        url : 'xxx.php',
        onComplete : function()
            This.is_loading = false;
        }});
    });
},
....
};
Copy Code 

使用组装的方法改写

//组装函数
function enable_single_thread_ajax(obj)
{
    extend(obj, {
        _is_ajax_ing : false,
        is_ajax_ing : function()
        {
            return this._is_ajax_ing;
        },
        ajax : function(params)
        {
            if (this.is_ajax_ing()) return;
            var This = this;
            this._is_ajax_ing = true;
 
            var _tmp_func = function(){};
 
            //为了保持ajax的参数不变,要做点小牺牲
            if (params['onComplete'])
            {
                _tmp_func = params['onComplete'];
            }
 
            params['onComplete'] = function()
            {
                This._is_ajax_ing = false; 
                _tmp_func.apply(this, arguments);
            };
 
            return Ajax(params);
        }
    });
}
 
//还是那个对象 
obj = { 
load_sth : function()
{
    //打完收工了~
    this.ajax({
        url : 'xxx.php'
    });
}   
};
//给对象扩充方法
enable_single_thread_ajax(obj);
Copy Code 

还可以直接扩展原型,达到扩充类的目的~,以前写过一篇自定义事件的文章,也是用的这种方法 : 简单实现js里的自定义事件

今天特地翻开没怎么看的<javascript设计模式>,里面定义这种扩展方式为”掺元类”,感觉这么翻译不是特好理解…

给图片定宽高减少reflow的一个想法

近期的前端优化主要集中在提高渲染速度,回家在公车上想的一个方案:
————————-
页面渲染慢最重要的一个原因就是reflow, 而造成reflow的主要有两大块: 图片和javascript的dom操作,这里主要说图片.未指明宽高的图片,在页面dom渲染完毕时没有加载媒体时宽高是0×0,当一张图片加载完毕,就不得不重新渲染图片宽高变化所影响的区域.

解决这个问题的最佳效果就是给每张图片定宽定高:

<img width="300" height="200" src="abc.gif" />
Copy Code 

问题: 做页面的同学可以给自己切的图定宽高,但是用户上传的图片呢? 新鲜事里充斥了大量用户上传的图片~

参考解决方案:
这个方案的缺点就是需要一个良好的图片存储初期设计…
比如这是一个普通的图片上传后的地址

fmn041/20100302/2155/p_main_y8Hj_3b9e0000134b2d10.jpg

而这个方案需要在图片上传时就将宽度信息写到图片名称里,让使用它的cgi, httpd, javascript都能看名字就能知道它的三围

fmn041/20100302/2155/p_main_y8Hj_3b9e0000134b2d10_300_500.jpg

然后使用时就很灵活了

//对于新鲜事,使用自己的处理函数
<img width="<?php echo get_img_width($url) ?> height="<?php echo get_img_height($url) ?>" src="<?php echo $url?>" />
Copy Code 

而对于日志,帖子内容里的图片则需要输出过滤,给图片加宽高,或者是在发表阶段就通过js定宽高

//smarty里的输出过滤器
$smarty->load_filter('output', 'image_url_filter');
Copy Code 

cgi层过滤的话就不能及时flush输出,所以可以放到apache做http://httpd.apache.org/docs/2.2/filter.html

已有巨大量数据转换图片命名方案也是一件棘手的事….