如何写出坚实稳定的Ajax代码
发布于 2个月前 作者 tulayang 2345 次浏览 来自 分享
47 回复

感觉与其说是Ajax代码,不如说就是jQuery或者前端代码,和Ajax没啥关系。

楼主说的是事件代理吧,还有更高效的方法。

首先事件绑定在document上是没有问题的,然后触发事件后能够取到点击的元素,然后向上冒泡式的去判断dom元素上是否有需要事件处理的标记属性。当然需要部分代码来实现这个机制。我翻了一个之前同是写的一个库:https://github.com/zinkey/YayaEvent

额… 楼主,你可能弄错了ajax跟事件委托了,感觉你讲的是事件委托…

我讲的就是ajax,并不一定要写一个完整的jax。 当你写富ajax组件的时候,就会碰到了。

首先需要搞清楚ajax的目的,而不是接口如何调用。

其实可不可以不绑定document,而是绑定.remove和.append的最近公共父节点? 比如

<div class='items'>
<ul>
  <li>
    <button class="remove">x</button>[input] [input]
  </li>
</ul>
<button class="append">+</button>
</div>

绑定到.items上面

@spacewander

这就是本文所提议反对的。除了document这个主节点,其他的节点你都会面临未来改变的风险。

这会让你的模型结构变得难以修改,难以扩展,难以重用。

@tulayang 点赞,这才是我对这篇文章的理解0 0

其实绑定在接近目标元素的父级元素也是可以的

改标题吧, 楼上几位说的对, 本文内容和ajax毫无关系 这文章能加精我也是醉了 不过还是要感谢楼主分享前端JS的基础知识

@anubiskong

我在5楼说过了, 等你再写点ajax代码, 会知道这篇文章是ajax的核心内容.

当你使用ajax渲染大量的富组件的时候, 并且这些渲染的组件具有强大的事件功能的时候, 正是这篇文章的关注点.

你在文字中没有看到ajax, 那是因为我已经把无关重点的内容甩开了.

@tulayang 既然如此,你这篇文章也写得太含糊了。 建议楼主完善一下文章,让大家能明白你到底想表达什么意思。 为什么非让人猜呢?

@tulayang 孩子, 你写这个知识点的时候, 就已经说明你是前端新手了, 我5年前端经验不是你说的需要"再写点ajax代码"的那种人. 多年以后, 等你成为"不必再写点ajax代码"那种人的时候, 你会明白这篇帖子有多尴尬. 劝你能改标题还是改了吧, 做程序员要有这种纠错思维, 你在明显的错误面前继续纠缠下去只能说明你情商低.

@anubiskong

5年?! 就你这点狗P经验跟我这装比, 我刚玩编程的时候你还穿开裆裤呢.

我柜子里的书, 都比你高了.

不懂ajax, 就别在这跟我叽歪. 没有写过富客户端bibi个蛋.

@norfish 这文章是给富客户端程序员写的, 你看不懂就看不懂吧

@anubiskong

就你那文字里的js水平, 你哪来的脸跟我嘚瑟. 我年龄都能当你叔叔了.

算了, 不想打击楼主, 你慢慢搞吧, 这种小学生东西也拿出来发? 难道jQuery的live事件不就是用来解决这种问题的么! 还想说一句, 这都加精, @alsotang你眼瞎了么

@xujun52011

你是脑残吗? 还live, live已经被作者提出禁止使用.

就你这水平, 看不懂就别tm bb.

老子给你贴个多的, 你 tmb 看得懂吗???

(function ($, PAGELET) {
'use strict';

function renderSelect($article, options) {
    $article.html(PAGELET.render('/sections/select.tpl', options, {
        which: PAGELET.tpl('/which.tpl'),
        tables: PAGELET.tpl('/tables.tpl'),
        tablesAll: PAGELET.tpl('/tablesAll.tpl'),
        fields: PAGELET.tpl('/fields.tpl'),
        conditions: PAGELET.tpl('/conditions.tpl'),
        defaultconditions: PAGELET.tpl('/defaultconditions.tpl')
    }));
}

function renderAjax($article, options) {
    $article.html(PAGELET.render('/sections/ajax.tpl', options, {
        which: PAGELET.tpl('/which.tpl'),
        tables: PAGELET.tpl('/tables.tpl'),
        tablesAll: PAGELET.tpl('/tablesAll.tpl'),
        fields: PAGELET.tpl('/fields.tpl'),
        conditions: PAGELET.tpl('/conditions.tpl'),
        defaultconditions: PAGELET.tpl('/defaultconditions.tpl')
    }));
}

function renderSave($article, options) {
    $article.html(PAGELET.render('/sections/save.tpl', options, {
        which: PAGELET.tpl('/which.tpl'),
        tables: PAGELET.tpl('/tables.tpl'),
        tablesAll: PAGELET.tpl('/tablesAll.tpl'),
        fields: PAGELET.tpl('/fields.tpl')
    }));
}

function serializeSelect($sections) {
    var data = {};
    $sections.toArray().map(function (section) {
        var $section = $(section),
            spans = $section.find('.tables .box span').toArray(),
            fieldsLis = $section.find('.fields li').toArray(),
            conditionsLis = $section.find('.conditions li').toArray(),
            defaultconditionsLis = $section.find('.defaultconditions li').toArray(),
            id = $section.find('.id').val();
        data[id] = {};
        data[id].tables = spans.length > 0 ? spans.map(function (span) {
            return span.getAttribute('data-value');
        }).join(',') : '';
        data[id].fields = {};
        if (fieldsLis.length > 0) {
            fieldsLis.forEach(function (li) {
                var $li = $(li),
                    asfield = $li.find('.asfield').val(),
                    table = $li.find('.table').val(),
                    field = $li.find('.field').val();  
                data[id].fields[asfield] = table + '.' + field;
            });
        }
        data[id].conditions = {};
        if (conditionsLis.length > 0) {
            conditionsLis.forEach(function (li) {
                var $li = $(li),
                    asfield = $li.find('.asfield').val(),
                    flag = $li.find('.flag').val(),
                    table = $li.find('.table').val(),
                    field = $li.find('.field').val();  
                data[id].conditions[asfield] = {
                    name: table + '.' + field,
                    flag: flag
                };
            });
        }
        data[id].defaultconditions = {};
        if (defaultconditionsLis.length > 0) {
            defaultconditionsLis.forEach(function (li) {
                var $li = $(li),
                    value = $li.find('.value').val(),
                    flag = $li.find('.flag').val(),
                    table = $li.find('.table').val(),
                    field = $li.find('.field').val();  
                data[id].defaultconditions[table + '.' + field] = {
                    value: value,
                    flag: flag
                };
            });
        }  
    });
    return JSON.stringify(data, null, 4);
}

function serializeSave($sections) {
    var data = {};
    $sections.toArray().map(function (section) {
        var $section = $(section),
            fieldsLis = $section.find('.fields li').toArray(),
            id = $section.find('.id').val(),
            name = $section.find('.name').val(),
            point = $section.find('.id').val();
        data[id] = {};
        data[id].name = name;
        data[id].point = point;
        data[id].fields = {};
        if (fieldsLis.length > 0) {
            fieldsLis.forEach(function (li) {
                var $li = $(li),
                    asfield = $li.find('.asfield').val(),
                    table = $li.find('.table').val(),
                    field = $li.find('.field').val();  
                data[id].fields[asfield] = table + '.' + field;
            });
        }
    });
    return JSON.stringify(data, null, 4);
}

function getpage($article, pathname, confname, tablesAll, callback) {
    $.get('/design/' + pathname + '/' + confname, function (result) {
        var config = result.config,
            options = {};
        options[result.confname.replace(/\-config\.json$/, '')] = true;
        options.tablesAll = tablesAll;
        options.config = result.config;
        options.hrefInitpage = 'initpage-config.json';
        options.hrefSearch = 'search-config.json';
        options.hrefAjax = 'ajax-config.json';
        options.hrefMgsave = 'mgsave-config.json';
        options.hrefMsave = 'msave-config.json';
        options.hrefMisave = 'misave-config.json';
        if (confname === 'initpage-config.json' || 
            confname === 'search-config.json') {
            renderSelect($article, options);
        } else if (confname === 'ajax-config.json') { 
            renderAjax($article, options);
        } else if (confname === 'mgsave-config.json' || 
                   confname === 'msave-config.json' || 
                   confname === 'misave-config.json') {
            renderSave($article, options);
        }
    });
}
    
window.onload = function () {
    var $document = $(document),
        $article = $('#main > article'),
        pathname = '',
        confpath = '',

        // 数据库表格
        tablesAll = ['-- 表格 --'].concat(JSON.parse(decodeURIComponent($('#main').data('tablesall')))),
        fieldsMap = JSON.parse(decodeURIComponent($('#main').data('fieldsmap')));

    Object.keys(fieldsMap).forEach(function (key) {
        fieldsMap[key] = ['-- 字段 --'].concat(fieldsMap[key]);
    });

    $document.on('click', '#main > .append', function (e) {
        if (confpath === 'initpage-config.json' || 
            confpath === 'search-config.json') { console.log(111);
            $article.append(PAGELET.render('/sections/select.tpl', {
                config: {},
                tablesAll: tablesAll
            }, {
                tables: PAGELET.tpl('/tables.tpl'),
                tablesAll: PAGELET.tpl('/tablesAll.tpl'),
                fields: PAGELET.tpl('/fields.tpl'),
                conditions: PAGELET.tpl('/conditions.tpl'),
                defaultconditions: PAGELET.tpl('/defaultconditions.tpl')
            }));
        } else if (confpath === 'ajax-config.json') {

        } else if (confpath === 'mgsave-config.json' || 
                   confpath === 'msave-config.json' ||
                   confpath === 'misave-config.json') { 
            $article.append(PAGELET.render('/sections/save.tpl', {
                config: {},
                tablesAll: tablesAll
            }, {
                fields: PAGELET.tpl('/fields.tpl')
            }));
        } 
    });
    $document.on('click', 'section > .remove', function (e) {
        var $section = $(this).parent('section'),
            $article = $section.parent('article');
        $article[0].removeChild($section[0]);
    }); 


    $document.on('click', '.tables select option', function (e) {
        var $option = $(this),
            $box = $option.parent('select').siblings('.box'),
            val = $option.val();
        $box.append(PAGELET.render('/tables.tpl', { tables: [val] }));
    });
    $document.on('click', '.tables .box span', function (e) {
        var $span = $(this),
            $box = $span.parent('.box');
        $box[0].removeChild($span[0]);
    });


    $document.on('click', '.fields .append', function (e) {
        var $ul = $(this).prev('ul');
        $ul.append(PAGELET.render('/fields.tpl', { 
            fields: { tablesAll: tablesAll }
        }, {
            tablesAll: PAGELET.tpl('/tablesAll.tpl')
        }));
    });
    $document.on('click', '.fields .remove', function (e) {
        var $li = $(this).parent('li'),
            $ul = $li.parent('ul');
        $ul[0].removeChild($li[0]);
    });   

    $document.on('click', '.conditions .append', function (e) {
        var $ul = $(this).prev('ul');
        $ul.append(PAGELET.render('/conditions.tpl', { 
            conditions: { tablesAll: tablesAll }
        }, {
            tablesAll: PAGELET.tpl('/tablesAll.tpl')
        }));
    });
    $document.on('click', '.conditions .remove', function (e) {
        var $li = $(this).parent('li'),
            $ul = $li.parent('ul');
        $ul[0].removeChild($li[0]);
    });  

    $document.on('click', '.defaultconditions .append', function (e) {
        var $ul = $(this).prev('ul');
        $ul.append(PAGELET.render('/defaultconditions.tpl', { 
            defaultconditions: { tablesAll: tablesAll }
        }, {
            tablesAll: PAGELET.tpl('/tablesAll.tpl')
        }));
    });
    $document.on('click', '.defaultconditions .remove', function (e) {
        var $li = $(this).parent('li'),
            $ul = $li.parent('ul');
        $ul[0].removeChild($li[0]);
    });


    $document.on('click', '.tablesAll option', function (e) {
        var $option = $(this),
            $select = $option.parent('select'),
            $fieldsAll = $select.next('.fieldsAll'),
            $table = $select.siblings('.table'),
            $field = $select.siblings('.field'),
            val = $option.val(); 
        $fieldsAll.html(PAGELET.render('/select.tpl', { vals: fieldsMap[val] }));
        $table.val(val);
        $field.val('');
    });
    $document.on('click', '.fieldsAll option', function (e) {
        var $option = $(this),
            $select = $option.parent('select'),
            $field = $select.siblings('.field');
        $field.val($option.val());
    });


    $document.on('change', '.tablesAll', function (e) {
        var $tablesAll = $(this),
            $fieldsAll = $tablesAll.next('.fieldsAll'),
            $table = $tablesAll.siblings('.table'),
            $field = $tablesAll.siblings('.field'),
            val = $tablesAll.val(); 
        $fieldsAll.html(PAGELET.render('/select.tpl', { vals: fieldsMap[val] }));
        $table.val(val);
        $field.val('');
        if (val === '-- 表格 --') {
            $fieldsAll.removeClass('active');
        } else {
            $fieldsAll.addClass('active');
        }
    });
    $document.on('change', '.fieldsAll', function (e) {
        var $fieldsAll = $(this),
            $field = $fieldsAll.siblings('.field');
        $field.val($fieldsAll.val());
    });

    $document.on('click', '.dir', function (e) {
        var $lidir = $(this),
            $lidirs = $('.dir').not($lidir);
        $lidirs.removeClass('active');
        $lidir.toggleClass('active');
    });

    $document.on('click', '.link a', function (e) {
        var $a = $(this),
            $as = $('.link a');
        confpath = 'initpage-config.json';
        pathname = $a.data('href');
        $as.removeClass('active');
        $a.addClass('active');    
        getpage($article, pathname, confpath, tablesAll);
    });
    $document.on('click', 'header a', function (e) {
        var $a = $(this);
        confpath = $a.data('href');
        getpage($article, pathname, confname, tablesAll);
    });

    $document.on('click', '.save', function (e) {
        var result = null;
        if (confpath === 'initpage-config.json') {
            result = serializeSelect($('section'));
            $.post('/design/' + pathname + '/' + confpath, 'data=' + result, function (result) {
                // need validate   
            });
        } else if (confpath === 'search-config.json') { 
            result = JSON.stringify(JSON.parse(serializeSelect($('section'))).id);
            $.post('/design/' + pathname + '/' + confpath, 'data=' + result, function (result) {
                // need validate   
            });
        } else if (confpath === 'mgsave-config.json' || 
                   confpath === 'msave-config.json' || 
                   confpath === 'misave-config.json') {
            result = serializeSave($('section'));
            $.post('/design/' + pathname + '/' + confpath, 'data=' + result, function (result) {
                // need validate   
            });
        } else {
            // need validate   
        }
    });
};
}(jQuery, PAGELET));

@tulayang 楼主你别激动, 事实胜于雄辩, 我可以不"bibi", 你可以发几个你的作品出来, 让大家开开眼 ^_^

@anubiskong

我的作品链接摆在那, 自己不懂link?

我的博客 我的专题 我的GitHub 我最近重写完的编辑器和开发接口

欢迎指教.

我最近写的预编译代码, 不知道入不入得了法眼

var FS = require('fs'),
    PATH = require('path'),
    QHOGAN = require('./lib/qhogan.js'),
    DB = require('./lib/database'),
    searchMaps = require('./conf/search-maps.json'),
    it  = '* {{ID}}\n\n{{tpl}}\n',
    st  = 'exports[\'{{url}}\'] = {{object}};',
    rt  = 'exports[\'{{url}}\'] = {};',
    tnt = 'exports[\'{{url}}\'][\'{{id}}\'] = new QHOGAN.Template({{object}});',
    tgt = 'exports[\'{{url}}\'][\'{{tag}}\'] = {};',
    ttt = 'exports[\'{{url}}\'][\'{{tag}}\'][\'{{id}}\'] = new QHOGAN.Template({{object}});',
    routeTexts = [
        'var MIDDLEWARE = require(\'./middleware\');\n'
    ],
    qtplTexts = ['var QHOGAN = require(\'./qhogan\');\n'],
    qtplLogs = [],
    pathServlet = PATH.join(__dirname, './lib/servlet.js'),
    pathQtpls = PATH.join(__dirname, './lib/qtpls.js'),
    pathQtplsMD = PATH.join(__dirname, './qtpls.md'),
    pathServlets = PATH.join(__dirname, './servlets');

function readSync(paths, i) {
    if (i >= 0 && i < paths.length) {
        var stats = FS.statSync(paths[i]);
        if (stats.isFile()) {
            return readSync(paths, ++i);
        } else if (stats.isDirectory()) {
            var newPaths = FS.readdirSync(paths[i]).map(function (path) {
                return PATH.join(paths[i], path);
            });
            return readSync(paths.slice(0, i).concat(newPaths, 
                                                     paths.slice(i + 1)), 
                            i);
        } else {
            return readSync(paths.slice(0, i).concat(paths.slice(i + 1)), 
                            i);
        }
    } else {
        return paths;
    }
}

function underline(h, text, i, len) { 
    if (i >= 0 && i < len) {
        return underline(h, text + h, ++i, len);
    } else {
        return text += '\n';
    }
}

readSync([pathServlets], 0).forEach(function (path) {
    var urlname = path.replace(pathServlets, ''),
        extname = PATH.extname(urlname),
        content = FS.readFileSync(path),
        config, 
        query;

    if (extname === '.json') {
        urlname = urlname.replace(/\.json$/, '').replace(/\\/g, '/');
        config = JSON.parse(content);
        qtplLogs.push(underline('=', urlname + '\n', 0, urlname.length));
        qtplTexts.push(rt.replace('{{url}}', urlname));
        if (/initpage-config$/.test(urlname)) { 
            Object.keys(config).forEach(function (id) { 
                query = config[id].type ? DB.proCode(config[id].type) : DB.select(searchMaps, config[id]); 
                qtplLogs.push(it.replace('{{ID}}', id)
                                .replace('{{tpl}}', query));
                qtplTexts.push(tnt.replace('{{url}}', urlname)
                                  .replace('{{id}}', id)
                                  .replace('{{object}}', QHOGAN.compile(query, { asString: true })));
            });
        } else if (/search-config$/.test(urlname)) { 
            query = DB.select(searchMaps, config);
            qtplLogs.push(it.replace('{{ID}}', 'id')
                            .replace('{{tpl}}', query));
            qtplTexts.push(tnt.replace('{{url}}', urlname)
                              .replace('{{id}}', 'id')
                              .replace('{{object}}', QHOGAN.compile(query, { asString: true })));
         } else if (/ajax-config$/.test(urlname)) {
            Object.keys(config).forEach(function (tag) {
                qtplLogs.push(underline('-', tag + '\n', 0, tag.length));
                qtplTexts.push(tgt.replace('{{url}}', urlname)
                                  .replace('{{tag}}', tag));
                Object.keys(config[tag]).forEach(function (id) {
                    var query = DB.select(searchMaps, config[tag][id]);
                    qtplLogs.push(it.replace('{{ID}}', id)
                                    .replace('{{tpl}}', query));
                    qtplTexts.push(ttt.replace('{{url}}', urlname)
                                      .replace('{{tag}}', tag)
                                      .replace('{{id}}', id)
                                      .replace('{{object}}', QHOGAN.compile(query, { asString: true })));
                });
            });
        } else if (/msave-config$/.test(urlname)) {
            Object.keys(config).forEach(function (id) {
                query = DB.msave(config[id], id);
                qtplLogs.push(it.replace('{{ID}}', id)
                                .replace('{{tpl}}', query));
                qtplTexts.push(tnt.replace('{{url}}', urlname)
                                  .replace('{{id}}', id)
                                  .replace('{{object}}', QHOGAN.compile(query, { asString: true })));
            });
        } else if (/mgsave-config$/.test(urlname)) {
            query = DB.mgsave(config);
            qtplLogs.push(it.replace('{{ID}}', 'id')
                            .replace('{{tpl}}', query));
            qtplTexts.push(tnt.replace('{{url}}', urlname)
                              .replace('{{id}}', 'id')
                              .replace('{{object}}', QHOGAN.compile(query, { asString: true })));
        } else if (/misave-config$/.test(urlname)) {
            query = DB.misave(config);
            qtplLogs.push(it.replace('{{ID}}', 'id')
                .replace('{{tpl}}', query));
            qtplTexts.push(tnt.replace('{{url}}', urlname)
                .replace('{{id}}', 'id')
                .replace('{{object}}', QHOGAN.compile(query, { asString: true })));
        }
    } else if (extname === '.js') {
        urlname = urlname.replace(/\.js$/, '').replace(/\\/g, '/');
        routeTexts.push(st.replace('{{url}}', urlname)
                          .replace('{{object}}', content));
    }
});

FS.writeFileSync(pathServlet, routeTexts.join('\n'), {encoding:'utf8'});
FS.writeFileSync(pathQtpls,   qtplTexts.join('\n'),  {encoding:'utf8'});
FS.writeFileSync(pathQtplsMD, qtplLogs.join('\n'),   {encoding:'utf8'});

@tulayang 不用看你发的链接了, 就你贴上的那段高大上的代码就说明问题了, 看似很高端的东西让你写这么多行也是醉了. 你去把backbone的源码看看, 对你的提升很大, 那个不多, 认真看的话两天就看完了, 楼主有前途, 继续努力吧. 这个精华帖子快被楼主改成骂人帖了, 我不跟了, 各位随意

@anubiskong

看你妈的比呀, 眼睛瞎呀, 老子贴给你完整代码, 你 magebi 自己看不懂呀??? 还backbone, 你老子都不知道写过多少个backbone这样的框架了.

(function ($, PAGELET) {
'use strict';

function renderSelect($article, options) {
    $article.html(PAGELET.render('/sections/select.tpl', options, {
        which: PAGELET.tpl('/which.tpl'),
        tables: PAGELET.tpl('/tables.tpl'),
        tablesAll: PAGELET.tpl('/tablesAll.tpl'),
        fields: PAGELET.tpl('/fields.tpl'),
        conditions: PAGELET.tpl('/conditions.tpl'),
        defaultconditions: PAGELET.tpl('/defaultconditions.tpl')
    }));
}

function renderAjax($article, options) {
    $article.html(PAGELET.render('/sections/ajax.tpl', options, {
        which: PAGELET.tpl('/which.tpl'),
        tables: PAGELET.tpl('/tables.tpl'),
        tablesAll: PAGELET.tpl('/tablesAll.tpl'),
        fields: PAGELET.tpl('/fields.tpl'),
        conditions: PAGELET.tpl('/conditions.tpl'),
        defaultconditions: PAGELET.tpl('/defaultconditions.tpl')
    }));
}

function renderSave($article, options) {
    $article.html(PAGELET.render('/sections/save.tpl', options, {
        which: PAGELET.tpl('/which.tpl'),
        tables: PAGELET.tpl('/tables.tpl'),
        tablesAll: PAGELET.tpl('/tablesAll.tpl'),
        fields: PAGELET.tpl('/fields.tpl')
    }));
}

function serializeSelect($sections) {
    var data = {};
    $sections.toArray().map(function (section) {
        var $section = $(section),
            spans = $section.find('.tables .box span').toArray(),
            fieldsLis = $section.find('.fields li').toArray(),
            conditionsLis = $section.find('.conditions li').toArray(),
            defaultconditionsLis = $section.find('.defaultconditions li').toArray(),
            id = $section.find('.id').val();
        data[id] = {};
        data[id].tables = spans.length > 0 ? spans.map(function (span) {
            return span.getAttribute('data-value');
        }).join(',') : '';
        data[id].fields = {};
        if (fieldsLis.length > 0) {
            fieldsLis.forEach(function (li) {
                var $li = $(li),
                    asfield = $li.find('.asfield').val(),
                    table = $li.find('.table').val(),
                    field = $li.find('.field').val();  
                data[id].fields[asfield] = table + '.' + field;
            });
        }
        data[id].conditions = {};
        if (conditionsLis.length > 0) {
            conditionsLis.forEach(function (li) {
                var $li = $(li),
                    asfield = $li.find('.asfield').val(),
                    flag = $li.find('.flag').val(),
                    table = $li.find('.table').val(),
                    field = $li.find('.field').val();  
                data[id].conditions[asfield] = {
                    name: table + '.' + field,
                    flag: flag
                };
            });
        }
        data[id].defaultconditions = {};
        if (defaultconditionsLis.length > 0) {
            defaultconditionsLis.forEach(function (li) {
                var $li = $(li),
                    value = $li.find('.value').val(),
                    flag = $li.find('.flag').val(),
                    table = $li.find('.table').val(),
                    field = $li.find('.field').val();  
                data[id].defaultconditions[table + '.' + field] = {
                    value: value,
                    flag: flag
                };
            });
        }  
    });
    return JSON.stringify(data, null, 4);
}

function serializeSave($sections) {
    var data = {};
    $sections.toArray().map(function (section) {
        var $section = $(section),
            fieldsLis = $section.find('.fields li').toArray(),
            id = $section.find('.id').val(),
            name = $section.find('.name').val(),
            point = $section.find('.id').val();
        data[id] = {};
        data[id].name = name;
        data[id].point = point;
        data[id].fields = {};
        if (fieldsLis.length > 0) {
            fieldsLis.forEach(function (li) {
                var $li = $(li),
                    asfield = $li.find('.asfield').val(),
                    table = $li.find('.table').val(),
                    field = $li.find('.field').val();  
                data[id].fields[asfield] = table + '.' + field;
            });
        }
    });
    return JSON.stringify(data, null, 4);
}

function getpage($article, pathname, confname, tablesAll, callback) {
    $.get('/design/' + pathname + '/' + confname, function (result) {
        var config = result.config,
            options = {};
        options[result.confname.replace(/\-config\.json$/, '')] = true;
        options.tablesAll = tablesAll;
        options.config = result.config;
        options.hrefInitpage = 'initpage-config.json';
        options.hrefSearch = 'search-config.json';
        options.hrefAjax = 'ajax-config.json';
        options.hrefMgsave = 'mgsave-config.json';
        options.hrefMsave = 'msave-config.json';
        options.hrefMisave = 'misave-config.json';
        if (confname === 'initpage-config.json' || 
            confname === 'search-config.json') {
            renderSelect($article, options);
        } else if (confname === 'ajax-config.json') { 
            renderAjax($article, options);
        } else if (confname === 'mgsave-config.json' || 
                   confname === 'msave-config.json' || 
                   confname === 'misave-config.json') {
            renderSave($article, options);
        }
    });
}
    
window.onload = function () {
    var $document = $(document),
        $article = $('#main > article'),
        pathname = '',
        confpath = '',

        // 数据库表格
        tablesAll = ['-- 表格 --'].concat(JSON.parse(decodeURIComponent($('#main').data('tablesall')))),
        fieldsMap = JSON.parse(decodeURIComponent($('#main').data('fieldsmap')));

    Object.keys(fieldsMap).forEach(function (key) {
        fieldsMap[key] = ['-- 字段 --'].concat(fieldsMap[key]);
    });

    $document.on('click', '#main > .append', function (e) {
        if (confpath === 'initpage-config.json' || 
            confpath === 'search-config.json') { console.log(111);
            $article.append(PAGELET.render('/sections/select.tpl', {
                config: {},
                tablesAll: tablesAll
            }, {
                tables: PAGELET.tpl('/tables.tpl'),
                tablesAll: PAGELET.tpl('/tablesAll.tpl'),
                fields: PAGELET.tpl('/fields.tpl'),
                conditions: PAGELET.tpl('/conditions.tpl'),
                defaultconditions: PAGELET.tpl('/defaultconditions.tpl')
            }));
        } else if (confpath === 'ajax-config.json') {

        } else if (confpath === 'mgsave-config.json' || 
                   confpath === 'msave-config.json' ||
                   confpath === 'misave-config.json') { 
            $article.append(PAGELET.render('/sections/save.tpl', {
                config: {},
                tablesAll: tablesAll
            }, {
                fields: PAGELET.tpl('/fields.tpl')
            }));
        } 
    });
    $document.on('click', 'section > .remove', function (e) {
        var $section = $(this).parent('section'),
            $article = $section.parent('article');
        $article[0].removeChild($section[0]);
    }); 


    $document.on('click', '.tables select option', function (e) {
        var $option = $(this),
            $box = $option.parent('select').siblings('.box'),
            val = $option.val();
        $box.append(PAGELET.render('/tables.tpl', { tables: [val] }));
    });
    $document.on('click', '.tables .box span', function (e) {
        var $span = $(this),
            $box = $span.parent('.box');
        $box[0].removeChild($span[0]);
    });


    $document.on('click', '.fields .append', function (e) {
        var $ul = $(this).prev('ul');
        $ul.append(PAGELET.render('/fields.tpl', { 
            fields: { tablesAll: tablesAll }
        }, {
            tablesAll: PAGELET.tpl('/tablesAll.tpl')
        }));
    });
    $document.on('click', '.fields .remove', function (e) {
        var $li = $(this).parent('li'),
            $ul = $li.parent('ul');
        $ul[0].removeChild($li[0]);
    });   

    $document.on('click', '.conditions .append', function (e) {
        var $ul = $(this).prev('ul');
        $ul.append(PAGELET.render('/conditions.tpl', { 
            conditions: { tablesAll: tablesAll }
        }, {
            tablesAll: PAGELET.tpl('/tablesAll.tpl')
        }));
    });
    $document.on('click', '.conditions .remove', function (e) {
        var $li = $(this).parent('li'),
            $ul = $li.parent('ul');
        $ul[0].removeChild($li[0]);
    });  

    $document.on('click', '.defaultconditions .append', function (e) {
        var $ul = $(this).prev('ul');
        $ul.append(PAGELET.render('/defaultconditions.tpl', { 
            defaultconditions: { tablesAll: tablesAll }
        }, {
            tablesAll: PAGELET.tpl('/tablesAll.tpl')
        }));
    });
    $document.on('click', '.defaultconditions .remove', function (e) {
        var $li = $(this).parent('li'),
            $ul = $li.parent('ul');
        $ul[0].removeChild($li[0]);
    });


    $document.on('click', '.tablesAll option', function (e) {
        var $option = $(this),
            $select = $option.parent('select'),
            $fieldsAll = $select.next('.fieldsAll'),
            $table = $select.siblings('.table'),
            $field = $select.siblings('.field'),
            val = $option.val(); 
        $fieldsAll.html(PAGELET.render('/select.tpl', { vals: fieldsMap[val] }));
        $table.val(val);
        $field.val('');
    });
    $document.on('click', '.fieldsAll option', function (e) {
        var $option = $(this),
            $select = $option.parent('select'),
            $field = $select.siblings('.field');
        $field.val($option.val());
    });


    $document.on('change', '.tablesAll', function (e) {
        var $tablesAll = $(this),
            $fieldsAll = $tablesAll.next('.fieldsAll'),
            $table = $tablesAll.siblings('.table'),
            $field = $tablesAll.siblings('.field'),
            val = $tablesAll.val(); 
        $fieldsAll.html(PAGELET.render('/select.tpl', { vals: fieldsMap[val] }));
        $table.val(val);
        $field.val('');
        if (val === '-- 表格 --') {
            $fieldsAll.removeClass('active');
        } else {
            $fieldsAll.addClass('active');
        }
    });
    $document.on('change', '.fieldsAll', function (e) {
        var $fieldsAll = $(this),
            $field = $fieldsAll.siblings('.field');
        $field.val($fieldsAll.val());
    });

    $document.on('click', '.dir', function (e) {
        var $lidir = $(this),
            $lidirs = $('.dir').not($lidir);
        $lidirs.removeClass('active');
        $lidir.toggleClass('active');
    });

    $document.on('click', '.link a', function (e) {
        var $a = $(this),
            $as = $('.link a');
        confpath = 'initpage-config.json';
        pathname = $a.data('href');
        $as.removeClass('active');
        $a.addClass('active');    
        getpage($article, pathname, confpath, tablesAll);
    });
    $document.on('click', 'header a', function (e) {
        var $a = $(this);
        confpath = $a.data('href');
        getpage($article, pathname, confname, tablesAll);
    });

    $document.on('click', '.save', function (e) {
        var result = null;
        if (confpath === 'initpage-config.json') {
            result = serializeSelect($('section'));
            $.post('/design/' + pathname + '/' + confpath, 'data=' + result, function (result) {
                // need validate   
            });
        } else if (confpath === 'search-config.json') { 
            result = JSON.stringify(JSON.parse(serializeSelect($('section'))).id);
            $.post('/design/' + pathname + '/' + confpath, 'data=' + result, function (result) {
                // need validate   
            });
        } else if (confpath === 'mgsave-config.json' || 
                   confpath === 'msave-config.json' || 
                   confpath === 'misave-config.json') {
            result = serializeSave($('section'));
            $.post('/design/' + pathname + '/' + confpath, 'data=' + result, function (result) {
                // need validate   
            });
        } else {
            // need validate   
        }
    });
};
}(jQuery, PAGELET));

LZ大神 你的选择器用一个option对象封装起来会比较好 不然万一和外部样式冲突了你是改不动的

@zhounanbin

关于选择器, 几年前, 我就收录过这部分内容, 相信对你的理解有用:

样式系统从最右边的选择符开始向左进行匹配规则。只要当前选择符的左边还有其他选择符,样式系统就会继续向左移动,直到找到和规则匹配的元素,或者因为不匹配而退出。

如果你非常在意页面的性能那千万别使用CSS3选择器。实际上,在所有浏览器中,用 class 和 id来渲染,比那些使用同胞,后代选择器,子选择器(sibling, descendant and child selectors)对页面性能的改善更值得关注。

-safari和webkit的架构师David Hyatt

Google 资深web开发工程师Steve Souders对CSS选择器的效率从高到低做了一个排序:

  1. id选择器(#myid)
  1. 类选择器(.myclassname)
  1. 标签选择器 (div,h1,p)
  1. 相邻选择器(h1+p)
  1. 子选择器(ul < li)
  1. 后代选择器(li a)
  1. 通配符选择器(*)
  1. 属性选择器(a[rel="external"])
  1. 伪类选择器(a:hover,li:nth-child)

@zhounanbin 说的就是这个, 楼主一遍遍的帖他那段代码我都看醉了, 楼主写的代码有一半是字符串, 就这代码是要学学ajax了. 楼主你可以去看看<代码大全>里用数组简化代码的技巧, 对你很有用, 能让你代码行数少2/3, 别生气, 我是真心的在"指导"你!! 还有楼主你什么时候遇到了事件解绑的瓶颈, 然后用jQuery的事件命名空间解决了问题, 可以再发一篇文章, 一定会加精的, 我相信你和版主, 哈哈哈哈哈哈哈哈哈哈 不说了, 我去给前端团队讲需求了, 本来就cnodejs就很少上了, 这两天开眼了, 最近一年不用再来了哈

@anubiskong

楼主写的代码有一半是字符串

字符串? where? 什么是字符串呀!

楼主你可以去看看<代码大全>里用数组简化代码的技巧

我能说再蠢一点吗! 数组的性能, 还有脸用数组呢. 我的代码利用的是预编译的模板.

我想说, 菜鸟, 你懂什么是预编译模板吗???

还有楼主你什么时候遇到了事件解绑的瓶颈, 然后用jQuery的事件命名空间解决了问题

命名空间? 蠢到这种地步了. DOM树查找, 很基本的事情. 需要一一给你普及.

我去给前端团队讲需求了

就你这连常识都不会用, 还带团队, 这是什么水准的公司.

我还想说一句, 你TM连markdown语法都不会用吧, 还有脸带团队.

@tulayang 我实在不想跟你争 你去看看live的源代码, 看看live是怎么实现的, 你在到这来BiBi好么, 每个社区都有几个你这种喷子, 真的不奇怪, 楼主万寿无疆!

@tulayang 孩纸,你肿么爆粗了?

这么复杂的dom操作居然还用jquery写,怎么维护。看得我都醉了。

顺便说一句,楼主不用喷我了,小弟菜鸟一个。

@xujun52011

我实在不想跟你争 你去看看live的源代码, 看看live是怎么实现的, 你在到这来BiBi好么, 每个社区都有几个你这种喷子, 真的不奇怪, 楼主万寿无疆! xujun52011 27楼•18小时前

1.你哥的代码压根不用关心DOM生成事件重新注册,删除销毁事件,没有内存负担。还live! 在商城,社交网站,点赞,观看用户消息,生成大量的新消息框,新点赞按钮,删除一部分按钮,一部分消息框的时候,你就知道哥的代码在讲什么。没事看看书。书犹药也,擅读之可以医愚!!!

2.live存在bug和性能隐患,已经被废弃。(1.7定为过时,1.9删除)

3.哥原生代码也一样写,用jQuery是方便你这种看不懂原生代码者的:

function reg(elem, type, node, f) {
    elem.addEventListener(type, function (e) {
        var nodes = Array.prototype.slice.call(elem.querySeletorAll(node));
        nodes.forEach(function (item) {
            if (item.contains(e.target)) {
                f.call(item, e);
            }
        });
    }, false);
}

reg(document, 'click', '.whosyourdady', function (e) {
    console.log(this);
    console.log(e);
});

so,这篇文章就是给你这种没有常识的菜鸟上的课。

@pynixwang 蠢材一样的话。 亚马逊买本预编译模板的书看看

@tulayang 虽然不知道楼主想表达什么,但是好像很牛B的样子。。。

@pynixwang

一点都不牛B,想表达的是:你应该买本书系统的学习下,整天写码不看书会变的非常愚蠢,而且不利于你的工资进入五位数。

这B论坛, 我想这辈子我也不会再来了, 因为有楼主这样的人存在, jQuery的live就是把事件绑定在document上, 然后依靠事件冒泡, 就你这点本事还跑这来装B, 顺道说一句, 我不是搞前端的, 这不过是我的爱好而已, 只是看不过去此等菜鸟的菜B东西还被加精, 再顺便说一句, 本人工资已经是2倍最小的5位数了.

@xujun52011

live存在bug和性能隐患,已经被废弃。(1.7定为过时,1.9删除)

你 tm是脑残嘛!!!!!!!!!!!!!!要你爹重复多少次!!! 赶快滚你 made比去, 狗篮子, 滚回去多看看书, mgb的白痴!!!

@tulayang 我懒得跟你说, 自己看jquery document, 还有, 别动不动就是看书, 还有, 骂人别带脏字, 显得你很二, 懂不!

This method provides a means to attach delegated event handlers to the document element of a page, which simplifies the use of event handlers when content is dynamically added to a page

我记得jquery有个delegate,这个如何?

@alsotang 处理一下吧,这个对论坛可不是好事

@razor1895 @linmx0130 @yutingzhao1991 @think2011 @tulayang @spacewander @DevinXian @borisyu @anubiskong @norfish @xujun52011 @zhounanbin @chapgaga @pynixwang @imrememberlee @snoopy @ngot

不好意思各位,今天刚看到这个帖子的后续。17楼虽然有人 at 我了,但可能是由于用户名之后没有加空格所以提醒系统没有推送过来。

这个帖子在我看来,偏重事件绑定的知识而非 ajax。之前之所以加了精华,也是因为在 CNode 经常遇到楼主,所以出于信任,简单浏览了一下就加了精。

抛去文章和内容的相关性来说,这个帖子的内容还是有可取之处的。就楼上言词恶劣的争吵来说,我追溯了一下,觉得不是楼主先挑起的,大家都消消气吧。

下次遇到类似情况还请各位及时 at 我一下…

不明觉厉。。

@alsotang 楼上他们各种飙粗话,不文明~,alsotang还被骂吓眼,哈哈~ 另外js是脚本文件,和编译貌似没关系。。

@alsotang 管理员被骂的够惨~~深表同情和慰问^_^

@DoubleSpout @DevinXian 我只是管理社区正常运作而已啊…也很弱势的…他们骂架我也没法做道德仲裁啊不是吗…大家都是成年人…

我是菜鸟,看完评论,说一句话吧,用武术打个比方:相信楼主是个武功高强的人,但是武德这方面需要继续修养。 最近做的项目也涉及到LZ所说的事件代理的问题,看了帖子确实对在写项目代码时有帮助,THX!

回到顶部