refactor(component): tagInput/propertyInput/tableData 模板改为懒加载异步获取

原实现三个组件在 JS 顶层用 $.ajax({async:false}) 同步拉取 .html 模板,
每个页面打开固定发 3 个同步请求(阻塞主线程,与组件是否被使用无关),
且路径硬编码 /static/ 与 __STATIC__(OSS 部署)脱节,模板 URL 无版本
参数存在与 js 缓存不同步的漂移问题,请求失败时静默渲染空白。

改造内容:
- 模板改为首次 render() 时异步获取,Deferred 缓存供同页多实例共享,
  失败不缓存并在下次 render 自动重试,失败时 console.error + 提示
- 模板 URL 取 CONFIG.STATIC + CONFIG.STATIC_VERSION,layout 的
  window.CONFIG 新增这两项注入;无注入时逐级回退 /static 与 VERSION,
  兼容下游覆盖 layout 的旧页面
- 组件 CSS 由 _require.html 直接 link 引入(__STATIC__ + 版本键),
  替代原 JS 动态注入
- render() 返回 Promise(resolve Vue 实例);仓库内调用均为
  fire-and-forget,无兼容影响
This commit is contained in:
augushong
2026-10-05 14:08:03 +00:00
parent 14b190d9a8
commit f3ac7189f2
5 changed files with 392 additions and 319 deletions

View File

@@ -1,30 +1,51 @@
(function () {
const propertyInputCss = '/static/plugs/lay-module/propertyInput/propertyInput.css';
const propertyInputHtml = '/static/plugs/lay-module/propertyInput/propertyInput.html';
// 组件模板懒加载:首次 render 时才异步请求,同页多实例共享一次请求;
// 路径与版本跟随页面注入的 CONFIG.STATIC / CONFIG.STATIC_VERSION,
// 与 _require.html 中 js/css 的缓存键保持一致;失败不缓存,下次 render 重试。
// 样式 propertyInput.css 已改为在 _require.html 中直接引入,不再由 JS 注入。
var propertyInputTemplatePromise = null;
var propertyInput = function () {
$(function () {
var cssElement = document.createElement('link');
cssElement.setAttribute('rel', 'stylesheet');
cssElement.setAttribute('href', propertyInputCss);
document.body.appendChild(cssElement);
});
};
var propertyInputTemplate = '';
$.ajax({
type: "get",
url: propertyInputHtml,
cache: true,
async: false,
success: function (template) {
propertyInputTemplate = template;
function loadPropertyInputTemplate() {
if (propertyInputTemplatePromise !== null) {
return propertyInputTemplatePromise;
}
});
var config = window.CONFIG || {};
var staticRoot = config.STATIC || '/static';
var version = config.STATIC_VERSION || config.VERSION || '';
var url = staticRoot + '/plugs/lay-module/propertyInput/propertyInput.html?t=' + version;
var deferred = $.Deferred();
$.ajax({
type: 'get',
url: url,
cache: true,
dataType: 'text'
}).done(function (template) {
if ($.trim(template)) {
deferred.resolve(template);
} else {
deferred.reject('模板内容为空');
}
}).fail(function (xhr) {
deferred.reject(xhr);
});
propertyInputTemplatePromise = deferred.promise();
propertyInputTemplatePromise.fail(function (reason) {
console.error('propertyInput 模板加载失败: ' + url, reason);
var ua = window.UA_ADMIN || window.ua;
if (ua) {
ua.msg.error('propertyInput 组件初始化失败');
}
// 失败不缓存,下次 render 自动重试
propertyInputTemplatePromise = null;
});
return propertyInputTemplatePromise;
}
var propertyInput = function () { };
propertyInput.prototype.render = function (elem, data) {
@@ -184,88 +205,88 @@
}
}
app = new Vue({
el: elem,
data() {
return {
setting: options,
value: '',
listItem: [
return loadPropertyInputTemplate().then(function (template) {
return new Vue({
el: elem,
data() {
return {
setting: options,
value: '',
listItem: [
],
originalValue: '',
field: options.field,
};
},
],
originalValue: '',
field: options.field,
};
},
created() {
if (this.setting.value) {
this.originalValue = $.extend(true, [], this.setting.value);
this.listItem = $.extend(true, [], this.setting.value);
this.updateValue(this.listItem);
created() {
if (this.setting.value) {
this.originalValue = $.extend(true, [], this.setting.value);
this.listItem = $.extend(true, [], this.setting.value);
this.updateValue(this.listItem);
if (this.listItem.length == 0) {
this.onAddItem();
if (this.listItem.length == 0) {
this.onAddItem();
}
}
},
mounted() {
if (options.required == 1) {
$(this.$refs['propertyInput']).closest('.layui-form-item').children('.layui-form-label').addClass('required');
}
},
template: template,
methods: {
onResetItem() {
this.listItem = $.extend(true, [], this.originalValue);
if (this.listItem.length == 0) {
this.onAddItem();
}
this.updateValue(this.listItem);
},
onAddItem() {
var emptyItem = {};
emptyItem.uid = ua.randdomString();
for (var i = 0; i < this.field.length; i++) {
emptyItem[this.field[i].key] = this.field[i].default;
}
this.listItem.push(emptyItem);
this.updateValue(this.listItem);
},
onItemChange(item, index, itemField, event) {
this.listItem[index][itemField.key] = event.target.value;
this.updateValue(this.listItem);
},
onItemDelete(item, index) {
if (this.listItem.length <= 1) {
this.listItem = [
{
name: '',
value: ''
}
];
} else {
this.listItem.splice(index, 1);
}
this.updateValue(this.listItem);
},
updateValue(newValue) {
this.value = JSON.stringify(newValue);
}
}
},
mounted() {
if (options.required == 1) {
$(this.$refs['propertyInput']).closest('.layui-form-item').children('.layui-form-label').addClass('required');
}
},
template: propertyInputTemplate,
methods: {
onResetItem() {
this.listItem = $.extend(true, [], this.originalValue);
if (this.listItem.length == 0) {
this.onAddItem();
}
this.updateValue(this.listItem);
},
onAddItem() {
var emptyItem = {};
emptyItem.uid = ua.randdomString();
for (var i = 0; i < this.field.length; i++) {
emptyItem[this.field[i].key] = this.field[i].default;
}
this.listItem.push(emptyItem);
this.updateValue(this.listItem);
},
onItemChange(item, index, itemField, event) {
this.listItem[index][itemField.key] = event.target.value;
this.updateValue(this.listItem);
},
onItemDelete(item, index) {
if (this.listItem.length <= 1) {
this.listItem = [
{
name: '',
value: ''
}
];
} else {
this.listItem.splice(index, 1);
}
this.updateValue(this.listItem);
},
updateValue(newValue) {
this.value = JSON.stringify(newValue);
}
}
});
});
return app;
};
window.propertyInput = new propertyInput();