前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Qjs直出实现过程

Qjs直出实现过程

作者头像
腾讯IVWEB团队
发布2020-06-27 23:44:45
5150
发布2020-06-27 23:44:45
举报
文章被收录于专栏:腾讯IVWEB团队的专栏

直出要做什么

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

输入:

代码语言:javascript
复制
<div q-text="name"></div>
代码语言:javascript
复制
{"name": "Qjs"}

直出:

代码语言:javascript
复制
<div q-text="name">Qjs</div>

原理

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

编译:

代码语言:javascript
复制
<div q-text="name">Qjs</div>
<div q-class="red: isRed"></div>

处理directives编译成underscore模板:

代码语言:javascript
复制
<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

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

获得的模板

代码语言:javascript
复制
<div q-text="list | length"><%- __filterValue(__obj, {"arg":null,"name":"list","filters":[["length"]]}) %></div>

q-show

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

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

子模块:

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

代码语言:javascript
复制
<div q-vm="head_module"><%= _vm[0] %></div>

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

代码语言:javascript
复制
var output = compiled(_.extend({}, data, {
    _vm: '<div>head_module</div>'
}});

filters异常:

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

代码语言:javascript
复制
filters.width = function(val) {
    return Match.min(val, $(window).width());
};

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

代码语言:javascript
复制
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;
}

完整的一个例子

代码语言:javascript
复制
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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

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