常见问题
问题列表
Q1: 如何在非组件文件中使用 $global?
javascript
// utils/helper.js
let globalService = null;
export const setGlobalService = (service) => {
globalService = service;
};
export const useGlobal = () => {
if (!globalService) {
throw new Error('Global service not initialized');
}
return globalService;
};
// main.js 或 App.vue
import { setGlobalService } from './utils/helper';
const $global = inject('$global');
setGlobalService($global);Q2: 计算属性什么时候需要传 true?
当你需要在 computed 或 watch 中响应式地使用主题颜色时,应该传入 true:
javascript
// ✅ 响应式
const color = $tc('primary.main', true);
watch(color, (newColor) => {
// 主题切换时会触发
});
// ❌ 非响应式
const color = $tc('primary.main');
// 主题切换时不会更新Q3: 如何清空所有提醒组件?
可用性:
Scifi
Base
Admin
Prime
javascript
const {
$tMessageCloseAll,
$tNotifyCloseAll,
$tToastClose,
$tFlashClose
} = inject('$global');
const clearAllAttentions = () => {
$tMessageCloseAll();
$tNotifyCloseAll();
$tToastClose();
$tFlashClose();
};Q4: 自适应模式有什么区别?
fixed: 固定布局,不响应窗口变化flexible: 弹性布局,按比例缩放stretch: 拉伸布局,填充可用空间extension: 扩展布局,智能适配多种场景disabled: 禁用自适应
Q5: 如何判断设备类型?
vue
<script setup>
import { inject, computed } from 'vue';
const { $deviceInfo } = inject('$global');
const isMobile = computed(() =>
$deviceInfo.value.type === 'mobile' ||
$deviceInfo.value.touchable
);
const isTablet = computed(() =>
$deviceInfo.value.type === 'tablet'
);
</script>
<template>
<div v-if="isMobile">移动端界面</div>
<div v-else-if="isTablet">平板界面</div>
<div v-else>桌面端界面</div>
</template>Q6: Admin 的 keepAlive 如何工作?
可用性:
Scifi
Base
Admin
Prime
vue
<script setup>
import { inject } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute();
const { tabAdd, keepAliveAdd, $AKeepAlive } = inject('$global');
// 打开新标签页并启用缓存
const openCachedPage = (routeConfig) => {
// 添加标签页
tabAdd({
meta: {
label: 'UserList',
keepAlive: true
},
path: '/user/list'
});
// 添加到缓存列表
keepAliveAdd({ label: 'UserList' });
};
</script>
<template>
<router-view v-slot="{ Component }">
<keep-alive :include="$AKeepAlive">
<component :is="Component" />
</keep-alive>
</router-view>
</template>注意事项
- 响应式使用:状态值在模板中会自动解包
.value,在<script>中需要手动访问 - 计算属性:使用
$tc等方法获取计算属性时,记得传入true参数 - 注意力组件排序:使用
$tAttentionDispatcher可以统一管理多个提醒组件的显示顺序 - 主题切换:切换主题前确保主题已经在系统中注册
- Admin 功能:只有在
isActAdminFeatures为true时才能使用相关功能 - 加密存储:敏感数据建议使用
tStoreCrypto进行加密存储 - 重载选择:需要保持状态时使用
softReload(),需要完全刷新时使用hardReload() - 路由 Query:使用
updateRouteQuery不会触发页面刷新,适合动态更新 URL 参数 - 浮层挂载:建议使用
$optFloaterTo而非直接使用$gFloaterTo,前者会根据自适应状态智能选择 - 国际化初始化:在应用启动时应先调用
initI18n()确保语言数据加载完成
最佳实践
性能优化
vue
<script setup>
import { inject, computed } from 'vue';
const { $gTheme, $tc } = inject('$global');
// ✅ 好的做法:使用计算属性
const primaryColor = $tc('primary.main', true);
// ❌ 避免:在模板中重复调用
// <div :style="{ color: $tc('primary.main') }"></div>
</script>条件渲染
vue
<script setup>
import { inject } from 'vue';
const {
isActAdminFeatures,
isActEchartsFeatures,
$ADMIN
} = inject('$global');
</script>
<template>
<!-- 根据功能启用状态条件渲染 -->
<AdminPanel v-if="isActAdminFeatures" />
<ChartComponent v-if="isActEchartsFeatures" />
</template>错误处理
vue
<script setup>
import { inject } from 'vue';
const { $tLoading, $tLoadingClose, $tMessage } = inject('$global');
const handleAction = async () => {
$tLoading({
appendTo:"#app",
visible: true,
desc:'处理中...',
spinner: 'ringA'
});
try {
await performAction();
$tMessage({ type: 'success', content: '操作成功' });
} catch (error) {
$tMessage({
type: 'error',
content: error.message || '操作失败'
});
} finally {
$tLoadingClose();
}
};
</script>主题适配
vue
<script setup>
import { inject, computed } from 'vue';
const { $gThemeScheme, $tc } = inject('$global');
// 极其特殊的情况下,根据主题明暗方案动态调整样式,通常用不到
const echartsStyle = computed(() => ({
backgroundColor: $gThemeScheme.value === 'dark'
? $tc('common.bg')
: $tc('primary.base'),
color: $gThemeScheme.value === 'dark'
? '#fff'
: '#333'
}));
</script>响应式监听
vue
<script setup>
import { inject, watch } from 'vue';
const { $gResizeCounter, $gTheme } = inject('$global');
// 监听窗口大小变化
watch($gResizeCounter, (newVal) => {
console.log('窗口已调整大小', newVal);
// 执行响应式布局调整
});
// 监听主题变化
watch($gTheme, (newTheme) => {
console.log('主题已切换至', newTheme);
// 执行主题相关处理
});
</script>组件通信
更推荐provide/inject的方式进行组件通信,数据总线的这种通信方式在TechUI中的Tui3DPanel,用于所有同类型的同级Panel组件通信。
vue
<script setup>
import { inject, onMounted, onUnmounted } from 'vue';
const { $tBus } = inject('$global');
onMounted(() => {
// 监听全局事件
$tBus.on('dataUpdate', handleDataUpdate);
});
onUnmounted(() => {
// 清理监听器
$tBus.off('dataUpdate', handleDataUpdate);
});
const handleDataUpdate = (data) => {
console.log('收到数据更新', data);
};
const notifyOthers = () => {
// 发送全局事件
$tBus.emit('dataUpdate', { id: 1, name: 'test' });
};
</script>安全存储
vue
<script setup>
import { inject } from 'vue';
const { tStoreCrypto, openEnc, openDec } = inject('$global');
// 存储敏感数据
const saveUserCredentials = (credentials) => {
// 方式1: 使用 tStoreCrypto
tStoreCrypto.s('local','userCred', credentials);
// 方式2: 使用 openEnc/openDec
const encrypted = openEnc(credentials);
localStorage.setItem('userCred', encrypted);
};
// 读取敏感数据
const loadUserCredentials = () => {
// 方式1
return tStoreCrypto.g('local','userCred');
// 方式2
const encrypted = localStorage.getItem('userCred');
return openDec(encrypted);
};
</script>