首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Qjs直出实现过程

Qjs直出实现过程

作者头像
IMWeb前端团队
发布2019-12-04 10:49:04
3640
发布2019-12-04 10:49:04
举报
文章被收录于专栏:IMWeb前端团队IMWeb前端团队

本文作者:IMWeb 袁飞翔 原文出处:IMWeb社区 未经同意,禁止转载

直出要做什么

在服务端为Qjs填充默认的值,例如

输入:

<div q-text="name"></div>
{"name": "Qjs"}

直出:

<div q-text="name">Qjs</div>

原理

编译阶段处理directives, 输出阶段处理filters对数据取值渲染模板获取到html

编译:

<div q-text="name">Qjs</div>
<div q-class="red: isRed"></div>

处理directives编译成underscore模板:

<div q-text="name"><%= name %></div>
<div q-class="red: isRed" class="<% if (isRed) { %>red<% } %>"></div>

输出:

处理filters, 使用模板函数对数据做渲染

实现

编译阶段虚拟dom的大框架:

编译过程基本都在cheerio建立的虚拟dom上操作, 因此解析Qjs语法等都可以直接复用Qjs的, 只需重写一套directives

q-text

var $ = require('cheerio');
directives.text = function(exp) {
    $(this.el).html('{{- __filterValue(__obj, {}) }}');
}
<div q-text="list | length"></div>

获得的模板

<div q-text="list | length"><%- __filterValue(__obj, {"arg":null,"name":"list","filters":[["length"]]}) %></div>

q-show

var $ = require('cheerio');
directives.show = function(exp) {
    $(this.el).css('__tplstrings1', 0);
}
var tpl = dom.toString().replace('__tplstrings1', '<% if (__filterValue()) { %>display:block;<% } %>');

先添加一个无用的style,之后替换成想要的

子模块:

q-vm在编译阶段只简单地植入一个变量

<div q-vm="head_module"><%= _vm[0] %></div>

在输出阶段,先获取子模块的html, 而后放入数据中渲染

var output = compiled(_.extend({}, data, {
    _vm: '<div>head_module</div>'
}});

filters异常:

filter复用浏览器端的, 但某些filter是无法正常运行的, 例如

filters.width = function(val) {
    return Match.min(val, $(window).width());
};

因此必须考虑无法兼容的问题:

function __filterValue(data, exp) {
    var root = data[exp.name];
    var name, args;
    for (var i = 0; i < exp.filters.length; i++) {
        try {
            name = exp.filters[i][0];
            args = [].concat(exp.filters[i]);
            args[0] = root;
            root = filters[name].apply(data, args);
        } catch(ex) {
            console.warn('filter failed: ' + name);
            return root;
        }
    }
    return root;
}

完整的一个例子

var fs = require('fs');
var Promise = require('promise');
// QLoader 会自动处理模块依赖关系
var QLoader = require('q-tpl/loader');

// 编译
var q = QLoader.compile({
    root: 'root',
    getQ: function(id) {
        if (id === 'root') {
            return {
                raw: [
                    '<div q-text="list | length"></div>',
                    '<div q-vm="submodule"></div>'
                ].join(''),
                filters: {
                    length: function(list) {
                        return list.length;
                    }
                },
                data: function(loader) {
                    return Promise.resolve({
                        list: [23, 3, 22]
                    });
                }
            };
        } else if (id === 'submodule') {
            return {
                raw: '<h1 q-text="text"></h1>',
                data: function(loader) {
                    return Promise.resolve({
                        text: 'hello world submodule'
                    });
                }
            };
        }
    }
});

module.exports = function(req, res) {
    // 用户请求,输出
    var loader = new Loader(req);
    q(loader).done(function(html) {
        res.write(html);
    });
};

github: [https://github.com/feix760/Q.tpl]

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-09-30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 直出要做什么
  • 原理
  • 实现
  • 完整的一个例子
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档