magento2与1.x最大的区别是基于knockoutjs实现了web component,每个component都有自己独立的template,knockoutjs会把template动态渲染到页面上。但也由于是动态异步渲染,template的元素渲染完成的时间很难掌握,想用jquery操作渲染完成后的DOM就成了难题。knockoutjs并不鼓励用jquery操作它渲染出来的DOM,但丰富的jquery插件并不对knockoutjs友好,使用jquery几乎不可避免。

要让jquery操作knockoutjs的DOM关键在于template渲染完成后主动向外发出通知,jquery再截获通知。

渲染的核心代码在以下位置:

vendor/magento/module-ui/view/base/web/js/lib/ko/template/renderer.js

copy一份到以下位置实现重写:

app/design/frontend/<vendor>/<theme>/Magento_Ui/web/js/lib/ko/template/renderer.js

把以下代码

render: function (template) {
    var isRendered = $.Deferred(),
        resolve       = isRendered.resolve.bind(isRendered),
        loadTemplate  = this._load.bind(this),
        parseTemplate = this._parse.bind(this);

    loadTemplate(template)
        .then(parseTemplate)
        .done(resolve);

    return isRendered.promise();
}

改为

render: function (template) {
    var isRendered = $.Deferred(),
        resolve       = isRendered.resolve.bind(isRendered),
        loadTemplate  = this._load.bind(this),
        parseTemplate = this._parse.bind(this);

    loadTemplate(template)
        .then(parseTemplate)
        .done(resolve);

    return isRendered.promise().done(function(){
        $('body').trigger('custom.renderer.done', template);
    });
}

然后重建静态文件

grunt deploy

此时只需要在任意phtml文件中编写以下脚本,即可截获事件

require(["jquery"], function ($){
    $('body').on('custom.renderer.done', function(event, template){
        // template为完整模板名
        if(template == 'Magento_Checkout/billing-address/form') {
            // Magento_Checkout/billing-address/form 模板渲染完成
        }
    });
});

猫之良品
2.5k 声望139 粉丝

资深Drupal, magento与Joomla


引用和评论

0 条评论