mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-10-29 08:58:22 +08:00
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:
@@ -9,6 +9,9 @@
|
||||
<link rel="stylesheet" href="__STATIC__/admin/css/public.css?t={:get_site_version_key()}" media="all">
|
||||
<link rel="stylesheet" href="__STATIC__/common/css/theme/index.css?t={:get_site_version_key()}">
|
||||
<link rel="stylesheet" href="__STATIC__/plugs/wangeditor/style.css">
|
||||
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/tagInput/tagInput.css?t={:get_site_version_key()}">
|
||||
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/propertyInput/propertyInput.css?t={:get_site_version_key()}">
|
||||
<link rel="stylesheet" href="__STATIC__/plugs/lay-module/tableData/tableData.css?t={:get_site_version_key()}">
|
||||
|
||||
<!-- 基础js -->
|
||||
<script src="__STATIC__/plugs/jquery-3.4.1/jquery-3.4.1.min.js?t={:get_site_version_key()}"></script>
|
||||
|
||||
@@ -17,7 +17,13 @@
|
||||
IS_SUPER_ADMIN: "{$isSuperAdmin|default='false'}",
|
||||
VERSION: "{$version|default='1.0.0'}",
|
||||
CSRF_TOKEN: "{:token()}",
|
||||
PAGE_KEY_NAME:'{$pageKeyName|default=$Request.url}'
|
||||
PAGE_KEY_NAME:'{$pageKeyName|default=$Request.url}',
|
||||
// 静态资源根路径(与 __STATIC__ 模板替换一致,OSS 部署时指向 OSS),
|
||||
// 供 JS 内部动态拼接静态资源地址的组件使用(tagInput/propertyInput/tableData 等)
|
||||
STATIC: "__STATIC__",
|
||||
// 静态资源版本键,与 _require.html 中 js/css 的 ?t= 参数同源,
|
||||
// 保证动态请求的模板与引入的 js/css 缓存版本一致
|
||||
STATIC_VERSION: "{:get_site_version_key()}"
|
||||
};
|
||||
|
||||
var PATH_CONFIG = {
|
||||
|
||||
@@ -1,31 +1,52 @@
|
||||
(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) {
|
||||
|
||||
var defaultOption = {
|
||||
@@ -184,7 +205,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
app = new Vue({
|
||||
return loadPropertyInputTemplate().then(function (template) {
|
||||
return new Vue({
|
||||
el: elem,
|
||||
data() {
|
||||
return {
|
||||
@@ -215,7 +237,7 @@
|
||||
$(this.$refs['propertyInput']).closest('.layui-form-item').children('.layui-form-label').addClass('required');
|
||||
}
|
||||
},
|
||||
template: propertyInputTemplate,
|
||||
template: template,
|
||||
|
||||
methods: {
|
||||
onResetItem() {
|
||||
@@ -264,8 +286,7 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return app;
|
||||
});
|
||||
};
|
||||
|
||||
window.propertyInput = new propertyInput();
|
||||
|
||||
@@ -1,29 +1,53 @@
|
||||
(function () {
|
||||
const tableDataCss = '/static/plugs/lay-module/tableData/tableData.css';
|
||||
const tableDataHtml = '/static/plugs/lay-module/tableData/tableData.html';
|
||||
// 组件模板懒加载:首次 render 时才异步请求,同页多实例共享一次请求;
|
||||
// 路径与版本跟随页面注入的 CONFIG.STATIC / CONFIG.STATIC_VERSION,
|
||||
// 与 _require.html 中 js/css 的缓存键保持一致;失败不缓存,下次 render 重试。
|
||||
// 样式 tableData.css 已改为在 _require.html 中直接引入,不再由 JS 注入。
|
||||
var tableDataTemplatePromise = null;
|
||||
|
||||
var tableData = function () {
|
||||
$(function () {
|
||||
var cssElement = document.createElement('link');
|
||||
cssElement.setAttribute('rel', 'stylesheet');
|
||||
cssElement.setAttribute('href', tableDataCss);
|
||||
document.body.appendChild(cssElement);
|
||||
});
|
||||
};
|
||||
var tableDataTemplate = '';
|
||||
function loadTableDataTemplate() {
|
||||
if (tableDataTemplatePromise !== null) {
|
||||
return tableDataTemplatePromise;
|
||||
}
|
||||
|
||||
var config = window.CONFIG || {};
|
||||
var staticRoot = config.STATIC || '/static';
|
||||
var version = config.STATIC_VERSION || config.VERSION || '';
|
||||
var url = staticRoot + '/plugs/lay-module/tableData/tableData.html?t=' + version;
|
||||
var deferred = $.Deferred();
|
||||
|
||||
$.ajax({
|
||||
type: "get",
|
||||
url: tableDataHtml,
|
||||
type: 'get',
|
||||
url: url,
|
||||
cache: true,
|
||||
async: false,
|
||||
success: function (template) {
|
||||
tableDataTemplate = template;
|
||||
dataType: 'text'
|
||||
}).done(function (template) {
|
||||
if ($.trim(template)) {
|
||||
deferred.resolve(template);
|
||||
} else {
|
||||
deferred.reject('模板内容为空');
|
||||
}
|
||||
}).fail(function (xhr) {
|
||||
deferred.reject(xhr);
|
||||
});
|
||||
|
||||
tableDataTemplatePromise = deferred.promise();
|
||||
tableDataTemplatePromise.fail(function (reason) {
|
||||
console.error('tableData 模板加载失败: ' + url, reason);
|
||||
var ua = window.UA_ADMIN || window.ua;
|
||||
if (ua) {
|
||||
ua.msg.error('tableData 组件初始化失败');
|
||||
}
|
||||
// 失败不缓存,下次 render 自动重试
|
||||
tableDataTemplatePromise = null;
|
||||
});
|
||||
|
||||
return tableDataTemplatePromise;
|
||||
}
|
||||
|
||||
var tableData = function () { };
|
||||
|
||||
tableData.prototype.render = function (elem, data) {
|
||||
var app;
|
||||
var clienWidth, clientHeight;
|
||||
clienWidth = '100%';
|
||||
clientHeight = '100%';
|
||||
@@ -65,7 +89,8 @@
|
||||
options.className = 'layui-textarea';
|
||||
}
|
||||
|
||||
app = new Vue({
|
||||
return loadTableDataTemplate().then(function (template) {
|
||||
return new Vue({
|
||||
el: elem,
|
||||
data() {
|
||||
return {
|
||||
@@ -134,7 +159,7 @@
|
||||
$(this.$refs['tableData']).closest('.layui-form-item').children('.layui-form-label').addClass('required');
|
||||
}
|
||||
},
|
||||
template: tableDataTemplate,
|
||||
template: template,
|
||||
|
||||
methods: {
|
||||
openSelectPage() {
|
||||
@@ -180,8 +205,7 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return app;
|
||||
});
|
||||
};
|
||||
|
||||
window.tableData = new tableData();
|
||||
|
||||
@@ -1,31 +1,52 @@
|
||||
(function () {
|
||||
const tagInputCss = '/static/plugs/lay-module/tagInput/tagInput.css';
|
||||
const tagInputHtml = '/static/plugs/lay-module/tagInput/tagInput.html';
|
||||
// 组件模板懒加载:首次 render 时才异步请求,同页多实例共享一次请求;
|
||||
// 路径与版本跟随页面注入的 CONFIG.STATIC / CONFIG.STATIC_VERSION,
|
||||
// 与 _require.html 中 js/css 的缓存键保持一致;失败不缓存,下次 render 重试。
|
||||
// 样式 tagInput.css 已改为在 _require.html 中直接引入,不再由 JS 注入。
|
||||
var tagInputTemplatePromise = null;
|
||||
|
||||
var tagInput = function () {
|
||||
$(function () {
|
||||
var cssElement = document.createElement('link');
|
||||
|
||||
cssElement.setAttribute('rel', 'stylesheet');
|
||||
|
||||
cssElement.setAttribute('href', tagInputCss);
|
||||
|
||||
document.body.appendChild(cssElement);
|
||||
});
|
||||
};
|
||||
var tagInputTemplate = '';
|
||||
|
||||
$.ajax({
|
||||
type: "get",
|
||||
url: tagInputHtml,
|
||||
cache: true,
|
||||
async: false,
|
||||
success: function (template) {
|
||||
tagInputTemplate = template;
|
||||
function loadTagInputTemplate() {
|
||||
if (tagInputTemplatePromise !== null) {
|
||||
return tagInputTemplatePromise;
|
||||
}
|
||||
|
||||
var config = window.CONFIG || {};
|
||||
var staticRoot = config.STATIC || '/static';
|
||||
var version = config.STATIC_VERSION || config.VERSION || '';
|
||||
var url = staticRoot + '/plugs/lay-module/tagInput/tagInput.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);
|
||||
});
|
||||
|
||||
tagInputTemplatePromise = deferred.promise();
|
||||
tagInputTemplatePromise.fail(function (reason) {
|
||||
console.error('tagInput 模板加载失败: ' + url, reason);
|
||||
var ua = window.UA_ADMIN || window.ua;
|
||||
if (ua) {
|
||||
ua.msg.error('tagInput 组件初始化失败');
|
||||
}
|
||||
// 失败不缓存,下次 render 自动重试
|
||||
tagInputTemplatePromise = null;
|
||||
});
|
||||
|
||||
return tagInputTemplatePromise;
|
||||
}
|
||||
|
||||
var tagInput = function () { };
|
||||
|
||||
tagInput.prototype.render = function (elem, data) {
|
||||
|
||||
var defaultOption = {
|
||||
@@ -35,9 +56,8 @@
|
||||
|
||||
var options = $.extend(defaultOption, data);
|
||||
|
||||
|
||||
|
||||
app = new Vue({
|
||||
return loadTagInputTemplate().then(function (template) {
|
||||
return new Vue({
|
||||
el: elem,
|
||||
data() {
|
||||
return {
|
||||
@@ -71,7 +91,7 @@
|
||||
$(this.$refs['tagInput']).closest('.layui-form-item').children('.layui-form-label').addClass('required');
|
||||
}
|
||||
},
|
||||
template: tagInputTemplate,
|
||||
template: template,
|
||||
|
||||
methods: {
|
||||
onInputConfirm(e) {
|
||||
@@ -108,8 +128,7 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return app;
|
||||
});
|
||||
};
|
||||
|
||||
window.tagInput = new tagInput();
|
||||
|
||||
Reference in New Issue
Block a user