Skip to content

常见问题

问题列表

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

当你需要在 computedwatch 中响应式地使用主题颜色时,应该传入 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>

注意事项

  1. 响应式使用:状态值在模板中会自动解包 .value,在 <script> 中需要手动访问
  2. 计算属性:使用 $tc 等方法获取计算属性时,记得传入 true 参数
  3. 注意力组件排序:使用 $tAttentionDispatcher 可以统一管理多个提醒组件的显示顺序
  4. 主题切换:切换主题前确保主题已经在系统中注册
  5. Admin 功能:只有在 isActAdminFeaturestrue 时才能使用相关功能
  6. 加密存储:敏感数据建议使用 tStoreCrypto 进行加密存储
  7. 重载选择:需要保持状态时使用 softReload(),需要完全刷新时使用 hardReload()
  8. 路由 Query:使用 updateRouteQuery 不会触发页面刷新,适合动态更新 URL 参数
  9. 浮层挂载:建议使用 $optFloaterTo 而非直接使用 $gFloaterTo,前者会根据自适应状态智能选择
  10. 国际化初始化:在应用启动时应先调用 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>