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 模板渲染完成
}
});
});